最近更新 · 33 篇文章按系列阅读
[链接器的世界-实验篇07] 静态库按需取用:成员抽取的不动点
静态库是一组目标文件的容器,而不是一个更大的目标文件。本实验解析 ar 归档格式,按未解析的全局名字逐个抽取成员,并在同一个归档内反复扫描直到不再有新成员被选中。
阅读全文
[链接器的世界-原理篇16] 链接器工程:从能链接,到值得信赖
当输入增长到数万个目标文件,链接器既要提高速度,又要保持结果确定、错误可诊断。从并行阶段的依赖关系出发,讨论结构不变式、运行测试、差分测试、变异测试与模糊测试,分析增量链接和工具链集成怎样改变工程取舍。
阅读全文
[链接器的世界-原理篇15] 走出 ELF:Mach-O 与 PE/COFF 的另一套规则
从文件头、目录记录与内容的关系出发,对照 Mach-O 与 PE/COFF 的符号、重定位和加载机制;通过字节布局与地址换算解释导入、指针链、展开记录、去重及 TLS,并区分文件结构、链接接口与运行时契约。
阅读全文
[链接器的世界-原理篇14] C++ 与 Rust:语言特性留下的链接难题
两个 .cpp 包含同一个头文件,各自生成了同一个 inline 函数和模板实例,链接却不报重复定义。本文从这个谜题出发,读懂 Itanium C++ ABI 的名字修饰(_Z、N...E、模板参数、S_ 替换)、extern "C",以及为什么普通函数不编码返回类型;用汇编拆开 COMDAT 组和弱定义这两种 vague linkage 实现,复现 vtable 卷入的 ODR 违规和 undefined reference to vtable;用链接顺序演示静态初始化顺序问题,看 init_priority 与 .init_array.N 的排序、guard 变量与 __cxa_guard_acquire。Rust 部分拆开 rlib,对比 legacy 与 v0 两套修饰,看 no_mangle、used、link_section,用 --print link-args 逐项读 rustc 交给链接器的命令行和依赖顺序,比较 panic=unwind 与 panic=abort 的大小,最后不带标准库和 C 运行时链接一个最小的 Rust 程序。
阅读全文
[链接器的世界-原理篇13] ABI 演进:库升级了,旧程序怎么办
结构体加了一个字段,没有重新编译的旧程序照样能加载,算出来的数却错了。动态链接只按名字和版本配对,不看类型和布局。本文从这个故障出发,讲 ABI 和 API 的区别、哪些改动会破坏 ABI;libtool 的 current:revision:age 怎样变成 soname 和文件名,Debian 的包名为什么带 soname;符号版本在实践中怎么用:版本节点继承、同一个函数的新旧两个实现、glibc 的 memcpy 和 fmemopen、在新系统上编译的程序为什么到旧系统上报 GLIBC_2.34 not found 以及怎样用旧 sysroot 解决;最后用 abidiff 和 abi-compliance-checker 在发布前查出被改坏的 ABI。实验统一在 x86-64 Linux 原生执行,以 glibc 2.43 和隔离解包的 glibc 2.17 对照。
阅读全文
[链接器的世界-原理篇12] 链接期优化:看见更多代码之后
分开编译形成了优化的信息边界,LTO 通过保留 IR 并协调符号决议跨越这条边界。本文解释定义选择、内部化与代码生成的分工,分析 ThinLTO 的并行与缓存机制,再讨论 ICF 的等价判定、地址身份,以及函数布局如何影响代码局部性。
阅读全文
[链接器的世界-原理篇11] 调试信息:让机器码认回源代码
从代码地址、调试节内偏移与被删除代码的 tombstone 出发,解释 DWARF 如何随链接结果变化;进一步分析索引形式、字符串合并、压缩、独立调试文件和 split DWARF 的引用与分发机制。
阅读全文
[链接器的世界-原理篇10] 链接器脚本:当程序需要自己安排内存
链接器脚本把输入节组织成输出映像,并约定符号地址、存储区域与入口。本文区分 ELF 文件偏移、VMA 和 LMA,解释启动代码如何完成映射、数据复制与 BSS 清零,再以 QEMU、xv6、JOS 和 ROM/RAM 布局分析地址约定失配的后果。最后讨论数据嵌入、节保留、排序、对齐与脚本断言。
阅读全文