43

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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Igor Bezverhi
  • 483
  • 1
  • 5
  • 11

2 Answers2

61

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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • 4
    The shadow space is also useful to simplify var-args functions. They can just [dump the register args into the shadow space](http://stackoverflow.com/a/36851785/224132), and then the entire argument list is a contiguous array. IIRC, the ABI even requires FP args to be passed in both integer and xmm registers, so e.g. the start of `printf` can dump the 4 integer arg regs into the shadow space without figuring out which args are `double`. Or it can use the copy in `xmm0` direcly. This is pretty annoyingly redundant, and seems to go too far for simplicity over performance. :/ – Peter Cordes Jun 21 '16 at 08:55
  • 1
    This doesn't make sense to me - why can't a debugger just be smart enough to allocate new space on the stack (alloca) or on the heap for the register values? Why would you want to always have space allocated in the event you wanted to debug? – Evan Carroll Oct 02 '18 at 19:04
  • 6
    @eva: A debugger is an observer. It's not meant to change the code it observes. Of course a debugger could use its private memory to keep track of register values on function calls. But then you would have no way of inspecting the full call stack when you attach a debugger after the program has started running. Even though I wouldn't know of a better solution, I'm with you that this all feels a bit clunky. – IInspectable Oct 02 '18 at 19:24
  • A function "owns" its stack args, too, and can modify them after function entry. To be able to see args function were actually called with while backtracing, you'd have to write code that used different variables instead of modifying the incoming args. (Or the compiler could copy the stack args if you did that.) Since debug info shows where to find all vars, not just args, you can see arg variables in the stack frame where the compiler spilled them regardless of shadow space or not. e.g. the x86-64 System V calling convention doesn't have a problem with this, even without shadow space. – Peter Cordes Jan 13 '20 at 18:53
  • @pet: I believe I acknowledged that in my answer (*"When optimizations are enabled, \[...\] compilers generally treat the* Home *space as available for scratch use."*). There is no guarantee, that arguments spilled into the home space will survive across a function call, but there is hope. With rcx, rdx, r8, and r9 it's almost a given, that they will be overwritten for the next function call. If not for debugging, what's the primary goal of the home space? Are varargs/unprototyped functions really the only driving motivation? – IInspectable Jan 14 '20 at 08:45
  • Yes, varargs is the reason I've seen given for this (including by Raymond Chen, IIRC). (Along with other design decisions, e.g. passing any args wider than 8 bytes by reference, and the choice of not allowing 4 integer *and* 4 FP args in registers, but instead strictly 4 register-arg slots. And that for variadic functions, you have to copy any FP register args to the corresponding integer reg.) So functions are always able to create an array of all their args by dumping the integer regs into shadow space. [related](https://stackoverflow.com/a/35619528/224132) – Peter Cordes Jan 14 '20 at 12:54
  • Anyway, my point was that in a debug build, the compiler will spill register args *somewhere*, and for seeing incoming args in a backtrace it makes no difference whether they spilled them contiguous with the stack args or next to other locals. (Assuming you have debug info available.) Optimized code won't (necessarily) spill its register args at all; debug mode will always spill them so this works equally well in the x86-64 System V ABI (which has no shadow space and is more complicated but more efficient in many cases, see link in my last comment for differences.) – Peter Cordes Jan 14 '20 at 12:57
  • There's also the [**red zone**](https://en.wikipedia.org/wiki/Red_zone_(computing)), which bears some semblance to *shadow space*. Mentioning in case someone happens upon this Q&A, but their problem involves red zone instead. – Eljay Feb 17 '23 at 13:58
19

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.

ElderBug
  • 5,926
  • 16
  • 25
  • Thanks a lot, so minimum reservation must be 32Bytes, is there a maximum reservation? – Igor Bezverhi May 12 '15 at 12:42
  • @IgorBezverhi Not in the convention, but the callee function only expect 32 bytes + additional arguments, so it will(should) never use more. For the current function, you can use as much as you want, as long as it doesn't exceed the maximum stack size (the so-called stack overflow). – ElderBug May 12 '15 at 12:47