Before a program’s Process Control Block (PCB) is ready for dispatch, the operating system must perform a crucial setup stage involving the dynamic linker to ensure the executable can run securely and share memory efficiently. This process addresses the problem of relocation, which dictates that a program must function correctly regardless of where the kernel decides to load it into the virtual address space. For programs that use shared libraries, this is achieved through the generation of Position-Independent Code (PIC). PIC is code compiled such that its instructions use relative, rather than absolute, addressing, allowing the same library code to be mapped into the memory spaces of multiple processes without modification.
The core mechanisms facilitating PIC are the Global Offset Table (GOT) and the Procedure Linkage Table (PLT). The GOT is a table within the program’s data segment that contains all the absolute memory addresses of external functions and global variables the program needs to access. The PLT is a small section of executable code that acts as a jump table. When the program first calls an external library function (like printf), the instruction jumps to an entry in the PLT, which initially directs the execution back to the Dynamic Linker. The linker then locates the required function in the shared library, writes its actual memory address into the corresponding GOT entry, and directs execution to the now-resolved function. On all subsequent calls to that function, the PLT entry jumps straight to the GOT, which now holds the final, correct address. This lazy, on-demand resolution minimizes startup time and allows the core instruction code to remain completely independent of the run-time memory location, which is the defining characteristic of efficient dynamic linking.
