LD-2

了解苹果的LD

其实文章关于传统Section Based Linker那块我还没怎么读懂,有兴趣的欢迎互相探讨。

之前研究Xcode 10兼容libstdc++的时候,稍微把玩了下苹果的LD,借这个机会正好通读了下苹果的LD设计,本文做一下总结。

Atom & FixUp

苹果的LD,核心理念就是基于AtomFixUp,拿着两个术语是啥意思呢?

  • Atom就是一块代码(函数)或者数据(全局变量)之类的,每个Atom都有一些属性,比如名称、作用域、内容类型、字节对齐之类的。
  • Fixup可以理解为一个包含种类、便宜、辅助加数以及目标Atom的数据结构。

有点抽象对吧?概要来说,苹果LD通过AtomFixUP构建一张图,图中的节点都是Atom,连接Atom的则是FixUP

通过构建这样一张图,苹果就可以在链接期间进行一系列的优化,比如死代码剔除,怎么做呢?比如一段代码也会被抽象成Atom,如果没有FixUP连接的Atom就可以进行剔除

举一个简单的小例子main.c

#include <stdio.h>

int main()
{
    printf("hello world");
    return 0;
}

会被抽象出如下行为:

单独编译这个.c文件生成的.o会包含两个atom,一个是main函数,另外一个是C字符串"hello world"

printf 本质上也会一个atom,但是在这个编译单元内他还没加入图中。

fixup也存在两个,一个是去调用不知道在哪的函数printf的调用fixup,一个是去加载字符串的fixup

链接过程

  • 链接过程的第一步就是要处理输入文件,构建一张初始图。

    • 如果输入文件是.o,那么所有的atom都会被加入到初始图当中。
    • 如果输入文件是静态库(静态库基本上就是一组.o文件包含一个目录),初始状态下这里面的atom都默认不会加入到里面,当LD不断初始图中有没被决议的fixup,如果fixup对应的目标atom在这个静态库里面的话,就会把找到的atom的加入到图内。
    • 动态库其实在链接期间不会添加任何的atom,同静态库一样,如果有没被决议的fixup对应的atom在动态库内找到(比如tbd声明的那些),就就提供一个代理,这个代理标记了这个符号来自哪个动态库

本质上来说,链接期间动态库的作用就是参与标记一下。

  • 考虑完符号决议,还要考虑符号合并之类的,比如根据字符串表的设计,来自不同文件的相同字符串,比如"haha",不可能保留两份,需要合并。此外还有诸如C中的tentative definitionsC++ Weak Symbol

  • 处理fixup的时候,也需要分几种类型,见下图:

其他

虽然苹果的LD已经抽象成了Atom-FixUP的架构,但是它的可执行文件Mach-O还是传统的基于section的结构,这限制了Atom-FixUP的能力。