[The World of Linkers—Lab 00] Distrust the Input: The ELF Boundary
Establish the linker's input boundary: prove bytes exist before reading the supported ELF64 header and selecting section descriptors. Theory 02 explains the file/table/payload relationship and header field widths.
Starting point: class0 code and tests, in the private course repository; access is required. Implement three interfaces in the class0 crate library. A CLI, ELF writer, and test framework are not tasks in this class.
Implement the core classes in order from class0 to class15. Theory and lab numbers are independent: Lab 00 starts with Theory 02. The reading and implementation guide maps each task to its theory prerequisites and explains how later stages reuse earlier implementations.
Implementation tasks
| Task | Interface | Required outcome |
|---|---|---|
| C0.1 | checked_slice | Check a u64 interval and return borrowed input bytes or a precise error |
| C0.2 | parse_header | Validate the format and complete section table in contract order, returning Header |
| C0.3 | section_header | Select one 64-byte descriptor by table index and recheck the supplied input |
The class0 README defines fields and diagnostic order. Accept ELF64, little-endian, x86-64, ET_REL, version 1. Read every multibyte field at full width rather than inspecting its low byte.
Header describes the whole section table, not one section:
| Rust field | ELF field | Width | Meaning |
|---|---|---|---|
section_offset | e_shoff | 8 | Byte offset of the table from the file start |
section_count | e_shnum | 2 | Number of descriptors; for count 3, valid indexes are 0, 1, and 2 |
section_names_index | e_shstrndx | 2 | Index of the descriptor for the section-name string table |
section_header returns one 64-byte descriptor. It does not return that section's payload or assume the table is at EOF.
The course requires an ordinary section count 0 < e_shnum < 0xff00 and a nonzero name-table index strictly below the count. Extended numbering is unsupported. UnsupportedExtendedNumbering also covers violations of those count/index requirements; its name does not establish that every rejected input uses extended numbering.
Range proofs, table-size arithmetic, and widening before multiplication are explained in Theory 02: proving table ranges.
Check u64 addition before converting to usize or slicing. Widen counts and indexes before multiplying by 64. RangeOverflow means arithmetic cannot represent the interval; OutOfBounds means a representable interval lies outside input. An empty interval at EOF is valid. Callers can construct Header values, so section_header must perform its own bounds checks.
Remember three error layers: return Truncated when the input lacks the minimum bytes for a field; return the corresponding format error when the bytes exist but magic, class, endian, type, or version is unsupported; return RangeOverflow when addition or multiplication cannot represent the interval, and OutOfBounds when the interval is representable but exceeds input. These are distinct contract outcomes, and the tests construct them separately.
Acceptance and what it establishes
On native x86-64 Linux, from the cloned repository root; this class does not use cross-compilation:
cargo test --locked -p class0cargo test --locked -p class0 --releasepython3 scripts/grade.py class0Contract tests cover valid headers, truncation, full-width fields, competing-error priority, wide arithmetic, empty ranges, and fabricated Header values. They require the specified result without panics caused by these reads.
There is no native-execution test in this class. Passing establishes these three reading/error contracts, not validity of the entire object or executable output. Later decoders validate section contents.