||This article uses bare URLs for citations, which may be threatened by link rot. (June 2017) (Learn how and when to remove this template message)|
|This article needs additional or better citations for verification. (January 2007) (Learn how and when to remove this template message)|
In computing, position-independent code (PIC) or position-independent executable (PIE) is a body of machine code that, being placed somewhere in the primary memory, executes properly regardless of its absolute address. PIC is commonly used for shared libraries, so that the same library code can be loaded in a location in each program address space where it will not overlap any other uses of memory (for example, other shared libraries). PIC was also used on older computer systems lacking an MMU, so that the operating system could keep applications away from each other even within the single address space of an MMU-less system.
Position-independent code can be executed at any memory address without modification. This differs from relocatable code, in which a link editor or program loader modifies a program before execution so it can be run only from a particular memory location. Generating position-independent code is often the default behavior for compilers, but they may place restrictions on the use of some language features, such as disallowing use of absolute addresses (position-independent code has to use relative addressing). Instructions that refer directly to specific memory addresses sometimes execute faster, and replacing them with equivalent relative-addressing instructions may result in slightly slower execution, although modern processors make the difference practically negligible.
In early computers such as the IBM System/360 (1965), code was position-dependent: each program was built to be loaded into, and run from, a particular address. Where a multitasking operating system allowed multiple jobs to be run using separate programs at the same time, operations had to be scheduled such that no two concurrent jobs would run programs that required the same load addresses. For example, both a payroll program and an accounts receivable program built to run at address 32K could not both be run at the same time.
IBM DOS/360 (1966) did not have the ability to relocate programs during loading. Sometimes multiple versions of a program were maintained, each built for a different load address. A special class of programs, called self-relocating programs, were coded to relocate themselves after loading. IBM OS/360 (1966) relocated executable programs when they were loaded into memory. Only one copy of the program was required, but once loaded the program could not be moved.
By way of comparison, on early segmented or base and bounds systems such as Burroughs B5000 (1961) and Multics (1964), code was inherently position-independent, since addresses in a program were relative to the current segment rather than absolute.
Position-independent code was developed to eliminate these restrictions for non-segmented systems. A position-independent program could be loaded at any address in memory.
The invention of dynamic address translation (the function provided by an MMU) originally reduced the need for position-independent code because every process could have its own independent address space (range of addresses). However, multiple simultaneous jobs using the same code created a waste of physical memory. If two jobs run entirely identical programs, dynamic address translation provides a solution by allowing the system simply to map two different jobs' address 32K to the same bytes of real memory, containing the single copy of the program.
Different programs may share common code. For example, the payroll program and the accounts receivable program may both contain an identical sort subroutine. A shared module (a shared library is a form of shared module) gets loaded once and mapped into the two address spaces.
Procedure calls inside a shared library are typically made through small procedure linkage table stubs, which then call the definitive function. This notably allows a shared library to inherit certain function calls from previously loaded libraries rather than using its own versions.
Data references from position-independent code are usually made indirectly, through global offset tables (GOTs), which store the addresses of all accessed global variables. There is one GOT per compilation unit or object module, and it is located at a fixed offset from the code (although this offset is not known until the library is linked). When a linker links modules to create a shared library, it merges the GOTs and sets the final offsets in code. It is not necessary to adjust the offsets when loading the shared library later.
Position independent functions accessing global data start by determining the absolute address of the GOT given their own current program counter value. This often takes the form of a fake function call in order to obtain the return value on stack (x86) or in a special register (PowerPC, SPARC, MIPS, probably at least some other RISC processors[weasel words], ESA/390), which can then be stored in a predefined standard register. Some processor architectures, such as the Motorola 68000, Motorola 6809, WDC 65C816, Knuth's MMIX, ARM and x86-64 allow referencing data by offset from the program counter. This is specifically targeted at making position-independent code smaller, less register demanding and hence more efficient.
|This section does not cite any sources. (January 2015) (Learn how and when to remove this template message)|
Dynamic-link libraries (DLLs) in Microsoft Windows use variant E8 of the CALL instruction (Call near, relative, displacement relative to next instruction). These instructions do not need to be fixed up when a DLL is loaded.
Some global variables (e.g. arrays of string literals, virtual function tables) are expected to contain an address of an object in data section resp. in code section of the dynamic library; therefore, the stored address in the global variable needs to be updated to reflect the address where the DLL was loaded to. The dynamic loader calculates the address referred to by a global variable and stores the value in such global variable; this triggers copy-on-write of a memory page containing such global variable. Pages with code and pages with global variables that do not contain pointers to code or global data remain shared between processes. This operation needs to be done in any OS that can load a dynamic library at arbitrary address.
In Windows Vista and later versions of Windows, the relocation of DLLs and executables is done by the kernel memory manager, which shares the relocated binaries across multiple processes. Images are always relocated from their preferred base addresses, achieving address space layout randomization (ASLR).
Versions of Windows prior to Vista require system DLLs to be prelinked at non-conflicting fixed addresses at the link time in order to avoid runtime relocation of images. Runtime relocation in these older versions of Windows is performed by the DLL loader within the context of each process, and the resulting relocated portions of each image can no longer be shared between processes.
The handing of DLLs in Windows differs from the earlier OS/2 procedure from which it derives. OS/2 presents a third alternative and attempts to load DLLs that are not position-independent into a dedicated "shared arena" in memory, and maps them once they are loaded. All users of the DLL are able to use the same in-memory copy.
Position-independent executables (PIE) are executable binaries made entirely from position-independent code. While some systems only run PIC executables, there are other reasons they are used. PIE binaries are used in some security-focused Linux distributions to allow PaX or Exec Shield to use address space layout randomization to prevent attackers from knowing where existing executable code is during a security attack using exploits that rely on knowing the offset of the executable code in the binary, such as return-to-libc attacks.
Apple's Mac OS X and iOS fully support PIE executables as of versions 10.7 and 4.3, respectively; a warning is issued when non-PIE iOS executables are submitted for approval to Apple's App Store but there's no hard requirement yet and non-PIE applications are not rejected.
OpenBSD has PIE enabled by default on most architectures since OpenBSD 5.3, released on 1 May 2013. Support for PIE in statically linked binaries, such as the executables in
/sbin directories, was added near the end of 2014. Beginning with Fedora 23, Fedora maintainers decided to build packages with PIE enabled as the default. Ubuntu 17.10 will have PIE enabled by default across all architectures, to be released on 19 October 2017.
- John R. Levine (October 1999). "Chapter 8: Loading and overlays". Linkers and Loaders. San Francisco: Morgan-Kauffman. pp. 170–171. ISBN 1-55860-496-0.
- Alexander Gabert (January 2004). "Position Independent Code internals". Hardened Gentoo. Retrieved 2009-12-03.
direct non-PIC-aware addressing is always cheaper (read: faster) than PIC addressing.
- "iphone - Non-PIE Binary - The executable 'project name' is not a Position Independent Executable. - Stack Overflow". stackoverflow.com.
- "iOS Developer Library". apple.com.
- "OpenBSD 5.3 Release". 2013-05-01. Retrieved 2014-10-10.
- "Heads Up: Snapshot Upgrades for Static PIE". 2014-12-24. Retrieved 2014-12-24.
- "Changes/Harden All Packages - FedoraProject". fedoraproject.org.
- "Ubuntu Foundations Team - Weekly Newsletter, 21017-06-15". 2017-06-15. Retrieved 2017-06-17.
- "Security Enhancements in Android 1.5 through 4.1 - Android Open Source Project". Android Open Source Project.
- "Security Enhancements in Android 5.0 - Android Open Source Project". Android Open Source Project.
- John R. Levine (October 1999). "Chapter 8: Loading and overlays". Linkers and Loaders. Morgan-Kauffman. ISBN 1-55860-496-0.