В знаменитой статье "Smashing the Stack for Fun and Profit" ее автор использует функцию 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-битным машинам? Или что-то еще?
Edit
Код компилируется на машине x86_64 с использованием gcc версии 4.8.2 (Ubuntu 4.8.2-19ubuntu1) следующим образом:
$ gcc -S -o example1.s example1.c -fno-stack-protector -m32