对于 64 位 SPARC 动态库,过程链接表位于专用数据中。运行时链接程序可确定目标的绝对地址,并相应地修改过程链接表的内存映像。
过程链接表的前四项是保留项。尽管表 7–38 中显示了过程链接表的示例,但未指定这些项的原始内容。在该表中,前 32,768 项的每一项都占用 8 个字(32 字节),并且必须与 32 字节边界对齐。整个表必须与 256 字节边界对齐。如果所需项数大于 32,768,则其余各项由 6 个字(24 字节)和 1 个指针(8 字节)组成。指令以 160 项并后跟 160 个指针的块方式收集到一起。最后一组项和指针可以包含的项数少于 160。不需要进行填充。
数字 32,768 和 160 分别基于分支和装入目标文件位移的限制,并且位移会向下舍入以使代码和数据之间的分区落到 256 字节边界上,从而提高高速缓存的性能。
重定位表与过程链接表关联。_DYNAMIC 数组中的 DT_JMP_REL 项指定了第一个重定位项的位置。对于非保留的过程链接表的每一项,重定位表中都包含相同顺序的对应项。所有这些项的重定位类型均为 R_SPARC_JMP_SLOT。对于前 32,767 个插槽,重定位偏移将指定关联过程链接表项的第一个字节的地址,并且加数字段为零。符号表索引会指向相应的符号。对于插槽 32,768 及其之后的插槽,重定位偏移将指定关联指针的第一个字节的地址。加数字段是未重定位的值 -(.PLTN + 4)。符号表索引会指向相应的符号。
为说明过程链接表,表 7–38 显示了若干项。前三项显示了初始保留项。接下来的三项显示了初始的 32,768 个项的示例以及可能的解析格式,这些格式分别应用于目标地址位于项上下 2 GB 的地址空间内、目标地址位于低位的 4 GB 地址空间内或目标地址位与其他任意位置的情形。最后两项显示了后续各项的示例,这些项由指令和指针对组成。左列显示了进行动态链接之前目标文件中的指令。右列说明了运行时链接程序会用于修复过程链接表各项的可能指令序列。
表 7–38 64 位 SPARC: 过程链接表示例
以下步骤介绍了运行时链接程序和程序如何通过过程链接表来共同解析符号引用。所介绍的这些步骤仅用于说明。没有指定运行时链接程序的准确执行时行为。
初始创建程序的内存映像时,运行时链接程序会更改初始过程链接表的各项。修改这些项是为了将控制权转移给运行时链接程序自己的例程。运行时链接程序还会在第三项中存储一个扩展字的标识信息。运行时链接程序获取控制权后,会检查该字以标识调用方。
过程链接表的其他所有项最初都会传输给第一项或第二项。这些项将建立栈帧并调用运行时链接程序。
通过标识值,运行时链接程序可获取其用于目标文件的数据结构,包括重定位表。
运行时链接程序会计算表插槽对应的重定位项的索引。
使用索引信息,运行时链接程序可获取符号的实际值、展开栈、修改过程链接表项并将控制权转移给所需目标。
运行时链接程序不必在内存段列下创建指令序列。如果运行时链接程序创建了指令序列,则某些点需要更多说明。
要使代码可重复执行,可按特定顺序更改过程链接表的指令。如果运行时链接程序在修复函数的过程链接表项时收到信号,则信号处理代码必须能够调用具有可预测的正确结果的原始函数。
运行时链接程序最多可更改八个字来转换一项。对于指令执行,运行时链接程序只能自动更新一个字。因此,通过以下方法可实现重复执行:首先将 nop 指令覆写为其替换指令,如果使用 64 位存储,则之后还要修补 ba,a 和 sethi。如果仅在最后一个修补程序之前调用可重复执行的函数,则运行时链接程序会再次获取控制权。尽管两次调用运行时链接程序修改的过程链接表项都相同,但这些更改不会相互干扰。
如果更改初始 sethi 指令,则只能将该指令替换为 nop。
按照更改第二种格式的项的方式更改指针是通过使用一个原子的 64 位存储器完成的。
为 .PLT101、.PLT102 和 .PLT103 显示的不同指令序列说明了如何优化关联目标的更新。
LD_BIND_NOW 环境变量可更改动态链接行为。如果其值不为空,则运行时链接程序会在将控制权转移给程序之前处理 R_SPARC_JMP_SLOT 重定位项。