Вопрос выравнивания двойного стека с использованием компилятора gcc для архитектуры x86 - PullRequest
0 голосов
/ 15 октября 2019

Сомневаюсь в выравнивании типов данных, сейчас я изучаю выравнивание, и у меня есть несколько вопросов, поэтому я знаю, что double выравнивается до 4 байтов в linux при компиляции с gcc для архитектуры i386, и поэтому адрес double имеетвыровнен по кратному 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 align.c

1 Ответ

5 голосов
/ 15 октября 2019

Компиляторы могут и действительно хотят дать объекту больше выравнивания по причинам оптимизации , если только правила ABI для упаковки структуры не вынуждают их смещать его. alignof(double) = 4 для i386 System V, но gcc предпочитает , чтобы придать ему естественное выравнивание, как aligas(sizeof(double)) double x.

Современный x86 имеет преимущество от 8-байтового выравнивания дляdouble, но правило alignof(double) == 4 ABI имело смысл еще в 386 дней, когда не было кеша, а fld qword [mem] действительно выполняло 2 отдельные 32-битные загрузки. Но современное оборудование x86 может выполнять 8-байтовые (или даже 32-байтовые) загрузки за один доступ к кэшу, , если , он не разбит на две строки кэша, что возможно с alignof

Кроме того, выравнивание стека по 16, удешевляющее предоставление локальным 8 или 16-байтовым выравниванием, является более поздней модификацией Linux для i386 System V ABI. До этого каждая функция с локальным double была бы вынуждена сделать указатель кадра и сделать and $-8, %esp или что-то в этом роде.


IDK, почему вы думаете, что компилятор будет размещать локальные объекты в их порядкедекларации, как если бы это была структура. Компилятор может свободно собирать большие объекты, поэтому ему не нужно тратить место на отступы.

Посмотрите на вывод asm компилятора, чтобы увидеть, что происходит с его компоновкой стека. И не забудьте включить оптимизацию. Вы можете использовать volatile double, чтобы остановить оптимизацию адреса памяти.

...