堆栈分配,填充和对齐

我一直在努力深入理解编译器如何生成机器代码,更具体地说,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字节对齐。 为何差异?

作为参考,我正在使用gcc 4.0.1运行10.5的Mac上进行编译,并且未启用优化。


这是一个gcc特性,由-mpreferred-stack-boundary=n ,编译器试图将堆栈上的项目对齐到2^n 。 如果将n更改为2 ,则只会在堆栈上分配8个字节。 n的默认值是4即它将尝试对齐到16个字节的边界。

为什么存在“默认”8个字节,然后是24 = 8 + 16个字节是因为堆栈已经包含8个字节的leaveret ,所以编译后的代码必须先将堆栈调整8个字节,使其与2 ^ 4 = 16。


SSEx系列指令需要打包的128位向量对齐到16个字节 - 否则会出现段错误,试图加载/存储它们。 也就是说,如果您想安全地传递16个字节的矢量以用于堆栈中的SSE,堆栈需要一直保持对齐至16位。默认情况下,GCC占用了该位置。


我发现这个网站,在页面底部有一些体面的解释,说明为什么堆栈可能更大。 将概念扩展到64位机器,它可能解释你所看到的。

链接地址: http://www.djcxy.com/p/14101.html

上一篇: Stack allocation, padding, and alignment

下一篇: Why do we need virtual functions in C++?