Я пытался глубже понять, как компиляторы генерируют машинный код, и, в частности, как GCC работает со стеком. Поступая так, я писал простые программы на C, компилировал их в сборку и изо всех сил пытался понять результат. Вот простая программа и результат, который она генерирует:
asmtest.c:
void main() {
char buffer[5];
}
asmtest.s:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
leave
ret
Что меня озадачивает, так это то, почему для стека выделяется 24 байта. Я знаю, что из-за того, как процессор обращается к памяти, стек должен выделяться с шагом 4, но если бы это было так, мы должны переместить указатель стека только на 8 байтов, а не на 24. Для справки, буфер 17 bytes создает указатель стека, перемещаемый на 40 байтов, и никакой буфер вообще не перемещает указатель стека 8. Буфер между 1 и 16 байтами включительно перемещает ESP 24 байта.
Теперь, предполагая, что 8 байтов - необходимая константа (для чего она нужна?), Это означает, что мы выделяем блоки по 16 байтов. Почему компилятор выравнивается таким образом? Я использую процессор x86_64, но даже для 64-битного слова требуется выравнивание только на 8 байт. Почему неточность?
Для справки я компилирую это на Mac, работающем под управлением 10.5 с gcc 4.0.1 и без включенной оптимизации.
-mprefered-stack-boundaryнастройка по умолчанию, которая составляла 16 байтов для 32-битного кода еще до того, как i386 SysV ABI официально изменился на требование / гарантию. - person Peter Cordes   schedule 11.04.2018-mpreferred-stack-boundary=4, но есть только вычитание 16 изesp. - person Ta Thanh Dinh   schedule 13.06.2018sub $8, %espследует повторно выровнять стек и сделайте эти 8 байтов пригодными для использования в массиве. Дополнительные 16 - это пропущенная оптимизация gcc. - person Peter Cordes   schedule 25.07.2020