[链接器的世界-实验篇00] 先别相信输入:ELF 文件的第一道边界
本实验建立链接器的输入边界:先检查字节是否存在,再读取支持的 ELF64 头并定位节头。文件区域、节头表与内容的关系,以及 ELF 头各字段的宽度见原理篇 02。
起点:class0 代码与测试,位于 private 课程仓库,需要访问权限。在 class0 crate 的库接口中实现三个任务;本章不要求编写 CLI、ELF 输出器或测试框架。
核心实验按 class0–class15 顺序实现,原理篇与实验篇独立编号;实验 00 的前置知识是原理篇 02。阅读与实现路线列出每章需要的原理及后续阶段如何复用已有实现。
实现任务
| 任务 | 接口 | 要达到的结果 |
|---|---|---|
| C0.1 | checked_slice | 检查 u64 范围,返回输入的借用切片或明确错误 |
| C0.2 | parse_header | 按规定顺序检查格式与完整节头表,返回 Header |
| C0.3 | section_header | 按表内下标安全选取一个 64 字节节头,重新检查给定输入 |
完整字段要求与诊断顺序见 class0 README。支持范围为 ELF64、小端、x86-64、ET_REL、版本 1;多字节字段按完整宽度读取,不能只比较低字节。
Header 描述整张节头表,而不是一个 section:
| Rust 字段 | ELF 字段 | 宽度 | 意义 |
|---|---|---|---|
section_offset | e_shoff | 8 | 整张节头表相对文件开头的字节偏移 |
section_count | e_shnum | 2 | 表中节头条目的数量;例如数量为 3 时下标是 0、1、2 |
section_names_index | e_shstrndx | 2 | 节名字符串表对应的节头下标,例如 2 表示表中第 2 项 |
section_header 返回其中一个 64 字节描述符,不返回它描述的 section 内容,也不假设表在文件末尾。
课程要求普通节头数量满足 0 < e_shnum < 0xff00,名字表下标非零且严格小于数量;不支持扩展编号。违反这些数量/下标要求时复用 UnsupportedExtendedNumbering;这不意味着每个被拒绝的文件都使用了扩展编号。
区间证明、表长计算与整数扩宽的推导见原理篇 02:从字段值到可读取的区间。
先检查 u64 加法,再转换为 usize 或切片;索引和数量先扩宽再乘以 64。RangeOverflow 表示算术不能表达区间,OutOfBounds 表示区间可表达但超出输入。EOF 的空区间合法。Header 可由调用者自行构造,不能跳过 section_header 的边界检查。
错误边界可以按三层记忆:输入连最小字段都没有时返回 Truncated;字段本身存在但魔数、class、endian、类型或版本不符合支持范围时返回相应的格式错误;字段值参与加法或乘法后无法表达区间时返回 RangeOverflow,区间仍可表达但超过 input 时返回 OutOfBounds。这些错误不是“都算解析失败”的同义词,合同测试会分别构造它们。
验收及其含义
在原生 x86-64 Linux 上,从克隆后的仓库根目录执行;本实验不使用交叉编译:
cargo test --locked -p class0cargo test --locked -p class0 --releasepython3 scripts/grade.py class0合同测试检查合法头、每种截断长度、完整宽度、多个错误的优先级、宽算术、空范围与伪造 Header。它们要求返回规定结果,任何输入都不能因这些读取操作 panic。
本章没有原生运行测试:通过证明的是三个接口的读取与错误合同,不是整个目标文件有效,更不是产物可以执行。节内容的验证由后续解析承担。