堆栈分配、填充和对齐 [英] Stack allocation, padding, and alignment

查看:20
本文介绍了堆栈分配、填充和对齐的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图更深入地了解编译器如何生成机器代码,更具体地说是 GCC 如何处理堆栈.在这样做的过程中,我一直在编写简单的 C 程序,将它们编译成汇编,并尽我所能理解结果.这是一个简单的程序及其生成的输出:

I've been trying to gain a deeper understanding of how compilers generate machine code, and more specifically how GCC deals with the stack. In doing so I've been writing simple C programs, compiling them into assembly and trying my best to understand the outcome. Here's a simple program and the output it generates:

asmtest.c:

void main() {
    char buffer[5];
}

asmtest.s:

pushl   %ebp
movl    %esp, %ebp
subl    $24, %esp
leave
ret

令我困惑的是为什么要为堆栈分配 24 个字节.我知道由于处理器寻址内存的方式,堆栈必须以 4 为增量分配,但如果是这种情况,我们应该只将堆栈指针移动 8 个字节,而不是 24 个字节.作为参考,缓冲区为 17bytes 产生一个移动了 40 个字节的堆栈指针,并且根本没有缓冲区移动堆栈指针 8.1 到 16 个字节之间的缓冲区移动 ESP 24 个字节.

What's puzzling to me is why 24 bytes are being allocated for the stack. I know that because of how the processor addresses memory, the stack has to be allocated in increments of 4, but if this were the case, we should only move the stack pointer by 8 bytes, not 24. For reference, a buffer of 17 bytes produces a stack pointer moved 40 bytes and no buffer at all moves the stack pointer 8. A buffer between 1 and 16 bytes inclusive moves ESP 24 bytes.

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

Now assuming the 8 bytes is a necessary constant (what is it needed for?), this means that we're allocating in chunks of 16 bytes. Why would the compiler be aligning in such a way? I'm using an x86_64 processor, but even a 64bit word should only require an 8 byte alignment. Why the discrepancy?

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

For reference I'm compiling this on a Mac running 10.5 with gcc 4.0.1 and no optimizations enabled.

推荐答案

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

It's a gcc feature controlled by -mpreferred-stack-boundary=n where the compiler tries to keep items on the stack aligned to 2^n. If you changed n to 2, it would only allocate 8 bytes on the stack. The default value for n is 4 i.e. it will try to align to 16-byte boundaries.

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

Why there's the "default" 8 bytes and then 24=8+16 bytes is because the stack already contains 8 bytes for leave and ret, so the compiled code must adjust the stack first by 8 bytes to get it aligned to 2^4=16.

这篇关于堆栈分配、填充和对齐的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆