Wrappres' Studio.

链接器

字数统计: 944阅读时长: 3 min
2019/10/26 Share

链接器最主要的作用就是将符号绑定到地址上

编译过程

  • LLVM 对代码进行预处理,将宏嵌入到对应的位置
  • LLVM 对代码进行词法分析和语法分析,生成AST。AST 是抽象语法树,结构上比代码更精简,遍历起来更快,所以使用 AST 能够更快的进行静态检查,同时还能更快地生成 IR (中间表示)。
  • AST 生成 IR,IR 是一种更接近机器码的语言,区别在于和平台无关。通过 IR 可以生成多份适合不同平台的机器码。对于 iOS 系统,IR 生成的可执行文件就是 Mach-O。

Mach-O

Mach-O 文件里的内容,主要就是代码和数据:代码是函数的定义,数据是全局变量的定义,包括全局变量的初始值。不管是代码还是数据,它们的实例都需要由符号将其关联起来。Mach-O文件里的代码,比如 if,for,while 生成的机器指令序列,要操作的数据会存储在某个地方,变量符号就需要绑定到数据的存储地址。同时代码也会引用其他代码,引用的函数符号也需要绑定到该函数的地址上。

链接器对代码主要的操作

  • 去项目文件里查找目标代码文件里没有定义的变量
  • 扫描项目中不同的文件,将所有符号定义和引用地址收集起来,并放到全局符号表中
  • 计算后合并长度和位置,生成同类型的段进行合并,建立绑定
  • 对项目中不同文件里的变量进行地址重定位

因为一个项目不可能只有一个文件,所以链接器也需要将多个 Mach-O 文件合并成一个。链接器

动态库链接

链接的公用库分为静态库和动态库:静态库是编译时链接的库,需要链接进你的 Mach-O 文件里,如果需要更新就咬重新编译一次,无法动态加载和更新。而动态库是运行时链接的库,使用 dyld 就可以实现动态加载。
Mach-O 文件是编译后的产物,而动态库在运行是才会被链接,并没有参与 Mach-O 文件的编译和链接,所以 Mach-O 文件里并没有包含动态库里的符号定义。这些符号会显示未定义。但它们的名字和对应的库的路径会被记录下来。运行时通过 dlopen 和 dlsym 导入动态库时,先根据记录的库路径找到对应的库,再通过记录的名字符号找到绑定的地址。
dlopen 会把共享库载入运行进程的地址空间,载入的共享库也会有为定义的符号,这样会触发更多的共享库被载入。dlopen 也可以选择是立刻解析所有引用还是滞后去做。dlopen 打开动态库返回的是引用的指针。dlsym 的作用是通过 dlopen 返回的动态库的指针和函数符号,得到函数的地址,然后使用。

使用 dyld 加载动态库,有两种方式:

  • 程序启动加载时绑定
  • 符号第一次被使用时绑定

为了减少启动时间,大部分动态库使用的是第一次被使用时绑定的方式。

通过注入动态库的方式,实现极速编译和调试

Injection 可以动态的将 Objective-C 或 Swift 代码放到已运行的程序中执行,加快调试速度,保证程序不用重启。

CATALOG
  1. 1. 编译过程
  2. 2. Mach-O
  3. 3. 链接器对代码主要的操作
  4. 4. 动态库链接
  5. 5. 通过注入动态库的方式,实现极速编译和调试