Concept

Linking

Definition

Linking is the build-pipeline phase that takes the object files produced by a compiler and combines them — together with any pre-built libraries they depend on — into a single executable or shared library. Each object file contains compiled machine code plus a symbol table listing the function and variable names it defines and the external names it references. The linker's job is to satisfy every external reference by finding its definition in some other object file or library, then write a final binary in which every reference is resolved to a concrete memory address.

There are two flavours. Static linking copies the needed code from each library into the final binary, producing a self-contained executable. Dynamic linking leaves references unresolved at build time and binds them at program start (or even later, on first use) against shared libraries loaded into memory.

Why it matters

How it works

A compiler emits one object file per source file. Each object file holds machine code with placeholders where it refers to symbols defined elsewhere — function calls into the standard library, references to global variables, even calls into other functions in the same project that happened to be in a different source file. The object file also carries a relocation table describing each placeholder: which symbol it needs, where the address should be patched in, and what kind of arithmetic the patch requires (absolute address, PC-relative offset, GOT index). When the linker runs, it concatenates the object files' code and data sections, builds a unified symbol table, walks every relocation entry, and patches each placeholder with the address the symbol resolved to.

Dynamic linking complicates this by deferring most resolution to program-load time. The linker still produces a binary with unresolved references, but it embeds enough metadata — a list of needed shared libraries, a hash table of symbols, a relocation table — that the dynamic linker (a separate program loaded automatically by the kernel) can perform the same patching at startup against libraries currently present on the system. The benefit is that one copy of libc lives in memory and serves every program using it. The cost is that every program-start pays the resolution cost and that an incompatible library change can break programs that previously worked. The ldd command shows which shared libraries a binary needs and where the dynamic linker will find them.

Where it goes next

Continue exploring

Tags