在main
函数(一个简单的玩具程序)的序言中,使用gcc -g -o program -m32 program.c
在64位计算机上运行(运行ubuntu 14.04),我得到以下反汇编:
dump of assembler code for function main:
0x08048e24 <+0>: push %ebp
0x08048e25 <+1>: mov %esp,%ebp
0x08048e27 <+3>: and $0xfffffff0,%esp
...
&lt; + 3&gt;指令的目的是什么?
也就是说,为什么$esp
指向一个16对齐的地址?
答案 0 :(得分:0)
i386 System V ABI的现代版本与x86-64 System V(@ouah的答案提到)具有相同的16字节堆栈对齐要求/保证。
这包括保证内核在%esp
处将_start
对齐16。因此,也保持16字节对齐的CRT启动代码将调用main
,堆栈对齐16字节。
从历史上看,i386 System V ABI只需要4字节的堆栈对齐,而将堆栈对齐16位只是编译器可以选择进行的工作;当GCC只是一个好主意,而不是法律(在MacOS和Linux上)时,默认设置为-mpreferred-stack-boundary=4
。
我认为某些BSD版本仍然不需要32位代码中的16字节堆栈对齐,因此想要对double
,int64_t
或特别是XMM向量,确实需要手动对齐堆栈,而不是依赖传入的堆栈对齐。
但是,即使在现代Linux上,-m32
的GCC的32位模式(main
)行为也不假定main
的调用者(或内核)遵循ABI ,然后手动对齐堆栈。
有关更多信息,请参见Responsibility of stack alignment in 32-bit x86 assembly;另一个问题是,过时的指令会基于需要的假设而导致混乱。
在x86-64上的GCC不会 这样做,只是利用了x86-x中始终要求16字节堆栈对齐 的事实64系统V ABI。 (以及Windows x64 ABI)。