【问题标题】:GCC 4.3/4.4 vs MSC 6 on i386 optimization for size failGCC 4.3/4.4 vs MSC 6 on i386 大小优化失败
【发布时间】:2011-09-04 20:37:18
【问题描述】:

我不确定我做错了什么,但我尝试阅读有关 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 生成类似大小的代码?任何提示,提示?您不同意生成的代码应该那么小吗?为什么 GCC 会附加这么多无用的代码?我认为在优化大小时它会比 msc6 之类的旧东西更聪明。我在这里错过了什么?

【问题讨论】:

  • 使用-O3 而不是-Os 会为我生成一个更小的文件。
  • 对我来说它生成 0x28 vs 0x25 字节,你的版本是什么?
  • 我什至不明白代码应该做什么;)

标签: c gcc assembly x86 compiler-optimization


【解决方案1】:

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

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

【讨论】:

  • -nostdlib 并不真正相关...尝试-ffreestanding。我认为其他差异也归结为对齐。您可以使用 -mpreferred-stack-boundary=2 覆盖它。
【解决方案2】:

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 && 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

【讨论】:

  • 抱歉,我没有注意到链接文档中提到的“size”和“optim”字样或任何其他提示。那描述了linux ELF和glibc方面,这应该如何与我的问题联系起来,我不是试图链接它,只是编译和组装。你究竟是如何编译它的,你得到了什么大小?
  • 连接在于对象格式,该平台可能需要一些启动的东西。我将使用生成的 asm 更新我的答案。
  • 太糟糕了...我无法获得相同的代码。不过,如果你的 cc 的目标是 pe-i386 并不重要,代码仍然可以更小,移动到 [esp] 的方式看起来令人毛骨悚然,它应该是两字节操作码“push 0x7F”。 ..等等等等...我仍然不明白如何优化它。
猜你喜欢
  • 2015-03-03
  • 1970-01-01
  • 2011-04-20
  • 2011-01-30
  • 2013-09-27
  • 1970-01-01
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
相关资源
最近更新 更多