GCC 4.3 / 4.4与MSC 6对i386优化大小失败

时间:2011-09-04 20:37:18

标签: c gcc assembly x86 compiler-optimization

我不确定我做错了什么,但我已经尝试阅读有关调用GCC惯例的手册,并且没有发现任何有用的内容。我目前的问题是GCC为一个非常简单的操作生成了过多的代码,如下所示。

main.c中:

#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 -c main.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

这是我能够获得的最小大小代码...如果我没有指定-O *或指定其他值,则它将是0x29 +字节长。

现在,让我们用ms c编译器v 6构建它(是的,98年iirc之一):wine /mnt/ssd/msc/6/cl /c /TC main.c;wine /mnt/ssd/msc/6/dumpbin /disasm main.obj

Dump of file main.obj

File Type: COFF OBJECT

_main:
  00000000: 55                 push        ebp
  00000001: 8B EC              mov         ebp,esp
  00000003: 6A 7F              push        7Fh
  00000005: B8 00 82 04 08     mov         eax,8048200h
  0000000A: FF D0              call        eax
  0000000C: 5D                 pop         ebp
  0000000D: C3                 ret

如何使GCC按大小代码生成类似的代码?任何提示,提示?你不同意结果代码应该小吗?为什么海湾合作委员会附加了这么多无用的代码?我认为在优化尺寸时,它比msc6这样的旧东西更聪明。我在这里缺少什么?

2 个答案:

答案 0 :(得分:4)

main()在这里很特别:gcc正在做一些额外的工作,使堆栈在程序的入口点处对齐16字节。所以结果的大小不能直接比较...尝试将main()重命名为f(),你会看到gcc生成截然不同的代码。

(MSVC编译的代码不需要关心对齐,因为Windows对堆栈对齐有不同的规则。)

答案 1 :(得分:-1)

This是我能得到的最佳参考。我现在在Windows上,懒得登录我的Linux进行测试。这里(MinGW GCC 4.5.2),代码比你的小。一个区别是调用约定,stdcall当然比cdecl有一些字节优势(如果未指定,则默认使用GCC,或者使用-O1,我猜也是-Os),以清理堆栈。

这是我编译的方式和结果(源代码纯粹是从帖子中复制粘贴的)

gcc -S test.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&amp;&amp; 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