汇编程序栈内地址指针异常: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
修复点说明
- 把
L2和L1标签移动到MCD_iterativo PROC与ENDP之间,确保标签属于函数代码段,避免跳转访问非法地址。 - 将
MCD_iterativo的返回指令改为ret 8,按照stdcall约定清理调用时push的两个参数,恢复栈平衡。 - 替换
main函数末尾的ret 0为invoke ExitProcess, 0,保证程序正常退出,避免非法返回地址引发的访问违规。 - 添加
mov mdc_result, eax代码,将计算得到的最大公约数保存到变量,方便后续查看结果。
内容的提问来源于stack exchange,提问作者Giovanni Mosquera
相关产品推荐
相关产品推荐

