我一直在努力深入理解编译器如何生成机器代码,特别是GCC如何处理堆栈。为此,我编写了一些简单的C程序,将它们编译成汇编语言,并尽力理解输出结果。以下是一个简单的程序及其生成的输出:
asmtest.c
:
void main() {
char buffer[5];
}
asmtest.s
:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
leave
ret
对我来说令人困惑的是,为什么要为堆栈分配24字节。我知道由于处理器寻址内存的方式,堆栈必须按4字节递增分配,但如果是这种情况,我们只应该将堆栈指针移动8字节,而不是24字节。参考一下,17字节的缓冲区会导致堆栈指针移动40字节,而没有缓冲区会导致堆栈指针移动8字节。大小在1到16字节之间的缓冲区会导致ESP
移动24字节。
现在假设8字节是必要的常量(它需要用来做什么?),这意味着我们以16字节的块进行分配。为什么编译器要以这种方式对齐呢?我正在使用x86_64处理器,但即使是64位的字也只需要8字节对齐。为什么会有这种差异?
参考资料:我在运行Mac OS 10.5上编译此代码,并使用gcc 4.0.1且未启用任何优化选项。
-mprefered-stack-boundary
默认设置,即使在i386 SysV ABI正式更改要求/保证之前,32位代码的默认设置也是16字节。 - Peter Cordes-mpreferred-stack-boundary = 4
,但只有从esp
减去16。 - Ta Thanh Dinhsub $8, %esp
应该重新对齐堆栈,并使这8个字节可用于数组。额外的16是GCC未优化的结果。 - Peter Cordes