5.3.4 · D1Build Systems & Toolchain

Foundations — Dynamic - shared libraries — .so - .dll, dynamic linking, PIC

2,133 words10 min readBack to topic

This page assumes nothing. Before you read the parent topic, we build every word it leans on — from "what is machine code" up to "what is the GOT". Read top to bottom; each block only uses words defined above it.


1. Machine code, and what an "address" is

Figure — Dynamic - shared libraries — .so  -  .dll, dynamic linking, PIC
0x7f000000
A number written in hexadecimal (base-16), a compact way programmers write big address numbers. 0x just means "hex follows".

2. Absolute vs relative addressing

Figure — Dynamic - shared libraries — .so  -  .dll, dynamic linking, PIC

3. The Program Counter (PC / instruction pointer)

Relative addressing works because the CPU can read its own PC: "target = PC + 80". The parent's formula phrase "PC-relative offset" literally means "a distance measured from the current PC".

PC
The register holding the address of the instruction currently running; the reference point all relative addresses are measured from.

4. Virtual addresses and why two programs can both use 0x7f000000

This is the machinery behind Virtual Memory & mmap. It matters here for one reason:

Figure — Dynamic - shared libraries — .so  -  .dll, dynamic linking, PIC

5. Symbols — names for code and data

Symbols split into two flavours the parent cares about:

  • Internal symbol — defined inside the same library. Reachable by a plain PC-relative offset (its distance from the caller is fixed).
  • External symbol — defined in another library (e.g. printf lives in libc). Its distance is not fixed, because the other library loads separately. This is the hard case the GOT solves.

6. Linking vs loading — two different jobs


7. Relocation — patching the numbers in


8. GOT and PLT — the two rescue tables

Now the vocabulary is ready for the parent's centrepiece.


9. File formats — where all this is stored


Prerequisite map

Machine code and addresses

Absolute vs relative addressing

Program Counter PC

Virtual addresses and pages

Sharing physical differ virtual

Symbols and symbol tables

Linker at build time

Loader at run time

Relocation

Position Independent Code

GOT and PLT

Shared Libraries topic


Once these foundations are solid, they feed directly into: Static libraries — .a .lib (the copy-in alternative), ASLR & Security (why load addresses are deliberately randomised), dlopen and Plugin Architectures (loading libraries on demand), and of course the parent topic itself.


Equipment checklist

An address is just...
the number of a memory "mailbox"; code and data both live at addresses.
Absolute vs relative addressing
absolute = a fixed box number baked in; relative = a distance measured from the current instruction (the PC).
Why relative addressing survives the code being moved
if the whole library slides together, distances between its own parts stay the same, so "80 boxes ahead" is still correct.
What the PC (Program Counter) holds
the address of the instruction running right now — the reference point for all PC-relative offsets.
Virtual vs physical address
virtual = each process's private illusion of the memory street; the same physical page can appear at different virtual addresses in different processes.
Why shared code bytes may contain no per-process number
because the identical physical page is seen by every sharer; any per-process value would be wrong for some of them.
Code page vs data page
code pages hold instructions (shared, read-only); data pages hold variables (private, writable) — the GOT lives on a data page.
What a symbol is
a name (like printf) for a piece of code or data; the machine ultimately needs its address.
Internal vs external symbol
internal lives in the same library (fixed distance, plain PC-relative); external lives in another library (address unknown until load — needs the GOT).
Linker vs loader
linker (build time) checks symbols exist and records dependencies; loader (run time) finds the file and patches real addresses.
What relocation does
writes the now-known real box numbers into placeholder slots — arranged to touch data pages only.
What the GOT stores and why writable
real per-process addresses of external symbols; writable so the loader can patch them without disturbing shared code.
What the PLT does / lazy binding
stubs that resolve a function's address on its first call, store it in the GOT, then jump; later calls skip resolution.
ELF vs PE
file formats for library files — ELF on Linux, PE (with an Import Address Table) on Windows.