The relocation type determines how the linker computes the value to patch into the binary. Different types produce different addressing modes — absolute addresses, PC-relative offsets, GOT entries, PLT calls. Choosing the wrong type means broken code.
Understanding relocation types explains why position-independent code (PIC) works differently from non-PIC, and why shared libraries use different call mechanisms than executables.
There are two fundamental ways to reference a symbol:
PC-relative is the default for modern code because it's position-independent — the code works at any address without patching.
The most common x86-64 relocation types:
| Type | Value | Formula | Usage |
|---|---|---|---|
| R_X86_64_64 | 1 | S + A | Absolute 64-bit address (data references) |
| R_X86_64_PC32 | 2 | S + A - P | 32-bit PC-relative (call/jmp in non-PIC) |
| R_X86_64_PLT32 | 4 | L + A - P | 32-bit PC-relative via PLT (function calls) |
| R_X86_64_GOTPCRELX | 41 | G + GOT + A - P | PC-relative to GOT entry (optimized PIC) |
| R_X86_64_32 | 10 | S + A (truncated) | 32-bit absolute (non-PIE, low memory) |
Where:
Key differences between R_X86_64_PC32 and R_X86_64_PLT32:
# Non-PIE executable -- uses R_X86_64_PLT32 # test.c: helper() returns 42, caller() calls helper() $ gcc -no-pie -c test.c $ readelf -rW test.o 00000000000a 000300000004 R_X86_64_PLT32 0000000000000000 helper - 4 # PIE executable -- uses R_X86_64_GOTPCRELX (optimized PIC) $ gcc -pie -c test.c $ readelf -rW test.o 00000000000a 000300000029 R_X86_64_GOTPCRELX 0000000000000000 helper - 8
The PLT32 relocation generates a direct call instruction. The GOTPCRELX relocation generates a lea + call *reg sequence that goes through the GOT for lazy binding.
# Compare relocation types: PIE vs non-PIE # compare.c: calls an external function # Non-PIE: PLT32 gcc -no-pie -c compare.c readelf -rW compare.o | grep external # PIE: GOTPCRELX gcc -pie -c compare.c readelf -rW compare.o | grep external # See the generated assembly difference gcc -no-pie -S compare.c -o - | grep call gcc -pie -S compare.c -o - | grep call
What does R_X86_64_PLT32 compute?
Why does PIE code use R_X86_64_GOTPCRELX instead of R_X86_64_PLT32?
Static relocations are resolved at link time. But shared libraries also need dynamic relocations — patches applied by ld.so at load time. That's the next concept.
Sort the relocation types from simplest (least work at link time) to most complex (most work):