Keyboard Shortcuts

Ctrl+K
Open search
Esc
Close search / dialog
↑
Back to top

Dynamic Relocations

18 minintermediateModule 6: RelocationsContinues from relocation-types

Why This Matters

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.

A Simple Model

Think of dynamic relocations as a to-do list for ld.so:

  1. Load the program and all shared libraries into memory
  2. Process .rela.dyn — patch data references (global variables, GOT entries)
  3. Process .rela.plt — set up PLT stubs for lazy function binding
  4. Jump to the program's entry point

Most dynamic relocations use lazy binding — function addresses are resolved on first call, not at load time. This speeds up program startup.

The Actual Detail

Dynamic relocations live in two sections:

SectionPurposeProcessed ByWhen
.rela.dynData references, global offsetsld.so (or static linker)Load time
.rela.pltFunction calls via PLTld.so (lazy)First call

The most common dynamic relocation types on x86-64:

TypeValueFormulaUsage
R_X86_64_RELATIVE8B + ABase address + addend (PIC data in shared libs)
R_X86_64_GLOB_DAT6SGlobal variable address (GOT entry)
R_X86_64_JUMP_SLOT7SFunction address (PLT/GOT entry, lazy binding)
R_X86_64_641S + AAbsolute 64-bit (non-PIC data)

Where:

A Real Example

$ 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:

  1. At load time, ld.so writes the address of a resolver stub into each JUMP_SLOT GOT entry
  2. When the program first calls read(), it jumps through the PLT to the GOT entry
  3. The GOT entry points to the resolver stub (not the actual function yet)
  4. The resolver stub calls ld.so's _dl_runtime_resolve()
  5. ld.so finds the real read() address, writes it into the GOT, and jumps to it
  6. On subsequent calls, the GOT entry points directly to read() — no resolver overhead

Try It

# 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

Check Your Understanding

What is the difference between R_X86_64_GLOB_DAT and R_X86_64_JUMP_SLOT?

Apply It

What happens if you set LD_BIND_NOW=1?

Connect

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.

← Swipe to navigate →