[链接器的世界-实验篇01] 节与名字:把一段字节切成有意义的区域
本实验把 class0 的输入边界扩展为带名字的节列表。你将解码节头、取得内容并从字符串表借用名字。节头字段、标志与文件坐标见原理篇 02。
起点:class1 代码与测试,位于 private 仓库,需要访问权限。class0 是实际依赖;保留公共接口与提供的测试,在 class1 crate 的库接口中补全四项。
实现任务
| 任务 | 接口 | 要达到的结果 |
|---|---|---|
| C1.1 | section | 解码一个节头,验证 alignment 与 entry_size |
| C1.2 | payload | 按文件范围借用内容,正确处理 NULL/NOBITS |
| C1.3 | string_at | 从表内偏移找到 NUL 结尾字节名,不要求 UTF-8 |
| C1.4 | sections | 按合同分阶段校验,返回原表顺序中的 Section 与名字 |
本章使用的节标志是可组合的位:SHF_WRITE=1、SHF_ALLOC=2、SHF_EXECINSTR=4。例如 flags=6 表示可分配且可执行;这些是 section flags,与程序头的 PF_W/PF_R/PF_X 使用不同的字段和数值,不能互换。link 与 info 各占 4 字节;它们通常是另一张表的下标或类型相关参数,本章先完整保留,后续接口再解释其语义。alignment=8 时,下一段起点须向上取整到 8 的倍数;entry_size=24 且 size=72 表示其中有 3 条定长记录。
字段偏移、错误值和检查顺序见 class1 README。Section.offset 是输入文件偏移,size 对 NOBITS 是内存长度,两者都不是输出地址。sh_addr 不保存在这个 Section API 中。
NULL 和 NOBITS 的 payload 返回空切片,不读取其 offset;其余类型通过 class0 检查范围。名字可以从另一个名字的后缀开始,但终止 NUL 必须在字符串表内。未知节类型与标志原样保留,保留不意味着后续链接支持它们。
sections 先解码所有节头,再检查选中的名字表,最后按表序逐项检查 payload、解析名字。该顺序是课程的诊断合同,不能替换为“先检查全部 payload,再检查全部名字”。 返回值的形状是 Vec<(Section, &[u8])>:tuple 的第二项是该节在 .shstrtab 中解析出的名字字节,不是该节的 payload。C1.4 会按顺序验证 payload,但不把 payload 放进返回值;需要内容时,调用者再把同一个 Section 传给 payload。
例如,若 e_shstrndx = 2,表中第 2 项必须是 SHT_STRTAB;节头第 1 项的 name_offset = 1 就是在第 2 项的字符串表中从字节 1 开始找名字,而不是在第 1 项内容中找。若第 1 项是 SHT_NOBITS,它的 sh_size 描述内存中的零填充长度,payload 仍返回空切片;不能因为这个长度非零就读取文件范围。
验收及其含义
在克隆后的仓库根目录、原生 x86-64 Linux 上执行:
cargo test --locked -p class0 -p class1cargo test --locked -p class0 -p class1 --releasepython3 scripts/grade.py class1合同测试检查完整宽度、名称字节与后缀、NOBITS、表边界和分阶段错误顺序。原生测试使用 GNU as 生成代码与 BSS,检查解码后的机器码和 BSS 的内存大小、空 payload。
通过说明你能从独立工具生成的输入正确取得节信息,不说明符号或重定位已解码,也不产生可执行文件。