Почему в x64 функции epilog нет инструкции `отпуска`?
Я собираюсь понять, как работает стек на компьютерах с архитектурой x86 и x64. Однако я заметил, что когда я вручную пишу код и разбираю его, он отличается от того, что я вижу в коде, который предоставляют люди (например, в своих вопросах и руководствах). Вот маленький пример:
Источник
int add(int a, int b) {
int c = 16;
return a + b + c;
}
int main () {
add(3,4);
return 0;
}
x86
add(int, int):
push ebp
mov ebp, esp
sub esp, 16
mov DWORD PTR [ebp-4], 16
mov edx, DWORD PTR [ebp+8]
mov eax, DWORD PTR [ebp+12]
add edx, eax
mov eax, DWORD PTR [ebp-4]
add eax, edx
leave (!)
ret
main:
push ebp
mov ebp, esp
push 4
push 3
call add(int, int)
add esp, 8
mov eax, 0
leave (!)
ret
Сейчас идет х64
add(int, int):
push rbp
mov rbp, rsp
(?) where is `sub rsp, X`?
mov DWORD PTR [rbp-20], edi
mov DWORD PTR [rbp-24], esi
mov DWORD PTR [rbp-4], 16
mov edx, DWORD PTR [rbp-20]
mov eax, DWORD PTR [rbp-24]
add edx, eax
mov eax, DWORD PTR [rbp-4]
add eax, edx
(?) where is `mov rsp, rbp` before popping rbp?
pop rbp
ret
main:
push rbp
mov rbp, rsp
mov esi, 4
mov edi, 3
call add(int, int)
mov eax, 0
(?) where is `mov rsp, rbp` before popping rbp?
pop rbp
ret
Как вы можете видеть, моя главная путаница в том, что когда я компилирую с x86 - я вижу то, что ожидаю. Когда это x64 - я пропускаю инструкцию или точную следующую последовательность: mov rsp, rbp
затем pop rbp
, Что за работа?
ОБНОВИТЬ
Это похоже на leave
отсутствует только потому, что он не был изменен ранее. Но тогда возникает другой вопрос - почему в кадре нет выделения для локальных переменных?
На этот вопрос @melpomene дает довольно прямой ответ - из-за "красной зоны". Что в основном означает, что функция, которая не вызывает дальнейшие функции (лист), может использовать первые 128 байтов под стеком без выделения места. Так что, если я вставлю звонок внутри add()
к любой другой тупой функции - sub rsp, X
а также add rsp, X
будут добавлены к прологу и эпилогу соответственно.