A dynamically linked program or shared object has a PT_DYNAMIC segment
(the .dynamic section, labelled by the symbol _DYNAMIC): an
array of tag–value pairs that tells the dynamic linker what to load and how to
relocate. This page follows the gABI chapter 5, with GNU additions from glibc’s
elf.h.
Dynamic entry
| Offset 32 | Offset 64 | Type 32 / 64 | Field | Meaning |
|---|---|---|---|---|
0x00 | 0x00 | Sword / Sxword | d_tag | The tag, below. |
0x04 | 0x08 | Word / Xword or Addr | d_un | d_val (an integer) or d_ptr (a virtual address), as the tag says. |
Entries are 8 or 16 bytes. The array ends with DT_NULL. Apart from that
and the order of DT_NEEDED entries, order does not matter. Addresses are
not relocated in the file; the dynamic linker adds the base address. Even tags use
d_ptr and odd tags d_val or nothing, except tags below
DT_ENCODING and between DT_HIOS and
DT_LOPROC.
DT_FLAGS
| Value | Name | Meaning |
|---|---|---|
0x1 | DF_ORIGIN | The object may use $ORIGIN |
0x2 | DF_SYMBOLIC | Look up symbols in this object first |
0x4 | DF_TEXTREL | Relocations may modify a non-writable segment |
0x8 | DF_BIND_NOW | Do all relocations before running the program (no lazy binding) |
0x10 | DF_STATIC_TLS | Uses static TLS: must not be loaded dynamically |
DT_FLAGS_1 (glibc)
| Value | DF_1_ | Value | DF_1_ |
|---|---|---|---|
0x1 | NOW | 0x10000 | DISPRELPND |
0x2 | GLOBAL | 0x20000 | NODIRECT |
0x4 | GROUP | 0x40000 | IGNMULDEF |
0x8 | NODELETE | 0x80000 | NOKSYMS |
0x10 | LOADFLTR | 0x100000 | NOHDR |
0x20 | INITFIRST | 0x200000 | EDITED |
0x40 | NOOPEN | 0x400000 | NORELOC |
0x80 | ORIGIN | 0x800000 | SYMINTPOSE |
0x100 | DIRECT | 0x1000000 | GLOBAUDIT |
0x200 | TRANS | 0x2000000 | SINGLETON |
0x400 | INTERPOSE | 0x4000000 | STUB |
0x800 | NODEFLIB | 0x8000000 | PIE |
0x1000 | NODUMP | 0x10000000 | KMOD |
0x2000 | CONFALT | 0x20000000 | WEAKFILTER |
0x4000 | ENDFILTEE | 0x40000000 | NOCOMMON |
0x8000 | DISPRELDNE |
DT_FEATURE_1: DTF_1_PARINIT 0x1,
DTF_1_CONFEXP 0x2. DT_POSFLAG_1:
DF_P1_LAZYLOAD 0x1, DF_P1_GROUPPERM 0x2. The sources read
give no further meaning for these GNU and Sun flags than their names.
Hash table (DT_HASH)
An array of Words, the same in 32-bit and 64-bit files:
| Field | Count | Meaning |
|---|---|---|
nbucket | 1 | Number of buckets |
nchain | 1 | Number of chain entries: the number of symbols |
bucket | nbucket | Symbol index of the first symbol in each bucket |
chain | nchain | For each symbol, the next symbol index in its chain, or STN_UNDEF |
To look up a name, compute its hash h, start at
bucket[h % nbucket] and follow chain until the name matches
or the index is STN_UNDEF. The hash function:
h = 0
for each byte c of the name:
h = (h << 4) + c
g = h & 0xF0000000
if g != 0: h ^= g >> 24
h &= ~g
return h
The GNU hash table (DT_GNU_HASH, SHT_GNU_HASH) has a
different layout that none of the sources read describes; it is not covered here.
Symbol versioning (GNU)
Three sections: .gnu.version (SHT_GNU_versym) has one
Half per dynamic symbol giving its version index;
.gnu.version_d (SHT_GNU_verdef) defines versions;
.gnu.version_r (SHT_GNU_verneed) lists versions needed
from other files. Their structures, from glibc (the same in 32-bit and 64-bit
files):
Version index values
| Value | Name |
|---|---|
0 | VER_NDX_LOCAL |
1 | VER_NDX_GLOBAL |
0xFF00 | VER_NDX_LORESERVE |
0xFF01 | VER_NDX_ELIMINATE |
Verdef (20 bytes)
| Offset | Type | Field | Meaning |
|---|---|---|---|
0 | Half | vd_version | Structure revision: VER_DEF_CURRENT (1); 0 is VER_DEF_NONE |
2 | Half | vd_flags | VER_FLG_BASE 0x1, VER_FLG_WEAK 0x2 |
4 | Half | vd_ndx | Version index used in .gnu.version |
6 | Half | vd_cnt | Number of Verdaux entries |
8 | Word | vd_hash | Hash of the version name |
12 | Word | vd_aux | Offset in bytes to the Verdaux array |
16 | Word | vd_next | Offset in bytes to the next Verdef |
Verdaux (8 bytes): vda_name (Word, string offset of a version or
dependency name), vda_next (Word, offset to the next Verdaux).
Verneed (16 bytes)
| Offset | Type | Field | Meaning |
|---|---|---|---|
0 | Half | vn_version | Structure version: VER_NEED_CURRENT (1); 0 is VER_NEED_NONE |
2 | Half | vn_cnt | Number of Vernaux entries |
4 | Word | vn_file | String offset of the file name of this dependency |
8 | Word | vn_aux | Offset in bytes to the Vernaux array |
12 | Word | vn_next | Offset in bytes to the next Verneed |
Vernaux (16 bytes)
| Offset | Type | Field | Meaning |
|---|---|---|---|
0 | Word | vna_hash | Hash of the dependency (version) name |
4 | Half | vna_flags | Dependency-specific flags |
6 | Half | vna_other | Unused, per glibc’s comment |
8 | Word | vna_name | String offset of the name |
12 | Word | vna_next | Offset in bytes to the next Vernaux |
Syminfo and move entries (Sun)
Syminfo (4 bytes): si_boundto (Half; 0xFFFF
self, 0xFFFE parent, from 0xFF00 reserved) and
si_flags (Half; 0x1 direct, 0x2 pass-through, 0x4 copy, 0x8 lazy load).
Move entries (32-bit form) hold m_value (Xword),
m_info (Word: symbol index in the bits above 8, size in the low byte), m_poffset (Word),
m_repeat and m_stride (Half each).
Dependencies and search order
- Each
DT_NEEDEDobject is loaded once. Symbols are resolved breadth first: the executable, its dependencies in order, then theirs. - A name with a slash is a path. Otherwise the linker searches
LD_LIBRARY_PATH, then the needing object’sDT_RUNPATH(which applies to its own dependencies only), then default directories such as/usr/lib.DT_RPATHis searched beforeLD_LIBRARY_PATHand ignored ifDT_RUNPATHexists. Set-ID programs ignoreLD_LIBRARY_PATH. $ORIGIN(or${ORIGIN}) inDT_NEEDED,DT_RUNPATHordlopen()paths is the directory of the object that contains it.- Dependencies are initialised before the objects that need them, and the
executable last;
DT_INITruns beforeDT_INIT_ARRAY,DT_FINI_ARRAY(in reverse) beforeDT_FINI.
Sources
- gABI chapter 5: Dynamic Linking – dynamic entry, tags 0–34, ranges, DT_FLAGS, hash table and function, search order, $ORIGIN, initialisation order
- glibc elf.h – RELR tags, GNU and Sun tags, DF_1, DTF_1 and DF_P1 flags, versioning structures and constants, Syminfo and Move
- elf(5) – the versioning section names