Clang中x86-64平台PLT32的含义及动态链接相关疑问
x86-64平台R_X86_64_PLT32重定位解析
问题背景
测试代码
#include <stdio.h> __attribute__((noinline)) int add(int a, int b) { return a + b; } int add_external_def(int a, int b); int main() { printf("5 + 5 = %d\n", add(5, 5)); printf("5 + 5 = %d\n", add_external_def(5, 5)); return 0; }
编译结果对比
使用Clang 17.0.1针对x86-64平台以-O3编译为可执行文件时,生成的函数调用汇编片段如下:
call add
call printf@PLT
call add_external_def@PLT
当仅编译为二进制目标文件(.o)时,这些调用的汇编形式变为:
call 20 <main+0x10> R_X86_64_PLT32 add-0x4
call 33 <main+0x23> R_X86_64_PLT32 printf-0x4
call 42 <main+0x32> R_X86_64_PLT32 add_external_def-0x4
用户疑问
R_X86_64_PLT32 ...-0x4部分的含义是什么?- “该函数是否通过PLT解析”的信息去哪里了?
解答
1. R_X86_64_PLT32 ...-0x4的含义
- **
R_X86_64_PLT32**是x86-64平台的一种重定位类型,作用是告知链接器:在最终链接阶段,要将当前call指令的目标地址修正为对应函数的PLT(过程链接表)项地址,用于实现动态链接的延迟绑定。 ...-0x4是指令地址计算的必然要求:x86-64的call指令使用32位相对偏移,偏移值是从当前call指令的下一条指令开始计算的。而call指令本身长度为4字节,所以重定位时需要用目标PLT项地址减去当前call指令地址,再减去4,才能得到正确的偏移量。汇编中的add-0x4是这个计算逻辑的简化表示,链接器会自动完成最终的偏移计算。
2. “是否通过PLT解析”的信息位置
在目标文件(.o)阶段,R_X86_64_PLT32这个重定位类型本身就是“该调用将通过PLT解析”的明确标记。
你在可执行文件中看到的不同调用形式,是链接完成后的最终优化结果:
- 对于
add这种内部定义且未导出的函数,链接器可以直接将调用地址指向函数实际入口,无需经过PLT; - 对于
printf这种动态库提供的函数,链接器必须保留PLT调用以实现动态绑定; - 对于
add_external_def这种外部未定义函数,若最终链接时它被解析为动态库函数,则保留PLT调用;若被解析为同一可执行文件内的函数,链接器会自动优化掉PLT,改为直接调用。
内容的提问来源于stack exchange,提问作者doliphin
相关产品推荐
相关产品推荐

