[链接器的世界-实验篇07] 静态库按需取用:成员抽取的不动点
本实验让链接器按尚未满足的全局名称,从静态库中选择对象成员,再交给现有链接管线。静态库、输入顺序和重复扫描的通用原理见原理篇 03。
起点:class7 代码与测试,位于 private 仓库,需要访问权限。复用 ELF 解析、class3 全局选择和 class6 链接,在 class7 crate 的库接口中实现三个接口。CLI 已提供;实现中不调用 ar、nm 或 ld。
实现任务
| 任务 | 接口 | 要达到的结果 |
|---|---|---|
| C7.1 | members | 验证普通 GNU/System V ar 的成员边界和名称,返回借用的对象内容 |
| C7.2 | select | 按输入顺序抽取必要成员,在当前归档内扫描至不动点 |
| C7.3 | link | 将选出的对象交给 class6,不把整个归档展开进输出 |
记录格式、名称编码与抽取规则见 class7 README。先检查所有成员边界,再解析名称;奇数长度内容后的换行填充不属于内容。支持 GNU 长名称表,即使它出现在引用者之后。相同文件名可以重复,成员身份由位置决定;名称不要求 UTF-8。
显式对象立即进入选择集。在每个归档中,先解析所有普通成员的 ELF 符号元数据,再按归档顺序查找能满足当前 GLOBAL/UNDEF 的定义。每抽取一个成员立即重新计算需求;只要本轮有抽取,就继续扫描当前归档。不能把每轮结束才更新需求误当成等价实现,也不能自动回头扫描之前的归档。
未解析 WEAK 不触发抽取;已有 WEAK 或 COMMON 定义已满足名称,不为了更强定义额外抽取成员。入口查找发生在抽取之后,本身不强制拉入成员。这是本阶段明确的选择策略;不实现 thin archive、group、whole-archive 或库搜索。
所有普通成员都要通过符号元数据检查,即使未被选中;但分配节的支持策略只应用于选中对象。未选中的正常成员不能给最终输出带入重复定义或 TLS 存储。
最小的不动点例子是:main.o 引用 a,归档先出现定义 a 的 a.o,而 a.o 又引用 b;同一归档后面才出现定义 b 的 b.o。抽取 a.o 后,未解析集合新增 b,因此必须继续当前归档并抽取 b.o。如果只在第一轮开始时计算一次需求,最终程序会留下 b 未解析;如果把整个归档都展开,又会错误地带入未使用成员。
验收及其含义
在克隆后的仓库根目录、原生 x86-64 Linux 上执行:
cargo test --locked -p class7cargo test --locked -p class7 --releasepython3 scripts/grade.py class7合同测试覆盖成员边界、填充、长名称、重复名称、截断与扫描规则。原生测试使用 GNU as/ar 生成输入,将依赖成员放在调用者之前以要求第二轮扫描,并放入不能被抽取的多余成员。
测试同时断言选择的对象集合和最终执行结果;前者检验按需抽取,后者检验这些对象确实能完成链接。更早的归档不自动重访、弱引用不抽取、首个提供者满足需求和未使用成员的损坏元数据也分别有验收。