GAS为何为外部符号调用生成R_X86_64_PLT32重定位?链接后为何表现如PC32?
关于GAS汇编重定位类型的两个问题
问题1
汇编以下代码(使用GNU汇编器GAS):
.extern foo .global bar .section .text bar: call foo ret
生成的目标文件中,调用foo的位置存在类型为R_X86_64_PLT32的重定位项,该重定位项通过公式L + A - P解析(其中L为符号的PLT条目地址,A为加数,P为重定位项引用的位置)。由于该文件未定义PLT,请问GAS为何选择此类重定位?
问题2
将上述目标文件与汇编以下代码生成的目标模块链接时:
.global foo .section .text foo: ret
上述R_X86_64_PLT32重定位项的解析行为与R_X86_64_PC32类型一致,这是为什么?
解答
针对问题1的解释
GAS选择R_X86_64_PLT32重定位,核心是为了兼容动态链接场景:
- 汇编器处理
.extern foo时,无法提前判断foo是程序内部符号还是动态库中的外部符号。为了避免后续链接时出现兼容性问题,汇编器默认采用PLT相关的重定位类型——这种类型既能支持动态链接时的延迟绑定(通过PLT跳转表实现),也能在静态链接场景下正常工作。 - PLT是链接阶段才会生成的结构,汇编器只需要标记出需要PLT重定位的位置,后续链接器会根据符号的实际来源(本地/动态库)决定是否生成对应的PLT条目。
针对问题2的解释
当链接时发现foo是当前可执行文件内的本地符号(非动态库符号),链接器会对R_X86_64_PLT32重定位做优化处理:
- 此时不需要通过PLT跳转,链接器会直接计算
foo的实际地址与重定位位置P的偏移,逻辑和R_X86_64_PC32完全一致(后者公式为S + A - P,S为符号实际地址)。 - 在静态链接场景下,PLT条目地址
L会直接指向foo的实际地址S,因此L + A - P和S + A - P的计算结果完全相同,表现出的解析行为就和R_X86_64_PC32一致。
内容的提问来源于stack exchange,提问作者mdjukan
相关产品推荐
相关产品推荐

