5.3.2 · D1Build Systems & Toolchain

Foundations — Object files — .o - .obj, symbol table, relocation entries

2,159 words10 min readBack to topic

This page assumes you know nothing about compilers. We build every word the parent note uses, in an order where each idea leans only on the one before it. If a term ever appears before we have earned it, that is a bug — tell no one, just re-read, because it should not happen.


0. The one picture to hold in your head

Figure — Object files — .o  -  .obj, symbol table, relocation entries

Look at the figure. On the left, three separate source files each become a separate box of bytes (an object file). None of them is a finished program — each has gaps (the plum question-marks) where an address should go. On the right, the linker lines up all the boxes, decides where everything lives, and fills the gaps. The whole topic is about what is inside one of those left-hand boxes and how the gaps are described.


1. Byte — the atom of everything

Why start here? Because an object file is, physically, just a long row of bytes on disk. Machine code is bytes. Addresses are bytes. Placeholders are bytes. If "byte" is fuzzy, nothing above it can be sharp.

is just the number 18 written in hexadecimal (base 16), a shorthand programmers use because it lines up neatly with bytes. We use it because the tools (readelf, objdump) print offsets that way — see §5.


2. Machine code — bytes the CPU obeys

Why the topic needs it: an object file's .text section is machine code. But some instructions want to say "jump to printf" — and the puncher doesn't yet know where printf sits, so it punches a blank slot there. Those blanks are the reason relocations exist (§7).


3. Address — a number that names a location

Figure — Object files — .o  -  .obj, symbol table, relocation entries

The figure shows memory as one long numbered strip. The teal marker is the address of a variable g; the orange marker is the address of a call instruction. The entire drama of linking is choosing these numbers. At compile time they are unknown, so the compiler cannot write them yet.

Why the topic needs it: the parent's symbols and are both addresses (numbers on this strip). We must have the word "address" before we can say what or mean.


4. Section — a labelled shelf inside the file

For the full tour of shelves, see Sections — .text .data .bss .rodata.


5. Offset — position within a section (not yet an address)

Why the topic needs it: a symbol's value field and a relocation's offset field are both offsets, because that is all the compiler can honestly know. This offset-vs-address distinction is the whole reason the file is called relocatable — its contents can be slid to any address later.


6. Symbol & the symbol table — the "offer / need" badges

Figure — Object files — .o  -  .obj, symbol table, relocation entries

The figure is the parent's "meetup" idea drawn out. Each object file wears two badges: a teal "I provide" badge (its DEFINED symbols) and an orange "I'm looking for" badge (its UND symbols). The linker's core job (see Linker — symbol resolution and relocation) is to draw a line from every looking-for to exactly one provide.

Why the topic needs it: symbol resolution (matching needs to offers) is half of what a linker does. The other half is relocation, which needs symbols to point at.


7. Relocation entry — a patch instruction

Why the topic needs it: relocations are the entire reason an .o is not runnable. The bytes are real, but the address-slots are hollow until patched.


8. The three address-letters: , , — and the formula

Now every ingredient exists, so the parent's formula stops being magic.

Figure — Object files — .o  -  .obj, symbol table, relocation entries

Read the figure left-to-right along the memory strip. The orange bracket is (the patch slot). The instruction ends 4 bytes later at . The teal marker far right is (the target). A PC-relative jump on x86-64 lands at , so to make it land on we must store the distance . Since , that distance is , i.e. with . The addend simply is the "" that measures the slot-to-end gap.

Why two formulas? Because a data pointer wants the actual address (), but a branch instruction hardware-adds its stored number to the next-instruction address, so it wants a displacement (). Same idea, different arithmetic — the type field tells the linker which to use. The mechanics of PC-relative addressing are unpacked in PC-relative addressing in x86-64.


9. Where this all sits in the bigger machine

The object file is one stop on the compilation pipeline. The container format (how sections and tables are laid out on disk) is ELF or COFF. What the linker does next splits into static vs dynamic linking, and if you write C++, symbol names get transformed first by Name mangling in C++.

Bit and Byte

Machine code

Address

Sections text data bss rodata

Offset within a section

Symbol and symbol table

Defined vs Undefined

Relocation entry offset type addend

S A P addresses

Formula S plus A minus P

Object file topic 5.3.2

Read top-down: bits build bytes, bytes build machine code and addresses, those build sections and offsets, which build symbols and relocations, which together with build the patch formula — and all of it feeds the parent topic, Object files.


Equipment checklist

Self-test: cover the right side and answer aloud before revealing.

A byte holds how many distinct values?
(8 bits).
What is machine code, in one line?
The sequence of bytes the CPU executes directly.
Address vs offset — the difference?
An address is a location in whole memory; an offset is a distance from the start of one section (compiler knows offsets, linker chooses addresses).
Which section stores its data as only a size, no bytes?
.bss (zero-initialised globals).
A nm line marked U means what?
An undefined symbol — used here but provided by another file.
The two badges each object file "wears"?
"I provide" (defined symbols) and "I'm looking for" (undefined symbols).
The four fields of a relocation entry?
offset, symbol, type, addend.
What do , , stand for?
= symbol's final address, = addend constant, = address of the patch slot.
Absolute vs PC-relative patch formula?
Absolute writes ; PC-relative writes .
Why is the addend for a 4-byte call displacement?
It measures the 4 bytes from the patch slot to the next-instruction address , so the branch lands exactly on .