The World of Linkers/ Labs/ 16 articles
2 min readPublic

[The World of Linkers—Lab 04] The First Executable: Two Program Headers and an Entry Point

Emit an ELF64 file that the Linux kernel can execute directly. The input contains one nonempty code section and no relocations: place its bytes, describe the mapping, and select the entry point. Theory 02 explains sections, segments, and program-header fields; Theory 06 explains startup.

Starting point: class4 code and tests, in the private repository; access is required. Reuse classes0–3 and implement three interfaces in the class4 crate library. Command-line I/O and executable permissions are supplied.

Implementation tasks

TaskInterfaceRequired result
C4.1layoutCompute the code file offset, file size, and entry virtual address without allocating
C4.2executableSerialize the ELF header, two program headers, zero padding, and code
C4.3link_singleParse one object, enforce the supported subset, select its entry, and emit the executable

class4 README specifies field values, error order, and boundaries. Headers occupy 176 bytes; code begins at the next position satisfying its alignment. File offset zero maps to BASE=0x400000, so the entry is BASE + code_offset + entry_offset. With 12 code bytes, alignment 16, and entry offset zero, code occupies [176,188) and the entry is 0x4000b0.

Emit ET_EXEC with an RX PT_LOAD covering the complete file and a PT_GNU_STACK requesting a readable, writable, non-executable stack. Omit the section table. Write little-endian fields explicitly; Rust struct layout is not the file format. Input section flags and output segment permissions use different encodings.

Accept exactly one nonempty allocated PROGBITS code section, one symbol table, and no nonempty REL/RELA sections. The entry must be a global section definition strictly inside that code, not ABS, COMMON, or an end label. Identify code by type and flags rather than the name .text. Invoking another linker or emitting a script does not implement this task.

Acceptance and what it establishes

From the cloned repository root, on native x86-64 Linux:

cargo test --locked -p class4
cargo test --locked -p class4 --release
python3 scripts/grade.py class4

Contract tests check layout boundaries, diagnostic order, serialized fields, zero padding, and nonzero entry offsets. Native tests assemble syscall-only inputs, inspect output with readelf, and execute it. They cover multiple exit statuses, the CLI, a custom code-section name, and rejected inputs.

Correct execution establishes that the code ran. Structural checks separately establish the required mappings and stack policy. Both matter. Keep input file offsets, output file offsets, and runtime virtual addresses distinct throughout the implementation.