为什么GCC在没有必要时会产生堆栈保存说明?

时间:2013-07-02 20:38:56

标签: c optimization gcc

我正在编译以下简单的演示函数:

int add(int a, int b) {
    return a + b;
}

当然这个函数会被内联,但是我们假设它是动态链接的或者由于其他原因没有内联。禁用优化后,编译器将生成预期的代码:

00000000 <add>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
   6:   03 45 08                add    eax,DWORD PTR [ebp+0x8]
   9:   5d                      pop    ebp
   a:   c3                      ret

由于此函数内没有函数调用,0,1和9的指令似乎没有用处。由于禁用了优化,因此这是可以接受的。

但是,在使用-Os -s优化大小时进行编译时,会生成完全相同的代码。使用这些选项将函数的大小增加66%似乎相当浪费。

为什么代码未针对以下内容进行优化?

00000000 <add>:
   0:   8b 45 0c                mov    eax,DWORD PTR [esp+0x8]
   3:   03 45 08                add    eax,DWORD PTR [esp+0x4]
   6:   c3                      ret

编译器是否认为这不值得优化,还是与函数对齐等其他细节有关?

2 个答案:

答案 0 :(得分:15)

这样做是为了保持调试器逐步执行代码的能力。

如果你真的想要禁用此尝试-fomit-frame-pointer

使用-Os -fomit-frame-pointer -S -masm=intel编译您的上述代码,结果如下:

    .file   "frame.c"
    .intel_syntax noprefix
    .text
    .globl  _add
    .def    _add;   .scl    2;  .type   32; .endef
_add:
    mov eax, DWORD PTR [esp+8]
    add eax, DWORD PTR [esp+4]
    ret
    .ident  "GCC: (rev0, Built by MinGW-builds project) 4.8.0"

答案 1 :(得分:0)

当函数进入时,EBP的值是未知的。代码可以使用mov eax,dword ptr [esp+8]而不用BP寄存器,但许多调试工具假设每个局部变量相对于某个寄存器处于固定偏移量。即使编译器可以跟踪堆栈上推送的内容并适当调整索引偏移量,调试器也可能无法这样做。