Linkers, Loaders & Object Formats

the dynamic section

When the dynamic linker takes over at startup, it needs a set of instructions: which libraries to load, where the symbol table is, where to find the relocations, and so on. That instruction list lives in the .dynamic section of the ELF file — a compact array of tagged entries that is essentially the dynamic linker's to-do list and lookup directory rolled into one. Each entry is a pair: a tag saying what kind of information this is, and a value (often an address or an offset into a string table).

A few tags are worth knowing by name. DT_NEEDED entries name the shared libraries this object directly depends on — one DT_NEEDED per library, like 'libc.so.6' and 'libssl.so.3' — and the dynamic linker loads each of them. DT_SONAME records this library's own canonical name. DT_STRTAB and DT_SYMTAB point at the dynamic string and symbol tables. And two closely related tags control search: DT_RPATH and the newer DT_RUNPATH embed a list of directories, baked into the binary, where the dynamic linker should look for the needed libraries. The difference between them is subtle but real: RPATH is consulted before the LD_LIBRARY_PATH environment variable, while the newer RUNPATH is consulted after it, so RUNPATH lets a user override the baked-in path and is the recommended one; RPATH is deprecated for that reason.

It matters because the .dynamic section is the contract between a binary and the dynamic linker — change it and you change which libraries load and from where. Tools like patchelf edit these tags to fix a binary's library paths after the fact. A common real-world trap is RPATH/RUNPATH containing an insecure or relative directory: if a binary searches a writable directory before the system ones, an attacker who can drop a malicious .so there can hijack the program. The use of $ORIGIN in a RUNPATH (meaning 'the directory the binary lives in') is the safe, common way to ship a program with its own bundled libraries.

$ readelf -d app Tag Type Name/Value (NEEDED) Shared lib [libc.so.6] (NEEDED) Shared lib [libssl.so.3] (RUNPATH) Library runpath [$ORIGIN/../lib]

The .dynamic section lists each needed library (DT_NEEDED) and where to search for them (DT_RUNPATH, here relative to the binary via $ORIGIN).

RPATH is checked before LD_LIBRARY_PATH and is deprecated; RUNPATH is checked after it and is preferred because a user can still override it. A writable or relative directory in either is a security hole — prefer $ORIGIN-relative absolute paths.

Also called
.dynamicDT_NEEDEDRPATHRUNPATH動態節區標籤