Является ли резервирование пространства стека необходимым для функций менее четырех аргументов?

Просто начал изучать сборку x64, и у меня есть вопрос о функциях, аргументах и ​​стеке. Насколько я понимаю, первые четыре аргумента в функции передаются в регистры rcx, rdx, r8 и r9 (и xmm0-xmm3 для поплавков) в Windows. Таким образом, тривиальная функция добавления с четырьмя параметрами будет выглядеть так:

add:
   mov r10, rcx
   add r10, rdx
   add r10, r8
   add r10, r9
   mov rax, r10
   ret

Однако я столкнулся с документацией, которая упоминает об этом:

. Как минимум, каждая функция должна резервировать 32 байта (четыре 64-разрядных значения) в стеке. Это пространство позволяет легко переписывать регистры, передаваемые в функцию, в хорошо известное местоположение стека, Функция вызова не требуется, чтобы различать параметры входного регистра в стек, но резервирование пространства стека гарантирует, что оно может при необходимости.

Итак, мне нужно зарезервировать пространство стека, даже если выполняемые мной функции берут четыре параметра или меньше, или это просто рекомендация?

Ответ 1

Ваша цитата из части документа "вызов". По крайней мере, вам не нужно беспокоиться об этом, если вы не вызываете другие функции из вашего ассемблерного кода. Если вы это сделаете, тогда вы должны уважать, среди прочего, "красную зону" и соображения выравнивания стека, что рекомендуемая вами рекомендация предназначена для обеспечения.

EDIT: этот пост разъясняет разницу между "красной зоной" и "теневым пространством".

Ответ 2

Я просто столкнулся с этим, не зная, и, похоже, это так. Первые две команды в GetAsyncKeyState, например, перезаписывают стек выше возвращаемого значения в области байтов 0x20, которую вы должны зарезервировать для вызываемого абонента для использования для параметров:

user32.GetAsyncKeyState  - mov [rsp+08],rbx
user32.GetAsyncKeyState+5- mov [rsp+10],rsi
user32.GetAsyncKeyState+A- push rdi
user32.GetAsyncKeyState+B- sub rsp,20