针对 x86 架构使用 gcc 编译器的双堆栈对齐问题

Double stack alignment question using gcc compiler for x86 architecture

关于数据类型对齐的疑问,我现在正在学习对齐,我有一些问题,所以我知道在linux中用gcc编译i386架构时双对齐到4字节,所以地址double 的 has 对齐到 4 的倍数,但是当我使用堆栈时它不会发生,只有当我使用数据结构时才会发生

#include <stdio.h>

int main(void) {

    double x = 5; //     8 
    char s = 'a'; //    +1
    double y = 2; //   ---- = 9 + 8 = 17 + alignment = 20 

    //int x = 5; //     4
    //char s = 'a';    +1
    //int y = 2;     --------= 5 + 4 = 9 + alignment = 12 

    size_t a, b;
    a = (size_t)&s;
    b = (size_t)&y;

    printf("%zu", a - b); // it wasn't supposed to be 11 instead of 15
    return 0;
}

编译: $ gcc -m32 -o 对齐 align.c

出于优化的原因,编译器可以而且确实会选择为对象提供更多对齐方式,除非 ABI 的结构打包规则强制它们不对齐。 alignof(double) = 4 对于 i386 System V,但 gcc 更喜欢 以使其自然对齐,例如 aligas(sizeof(double)) double x.

现代 x86 受益于 double 的 8 字节对齐,但 alignof(double) == 4 ABI 规则在 386 天之前就有意义了t 缓存,并且 fld qword [mem] 确实需要 2 个独立的 32 位加载。但是现代 x86 硬件可以在对缓存的单次访问中执行 8 字节(甚至 32 字节)加载,if 它不会拆分为两个缓存行,这可以通过 alignof < sizeof.

此外,将堆栈按 16 位对齐使得为本地人提供 8 或 16 字节对齐变得便宜是对 i386 System V ABI 的更新 Linux 修改。在此之前,每个具有 double 本地的函数都将被迫创建一个帧指针并执行 and $-8, %esp 或其他操作。


不知道为什么你认为编译器会按照声明的顺序排列局部变量,就像它是一个结构一样。编译器可以自由地将大对象放在一起,因此不必在填充上浪费 space。

查看编译器 asm 输出以了解其堆栈布局发生了什么。并且不要忘记启用优化。您可以使用 volatile double 来阻止其内存地址优化。