||This article needs additional citations for verification. (January 2007)|
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 copied to any memory location and executed without modification. This differs from relocatable code, which requires special processing by a link editor or program loader to make it suitable for execution at a given location. Position independent code must adhere to a specific set of semantics in the source code and compiler support is required. Instructions that refer to specific memory addresses, such as absolute branches, must be replaced with equivalent program counter relative instructions. The extra indirection may cause PIC to be less efficient, although modern processors make the difference practically negligible.
In early computers, code was position-dependent: each program was built to be loaded into, and run from, a particular address. In order to run multiple jobs using separate programs at the same time, an operator had to carefully schedule the jobs so that no two simultaneous jobs would run programs that required the same load addresses. For example, if both the payroll program and the accounts receivable program were built to run at address 32K, the operator could not run both at the same time. Sometimes, an operator would keep multiple versions of a program around, each built for a different load address, to expand his options.
To make things more flexible, position-independent code was invented. Position-independent code could run from any address at which the operator chose to load it.
The invention of dynamic address translation (the function provided by an MMU) almost made position-independent code obsolete because every process could have its own separate 32-bit (or even more) address space. Because position-independent code is less efficient than position-dependent code, this was a better solution to the problem.
The next problem to be attacked was the memory waste that happens when the same code is loaded multiple times to be used by multiple simultaneous jobs. 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.
But more often, the programs are different and merely share a lot of common code. For example, the payroll program and the accounts receivable program probably both contain an identical sort subroutine. So designers invented shared modules (a shared library is a form of shared module). While the main payroll and accounts receivable programs get loaded into separate memory, the shared module gets loaded once and simply mapped into the two address spaces.
Position-independent code has been used not only to coordinate the work of user-level applications, but within operating systems as well. The earliest paging systems did not use virtual memory address spaces; instead, the operating system would explicitly load individual modules of itself as needed, overwriting less needed ones (the memory available for the operating system was much smaller than the operating system). A module had to be capable of running in whatever memory was free at the time it was needed, so individual operating system modules were made of position-independent code.
The invention of virtual memory made that method obsolete, because the operating system could have a virtual address space so big that every module of the operating system could have its own permanent virtual address.
Technical details 
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, 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.
Windows DLLs 
|This section's factual accuracy may be compromised due to out-of-date information. (April 2013)|
Microsoft Windows DLLs are not shared libraries in the Unix sense and do not use position independent code. This means they cannot have their routines overridden by previously loaded DLLs and require small tricks for sharing selected global data. Code has to be relocated after it has been loaded from disk, making it potentially non-shareable between processes; sharing mostly occurs on disk.
To alleviate this limitation, almost all Windows system DLLs are pre-mapped at different fixed addresses in such a way that there is no conflict. It is not necessary to relocate the libraries before using them and memory can be shared. Even pre-mapped DLLs still contain information which allows them to be loaded at arbitrary addresses if necessary.
A sharing technique Windows calls "memory mapping" is sometimes able to allow multiple processes to share an instance of a DLL loaded into memory. However, the reality is that Windows is not always able to share one instance of a DLL loaded by multiple processes. Windows requires each compiled program to know where in its address space each DLL will be accessed — there is no support for position independence.
A DLL specifies its desired base address when it is created, called its RVA (Visual C++ defaults to an offset of 0x10000000). However, if multiple DLLs have the same desired base address, a program cannot relocate them all to that base offset and must specify new offsets when linking. When the Windows loader loads an executable into memory for execution, it checks to see if each DLL has already been loaded with the offset used when the executable was created (not the DLL). If the DLL is not already loaded with that offset, it is relocated to the base requested by the executable. Note that this will provide sharing across multiple processes of the same executable (e.g. if started in different accounts via Fast User Switching), but not necessarily across different programs that link to the same DLL.
Other platforms such as Mac OS X and Linux now support forms of prebinding as well. For Mac OS X the system is called prebinding. Under Linux, the system used is implemented via a program called prelink. This is vastly different from memory mapping.
In the Itanium version of Microsoft Windows, the system has been altered to use position-independent code, however X64 versions still use standard relocation techniques alongside position independent methods and thus cannot be considered true "position independent" libraries.
Position-independent executables 
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. Windows NT uses address space layout randomization since Windows Vista.
See also 
- 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."
- Rick Anderson (January 2000). "The End of DLL Hell". Microsoft Developer Network. Retrieved 2007-04-26. "Sharing common DLLs does provide a significant savings on memory load. But Windows is not always able to share one instance of a DLL that is loaded by multiple processes."
- Matt Pietrek (February 2002). "An In-Depth Look into the Win32 Portable Executable File Format". MSDN Magazine. Retrieved 2012-01-28. "PE files can load just about anywhere in the process address space. While they do have a preferred load address, you can't rely on the executable file actually loading there. To avoid having hardcoded memory addresses in PE files, RVAs are used. An RVA is simply an offset in memory, relative to where the PE file was loaded."
- Matt Pietrek (December 2000). "MSDN Magazine - Under the Hood - Programming for 64-bit Windows". Retrieved 2011-02-09. "Position-independent code eliminates the need for the base relocations that are used in the x86 version of Windows."
- Ken Johnson (November 2007). "Nynaeve - Adventures in Windows debugging and reverse engineering.". Retrieved 2012-10-21. "For example, the base relocation information (not including alignment padding) on the 64-bit ntdll.dll (for Windows Vista) is a mere 560 bytes total, compared to 18092 bytes in the Wow64 (x86) version."
Further reading 
- John R. Levine (October 1999). "Chapter 8: Loading and overlays". Linkers and Loaders. Morgan-Kauffman. ISBN 1-55860-496-0.
- Introduction to Position Independent Code
- Position Independent Code internals
- Programming in Assembly Language with PIC