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

编写64位Pentium汇编调用printf时栈空间分配的疑问

MSVC x86-64汇编调用printf需预留32字节栈空间的原因

这是由MSVC的x86-64调用约定(__fastcall)决定的:调用任何函数前,调用者必须在栈上预留32字节的影子空间(Shadow Space),无论是否用到前4个寄存器参数(rcx、rdx、r8、r9)。

初始代码失败的原因

你第一次的代码里,push的rcx、rdx、rdi、rsi四个寄存器值占据了栈顶32字节,但这部分空间并没有被当作约定的影子空间。printf作为标准库函数,会默认调用方已在栈顶预留影子空间,内部可能会将参数写入该区域——直接覆盖了你push的寄存器值,导致后续pop无法恢复正确内容。

修改后代码正常的原因

sub rsp,20h(32字节)专门预留了符合约定的影子空间,此时printf只会操作这个栈顶区域,你push的寄存器值位于影子空间下方,不会被覆盖,因此pop时能正确恢复寄存器。

为什么C编译器生成的代码无需额外分配?

C编译器会在函数开头统一分配栈空间,这个空间已经包含了影子空间、局部变量空间,同时满足16字节栈对齐要求:

  • 若函数无局部变量,编译器可能在开头直接执行sub rsp, 32预留影子空间;
  • 若函数有局部变量,编译器会计算总需求(影子空间+局部变量+对齐字节),一次性完成分配,因此调用printf时无需额外执行sub rsp。

额外注意:栈对齐要求

MSVC调用约定还规定,执行call指令时rsp必须是16字节对齐的。call会压入8字节返回地址,调用后rsp变为8字节对齐,符合被调用方的栈布局要求。你修改后的代码中,push四个寄存器(32字节)+ sub rsp,32,总栈偏移为64字节(16的倍数),确保了call前rsp是16字节对齐,这也是代码正常运行的必要条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 22:18:10