首页 > 解决方案 > Windows 堆栈上的“额外”32 个字节是什么?

问题描述

我正在 Windows 上学习汇编并试图弄清楚堆栈上的值是什么。Visual C++ 文档 说 RSP 以上的值是

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

内存快照中,RSP 从 0x0000000000DAF5E0 开始。彩色框是:

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

使用 VS2019、MASM64 构建并在 x64 调试模式下运行的 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

标签: assemblyx86-64masmcallstackstack-frame

解决方案


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

您的“家庭空间”又名影子空间您的返回地址上方 32 个字节,您只是没有使用它。 (相反,通过存储相对于可能具有任何值的某个寄存器来违反调用约定。在这种情况下,您的调用者可能还使用 RBP 作为传统帧指针,因此您可能只是踩到调用者的主空间。)


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


顺便说一句,当您使用 RBP 作为传统的帧指针时,//mov rsp, rbppop rbp/ret更有效add rsp, 16pop rbp代码大小略小,一些 CPU 会进行 mov-elimination 以避免mov. 这对你来说会更吵,比如可能从你的调用者的返回地址返回,你可能在单步执行时已经注意到了!

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

帧指针是可选的,并且不是堆栈帧布局的必需部分。诸如创建元数据之类的指令.allocstack 16使堆栈展开成为可能,而无需传统的帧指针链表。


推荐阅读