Procedure Linkage Table

动态链接在两个方便减慢了程序运行的速度:

  1. 在程序初始化的阶段,程序必须先运行动态链接器寻找并装载所有的共享对象,然后对所有符号进行地址查找和重定位操作
  2. 在程序运行阶段,对于全局的符号访问都要进行 GOT 定位,然后间接寻址

因此有一些优化方法,延迟绑定就是其中一种

核心思想是等到函数第一次使用的时候才进行绑定,如果没有用到则不进行绑定,有效缓解了第一个因素

ELF 使用 PLT 的方法来实现,绑定的必要信息是模块位置和函数的信息,PLT 在 GOT 层之前又加了一层间接跳转

bar@plt:
    jmp *(bar@GOT)
    push n
    push moduleID
    jump _dl_runtime_resolve

一开始 GOT 表里面的地址是 push n 这条指令的地址,所以第一次操作的时候相当于第一个是无效指令,后面用栈传参绑定,函数将正确的地址写入 GOT 表并执行

如果第二次进入 plt 的话第一个指令就会正确执行,然后通过栈顶的 ret 地址返回正确的位置上,而不是 push n 的位置

ELF 将 GOT 拆分成了两个表:.got.got.plt。其中 .got 用来保存全局变量引用的地址,.got.plt 用来保存函数引用的地址,前三项有特殊意义:

  1. .dynamic 地址,该段保存动态链接相关的信息
  2. 本模块 ID
  3. 保存 _dl_runtime_resolve() 地址

同时为了减少代码重复,plt 表会跳转到 plt0 执行重复指令,段名是 .plt