GOT是一个存储外部库函数的表
PLT则是由代码片段组成的,每个代码片段都跳转到GOT表中的一个具体的函数调用
重定位
链接时重定位
链接阶段是将一个或多个中间文件(.o文件)通过链接器将它们链接成一个可执行文件,主要做的事情有
对各个中间文件的同名section进行合并
对代码段,数据段等进行地址分配
进行链接时重定位
两种情况:
如果是在其他中间文件中已经定义了的函数,链接阶段可以直接重定位到函数地址
如果是在动态库中定义了的函数,链接阶段无法直接重定位到函数地址,只能生成额外的小片段代码,也就是PLT表,然后重定位到该代码片段
运行时重定位
运行后加载动态库,把动态库中的相应函数地址填入GOT表,由于PLT表是跳转到GOT表的,这就构成了运行时重定位
延迟重定位
只有动态库函数在被调用时,才会进行地址解析和重定位工作,这时候动态库函数的地址才会被写入到GOT表项中
函数第一次被调用过程
第一步由函数调用跳入到PLT表中,然后第二步PLT表跳到GOT表中,可以看到第三步由GOT表回跳到PLT表中,这时候进行压栈,把代表函数的ID压栈,接着第四步跳转到公共的PLT表项中,第5步进入到GOT表中,然后_dl_runtime_resolve对动态函数进行地址解析和重定位,第七步把动态函数真实的地址写入到GOT表项中,然后执行函数并返回。
解释下dynamic段,link_map和_dl_runtime_resolve
dynamic段:提供动态链接的信息,例如动态链接中各个表的位置
link_map:已加载库的链表,由动态库函数的地址构成的链表
_dl_runtime_resolve:在第一次运行时进行地址解析和重定位工作
函数之后被调用过程
可以看到,第一步还是由函数调用跳入到PLT表,但是第二步跳入到GOT表中时,由于这个时候该表项已经是动态函数的真实地址了,所以可以直接执行然后返回。
对于动态函数的调用,第一次要经过地址解析和回写到GOT表项中,第二次直接调用即可