ZHCADC4A September 2011 – March 2014
对于大型程序,加载时符号解析会显著缩短程序启动时间。延迟绑定是一种机制,能够延迟函数符号的解析,直到程序实际调用函数符号为止,从而缩短启动时间并提高整体性能,因为只需要解析实际调用的函数。
一般方法是,通过 PLT 向量进行的首次调用依靠动态链接器中的解析器函数来实现控制,该函数执行解析并将后续调用直接重新路由至函数本身。
解析器需要两个实参。第一个是标识当前模块(该模块包含引用)的模块 id。模块 id 的表示不是 ABI 指定的,而是由加载器确定。第二个实参指定对应于目标函数的重定位条目。而该重定位条目提供目标符号的名称以及 GOT 中引用的位置。重定位条目由其在目标文件中的文件 .dynamic 段中 DT_RELPLT 标记中地址的字节偏移量指定。
所有这些都发生在调用方的后方,因此该机制必须保留影响标准函数调用接口的任何状态。特别是,它不得干扰任何用于实参传递的寄存器或返回地址寄存器,并且必须保留所修改的任何由被调用方保存的寄存器。为避免干扰正常实参寄存器,解析器的两个实参在 B0 和 B1 中传递。
保留全局偏移量表中的两个时隙,以供动态加载器用来实现延迟绑定。加载器使用 GOT[0] 来保存解析器函数的地址。GOT[1] 用于保存模块 id。
描述该机制的序列如下:
延迟绑定 PLT 条目
$sym$plt:
MVK reloc_offset(sym),B0 ;byte offset of GOT reloc entry from DT_RELPLT
MVKH reloc_offset(sym),B0
LDW *+DP($GOT(sym)),tmp ;&PLT0 first time, &sym after that
B tmp
解析器存根—PLT0
PLT0:
LDW *+DP($GOT(0)),tmp ; address of resolver
LDW *+DP($GOT(4)),B1 ; module id
B tmp ; tail-call resolver
全局偏移量表
; $GOT(0) reserved, initialized to module id
; $GOT(4) reserved, initialized to &resolver function
; ...
; $GOT(sym) R_C6000_JUMP_SLOT initialized to &PLT0
; updated to &sym by resolver