[The World of Linkers—Lab 01] Sections and Names: Carving Bytes into Regions
Extend class0's boundary into a list of named sections. Decode descriptors, obtain payloads, and borrow names from the string table. Theory 02 explains the fields, flags, and file coordinates.
Starting point: class1 code and tests, in the private repository; access is required. Your class0 implementation is the dependency. Preserve public interfaces and supplied tests while completing four tasks in the class1 crate library.
Implementation tasks
| Task | Interface | Required outcome |
|---|---|---|
| C1.1 | section | Decode one descriptor and validate alignment and entry_size |
| C1.2 | payload | Borrow checked file bytes, handling NULL/NOBITS correctly |
| C1.3 | string_at | Resolve a NUL-terminated byte name at a table offset, without requiring UTF-8 |
| C1.4 | sections | Validate in contract stages and return Sections and names in table order |
The section flags are composable bits: SHF_WRITE=1, SHF_ALLOC=2, and SHF_EXECINSTR=4; flags=6 means allocatable and executable. This encoding differs from program-header PF_W/PF_R/PF_X. link and info each occupy four bytes; preserve their values here, then interpret their type-dependent meaning in later interfaces. With alignment=8, a start is rounded up to a multiple of 8; entry_size=24 and size=72 describe three fixed-size records.
The class1 README specifies offsets, errors, and order. Section.offset is an input-file offset; for NOBITS, size is a memory length. Neither is an output address. This Section API does not retain sh_addr.
NULL and NOBITS yield empty payloads without reading offset. Other kinds use class0's checked ranges. A name may start in another name's suffix, but its NUL must be inside the table. Preserve unknown kinds and flags; preservation does not establish later linking support.
sections decodes all descriptors first, validates the selected name table, then checks each payload before its name in table order. This diagnostic contract differs from validating all payloads before all names. Its return shape is Vec<(Section, &[u8])>: the second tuple item is the section name bytes resolved in .shstrtab, not the section payload. C1.4 validates payload ranges in order but does not return those payloads; a caller asks payload for content using the same Section.
For example, if e_shstrndx = 2, entry 2 must be SHT_STRTAB; name_offset = 1 in entry 1 means “read from byte 1 of entry 2's string-table payload,” not from entry 1's contents. If entry 1 is SHT_NOBITS, its sh_size describes zero-filled memory rather than file bytes, so payload returns an empty slice even when that size is nonzero.
Keep the error ownership separate: alignment or fixed-record problems are InvalidAlignment/InvalidEntrySize; an unavailable file range remains a class0 input error; a wrong string-table type or missing boundary NUL is InvalidNameTable; a name offset that cannot reach a terminating NUL is BadStringOffset or UnterminatedString. A nonzero sh_size on SHT_NOBITS is not a file-range error because that section has no file payload.
For example, if e_shstrndx = 2, entry 2 must be SHT_STRTAB; name_offset = 1 in entry 1 means “read from byte 1 of entry 2's string-table payload,” not from entry 1's contents. If entry 1 is SHT_NOBITS, its sh_size describes zero-filled memory rather than file bytes, so payload returns an empty slice even when that size is nonzero.
Acceptance and what it establishes
From the cloned repository root on native x86-64 Linux:
cargo test --locked -p class0 -p class1cargo test --locked -p class0 -p class1 --releasepython3 scripts/grade.py class1Contract tests cover full widths, name bytes and suffixes, NOBITS, table bounds, and staged error order. A native test generates code and BSS with GNU as, then checks decoded machine bytes, BSS memory size, and its empty payload.
Passing establishes section interpretation of independently generated input. It does not decode symbols or relocations or produce an executable.