我只是围绕着功能序言的概念,但这给了我一些麻烦。
我在C中编写了一个简单的hello world程序,然后查看了生成的汇编代码:
#include <stdio.h>
int main()
{
puts("hello");
return 0;
}
程序集(MinGW 4.8.1,Windows 7 32位):
004016B0 /$ 55 PUSH EBP
004016B1 |. 89E5 MOV EBP,ESP
004016B3 |. 83E4 F0 AND ESP,FFFFFFF0
004016B6 |. 83EC 10 SUB ESP,10
004016B9 |. E8 A2050000 CALL hello.00401C60
004016BE |. C70424 64504000 MOV DWORD PTR SS:[ESP],hello.00405064 ; |ASCII "hello"
004016C5 |. E8 9E1F0000 CALL <JMP.&msvcrt.puts> ; \puts
004016CA |. B8 00000000 MOV EAX,0
004016CF |. C9 LEAVE
004016D0 \. C3 RETN
ANDing ESP在第三行的目的是什么?我遇到过这个问题:Why does this function prologue use several instructions to calculate the esp reduction?,在哪里 据说
先清除esp中的低4位,新的esp将是 根据ABI,十六字节对齐。为什么不在main + 6之后简单地使用esp? 因为在x86上,堆栈从内存顶部向下增长。 简单地掩盖esp的低位可能会破坏当地的情况 变量。因此减法使堆栈增长到16 字节边界。
所以我的问题是,为什么要这样做?它在性能方面是否更好,或者编译器只是遵循一些固定标准?
答案 0 :(得分:1)
将堆栈对齐在16字节边界上。对齐堆栈的原因是需要16字节对齐的东西,如16字节SSE向量,可以用作函数中的局部变量。
我应该补充一点,这通常只由MinGW为main
完成。它在程序开始时将堆栈对齐一次,然后通过始终将堆栈增加16个字节的倍数,使堆栈在其他函数中保持16字节对齐。