c - 堆栈分配、填充和对齐

标签 c gcc assembly x86 stack

我一直在努力更深入地了解编译器如何生成机器代码,更具体地说,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 bytes 产生一个堆栈指针移动 40 个字节,并且根本没有缓冲区移动堆栈指针 8。1 到 16 个字节之间的缓冲区移动 ESP 24 个字节。

现在假设 8 个字节是一个必要的常量(需要它做什么?),这意味着我们正在分配 16 个字节的 block 。为什么编译器会以这种方式对齐?我使用的是 x86_64 处理器,但即使是 64 位字也只需要 8 字节对齐。为什么会出现差异?

作为引用,我在运行 10.5 和 gcc 4.0.1 且未启用优化的 Mac 上编译它。

最佳答案

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

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

关于c - 堆栈分配、填充和对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52338467/

相关文章:

c - 通过套接字传输压缩文件?

将 C 变量的内容复制到寄存器 (GCC)

linux - 如果不是 gcc -static 那么 shell 说 'no such file'

c - 如何在 CPP 中串联宏

c - 使用 Malloc 和 Free 调试指针

c++ - 函数参数在 64 位操作系统的寄存器中传输?

assembly - x86中的JCC指令是什么

c++ - 线程安全的 Hook 函数

c - 如何使用 Oscar Anderson 的 ISO8583 库获取消息长度?

visual-c++ - 是否有像 gcc 的 -M 这样的 MSVC 依赖生成标志