堆栈分配,填充和对齐堆栈分配,填充和对齐(Stack allocation, padding, an

2019-05-14 05:57发布

我一直在试图获得的编译器产生怎样的机器代码有更深的了解,更具体如何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字节对齐。 为什么不一致?

仅供参考我运行10.5用gcc 4.0.1在Mac上编译这个并启用任何优化。

Answer 1:

它是由控制的GCC功能-mpreferred-stack-boundary=n当编译器试图保持项目排列在栈上2^n 。 如果您更改n2 ,将只分配在堆栈上的8个字节。 为默认值n4 ,即它会尝试对齐到16字节边界。

为什么有“默认”的8个字节,然后24 = 8 + 16个字节,因为堆栈已经包含了8个字节leaveret ,所以编译后的代码必须是8个字节首先调整堆得到它对齐到2 ^ 4 = 16。



Answer 2:

该SSEX家庭指令要求包装对齐到16个字节的128位向量 - 否则,你得到一个段错误试图加载/存储它们。 也就是说,如果你想要安全通过16字节向量与上证所在堆栈上使用,堆栈必须始终保持一致,以16 GCC账户,默认情况下。



Answer 3:

我发现这个网站 ,其中有大约为什么堆栈可能更大页面底部的一些体面的解释。 缩放概念到一个64位的机器,它可以解释你所看到的。



Answer 4:

LWN对内存对齐的文章 ,你可能会觉得有趣。



Answer 5:

Mac OS X的/达尔文86 ABI需要16个字节的栈对齐。 这是不是在其他x86平台,如Linux,Win32中,FreeBSD的情况下...



Answer 6:

的8个字节是因为有所述第一指令将在堆栈上的%ebp的起始值(假设64位)。



文章来源: Stack allocation, padding, and alignment