Windows 堆栈上的 "extra" 32 字节是什么?

What are the "extra" 32 bytes on the Windows stack?

我正在 Windows 上学习汇编,并试图弄清楚堆栈上的值是什么。
Visual C++ documentation 表示高于 RSP 的值是:

问题是文档中没有提到堆栈中有 32 个额外的字节。

在 memory snapshot 中,RSP 从 0x0000000000DAF5E0 开始。彩色框是:

那些红色的字节可能是什么?

在 x64 调试模式下使用 VS2019、MASM64 和 运行 构建的 MASM 源代码。

C++ 标志:/JMC /permissive- /GS /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc142.pdb" /Zc:inline /fp:precise / D "_D​​EBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"x64\Debug\" /EHsc / nologo /Fo"x64\Debug\" /Fp"x64\Debug\ConsoleApplication1.pch" /diagnostics:column

.code

; int64_t StackFrameDemo_(int8_t a, int16_t b, int32_t c, int64_t d, int8_t e, int16_t f, int32_t g, int64_t h)
StackFrameDemo_ proc frame

; prolog
push rbp
.pushreg rbp

; allocate 16 bytes on the stack
sub rsp, 16
.allocstack 16
.endprolog

; save registers to register home
mov qword ptr [rbp+8], rcx
mov qword ptr [rbp+16], rdx
mov qword ptr [rbp+24], r8
mov qword ptr [rbp+32], r9

; save the two variables
mov rax, 9
mov [rsp], rax
mov [rsp+type qword], rax

nop ; set the break point here to view memory

; epilog
add rsp, 16 ; release local stack space
pop rbp     ; restore caller's rbp register

ret

StackFrameDemo_ endp

end

您忘记执行 mov rbp, rsp(在 push rbp 之后)使 RBP 成为 您的 堆栈帧的帧指针。

你的 "home space" 又名影子 space 在你的 return 地址上方 32 个字节,你只是不使用它。(而不是通过相对于某个可能具有任何值的寄存器进行存储来违反调用约定。在这种情况下,您的调用者可能也将 RBP 用于遗留帧指针,因此您可能只是步进在来电者的家里 space.)


请注意,0xCC 是 MSVC 调试模式用来毒害堆栈的值,有助于检测未初始化内存的读取。 (如果你不小心用这些内容执行内存,那就是 x86 int3 调试断点指令。)


顺便说一句,当您使用 RBP 作为传统的帧指针时,mov rsp, rbp / pop rbp / retadd rsp, 16 / [=15 更有效=].代码量略小,一些 CPU 进行移动消除以避免 mov 需要一个执行单元。这对你来说会更吵闹,比如可能 return 从你的呼叫者的 return 地址,你在单步执行时可能已经注意到了!

(leave = mov/pop,因此您可以将其用于更小的代码大小。与 enter 不同,它的性能还可以;GCC 在中使用 leave具有以 RSP 结尾的帧指针的函数尚未指向已保存的 RBP。其他一些编译器更喜欢 mov/pop。但编译器通常只在根本不使用帧指针时才使用 add rsp, n。)

帧指针是可选的,不是堆栈帧布局的必需部分。 .allocstack 16 等指令创建元数据,无需传统的帧指针链表即可展开堆栈。