为什么这段代码:
#include "stdio.h"
int main(void) {
puts("Hello, World!");
}
决定初始化堆栈帧?这是汇编代码:
.LC0:
.string "Hello, World!"
main:
push rbp
mov rbp, rsp
mov edi, OFFSET FLAT:.LC0
call puts
mov eax, 0
pop rbp
ret
为什么编译器初始化一个堆栈帧只是为了稍后将其销毁,而不使用它?这肯定不会在主函数外部导致任何错误,因为我从不使用堆栈,所以我不会导致任何错误。为什么要这样编译呢?
在每个编译函数中包含这些步骤是编译器的“基线”,未经优化。拆解后看起来很干净,而且很有道理。但是,编译器可以优化输出以减少没有实际效果的代码的开销。您可以通过使用不同的优化级别进行编译来看到这一点。
你得到的就像this:
.LC0:
.string "Hello, World!"
main:
push rbp
mov rbp, rsp
mov edi, OFFSET FLAT:.LC0
call puts
mov eax, 0
pop rbp
ret
这是在 GCC 中编译的,没有任何优化。
添加标志 -O4 给出this output:
.LC0:
.string "Hello, World!"
main:
sub rsp, 8
mov edi, OFFSET FLAT:.LC0
call puts
xor eax, eax
add rsp, 8
ret
您会注意到,这仍然会移动堆栈指针,但它会跳过更改基指针,并避免与之相关的耗时的内存访问。
假定堆栈在 16 字节边界上对齐。返回地址已被压入后,还需要减去另外 8 个字节才能到达函数调用之前的边界。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)