具有优化的反汇编代码局部变量保持在哪里

时间:2017-03-24 01:01:18

标签: c gdb disassembly

我是汇编程序的新手。我正在寻找使用-g和-O3 fiag编译代码的差异(优化。

在优化代码的情况下,反汇编代码不会显示局部变量存储在堆栈上?这是我的理解,无论何时我们调用任何函数,它都会跟踪堆栈上的局部变量,并在执行下一个函数时移动到下一个堆栈帧。

以下是优化版本的反汇编代码。

(gdb) disassemble main
Dump of assembler code for function main:
   0x00000000004004d0 <+0>:     mov    $0x1e,%eax
   0x00000000004004d5 <+5>:     retq
End of assembler dump.
(gdb) disassemble foo
Dump of assembler code for function foo:
   0x00000000004004c0 <+0>:     lea    (%rsi,%rdi,1),%eax
   0x00000000004004c3 <+3>:     retq
End of assembler dump.

源代码:

int
foo(int a, int b) {
    int c = 0;
    c = a + b;
    return (c);
}
int
main()
{
    int z = 10;
    int y = 20;
    int ret = 0;
    ret = foo(z, y);
    return (ret);
}

2 个答案:

答案 0 :(得分:3)

C没有关于局部变量必须生存的规则 - 它们可以存在于堆栈,寄存器,内存中,或完全省略。

在您的示例中,您的大多数局部变量似乎已完全优化。在-O3 gcc将积极地将变量移动到寄存器中,删除未使用的变量,并完全跳过局部变量(如果它们只是偶然的临时变量)。例如,在foo中,gcc会优化c,并将添加结果直接存储在结果寄存器%eax中。请注意,它根本不会将c = 0;编译到输出中,因为它知道c被下一个语句破坏了。

main中,zy在输入foo时会有已知值,因此您的编译器只会内联foo的定义。常量折叠和传播会将main简化为return 30;,这根本不需要局部变量 - 这是您在程序集中看到的输出(0x1e = 30)。

答案 1 :(得分:3)

编译器注意到foo()是一个如此简单的函数,它可以内联编译。然后它看到所有参数都是常量,因此它计算了结果。因此,您的main()函数已经过优化,相当于:

int main() {
    return 30;
}

$0x1e是十六进制的数字30

foo()的汇编已删除变量c,并将其编译为简单:

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

参数在寄存器RSIRDI中传递,它们被添加,并且总和被放入EAX以便返回。