共享库内部函数为何经PLT调用?每个共享库都有独立.got/.plt吗?
关于共享库内部函数调用与GOT/PLT段的问题解答
问题1:同文件内的函数调用为何通过PLT实现,而非PC偏移调用?
这种情况是位置无关代码(PIC)编译策略与动态符号绑定机制共同作用的结果,核心原因如下:
- 全局符号的动态覆盖需求:用
-fpic编译共享库时,默认所有非static的函数符号都是全局可见的。动态链接器允许程序加载时,用全局符号表中优先级更高的同名符号(比如主程序或其他共享库中的add_nums)覆盖当前库的内部符号。通过PLT调用能支持这种动态重定向——PLT会间接跳转到GOT中存储的实际函数地址,而GOT中的地址可在加载时或首次调用时被修改为外部符号的地址。 - PIC编译的统一逻辑:编译器为简化位置无关代码的生成流程,会对所有外部可见的函数调用统一使用PLT机制,哪怕是同文件内的函数。这样无需区分“内部”“外部”函数,统一生成兼容动态重定位的代码。
- 触发PC偏移调用的方法:若想让同文件内函数调用使用PC相对偏移,只需将函数声明为
static(符号仅文件内可见),或编译时添加-fvisibility=hidden选项隐藏所有全局符号。此时编译器能确定这些函数不会被外部覆盖,就会生成直接的PC相对跳转指令。
问题2:每个共享库是否拥有独立的.got和.plt段?
每个共享库(包括主可执行程序)都拥有独立的.got和.plt段,加载器不会将多个库的这些段合并:
- 共享库的.got(全局偏移表)和.plt(过程链接表)是ELF文件结构的固有组成部分,每个库在编译时就生成了属于自己的这两个段。.got存储该库需要动态重定位的符号地址,.plt是实现延迟绑定的跳转表,二者都是库自身位置无关代码的配套结构。
- 加载器将共享库映射到进程地址空间时,会为每个库的各个段分配独立的虚拟内存区域,不同库的.got、.plt段彼此独立,各自管理自身的重定位项和跳转逻辑。
内容的提问来源于stack exchange,提问作者qwerty_url
相关产品推荐
相关产品推荐

