Действительно причудливая gcc quirk. Проверьте это:
main() { int a[100]; a[0]=1; }
создает эту сборку:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 81 ec 18 01 00 00 sub $0x118,%rsp
b: c7 85 70 fe ff ff 01 movl $0x1,-0x190(%rbp)
12: 00 00 00
15: c9 leaveq
16: c3 retq
В верхней части стека явно 400, так как его массив 100 * 4. Поэтому, когда он записывается в первую запись, он делает rbp-400 (строка 'b'). Хорошо. Но почему он вычитает 280 из указателя стека (строка "4" )? Не указывает ли это на середину массива?
Если после этого добавить вызов функции, gcc делает правильную вещь:
b() {}
main() { int a[100]; a[0]=1; b(); }
создает эту сборку:
0000000000000000 <b>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: c9 leaveq
5: c3 retq
0000000000000006 <main>:
6: 55 push %rbp
7: 48 89 e5 mov %rsp,%rbp
a: 48 81 ec 90 01 00 00 sub $0x190,%rsp
11: c7 85 70 fe ff ff 01 movl $0x1,-0x190(%rbp)
18: 00 00 00
1b: b8 00 00 00 00 mov $0x0,%eax
20: e8 00 00 00 00 callq 25 <main+0x1f>
25: c9 leaveq
26: c3 retq
Здесь он правильно вычитает 400 (строка 'a').
Почему изменение при добавлении вызова функции? Является ли gcc просто ленивым и не делает это правильно, потому что это не имеет значения? Что происходит? Очевидно, это происходит только при компиляции для x86_64, но не для простого x86. Имеет ли это что-то странное с x86_64 "redzone"? Что происходит точно?