Компиляторы могут свободно организовывать кадры стека (при условии, что они даже используют стеки) любым способом, каким они пожелают.
Они могут делать это по причинам выравнивания, или по соображениям производительности, или вообще без причины. Вам было бы неразумно принимать какой-либо конкретный заказ.
Если бы вы не вызвали неопределенное поведение из-за переполнения буфера, вы, вероятно, никогда бы об этом не узнали, и так оно и должно быть.
Компилятор может не только реорганизовать ваши переменные, но и оптимизировать их из существования, если он может установить, что они не используются. С кодом:
#include <stdio.h>
int main (void) {
char bing[71];
int x = 7;
bing[0] = 11;
return 0;
}
Сравните нормальный вывод ассемблера:
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $80, %esp
movl %gs:20, %eax
movl %eax, 76(%esp)
xorl %eax, %eax
movl $7, (%esp)
movb $11, 5(%esp)
movl $0, %eax
movl 76(%esp), %edx
xorl %gs:20, %edx
je .L3
call __stack_chk_fail
.L3:
leave
ret
с безумно оптимизированным:
main:
pushl %ebp
xorl %eax, %eax
movl %esp, %ebp
popl %ebp
ret
Заметили что-нибудь пропущенное в последнем? Да, есть нет стековых манипуляций для создания пространства для bing
или x
. Их не существует Фактически вся последовательность кода сводится к:
- установить код возврата на 0.
- возвращение.