Windows x64汇编中可变参数转发问题求助
Fastcall参数转发问题的安全解决方案(无栈帧)
原代码的核心问题
你当前的实现中,add rsp,40后调用foo会导致风险:x64栈是向下增长的(rsp值越小,内存地址越低),foo作为被调用者可能会执行push非易失寄存器、分配栈空间等操作,这些操作会让rsp向更低地址移动,直接覆盖你保存的r13、r14以及forward的返回地址,进而引发崩溃或错误。
正确的实现思路
要安全转发参数,需满足两个要求:
- 保存
forward自身的参数到非易失寄存器(r13/r14符合要求) - 调用
foo时,确保foo的栈操作不会触及forward保存的寄存器和返回地址——通过为foo单独分配独立的栈空间(包含shadow space和栈参数区域),将需要转发的栈参数复制到该区域后再调用foo。
固定栈参数数量的示例代码
假设forward需要转发2个栈上参数(forward的第5、6个参数对应foo的第3、4个参数),实现如下:
forward: ; 保存非易失寄存器,避免被后续操作破坏 push r14 push r13 ; 保存forward自身的两个参数(rcx、rdx) mov r13, rcx mov r14, rdx ; 设置foo的前两个寄存器参数(forward的第3、4个参数) mov rcx, r8 ; foo arg1 = forward arg3 mov rdx, r9 ; foo arg2 = forward arg4 ; 为foo分配栈空间:32字节shadow space + 16字节(2个栈参数)= 48字节 sub rsp, 48 ; 复制forward的栈参数到foo的栈参数位置 ; 计算forward栈参数的地址:push的2个寄存器(16) + 返回地址(8) + forward的shadow space(32) = 56字节偏移 ; 因已sub rsp 48,当前地址需额外加48 mov rax, [rsp + 104] mov [rsp + 32], rax ; foo arg3 放在shadow space之后 mov rax, [rsp + 112] mov [rsp + 40], rax ; foo arg4 放在arg3之后 ; 安全调用foo,此时foo的栈操作不会触及forward的保存数据 call foo ; 清理为foo分配的栈空间 add rsp, 48 ; 恢复寄存器 pop r13 pop r14 ret
关键细节说明
- Shadow Space要求:x64 Fastcall规定,调用者必须为被调用者分配32字节的shadow space,不管被调用者是否使用,因此代码中必须预留这部分空间。
- 栈地址计算:复制栈参数时,需考虑
push寄存器和sub rsp对栈地址的影响,确保能正确读取到forward的栈参数。 - 非易失寄存器:
r13/r14属于非易失寄存器,必须保存后再使用,否则会破坏调用者的上下文。
内容的提问来源于stack exchange,提问作者sentientbottleofwine
相关产品推荐
相关产品推荐

