Выравнивание памяти сегодня и 20 лет назад
В известной статье «Разбивая стек для удовольствия и прибыли», ее автор получает функцию C
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
и генерирует соответствующий вывод ассемблерного кода
pushl %ebp
movl %esp,%ebp
subl $20,%esp
Автор объясняет, что, поскольку компьютеры адресуют память кратными размеру слова, компилятор зарезервировал 20 байтов в стеке (8 байтов для buffer1, 12 байтов для buffer2).
Я попытался воссоздать этот пример и получил следующее
pushl %ebp
movl %esp, %ebp
subl $16, %esp
Другой результат! Я пробовал различные комбинации размеров для buffer1 и buffer2, и кажется, что современный gcc больше не дополняет размеры буфера до кратных размеру слова. Вместо этого он придерживается-mpreferred-stack-boundary
вариант.
В качестве иллюстрации - используя арифметические правила статьи, для buffer1 [5] и buffer2 [13] я получу 8 + 16 = 24 байта, зарезервированных в стеке. Но на самом деле я получил 32 байта.
Бумага довольно старая, и с тех пор произошло много всего. Я хотел бы знать, что именно мотивировало это изменение поведения? Это движение в сторону 64-битных машин? Или что-то другое?
редактировать
Код скомпилирован на компьютере x86_64 с использованием gcc версии 4.8.2 (Ubuntu 4.8.2-19ubuntu1) следующим образом:
$ gcc -S -o example1.s example1.c -fno-stack-protector -m32