我是汇编程序的新手。我正在寻找使用-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);
}
答案 0 :(得分:3)
C没有关于局部变量必须生存的规则 - 它们可以存在于堆栈,寄存器,内存中,或完全省略。
在您的示例中,您的大多数局部变量似乎已完全优化。在-O3
gcc
将积极地将变量移动到寄存器中,删除未使用的变量,并完全跳过局部变量(如果它们只是偶然的临时变量)。例如,在foo
中,gcc
会优化c
,并将添加结果直接存储在结果寄存器%eax
中。请注意,它根本不会将c = 0;
编译到输出中,因为它知道c
被下一个语句破坏了。
在main
中,z
和y
在输入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;
}
参数在寄存器RSI
和RDI
中传递,它们被添加,并且总和被放入EAX
以便返回。