类Unix系统中的共享对象(*.so)由于符号插入而效率低下:.so内部对全局变量的每次访问都需要GOT查找,而.so内部从一个函数到另一个函数的每次调用都需要一个PLT抬头.因此,我很高兴看到gcc版本5.1添加了选项-fno-semantic-interposition.但是,当我尝试在没有使用PLT的情况下创建一个函数调用另一个函数的.so时,我收到错误消息:
在创建共享对象时,不能使用符号`functionname'重定位R_X86_64_PC32; 用-fPIC重新编译
我期望选项-fno-semantic-interposition可以消除此错误消息,但事实并非如此.-mcmodel = large也无济于事.对函数的引用确实与位置无关,错误消息实际确认了这一点(R_X86_64_PC32表示在64位模式下与PC相关的32位重定位).-fPIC实际上并不意味着与位置无关,正如名称所暗示的那样,它实际上意味着使用GOT和PLT.
我无法使用,__attribute__((visibility ("hidden")))
因为被调用的函数和调用者是在单独的文件中编译的(调用者在C++中,称为函数在汇编中).
我试图制作一个汇编列表来查看-fno-semantic-interposition选项的作用.我发现当一个函数在同一个文件中调用另一个函数时,它会引用一个本地别名,但在另一个文件中调用一个函数时它仍然使用PLT.
(g ++版本是5.2.1 Ubuntu,64位模式).
有没有办法让链接器在没有GOT/PLT查找的情况下接受.so内的交叉引用?
有没有办法让链接器在没有GOT/PLT查找的情况下接受.so内的交叉引用?
是的:attribute((visibility("hidden")))
正是这样做的.
我不能使用attribute((visibility("hidden")))因为被调用的函数和调用者是在单独的文件中编译的
您感到困惑:visibility("hidden")
意味着当符号最终链接时,不会从共享库中导出符号.但该符号是全局的,并且在最终链接之前跨多个翻译单元可见.
证明:
$ cat t1.c extern int foo() __attribute__((visibility("hidden"))); int main() { return foo(); } $ cat t2.c int foo() __attribute__((visibility("hidden"))); int foo() { return 42; } $ gcc -c -fPIC t1.c t2.c $ gcc -shared t1.o t2.o -o t.so $ nm -D t.so | grep foo $
我试图制作一个汇编列表来查看-fno-semantic-interposition选项的作用.我发现当一个函数在同一个文件中调用另一个函数时,它会引用一个本地别名,但在另一个文件中调用一个函数时它仍然使用PLT.
如果你读了讨论,在GCC-补丁,你会看到-fno-semantic-interposition
大约是允许的可能interposable函数内联,不是不内联时,他们实际上是调用方式.