2026-04-30
You've seen how the linker resolves symbols and how ELF organizes binaries. But there's a critical mechanism bridging them: relocations. A relocation is an instruction left by the compiler saying "I don't know this address yet — patch it in later." Understanding relocations demystifies linker errors and is essential for writing code that links correctly across shared libraries and architectures.
When the compiler emits an object file, it can't know the final address of external symbols or even the final position of its own sections. Instead, it emits placeholder values (usually zero) and records a relocation entry in the .rela.text or .rela.dyn sections. Each entry contains three things:
On x86-64, the most common relocation types are:
S + A - P (symbol address + addend - patch location). Used for local function calls and branch targets.Real-world example: compile a simple file and inspect its relocations:
gcc -c foo.c -o foo.o && readelf -r foo.o
You'll see entries like R_X86_64_PLT32 printf - 4, meaning "at this offset, patch in a PC-relative jump to printf, minus 4 bytes because the offset is measured from the end of the instruction." The -4 addend accounts for the 4-byte displacement field in the call instruction itself.
Rule of thumb for relocation limits: R_X86_64_PC32 uses a signed 32-bit displacement, limiting the distance between the call site and target to ±2 GB. This is why the "small" code model works for executables under 2 GB but large shared libraries or address-space-hungry programs need -mcmodel=medium or -mcmodel=large.
Static linking resolves all relocations at link time, producing a fully patched binary. Dynamic linking defers some relocations to load time (or even later with lazy binding). The dynamic linker processes entries in .rela.dyn (data relocations) eagerly at startup and .rela.plt (function call relocations) lazily on first call — unless you set LD_BIND_NOW=1, which forces all relocations upfront. This is why startup time increases with more shared library dependencies: each imported symbol requires a relocation to resolve.
