链接器的世界/ 实验篇/ 16 篇
5 分钟阅读公开阅读

[链接器的世界-实验篇00] 先别相信输入:ELF 文件的第一道边界

本实验建立链接器的输入边界:先检查字节是否存在,再读取支持的 ELF64 头并定位节头。文件区域、节头表与内容的关系,以及 ELF 头各字段的宽度见原理篇 02。

起点:class0 代码与测试,位于 private 课程仓库,需要访问权限。在 class0 crate 的库接口中实现三个任务;本章不要求编写 CLI、ELF 输出器或测试框架。

核心实验按 class0–class15 顺序实现,原理篇与实验篇独立编号;实验 00 的前置知识是原理篇 02。阅读与实现路线列出每章需要的原理及后续阶段如何复用已有实现。

实现任务

任务接口要达到的结果
C0.1checked_slice检查 u64 范围,返回输入的借用切片或明确错误
C0.2parse_header按规定顺序检查格式与完整节头表,返回 Header
C0.3section_header按表内下标安全选取一个 64 字节节头,重新检查给定输入

完整字段要求与诊断顺序见 class0 README。支持范围为 ELF64、小端、x86-64、ET_REL、版本 1;多字节字段按完整宽度读取,不能只比较低字节。

Header 描述整张节头表,而不是一个 section:

Rust 字段ELF 字段宽度意义
section_offsete_shoff8整张节头表相对文件开头的字节偏移
section_counte_shnum2表中节头条目的数量;例如数量为 3 时下标是 0、1、2
section_names_indexe_shstrndx2节名字符串表对应的节头下标,例如 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 class0
cargo test --locked -p class0 --release
python3 scripts/grade.py class0

合同测试检查合法头、每种截断长度、完整宽度、多个错误的优先级、宽算术、空范围与伪造 Header。它们要求返回规定结果,任何输入都不能因这些读取操作 panic。

本章没有原生运行测试:通过证明的是三个接口的读取与错误合同,不是整个目标文件有效,更不是产物可以执行。节内容的验证由后续解析承担。