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

Windows x64汇编中可变参数转发问题求助

Fastcall参数转发问题的安全解决方案(无栈帧)

原代码的核心问题

你当前的实现中,add rsp,40后调用foo会导致风险:x64栈是向下增长的(rsp值越小,内存地址越低),foo作为被调用者可能会执行push非易失寄存器、分配栈空间等操作,这些操作会让rsp向更低地址移动,直接覆盖你保存的r13、r14以及forward的返回地址,进而引发崩溃或错误。

正确的实现思路

要安全转发参数,需满足两个要求:

  1. 保存forward自身的参数到非易失寄存器(r13/r14符合要求)
  2. 调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:20:53