【问题标题】:masm call procedure access violationmasm 调用程序访问冲突
【发布时间】:2016-03-13 18:27:40
【问题描述】:

所以我正在组装中的一项任务以生成斐波那契数列。我已经在主程序中成功编写了代码,但是当我尝试将其包装在它自己的程序中并调用该程序时,我遇到了访问冲突错误。这是我的代码:

INCLUDE Irvine32.inc

.data
array DWORD 47 DUP(?)

.code
main proc
mov esi, OFFSET array

call generate_fibonacci

invoke ExitProcess,0
main endp

generate_fibonacci PROC

mov DWORD PTR [esi], 1h
add esi, 4
mov DWORD PTR [esi], 1h
push [esi]
push [esi - 4]
add esi, 4
mov ecx, 45
L1: 
pop eax
pop ebx
add eax, ebx
mov DWORD PTR [esi], eax
add esi, 4
push [esi - 4]
push [esi - 8]
loop L1
ret

generate_fibonacci ENDP

end main

错误看起来像这样:“在项目中的某个内存位置引发异常...:访问冲突执行位置相同的内存位置

我注意到在执行 call generate_fibonacci 指令时,错误消息中列出的内存位置正在加载到 EIP 寄存器中。我不确定如何解决这个问题。

【问题讨论】:

  • 为什么在这个非递归解决方案中使用堆栈?为什么不直接写:mov eax,[esi-4]mov ebx,[esi]
  • 顺便说一句,在esi 中传递第一个参数不是 32 位的正常调用约定。 main 不保存调用者的 esi 值是可以的,因为它永远不会返回。 (您改为调用 ExitProcess。)请参阅 x86 tag wiki 以获取有关调用约定的信息的链接。
  • 部分任务是利用推送和弹出指令以及创建和调用过程。我知道,这很奇怪,我最初能够在没有这些东西的情况下编写代码。

标签: visual-studio assembly masm irvine32


【解决方案1】:

PROC 中的推送和弹出不平衡。

在循环 L1: 之前,您进行了 2 次推送。在循环L1: 中,您进行了 2 次弹出和 2 次推送。当循环L1: 结束时,当ret 尝试拉出返回地址时,堆栈上仍有2 个项目。所以代码会尝试在导致访问冲突的地方恢复执行。

请在ret指令前添加两行代码清理堆栈

pop eax
pop eax
ret

如果相同的代码在main 中有效,则它有效,因为main 不以ret 结尾。

编辑。您可以通过将最近的术语保存在寄存器中来大大简化它。最后三个术语将在eaxebxedx

generate_fibonacci PROC

    mov     eax, 1                  ;init first two terms
    mov     DWORD PTR [esi], eax    ;store first two terms
    add     esi, 4
    mov     DWORD PTR [esi], eax
    add     esi, 4

    mov     ebx, eax
    mov     ecx, 45                 ;init loop count
L1: 
    mov     edx, ebx                ;move terms along
    mov     ebx, eax
    add     eax, edx                ;sum last two terms
    mov     DWORD PTR [esi], eax
    add     esi, 4
    loop    L1
    ret

generate_fibonacci ENDP

【讨论】:

  • 啊,难怪我的那部分代码也困扰着我,但不知道它实际上导致了一个问题,因为它在主要运行时运行良好。谢谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-07
  • 2016-04-04
相关资源
最近更新 更多