我有没有公开任何函数的库,除了说“CreateObject”。尽管如此,它们的所有函数都是间接调用的,所以我在性能报告中看到,在__i686.get_pc_thunk.bx中花费了高达1.65%的时间。函数(类方法)被称为1.6亿次,它们是共享库的内部,即未公开。
我想知道是否可以在没有重定位的情况下编译内部方法 - 即使用相对偏移或类似的东西。
gcc是4.5.2
更新:实际上我认为那是因为makefile中还剩下了-O0。所以现在这不是什么大问题,但我仍然希望对-O0做同样的事情,因为它对于探查器而言不那么“垃圾”。我想知道这是什么-O2“真实”选项。
UPDATE2:嗯,它不是-O2,可能是--dynamic-list,降低了pc_thunk的性能,但它仍然存在......所以甚至不确定--dynamic-list是否真的有帮助。如果隐藏的符号仍然包含间接的thunk,它是否正确?
UPDATE3:我创建了一个测试项目,对于内部库函数我设置属性可见性隐藏,我用gcc 4.7编译并且-O2和LTO启用,我将--dynamic-list传递给链接器而没有内部函数,并且尽管如此,对get_pc_thunk的调用仍然存在。
这是测试共享库中的代码:
#include <stdio.h>
__attribute__((visibility("hidden"), noinline)) void lib1f2()
{
puts("I should have PLT disabled");
}
void lib1f()
{
puts("I'm lib1");
lib1f2();
}
在gdb中我仍然看到lib1f2中的thunk。
有趣的是,-fwhole-program lib1f2 内联到主可执行文件中,但仍然包含对thunk的调用。
UPDATE4:好的我已经接近了(意识到我是愚蠢的),程序(和上面的代码)使用数据,即使它只是一个const字符串,所以它需要GOT调用。所以现在的问题是:
答案 0 :(得分:1)
您可能对GCC可见性支持感兴趣
http://gcc.gnu.org/wiki/Visibility
要将所有符号设为私有,您可以使用-fvisibility = hidden选项。还记得使用属性((visibility(“default”))将CreateObject方法标记为公共方式。)
答案 1 :(得分:0)
在您的功能中使用visibility attribute,尤其是hidden
。你可以定义
#ifdef __GNUC__
#define MODULE_VISIBILITY __attribute__ ((visibility ("hidden")))
#else
#define MODULE_VISIBILITY
#endif
然后声明你的功能,例如与
extern void MODULE_VISIBILITY my_module_fun(int);
使用最新的(4.6或4.7)GCC编译器,您还可以使用链接时间optimizations进行编译和链接,例如在CXX= g++ -flto
中使用Makefile
。
答案 2 :(得分:0)
1)尽管如此,我还能避免GOT的砰砰声吗?
我想不是。至少不在i686上。问题是代码可以自动执行相对跳转...或者说x86上的所有跳转都是相对的,除了间接跳转IIRC。另一方面,没有办法索引相对于当前程序计数器的数据。这个问题实际上是在x86_64中解决的,因为有一个新的指令指针相对寻址,可以完全用于这种情况。
您的测试,使用gcc -fPIC -shared -O2 -flto
编译开32位:
00000530 <lib1f2.2321>:
push %ebx
call 52b <__x86.get_pc_thunk.bx>
add $0x1aca,%ebx
sub $0x18,%esp
lea -0x1a67(%ebx),%eax
mov %eax,(%esp)
call 3f0 <puts@plt>
add $0x18,%esp
pop %ebx
ret
00000560 <lib1f>:
push %ebx
call 52b <__x86.get_pc_thunk.bx>
add $0x1a9a,%ebx
sub $0x18,%esp
lea -0x1a4c(%ebx),%eax
mov %eax,(%esp)
call 3f0 <puts@plt>
add $0x18,%esp
pop %ebx
jmp 530 <lib1f2.2321>
nop
64位
00000000000006b0 <lib1f2.2352>:
lea 0x2a(%rip),%rdi
jmpq 590 <puts@plt>
00000000000006c0 <lib1f>:
lea 0x35(%rip),%rdi
sub $0x8,%rsp
callq 590 <puts@plt>
xor %eax,%eax
add $0x8,%rsp
jmp 6b0 <lib1f2.2352>
2)(相关)通过,也许,没有-fPIC进行编译 - 会有什么缺点?
嗯,虽然令人尴尬但我不得不承认我在这里有些困惑。乍一看,我会说使用-fPIC编译共享库。相反,以下两个命令都可以正常工作
gcc -fPIC -m32 -shared -O2 -flto test.c -o test.so
gcc -m32 -shared -O2 -flto test.c -o test.so
在非-fPIC情况下,代码也不需要调用get_pc_thunk。技巧是动态加载程序在运行时使用正确的数据地址修复库代码。
这是一个问题,因为你获得了一些避免thunk的速度,但你失去了实际 共享 共享库的能力,因为操作系统必须创建一个包含重定位的库的每个代码页的新副本。另一方面,当使用GOT时,只有GOT页面必须重复,当许多应用程序链接到同一个库时,大大减少了内存占用。
有趣的是,在64位模式下无法在非pic模式下编译库,以下命令失败
gcc -m64 -shared -O2 -flto test.c -o test.so
尽管如此,由于处理器提供了对代码相对寻址的支持,因此这不是问题。