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

汇编程序栈内地址指针异常:main函数ret阶段访问违规错误求助

汇编MCD迭代程序访问违规错误修复

我编写了如下汇编代码,用于实现迭代版最大公约数(MCD)计算:

.686
.model flat, stdcall
.stack 4096
ExitProcess proto, dwExitCode : dword

.data
    Temporal DWORD ?
    mdc_result DWORD ?

.code
    main PROC
        push ebp
        mov ebp, esp 

        push 120
        push 25
        call MCD_iterativo

        pop ebp
        ret 0

    main ENDP

    MCD_iterativo PROC ; a = 4, b = 8
        push ebp
        mov ebp, esp
        jmp L2

        pop ebp
        ret 
    MCD_iterativo ENDP

    L2:
        cmp DWORD PTR [ebp + 8], 0
        je L1

        mov eax, DWORD PTR [ebp + 8]
        mov DWORD PTR Temporal, eax 

        mov eax, DWORD PTR [ebp + 12]
        cdq
        idiv DWORD PTR [ebp + 8]
        mov DWORD PTR [ebp + 8], edx

        mov ecx, DWORD PTR Temporal
        mov DWORD PTR [ebp + 12], ecx

        jmp L2

    L1:
        mov eax, DWORD PTR [ebp + 12]
        pop ebp
        ret 0

END main

程序运行时触发错误:
Exception occurred at 0x00000005 in ASM_Miercoles_Semana10.exe: 0xC0000005: Access violation when executing location 0x00000005.

我尝试调整esp和ebp寄存器恢复初始地址,但未解决问题。程序的循环逻辑运行正常,但错误出现在main PROC末尾的ret指令处,希望修复错误让程序正常运行。


错误原因分析

  • 栈平衡破坏:代码使用stdcall调用约定,该约定要求被调用函数负责清理参数栈。但原MCD_iterativo函数的ret指令未指定要弹出的参数字节数,L1中的ret 0也不符合要求——调用该函数时push了两个DWORD参数(共8字节),被调用函数需用ret 8完成栈清理。
  • 标签位置非法:L2和L1标签被定义在MCD_iterativo ENDP之后,不属于该函数的代码段,执行跳转时会触发指令访问异常。
  • 程序退出方式错误:原main函数末尾直接用ret 0退出,未调用ExitProcess,不符合stdcall程序的退出规范,会导致程序返回非法地址,触发访问违规。

修复后的代码

.686
.model flat, stdcall
.stack 4096
ExitProcess proto, dwExitCode : dword

.data
    Temporal DWORD ?
    mdc_result DWORD ?

.code
    main PROC
        push ebp
        mov ebp, esp 

        push 120
        push 25
        call MCD_iterativo
        mov mdc_result, eax ; 将计算结果保存到变量

        pop ebp
        invoke ExitProcess, 0 ; 调用ExitProcess正常退出程序
    main ENDP

    MCD_iterativo PROC ; 参数:[ebp+12] = 初始a值, [ebp+8] = 初始b值
        push ebp
        mov ebp, esp

    L2: ; 将标签移至函数代码内部
        cmp DWORD PTR [ebp + 8], 0
        je L1

        mov eax, DWORD PTR [ebp + 8]
        mov DWORD PTR Temporal, eax 

        mov eax, DWORD PTR [ebp + 12]
        cdq
        idiv DWORD PTR [ebp + 8]
        mov DWORD PTR [ebp + 8], edx

        mov ecx, DWORD PTR Temporal
        mov DWORD PTR [ebp + 12], ecx

        jmp L2

    L1:
        mov eax, DWORD PTR [ebp + 12] ; 将结果存入eax作为返回值
        pop ebp
        ret 8 ; 清理两个DWORD参数(共8字节),符合stdcall约定
    MCD_iterativo ENDP

END main

修复点说明

  1. 把L2和L1标签移动到MCD_iterativo PROC与ENDP之间,确保标签属于函数代码段,避免跳转访问非法地址。
  2. 将MCD_iterativo的返回指令改为ret 8,按照stdcall约定清理调用时push的两个参数,恢复栈平衡。
  3. 替换main函数末尾的ret 0为invoke ExitProcess, 0,保证程序正常退出,避免非法返回地址引发的访问违规。
  4. 添加mov mdc_result, eax代码,将计算得到的最大公约数保存到变量,方便后续查看结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:01:24