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

Yur*_*que 0 c x86 gcc abi

关于数据类型对齐的怀疑,我现在正在学习对齐,还有一些问题,所以我知道在用gcc编译i386体系结构时,linux中double对齐为4个字节,因此double的地址与a对齐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;
}
Run Code Online (Sandbox Code Playgroud)

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

Pet*_*des 5

出于最佳化的考虑编译器可以而且确实会选择给予对象更多的对齐方式,除非ABI的结构打包规则强迫它们将其对齐。 alignof(double) = 4适用于i386 System V,但gcc 更喜欢使其自然对齐,例如aligas(sizeof(double)) double x

现代x86 确实受益于的8字节对齐double,但是alignof(double) == 4ABI规则在386天没有缓存时就有意义了,并且fld qword [mem]确实需要2个单独的32位负载。但是,如果现代x86硬件没有在两条缓存行之间拆分,可以在一次访问缓存中完成8字节(甚至32字节)的加载,这可以通过alignof <sizeof来实现。

另外,将堆栈对齐16可以使本地代码便宜8或16字节对齐,这是对i386 System V ABI的最新Linux修改。在此之前,每个带有double局部函数的函数都将被迫制作一个帧指针,然后执行and $-8, %esp某些操作。


IDK为什么您认为编译器会按照声明的顺序排列本地语言,就像它是一个结构一样。编译器可以自由地将大对象放在一起,因此不必在填充上浪费空间。

查看编译器的asm输出,以了解其堆栈布局的情况。并且不要忘记启用优化。您可能volatile double用来阻止其内存地址进行优化。