Подтвердить что ты не робот

Распределение стека, отступы и выравнивание

Я пытаюсь получить более глубокое понимание того, как компиляторы генерируют машинный код, а точнее, как GCC имеет дело со стеком. При этом я пишу простые программы на С, компилируя их в сборку и изо всех сил пытаюсь понять результат. Здесь простую программу и выходные данные, которые она генерирует:

asmtest.c:

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

asmtest.s:

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

Что меня озадачивает, так почему для стека выделяется 24 байта. Я знаю, что из-за того, как процессор обращается к памяти, стек должен быть распределен с шагом 4, но если это так, мы должны только перемещать указатель стека на 8 байтов, а не 24. Для справки буфер 17 байт вырабатывает указатель стека, перемещаемый 40 байтами, и никакой буфер вообще не перемещает указатель стека 8. Буфер между 1 и 16 байтами включительно перемещает ESP 24 байта.

Теперь, полагая, что 8 байтов - необходимая константа (для чего это необходимо?), это означает, что мы выделяем куски по 16 байт. Почему компилятор должен быть таким образом совмещен? Я использую процессор x86_64, но даже для 64-битного слова требуется только выравнивание по 8 байт. Почему расхождение?

Для справки я компилирую это на Mac, работающем 10.5 с gcc 4.0.1, и оптимизация не включена.

4b9b3361

Ответ 1

Это функция gcc, управляемая -mpreferred-stack-boundary=n, когда компилятор пытается сохранить элементы в стеке, выровненные с 2^n. Если вы изменили n на 2, он выделил бы только 8 байтов в стеке. Значение по умолчанию для n равно 4, т.е. Будет пытаться выровнять по 16-байтовым границам.

Почему там "по умолчанию" 8 байтов, а затем 24 = 8 + 16 байт, потому что стек уже содержит 8 байтов для leave и ret, поэтому скомпилированный код должен сначала отрегулировать стек на 8 байтов, чтобы получить он выровнен до 2 ^ 4 = 16.

Ответ 2

Семейство инструкций SSEx ТРЕБУЕТ упакованных 128-битных векторов, которые должны быть выровнены с 16 байтами - в противном случае вы получите segfault, пытающийся загрузить/сохранить их. То есть если вы хотите безопасно передавать 16-байтные векторы для использования с SSE в стеке, стек необходимо последовательно поддерживать в соответствии с 16. Учетные записи GCC по умолчанию.

Ответ 3

Я нашел этот сайт, в котором есть несколько полезных объяснений внизу страницы о том, почему стек может быть больше. Масштабируйте концепцию до 64-битной машины, и она может объяснить, что вы видите.

Ответ 5

Для Mac OS X/Darwin x86 ABI требуется выравнивание стека по 16 байт. Это не так на других платформах x86, таких как Linux, Win32, FreeBSD...

Ответ 6

8 байтов есть потому, что первая команда подталкивает начальное значение% ebp в стеке (предполагая 64-разрядную).