You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

何时需要Shadow Space?为何未分配该空间代码仍无报错?

X64调用约定中未分配Shadow Space却正常运行的原因

首先明确:微软X64调用约定确实要求调用者为被调用者预留32字节的Shadow Space,你当前代码能正常运行属于未定义行为下的巧合情况,并非符合规范的写法,具体原因如下:

  • 被调用函数的实现细节:
    printf这类CRT函数在禁用优化的编译环境下,内部可能并没有使用Shadow Space来保存RCX/RDX/R8/R9这些参数寄存器的值。只有当被调用函数需要将这些寄存器的值写入栈上的Shadow Space时,才会依赖调用者的预留操作;如果函数内部没做这个操作,自然不会触发错误。

  • 初始栈的空闲空间:
    你的main作为程序入口,在调用_CRT_INIT之后,栈顶下方通常还有一段未被使用的合法栈内存。即使你没显式分配Shadow Space,被调用函数如果偶然访问到这段空闲栈内存,也不会触发内存访问违规。但这种空闲空间的大小是不确定的,换个环境、修改CRT初始化逻辑或者增加其他栈操作后,就可能出现崩溃。

  • 优化开关的影响:
    禁用全程序优化后,CRT函数的实现会更偏向于“直白”的逻辑,不会为了性能去利用Shadow Space做寄存器优化。一旦开启优化,CRT函数的实现可能会主动使用Shadow Space来保存寄存器,此时未预留空间的代码必然会触发内存错误。

符合规范的正确写法

必须显式分配Shadow Space,示例代码修改如下:

includelib msvcrt.lib
includelib legacy_stdio_definitions.lib

extern _CRT_INIT: proc     
extern printf: proc
extern ExitProcess: proc

.data
     msg db "hello world!", 13, 10, 0

.code
main proc 
  call _CRT_INIT       
  sub rsp, 32        ; 为被调用者分配32字节Shadow Space
  lea rcx,msg
  call printf
  add rsp, 32        ; 调用完成后释放Shadow Space
  call ExitProcess
main endp
end

内容的提问来源于stack exchange,提问作者Mohammad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:01:41