Linker Guide
zero-link links compiler-emitted objects into executables. The current
implementation supports the direct object slice emitted by
compile-object-i64-file: multiple ELF64 ET_REL inputs, optional .text,
optional .rodata, .data, and .bss sections, global function/data symbols,
undefined direct-call symbols resolved across input objects, R_X86_64_PLT32
call relocations, R_X86_64_PC32 text-to-data/rodata/bss/local-text
references, R_X86_64_64 absolute data/rodata relocations, and an
ABI 0.1 marker.
No wrapper around ld is accepted as the production linker. zero-link reads
ELF section and symbol tables itself and writes a Linux ELF64 executable itself.
Host linkers may be used only as comparison tools while the linker grows.
Command Line
The released linker command is:
zero-link -o output object...
Current behavior:
- read one or more ELF64 relocatable objects emitted by the 0x0 compiler;
- accept data-only relocatable objects that provide
.data/.bsssymbols
without a .text payload;
- resolve the global
mainsymbol; - resolve defined and undefined function symbols across all input objects;
- lay out
.text, optional.rodata, optional.data, and optional.bss
sections in deterministic input order;
- require
.textto be allocated/executable,.rodatato be allocated,
and .data/.bss to be allocated/writable;
- reject duplicate global definitions;
- reject missing relocation targets;
- reject missing
main; - reject ABI marker mismatches;
- apply compiler-emitted in-object and cross-object
R_X86_64_PLT32
.rela.text relocations for direct calls;
- apply
R_X86_64_PC32relocations for PC-relative references to.data,
.rodata, .bss, or local .text symbols;
- apply
R_X86_64_64relocations for absolute addresses stored in.dataor
.rodata;
- write separate
PT_LOADsegments for read/execute text plus read-only data
and read/write data plus zero-filled .bss;
- preserve the accepted ABI marker in linked executable output;
- stream the executable header, startup code, relocated object text blocks, and
ABI note to the output file without materializing the full executable bytes;
- write completed executables through a same-directory temporary file and
atomically replace the requested output path only after the stream closes;
- write deterministic Linux ELF64/x86-64 executables.
Current archive behavior:
- read deterministic static archives written by
zero-ar; - use the archive symbol index to satisfy unresolved
mainor relocation
symbols;
- load only archive members selected by the symbol index;
- extract only required archive members, loading member bytes lazily after the
symbol index selects them;
- reject non-decimal or negative archive member sizes before advancing member
offsets;
- reject missing symbols with the same diagnostics used for object inputs.
- link user objects against the current
runtime/lib0x0.aABI runtime archive
slice.
Required full behavior:
- apply all relocations used by compiler output;
- link against the complete
runtime/lib0x0.a.
Diagnostics
Diagnostics must be stable enough for tests:
duplicate symbol: <name> first=<object> duplicate=<object>
missing symbol: <name> referenced by <object>
input file not found: <path>
output directory not found: <path>
output path is a directory: <path>
temporary output path is a symlink: <path>
temporary output path is a directory: <path>
unsupported object: missing ELF magic
malformed object: ELF header out of range
unsupported object: expected ELF64 little-endian
unsupported object: expected System V ELF ABI
unsupported object: expected clear ELF ident padding
unsupported object: expected ELF version 1
unsupported object: expected 64-byte ELF header
unsupported object: expected ET_REL
unsupported object: expected x86-64
unsupported object: expected clear ELF flags
unsupported object: expected no entry point
unsupported object: expected no program headers
unsupported object: expected 64-byte section headers
unsupported object: expected STRTAB section names
unsupported object: expected SYMTAB .symtab
unsupported object: expected STRTAB symbol strings
unsupported object: expected 24-byte symbols
unsupported object: expected RELA relocation section
unsupported object: expected PROGBITS note section
abi mismatch: <object> has <actual>, expected <expected>
malformed object: section header table out of range
malformed object: invalid shstrndx
malformed object: section payload out of range
malformed object: section payloads overlap
malformed object: section name offset out of range
malformed object: duplicate section: <name>
malformed object: section alignment missing
malformed object: section alignment not power of two
malformed object: section alignment mismatch
unsupported object: expected PROGBITS <section>
unsupported object: expected AX .text
unsupported object: expected A .rodata
unsupported object: expected WA .data
unsupported object: expected WA .bss
unsupported object: expected metadata flags clear <section>
malformed object: ABI marker missing NUL
malformed object: ABI marker is not UTF-8
malformed object: symbol name offset out of range
malformed object: unnamed defined symbol
malformed object: unnamed undefined symbol
malformed object: duplicate defined symbol: <name>
malformed object: symbol section index out of range
unsupported object: expected symbol in loadable section
malformed object: undefined symbol payload nonzero
malformed object: symbol range out of section
malformed object: string table missing initial NUL
malformed object: string table entry missing NUL
malformed object: string table entry is not UTF-8
malformed object: symbol table size not aligned
malformed object: symtab local info out of range
malformed object: missing null symbol
malformed object: invalid null symbol
malformed object: invalid null section
unsupported object: expected default symbol visibility
unsupported object: expected local/global symbol binding
malformed object: symbol binding order mismatch
unsupported object: expected function/object symbol type
unsupported relocation: <kind>
unsupported relocation type: <number>
malformed object: relocation symbol link out of range
malformed object: relocation target section out of range
malformed object: relocation section target mismatch
malformed object: relocation symbol index out of range
malformed object: relocation symbol is null
unsupported relocation target section: <section>
malformed object: relocation offset out of range
malformed object: RELA section size not aligned
relocation out of range
malformed archive: <path> invalid member header
malformed archive: <path> non-deterministic member header
malformed archive: <path> invalid member name
malformed archive: <path> member name is not UTF-8
malformed archive: <path> member name is not ASCII
unsupported archive: <path> long member names
malformed archive: <path> duplicate member name: <name>
malformed archive: <path> invalid member size
malformed archive: <path> truncated member
malformed archive: <path> missing member padding
malformed archive: <path> invalid member padding
malformed archive: <path> truncated symbol index
malformed archive: <path> symbol index must be first
malformed archive: <path> duplicate symbol index
malformed archive: <path> symbol index member mismatch: <name>
malformed archive: <path> truncated symbol names
malformed archive: <path> extra symbol names
malformed archive: <path> symbol index offset out of range
malformed archive: <path> empty symbol name
malformed archive: <path> symbol name is not UTF-8
duplicate archive symbol: <name>
executable not found: <path>
unsupported executable: missing ELF magic
malformed executable: ELF header out of range
unsupported executable: expected ELF64 little-endian
unsupported executable: expected System V ELF ABI
unsupported executable: expected clear ELF ident padding
unsupported executable: expected ELF version 1
unsupported executable: expected 64-byte ELF header
unsupported executable: expected ET_EXEC
unsupported executable: expected x86-64
unsupported executable: expected clear ELF flags
unsupported executable: expected no section headers
unsupported executable: expected 56-byte program headers
malformed executable: missing program headers
malformed executable: program header table overlaps ELF header
unsupported executable: expected PT_LOAD program header
unsupported executable: expected RX or RW PT_LOAD flags
malformed executable: program header table out of range
malformed executable: segment payload out of range
malformed executable: physical address differs from virtual address
malformed executable: segment memory smaller than file size
malformed executable: segment alignment missing
malformed executable: segment alignment not power of two
malformed executable: segment alignment mismatch
malformed executable: load segments overlap
malformed executable: load segment payloads overlap
malformed executable: entry outside executable segment
malformed executable: ABI marker missing NUL
malformed executable: ABI marker is not UTF-8
For an object note containing 0x0 ABI 9.9, the current exact diagnostic must
include:
has 0x0 ABI 9.9, expected 0x0 ABI 0.1
Internal crashes are not acceptable diagnostics for malformed user object sets.
Release Artifact
Releases include:
build/release/v<version>/bin/zero-link
The release manifest must hash the linker binary and every linked executable
used by release verification.
Validation
make linker-source-check verifies that zero-link's source-level contract
for accepted ELF64 ET_REL inputs, deterministic archive symbol-index lookup,
ABI marker handling, R_X86_64_PLT32 relocation application, executable output,
and documented diagnostics stays synchronized with the tests and release
metadata.
make memory-architecture-check verifies the RAM contract for the released
linker writer: final executable output must be streamed in chunks after
deterministic size calculation, not assembled through whole-output byte
concatenation. The same gate verifies archive members are loaded lazily from
the archive file instead of retained wholesale before symbol resolution.
make linker-check must build or locate compiler-emitted object files, invoke
the released zero-link, run the resulting executable, and verify stable output
and hashes.
make linker-relocations-check verifies the current relocation applier by
linking the compiler-emitted main -> helper call relocation, linking a
hand-built object whose main uses an R_X86_64_PC32 relocation against a
local text symbol, and checking the resulting executables exit with status
42.
make linker-diagnostics-check verifies stable missing-symbol, malformed
object, malformed section-table, malformed section-payload, malformed string
table name offsets, malformed symbol table, unsupported relocation type,
malformed relocation symbol-link, malformed relocation offset, malformed
RELA-size, malformed archive diagnostics, and malformed executable diagnostics
for zero-elf-info.
make linker-multi-object-check verifies multi-object symbol resolution,
cross-object call relocation, duplicate symbol rejection, missing external
symbol rejection, and deterministic artifact hashes for the current direct
object slice.
make linker-abi-check verifies linked executable output preserves the
accepted ABI marker while still running with the expected behavior. It also
links a fixture object with .rodata and an R_X86_64_PC32 relocation from
.text, then verifies the executable returns the referenced byte. A second
fixture stores an R_X86_64_64 absolute relocation in .data, references that
data slot from .text, and verifies the linked executable returns the byte
pointed at by the relocated data. A third fixture stores an absolute relocation
in .rodata, references that read-only slot from .text, and verifies the
linked executable returns the byte pointed at by the relocated read-only data.
A fourth fixture links an object with a SHT_NOBITS .bss symbol and verifies
the linked executable observes the zero-initialized storage through
R_X86_64_PC32 references by writing a byte to .bss and reading it back.
The same gate runs zero-elf-info on the linked .bss executable and verifies
the output is ELF64 ET_EXEC, carries the ABI marker, has two PT_LOAD
segments, keeps the first segment RX, keeps the second segment RW, and
records .bss as memory size beyond file size.
make archive-check verifies deterministic archive writing and archive-member
extraction through the symbol index.
make lib0x0-archive-fixture-check links a handcrafted user object against a
fixture lib0x0.a archive with the current ABI helper symbols and an unused
member. It compares archive linking with direct object linking so the gate fails
if the linker loads unrelated archive members or fails to resolve lib0x0 ABI
symbols from the archive index. The same fixture links a data-only archive
member selected by an STT_OBJECT symbol, proving archive extraction is not
limited to function symbols.
make lib0x0-archive-check verifies user object linking against
runtime/lib0x0.a.