What is the 'shadow space' in x64 assembly?

13,434

Solution 1

The Shadow space (also sometimes called Spill space or Home space) is 32 bytes above the return address which the called function owns (and can use as scratch space), below stack args if any. The caller has to reserve space for their callee's shadow space before running a call instruction.

It is meant to be used to make debugging x64 easier.

Recall that the first 4 parameters are passed in registers. If you break into the debugger and inspect the call stack for a thread, you won't be able to see any parameters passed to functions. The values stored in registers are transient and cannot be reconstructed when moving up the call stack.

This is where the Home space comes into play: It can be used by compilers to leave a copy of the register values on the stack for later inspection in the debugger. This usually happens for unoptimized builds. When optimizations are enabled, however, compilers generally treat the Home space as available for scratch use. No copies are left on the stack, and debugging a crash dump turns into a nightmare.

Challenges of Debugging Optimized x64 Code offers in-depth information on the issue.

Solution 2

The shadow space is the mandatory 32 bytes (4x8 bytes) you must reserve for the called procedure. It just means you must provide 32 bytes on the stack before calling. This space can be left uninitialized, it doesn't matter.

Note that in the x64 calling convention, arguments after the 4th are pushed on the stack, which are on top of this shadow space (pushed before the 32 bytes).

In short, you can see it as if functions in x64 have a minimum of 4 arguments, but with the value of the 4 first in registers.

Things like stack alignment should also be considered when calling x64.

Share:
13,434
Igor Bezverhi
Author by

Igor Bezverhi

Updated on June 03, 2022

Comments

  • Igor Bezverhi
    Igor Bezverhi almost 2 years

    I found plenty of topics about this shadow space, but I couldn't find the answer in none of them, so my question is:

    How much exactly bytes I need to subtract from the stack pointer, before entering to a procedure?

    And should I push the procedure parameters to the stack before subtracting the "shadow space"?

    I've disassembled my code, but I couldn't find the logic.