Procedure Linkage Table
动态链接在两个方便减慢了程序运行的速度:
- 在程序初始化的阶段,程序必须先运行动态链接器寻找并装载所有的共享对象,然后对所有符号进行地址查找和重定位操作
- 在程序运行阶段,对于全局的符号访问都要进行 GOT 定位,然后间接寻址
因此有一些优化方法,延迟绑定就是其中一种
核心思想是等到函数第一次使用的时候才进行绑定,如果没有用到则不进行绑定,有效缓解了第一个因素
ELF 使用 PLT 的方法来实现,绑定的必要信息是模块位置和函数的信息,PLT 在 GOT 层之前又加了一层间接跳转
一开始 GOT 表里面的地址是 push n
这条指令的地址,所以第一次操作的时候相当于第一个是无效指令,后面用栈传参绑定,函数将正确的地址写入 GOT 表并执行
如果第二次进入 plt 的话第一个指令就会正确执行,然后通过栈顶的 ret 地址返回正确的位置上,而不是 push n
的位置
ELF 将 GOT 拆分成了两个表:.got
和 .got.plt
。其中 .got
用来保存全局变量引用的地址,.got.plt
用来保存函数引用的地址,前三项有特殊意义:
.dynamic
地址,该段保存动态链接相关的信息- 本模块 ID
- 保存
_dl_runtime_resolve()
地址
同时为了减少代码重复,plt 表会跳转到 plt0 执行重复指令,段名是 .plt