When you link a shared library, the linker can't know where the library will be loaded in memory. Every reference to an external symbol (like calling printf from your library) needs to be patched at load time by the dynamic linker (ld.so).
Dynamic relocations are the mechanism that makes shared libraries work — they're the "fill in the blanks later" instructions that ld.so processes when loading your program.
Think of dynamic relocations as a to-do list for ld.so:
Most dynamic relocations use lazy binding — function addresses are resolved on first call, not at load time. This speeds up program startup.
Dynamic relocations live in two sections:
| Section | Purpose | Processed By | When |
|---|---|---|---|
| .rela.dyn | Data references, global offsets | ld.so (or static linker) | Load time |
| .rela.plt | Function calls via PLT | ld.so (lazy) | First call |
The most common dynamic relocation types on x86-64:
| Type | Value | Formula | Usage |
|---|---|---|---|
| R_X86_64_RELATIVE | 8 | B + A | Base address + addend (PIC data in shared libs) |
| R_X86_64_GLOB_DAT | 6 | S | Global variable address (GOT entry) |
| R_X86_64_JUMP_SLOT | 7 | S | Function address (PLT/GOT entry, lazy binding) |
| R_X86_64_64 | 1 | S + A | Absolute 64-bit (non-PIC data) |
Where:
$ readelf -rW /usr/lib/x86_64-linux-gnu/libc.so.6 | head -20 Relocation section '.rela.dyn' at offset 0x... contains 450 entries: Offset Info Type Sym. Value Sym. Name + Addend 0000003bc028 000000000008 R_X86_64_RELATIVE 1a1230 0000003bc030 000000000008 R_X86_64_RELATIVE 1a11f0 0000003be018 002400000006 R_X86_64_GLOB_DAT 00000000003c2018 __environ 0000003be020 002500000006 R_X86_64_GLOB_DAT 00000000003c2020 __progname Relocation section '.rela.plt' at offset 0x... contains 30 entries: Offset Info Type Sym. Value Sym. Name + Addend 0000003be0c8 000300000007 R_X86_64_JUMP_SLOT 0000000000123456 read + 0 0000003be0d0 000400000007 R_X86_64_JUMP_SLOT 0000000000123789 write + 0
The lazy binding mechanism:
# See dynamic relocations in a shared library readelf -rW /usr/lib/x86_64-linux-gnu/libc.so.6 | head -30 # See dynamic relocations in your own program gcc -o myprog myprog.c readelf -rW myprog | grep -E 'JUMP_SLOT|GLOB_DAT' # Watch lazy binding in action with strace strace -e trace=open,read,write ./myprog 2>1 | head -20 # Force eager binding (disable lazy) LD_BIND_NOW=1 ./myprog
What is the difference between R_X86_64_GLOB_DAT and R_X86_64_JUMP_SLOT?
What happens if you set LD_BIND_NOW=1?
Dynamic relocations are processed by the dynamic linker. The next module covers dynamic linking in depth — the .dynamic section, shared library dependencies, and how ld.so orchestrates everything.