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

汇编代码运行时检查失败:ESP值未正确保存问题排查

解决Run-Time Check Failure #0错误(ESP值未正确保存)

核心问题:Proc5函数的C++声明使用__fastcall调用约定,但汇编实现未遵循该约定的栈平衡、寄存器保存规则,导致ESP指针在调用后无法正确恢复,触发运行时检查错误。

__fastcall调用约定的关键规则

  • 前两个DWORD参数通过ECX、EDX寄存器传递,剩余参数从右往左依次入栈
  • 被调用者负责清理栈上的剩余参数(通过ret 数值指令)
  • 函数内使用EBX、ESI、EDI、EBP等非易失性寄存器时,必须先保存,函数结束前恢复

你的代码中的具体问题

  1. 栈平衡错误:汇编末尾使用ret而非带参数的ret。Proc5共6个参数,前两个用寄存器传递,剩余4个参数占16字节,被调用者需要通过ret 16清理栈,否则ESP无法回到调用前的正确位置。
  2. 非易失性寄存器未保存:汇编中直接使用了EBX、ESI,但未在函数开头保存这些寄存器,违反调用约定,破坏调用者的寄存器状态。
  3. 参数获取位置错误:__fastcall调用时,栈上参数的布局是返回地址后依次为raznost、n、N、result_5(从右往左入栈),你的代码中对栈参数的引用(如[esp + 12])全部错位,导致逻辑错误同时加剧栈不平衡。

修正后的汇编代码示例

@Proc5@24 proc
    ; 保存非易失性寄存器与栈帧
    push ebp
    mov ebp, esp
    push ebx
    push esi
    push edi

    ; 按__fastcall规则获取参数
    mov esi, ecx        ; esi = arr(第一个参数,ECX传递)
    mov edi, edx        ; edi = freq(第二个参数,EDX传递)
    mov ecx, [ebp + 8]  ; ecx = raznost(第三个参数,栈顶第一个)
    mov edx, [ebp + 12] ; edx = n(第四个参数)
    mov ebx, [ebp + 16] ; ebx = N(第五个参数)
    mov eax, [ebp + 20] ; eax = result_5(第六个参数)

    ; 统计元素频率逻辑(修正寄存器与参数引用)
    imul ecx, 4
    add edi, ecx        ; 调整freq数组偏移,处理负数
    xor ecx, ecx        ; 数组索引计数器

loop_1:
    cmp ecx, edx
    je loopend_1
    mov ecx, [esi + ecx*4] ; 获取arr[ecx]
    inc dword ptr [edi + ecx*4] ; 对应频率计数+1
    inc ecx
    jmp loop_1

loopend_1:
    ; 按频率排序逻辑(此处需根据需求调整,确保参数引用正确)
    xor ecx, ecx        ; 新数组元素计数器
outer_loop:
    cmp ecx, ebx        ; 遍历所有可能的数值范围(N)
    je outer_loopend

    ; ... 此处插入你的排序逻辑,注意使用正确的寄存器/参数 ...

outer_loopend:

    ; 恢复非易失性寄存器
    pop edi
    pop esi
    pop ebx
    pop ebp

    ; 清理栈上4个参数(共16字节),平衡ESP
    ret 16
@Proc5@24 endp

额外验证步骤

  • 确保C编译选项与汇编的调用约定一致(如VC中默认__cdecl,需显式指定__fastcall)
  • 调试时查看栈帧布局,确认每个参数的内存位置与代码中的引用匹配
  • 运行前检查所有非易失性寄存器的保存与恢复逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 19:54:53