Search code examples
assemblyx86-64calling-convention

What is the usage for the shadow space for the first 4 parameters in x64 calling convention


According to https://learn.microsoft.com/en-us/cpp/build/stack-usage?view=msvc-170, the caller must always allocate sufficient space for the 4 register parameters, even if the callee doesn’t have that many parameters. Space is always allocated for the register parameters, even if the parameters themselves are never homed to the stack.

What's the usage of this shadow space for the 4 register parameters?

I disassembled some programs compiled by VS and G++, and found that the callee saves the register parameters in the shadow space at the beginning. For example, WinMain(HINSTANCE *hInstance, HINSTANCE *hPrevInstance, char *lpCmdLine, int nCmdShow) function does the following pushing at its beginning:

mov     [rsp+arg_18], r9d
mov     [rsp+arg_10], r8
mov     [rsp+arg_8], rdx
mov     [rsp+arg_0], rcx

Why the callee saves the register parameters in the shadow space?
If the callee has to save the register parameters in the stack, why they use registers to pass the parameters instead of passing all the parameters by stack directly?


Solution

  • The callee may or may not need to save them, that depends entirely on the situation. For example, a function that just returns the sum of the arguments might not need to save them. In this case using registers saves a store and a load, while it does not incur any overhead in the other case (the store is just moved from the caller to the callee).

    Allocating the shadow space is practically free if you do it together with your local variables in the caller, and has the advantage that if the callee needs to save the arguments, the resulting block will be contiguous with the rest of the arguments already on the stack.