GCC 4.3/4.4与MSC 6在i386上针对大小失败的优化
我不确定我做错了什么,但我试着阅读了关于调用GCC约定的手册,但没有发现任何有用的东西。我当前的问题是GCC为一个非常简单的操作生成过大的代码,如下所示 主要条款c:GCC 4.3/4.4与MSC 6在i386上针对大小失败的优化,c,gcc,assembly,x86,compiler-optimization,C,Gcc,Assembly,X86,Compiler Optimization,我不确定我做错了什么,但我试着阅读了关于调用GCC约定的手册,但没有发现任何有用的东西。我当前的问题是GCC为一个非常简单的操作生成过大的代码,如下所示 主要条款c: #ifdef __GNUC__ // defines for GCC typedef void (* push1)(unsigned long); #define PUSH1(P,A0)((push1)P)((unsigned long)A0) #else // defines for MSC
#ifdef __GNUC__
// defines for GCC
typedef void (* push1)(unsigned long);
#define PUSH1(P,A0)((push1)P)((unsigned long)A0)
#else
// defines for MSC
typedef void (__stdcall * push1)(unsigned long);
#define PUSH1(P,A0)((push1)P)((unsigned long)A0)
#endif
int main() {
// pointer to nasm-linked exit syscall "function".
// will not work for win32 target, provided as an example.
PUSH1(0x08048200,0x7F);
}
现在,让我们用gcc构建并转储它:gcc-cmain.c-Os;objdump-d main.o
:
main.o: file format elf32-i386
Disassembly of section .text:
00000000 <.text>:
0: 8d 4c 24 04 lea 0x4(%esp),%ecx
4: 83 e4 f0 and $0xfffffff0,%esp
7: ff 71 fc pushl -0x4(%ecx)
a: b8 00 82 04 08 mov $0x8048200,%eax
f: 55 push %ebp
10: 89 e5 mov %esp,%ebp
12: 51 push %ecx
13: 83 ec 10 sub $0x10,%esp
16: 6a 7f push $0x7f
18: ff d0 call *%eax
1a: 8b 4d fc mov -0x4(%ebp),%ecx
1d: 83 c4 0c add $0xc,%esp
20: c9 leave
21: 8d 61 fc lea -0x4(%ecx),%esp
24: c3 ret
如何让GCC生成类似的大小代码?有什么提示吗?难道你不同意结果代码应该如此小吗?为什么GCC附加了这么多无用的代码?我认为在优化尺寸时,它比msc6这样的老东西更聪明。我在这里遗漏了什么?是我能得到的最好的参考资料。我现在在Windows上,懒得登录Linux进行测试。在这里(MingWGCC4.5.2),代码比您的小。一个不同之处是调用约定,stdcall当然比cdecl(如果未指定,则默认为GCC,或者使用-O1,我猜也使用-Os)有几个字节的优势来清理堆栈
以下是我编译的方式和结果(源代码完全是从您的帖子中复制粘贴的)
gcc-S测试c:
_main:
pushl %ebp #
movl %esp, %ebp #,
andl $-16, %esp #,
subl $16, %esp #,
call ___main #
movl $127, (%esp) #,
movl $134513152, %eax #, tmp59
call *%eax # tmp59
leave
ret
gcc-c-o test.o test.c和&objdump-d test.o:
test.o: file format pe-i386
Disassembly of section .text:
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
9: e8 00 00 00 00 call e <_main+0xe>
e: c7 04 24 7f 00 00 00 movl $0x7f,(%esp)
15: b8 00 82 04 08 mov $0x8048200,%eax
1a: ff d0 call *%eax
1c: c9 leave
1d: c3 ret
1e: 90 nop
1f: 90 nop
test.o:文件格式pe-i386
第节的分解。正文:
00000000 :
0:55推力%ebp
1:89 e5 mov%esp,%ebp
3:83 e4 f0和$0xfffffff0,%esp
6:83 ec 10子$0x10,%esp
9:e8 00呼叫e
e:c7 04 24 7f 00 00动产$0x7f,(%esp)
15:b8 00 82 04 08 mov$0x8048200,%eax
1a:ff d0呼叫*%eax
1c:c9离开
1d:c3 ret
1e:90无
1f:90无
main()在这里很特别:gcc正在做一些额外的工作,使堆栈16字节在程序的入口点对齐。所以结果的大小不能直接比较。。。尝试将main()重命名为f(),您将看到gcc生成完全不同的代码
(MSVC编译的代码不需要考虑对齐,因为Windows有不同的堆栈对齐规则。)使用
-O3
而不是-Os
为我生成一个较小的文件。对我来说,它生成0x28和0x25字节,你的版本是什么?我甚至不知道代码应该做什么;)抱歉,我没有注意到链接文档或任何其他提示中提到“大小”和“optim”字样。这描述了LinuxELF和glibc方面,这应该如何与我的问题联系起来,我不想把它联系起来,只想编译和组装。你到底是如何编译它的?你得到了多大的尺寸?连接在于对象格式,在这个平台上可能需要一些启动的东西。我将用生成的asm更新我的答案。太糟糕了。。。我不能得到相同的代码。尽管如此,如果你的cc的目标是pe-i386并不重要,代码仍然可能更小,移动到[esp]的方式看起来令人毛骨悚然,它应该是两字节的操作码“push 0x7F”。。。我还是不明白我该如何优化它。-Nostlib不是真的相关。。。试着重新理解。我相信其他的差异也可以归结为一致性;您可以使用-mprefered stack boundary=2覆盖它。
test.o: file format pe-i386
Disassembly of section .text:
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
9: e8 00 00 00 00 call e <_main+0xe>
e: c7 04 24 7f 00 00 00 movl $0x7f,(%esp)
15: b8 00 82 04 08 mov $0x8048200,%eax
1a: ff d0 call *%eax
1c: c9 leave
1d: c3 ret
1e: 90 nop
1f: 90 nop