如何强制 GCC 在不需要时不包含对 get_pc_thunk 的调用
How to force GCC to not include call to get_pc_thunk when not needed
我正在编写将被编译的代码(使用 gcc,目标 Android x86),然后由另一个程序处理。该程序对其输入有限制,例如代码不能进行间接调用或引用全局变量。要在 PIC/PIE 中执行此操作,请在调用 get_pc_thunk(或任何仅读取堆栈顶部和 returns)
的函数时编码工具错误
我的代码处于应满足这些要求的状态。所有函数都链接进来,链接后可以通过偏移调用。但是 GCC 在我的函数中留下了对 get_pc_thunk 的调用,即使它没有被使用。
我的代码是 (test.c):
unsigned long long API test(unsigned long long a, unsigned long long b)
{
return a / b;
}
构建这个我使用:
gcc.exe -o test.o -fno-stack-protector test.c -c -O0
gcc.exe -o libtest.so -m32 -static -static-libgcc -nostartfiles -shared test.o
我出来了:
000001d8 <test>:
1d8: 55 push ebp
1d9: 89 e5 mov ebp,esp
1db: 53 push ebx
1dc: 8d 64 24 dc lea esp,[esp-0x24]
1e0: e8 45 00 00 00 call 22a <__x86.get_pc_thunk.bx>
1e5: 81 c3 0f 1e 00 00 add ebx,0x1e0f
1eb: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
1ee: 89 45 f0 mov DWORD PTR [ebp-0x10],eax
1f1: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]
1f4: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
1f7: 8b 45 10 mov eax,DWORD PTR [ebp+0x10]
1fa: 89 45 e8 mov DWORD PTR [ebp-0x18],eax
1fd: 8b 45 14 mov eax,DWORD PTR [ebp+0x14]
200: 89 45 ec mov DWORD PTR [ebp-0x14],eax
203: 8b 45 e8 mov eax,DWORD PTR [ebp-0x18]
206: 8b 55 ec mov edx,DWORD PTR [ebp-0x14]
209: 89 44 24 08 mov DWORD PTR [esp+0x8],eax
20d: 89 54 24 0c mov DWORD PTR [esp+0xc],edx
211: 8b 45 f0 mov eax,DWORD PTR [ebp-0x10]
214: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]
217: 89 04 24 mov DWORD PTR [esp],eax
21a: 89 54 24 04 mov DWORD PTR [esp+0x4],edx
21e: e8 0b 00 00 00 call 22e <__udivdi3>
223: 8d 64 24 24 lea esp,[esp+0x24]
227: 5b pop ebx
228: 5d pop ebp
229: c3 ret
0000022a <__x86.get_pc_thunk.bx>:
22a: 8b 1c 24 mov ebx,DWORD PTR [esp]
22d: c3 ret
0000022e <__udivdi3>:
...
了解正在发生的事情后,我了解到在编译时 gcc 会为对 get_pc_thunk 和 __udivdi3 的调用添加占位符,因为它不知道 __udivdi3 将在何处调用是,它可能需要通过查找 table 来调用。但是,在链接后不再需要 get_pc_thunk。我查看了链接器选项,但找不到可以优化此调用的选项。
在这种情况下是否有删除这个不需要的调用的选项?
对于 Android NDK 版本的 gcc,有一个 -fno-pic 选项允许在像这样的特殊情况下禁用 PIC。
我正在编写将被编译的代码(使用 gcc,目标 Android x86),然后由另一个程序处理。该程序对其输入有限制,例如代码不能进行间接调用或引用全局变量。要在 PIC/PIE 中执行此操作,请在调用 get_pc_thunk(或任何仅读取堆栈顶部和 returns)
的函数时编码工具错误我的代码处于应满足这些要求的状态。所有函数都链接进来,链接后可以通过偏移调用。但是 GCC 在我的函数中留下了对 get_pc_thunk 的调用,即使它没有被使用。
我的代码是 (test.c):
unsigned long long API test(unsigned long long a, unsigned long long b)
{
return a / b;
}
构建这个我使用:
gcc.exe -o test.o -fno-stack-protector test.c -c -O0
gcc.exe -o libtest.so -m32 -static -static-libgcc -nostartfiles -shared test.o
我出来了:
000001d8 <test>:
1d8: 55 push ebp
1d9: 89 e5 mov ebp,esp
1db: 53 push ebx
1dc: 8d 64 24 dc lea esp,[esp-0x24]
1e0: e8 45 00 00 00 call 22a <__x86.get_pc_thunk.bx>
1e5: 81 c3 0f 1e 00 00 add ebx,0x1e0f
1eb: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
1ee: 89 45 f0 mov DWORD PTR [ebp-0x10],eax
1f1: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]
1f4: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
1f7: 8b 45 10 mov eax,DWORD PTR [ebp+0x10]
1fa: 89 45 e8 mov DWORD PTR [ebp-0x18],eax
1fd: 8b 45 14 mov eax,DWORD PTR [ebp+0x14]
200: 89 45 ec mov DWORD PTR [ebp-0x14],eax
203: 8b 45 e8 mov eax,DWORD PTR [ebp-0x18]
206: 8b 55 ec mov edx,DWORD PTR [ebp-0x14]
209: 89 44 24 08 mov DWORD PTR [esp+0x8],eax
20d: 89 54 24 0c mov DWORD PTR [esp+0xc],edx
211: 8b 45 f0 mov eax,DWORD PTR [ebp-0x10]
214: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]
217: 89 04 24 mov DWORD PTR [esp],eax
21a: 89 54 24 04 mov DWORD PTR [esp+0x4],edx
21e: e8 0b 00 00 00 call 22e <__udivdi3>
223: 8d 64 24 24 lea esp,[esp+0x24]
227: 5b pop ebx
228: 5d pop ebp
229: c3 ret
0000022a <__x86.get_pc_thunk.bx>:
22a: 8b 1c 24 mov ebx,DWORD PTR [esp]
22d: c3 ret
0000022e <__udivdi3>:
...
了解正在发生的事情后,我了解到在编译时 gcc 会为对 get_pc_thunk 和 __udivdi3 的调用添加占位符,因为它不知道 __udivdi3 将在何处调用是,它可能需要通过查找 table 来调用。但是,在链接后不再需要 get_pc_thunk。我查看了链接器选项,但找不到可以优化此调用的选项。
在这种情况下是否有删除这个不需要的调用的选项?
对于 Android NDK 版本的 gcc,有一个 -fno-pic 选项允许在像这样的特殊情况下禁用 PIC。