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

[链接器的世界-实验篇06] 文件里的字节与内存里的字节:数据、BSS 与段权限

本实验支持只读常量、初始化数据、BSS 和 COMMON,并为输出建立 RX、R、RW 三组加载映射。文件中有多少字节与内存中需要多少空间必须分别计算;通用布局与零填充原理见原理篇 05和原理篇 06。

起点:class6 代码与测试,位于 private 仓库,需要访问权限。复用 class1–3 的解析与选择、class5 的重定位运算,在 class6 crate 的库接口中实现三个接口。CLI 已提供。

实现任务

任务接口要达到的结果
C6.1plan验证贡献与 COMMON,生成存储、放置记录和三个加载段的规划
C6.2emit保留已重定位的内容,写出 ELF 头、三个 PT_LOAD 和 PT_GNU_STACK
C6.3link分类输入、选择全局定义、分配存储、绑定地址并应用重定位

完整类型、布局顺序与诊断见 class6 README。Contribution 的身份仍是 (file, section)。初始化内容的 memory_size 等于 bytes 长度;BSS 的 bytes 必须为空,但 memory_size 可以非零。先验证所有贡献和 COMMON 元数据,再进行布局和资源检查。

Text 从 288 字节头部之后开始;ReadOnly、Data 组从页边界开始。文件游标在初始化 Data 之后停止,内存游标继续分配 BSS 与 COMMON。后两者有运行时地址,没有可写入的文件偏移。COMMON 已由全局选择合并,plan 不重复合并;被强定义覆盖的 COMMON 不再分配。

支持范围是手册列出的四种精确类型/标志组合;TLS、merge、group 等已分配输入即使为空也不属于本阶段。数据中的指针可以指向 BSS,但 BSS 本身不能充当存储重定位字段的目标。emit 接收有效 plan 结果,保留重定位后的内容,不能从原始输入重新复制覆盖它。入口必须位于非空 Text 贡献内,头部和对齐填充均不算代码。

一个小布局可以校验两个游标:初始化 Data 有 12 个文件字节、BSS 需要 20 个内存字节。Data 写入文件后,文件长度只增加那 12 个字节;BSS 从同一内存游标继续向前 20 字节,却不增加文件长度。于是 Data 的 p_filesz 小于 p_memsz,差值由内核映射为零填充。若把 BSS 追加到文件,结构仍可能看似可读,却失去了本阶段要表达的文件/内存边界。

验收及其含义

在克隆后的仓库根目录、原生 x86-64 Linux 上执行:

cargo test --locked -p class6
cargo test --locked -p class6 --release
python3 scripts/grade.py class6

合同测试分别检查文件大小、内存大小、空贡献、边界、入口与段字段。原生测试验证全局变量、跨页 BSS 零初始化、共享 COMMON、强定义覆盖 COMMON,以及 Data 中指向 BSS 的指针。

权限测试要求写 Text/ReadOnly、执行 Data 的独立探针收到 SIGSEGV,并同时检查段权限字段。单纯崩溃不能证明权限正确;结构检查和正常程序执行共同排除布局、入口或重定位错误。