如何在MASM x64环境下将参数压入栈?
问题解答
核心问题原因
你遇到的崩溃、参数异常问题根源是没有遵守Windows x64调用约定的核心规则:
- 调用者需要为被调函数预留32字节的影子空间(Shadow Space),用于被调函数备份前4个寄存器参数(
rcx/rdx/r8/r9),哪怕被调函数实际不会用到这部分空间也必须预留 - 执行
call指令前,栈指针rsp必须对齐到16字节边界 - 额外的栈参数需要放在影子空间的上方,你之前直接写
[rsp + 20h]时没有预留栈空间,写入的地址刚好覆盖了当前函数的返回地址,所以执行ret时会把写入的参数值当成返回地址加载到rip,导致RIP变成异常值。
正确实现步骤
- 进入函数后先保存非易失寄存器、设置栈帧,再分配足够的栈空间:需要包含32字节影子空间 + 你要传递的额外参数的总空间,同时保证分配后
rsp满足16字节对齐要求 - 额外的第N个参数(N≥5)写入影子空间后的对应偏移位置
- 调用结束后恢复栈空间和非易失寄存器
你场景的正确汇编代码如下:
call_func PROC push rbx ; rbx是被调保护的非易失寄存器,修改前先保存 push rbp mov rbp, rsp sub rsp, 30h ; 分配48字节栈空间:32字节影子空间 + 2个8字节参数位(支持最多6个参数),同时满足16字节对齐 mov rbx, rcx ; 保存要调用的C函数地址 ; 前4个参数写入对应寄存器 mov rcx, 1 mov rdx, 2 mov r8, 3 mov r9, 4 ; 第5个参数写入影子空间后第一个位置 mov QWORD PTR [rsp + 20h], 5 ; 第6个参数写入下一个8字节位置(有需要时加) mov QWORD PTR [rsp + 28h], 6 call rbx ; 调用目标函数 mov rsp, rbp ; 恢复栈指针 pop rbp pop rbx ; 恢复rbx寄存器原值 ret call_func ENDP
异常情况说明
你之前测试6个参数时第6个传递成功、第5个异常,是因为你写入[rsp + 28h]时刚好没有覆盖返回地址,但第5个参数对应的位置没有预留空间,被栈上其他原有数据覆盖,才会出现取值异常。
内容的提问来源于stack exchange,提问作者Vento
相关产品推荐
相关产品推荐

