何为延迟绑定
延迟绑定指的是在程序运行过程中将动态链接库中的符号与程序中的代码进行绑定的过程,这样做的目的可以减少程序启动时间以及避免因静态链接带来的内存和磁盘空间浪费问题
延迟绑定涉及到plt表和got表这两个概念,下文对此加以说明
plt和got的狗血恋情
plt表和got表是什么
got表和plt表都是程序调用外部函数时,定位该函数需要使用到的表。
got
got表(Global Offset Table)是全局偏移量表,这是链接器在执行链接时需要填充的部分,保存了所有外部符号的地址信息。
got表分为以下四个部分
- GOT[0] 是.dynamic段的装载地址,.dynamic段包含了动态链接器用来绑定过程地址的信息,比如符号的位置和重定位信息;
- GOT[1] 是动态链接器的标识
link_map
的地址; - GOT[2] 包含动态链接器的延迟绑定代码
_dl_runtime_resolve
的入口点,用于得到真正的函数地址,回写到对应的got表中; - GOT[3] 从此开始就是函数的地址。
plt
plt表(Procedure Linkage Table)是程序链接表.位于代码段.plt节的PLT是一个数组,每个条目占16个字节。
- **PLT[0]**用于跳转到动态链接器
- **PLT[1]**用于调用系统启动函数__libc_start_main(),我们熟悉的main()函数就是在这里面调用的
- **PLT[2]**开始就是被调用的各个函数条目。
延迟绑定过程
这里先放一张流程图作为参考↑
现在以printf函数为例探究plt和got这俩小情侣是如何操作的
这里直接查看到printf第一次被调用时plt表里的内容
可以看到跳进plt表中后又跳进了0x404000地址,那我们继续跟进
这个地址中储存的地址其实就是我们plt表上的地址,所以这里又跳回来了
由图这里调回来后执行prepare resolver,推测是和将真实地址解析到got表相关的函数
那么程序接着执行跳转到0x401020位置,我们继续跟进看看这对小情侣到底要干嘛
这里执行了一系列代码
看不懂,但根据流程图应该是与解析地址有关的函数
那么执行完这一段代码后再来看看我们printf的got表地址
A,您猜怎么着,确实got表的内容变了,根据实践,这就是printf的真实地址
那么延迟绑定就到此结束了
之后函数再call printf函数时就可以直接通过got表跳转到真实地址了