能否不借助共享库强制函数调用通过PLT链接?
如何不使用共享库强制函数调用通过PLT链接?
可以,不需要依赖共享库就能实现强制函数调用走PLT,以下是几种验证有效的方法(基于Linux下GCC/Clang测试):
方法1:使用链接器--plt选项
给链接器传递-Wl,--plt参数,强制链接器为所有非隐藏函数调用生成PLT跳转,即使函数定义在当前可执行内部。修改你的编译命令如下:
$CC main.c fn.c -fpie -fpic -fplt -Wl,--plt -rdynamic -pie -Os && time ./a.out 1
这个选项会让链接器放弃对内部函数的直接绑定优化,统一走PLT路径。你可以通过objdump -d ./a.out查看main中的调用指令,会看到callq *fn@GOTPLT(%rip)这类PLT相关的指令,执行时间也会和动态库版本接近。
方法2:标记函数为弱符号
在函数定义上添加__attribute__((weak))属性,让链接器认为该函数可能被外部动态覆盖,从而自动生成PLT调用。修改fn.c内容:
__attribute__((weak)) void fn(void){} __typeof(fn) fn_H __attribute((alias("fn"),visibility("hidden")));
然后使用你原来的PIE编译命令即可:
$CC main.c fn.c -fpie -fpic -fplt -rdynamic -pie -Os && time ./a.out 1
弱符号的特性决定了链接器不会进行直接绑定,必须通过PLT来解析,确保运行时可以被外部模块替换。
方法3:使用链接器动态列表显式导出符号
创建一个动态列表文件(比如dyn_list.txt),显式指定需要动态解析的符号:
{ extern "C" { fn; }; };
编译时通过-Wl,--dynamic-list=dyn_list.txt告诉链接器将fn当作动态符号处理:
$CC main.c fn.c -fpie -fpic -fplt -Wl,--dynamic-list=dyn_list.txt -pie -Os && time ./a.out 1
这种方式可以精准控制哪些符号走PLT,适合只需要对特定函数生效的场景。
原理说明
在PIE可执行文件中,链接器默认会对内部可见的函数进行直接绑定优化(跳过PLT),因为它认为这些符号不会被外部修改。上述方法本质都是打破这种优化:要么强制链接器生成PLT,要么让链接器认为符号可能被外部动态修改,从而必须通过PLT进行间接调用。
内容的提问来源于stack exchange,提问作者Petr Skocik
相关产品推荐
相关产品推荐

