Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 汇编语言中的递归斐波那契_Assembly_Fibonacci - Fatal编程技术网

Assembly 汇编语言中的递归斐波那契

Assembly 汇编语言中的递归斐波那契,assembly,fibonacci,Assembly,Fibonacci,我试图在汇编中实现一个递归斐波那契程序。然而,我的程序崩溃了,出现了一个未处理的异常,我似乎无法找出问题所在。我不怀疑这涉及到我对堆栈的不当使用,但我似乎无法指出 .386 .model Flat public Fibonacci include iosmacros.inc ;includes macros for outputting to the screen .code Fibonacci proc MOV EAX, [EBP+8] CMP EAX, 1 JA Recurse

我试图在汇编中实现一个递归斐波那契程序。然而,我的程序崩溃了,出现了一个未处理的异常,我似乎无法找出问题所在。我不怀疑这涉及到我对堆栈的不当使用,但我似乎无法指出

.386
.model Flat
public Fibonacci
include iosmacros.inc ;includes macros for outputting to the screen

.code
Fibonacci proc

MOV EAX, [EBP+8]
CMP EAX, 1
    JA Recurse
    MOV ECX, 1
    JMP exit

Recurse:
    DEC EAX
    MOV EDX, EAX
    PUSH EAX
    CALL Fibonacci
    ADD ESP, 4
    MOV EBX, ECX
    DEC EDX
    PUSH EDX
    CALL Fibonacci
    ADD ECX, EBX
exit:
ret
Fibonacci endp


.data


end

另外,我在一个外部过程中将用于获取斐波那契值的数字推送到堆栈中。你知道问题出在哪里吗?

首先,你使用的堆栈偏移量是EBP的8,为什么?你是说ESP吗?一个普通的调用只使用一个32位单元,所以arg应该在偏移量4处。我敢肯定还有其他问题,但你可以从那开始。
您可能应该编写一些伪代码,以便您和我们能够看到您正试图实现的目标。
如果你想作弊,谷歌搜索“nasm递归斐波那契”会让你进入一个工作程序。但是如果你自己解决它,你会成为一个更好的程序员。

几个问题:

  • 如果要在堆栈上传递参数,则没有正确的(标准)函数项,因此EBP指向错误的位置
  • 您没有在edx中正确保存参数值
假设您正在堆栈上传递参数(最好在每条指令中添加注释),我认为您需要这样做 明确你的想法):

Fibonacci过程
推动EBP;保存上一帧指针
MOV-EBP,ESP;设置当前帧指针
MOV-EAX,[EBP+8];获取参数N
CMP-EAX,1;n1
JMP出口
递归:
DEC EAX;=N-1
MOV-EDX,EAX;=N-1
推动EDX;保存N-1
推动EAX;设置参数=N-1
称为斐波那契;计算Fib(N-1)到ECX
POP-EAX;流行音乐N-1
DEC EAX;=N-2
推动ECX;保存Fib(N-1)
推动EAX;设置参数=N-2
称为斐波那契;计算Fib(N-2)到ECX
POP EAX;=Fib(N-1)
添加ECX、EAX;=Fib(N-1)+Fib(N-2)
出口:
MOV-ESP,EBP;将堆栈重置为函数项处的值
POP-EBP;还原调用方的帧指针
RET;返回
但是您不必在堆栈上传递参数。使用寄存器更有效:

Fibonacci proc ; computes Fib(EAX) --> EAX; do not call with EAX==0
  CMP  EAX, 1      ; N<=1?
  JBE  exit        ; yes, we have the answer
  DEC  EAX         ; = N-1
  PUSH EAX         ; save N-1
  CALL Fibonacci   ; computing FIB(n-1)to EAX
  XCHG EAX,0[ESP]  ; swap FIB(n-1) for saved N-1 (You'll love this instruction, look it up in the Intel manual)
  DEC  EAX         ; = N-2
  CALL Fibonacci   ; computing FIB(N-2) to EAX
  POP  ECX         ; = FIB(N-1)
  ADD  EAX,ECX     ; = FIB(N-1)+FIB(N-2)
exit:
  RET
Fibonacci过程;计算Fib(EAX)->EAX;不要在EAX==0的情况下调用

CMP-EAX,1;N执行
调用时,下一个操作的地址作为返回值推送到堆栈中。创建函数时,通常会创建“堆栈框架”。此框架可用于打印调用堆栈,以及局部变量和参数的偏移量。框架是通过函数开头的两个操作创建的:

push ebp
mov ebp, esp
在函数结束时,使用
leave
删除调用堆栈,这相当于这两个操作的相反操作。使用堆栈帧时,
esp
的值存储在
ebp
中,使其指向堆栈上称为帧基的位置。由于在该地址上方有
ebp
的旧值和返回地址,因此通常使用
[ebp+8]
获得第一个参数。但是,您没有设置堆栈帧。这意味着
ebp
的旧值没有被推送到堆栈中,而
ebp
的当前值不能用于获取参数,因为您不知道它在哪里。因此,您应该使用
[esp+4]
获取您的参数

此外,通常将返回值放置在
eax
中,并为调用者保留
ebx
。您的代码不遵循这两种约定中的任何一种。另外,从技术上讲,函数不需要保留
ecx
edx
,因此如果希望保留它们,通常应在调用另一个函数之前将它们推到堆栈中。使用此代码,如果使用大于2的值调用,
edx
ebx
将被覆盖,从而导致无效结果

下面是一个完整的列表,其中包括我提到的所有修复程序。我没有创建堆栈帧,因为它不是必需的,而且您的代码也没有

.386
.model Flat
public Fibonacci
include iosmacros.inc ;includes macros for outputting to the screen

.code
Fibonacci proc

    MOV EAX, [ESP+4]
    CMP EAX, 1
    JA Recurse
    MOV EAX, 1 ; return value in eax
    JMP exit

Recurse:
    PUSH EBX ; preserve value of ebx
    DEC EAX
    PUSH EAX
    CALL Fibonacci
    MOV EBX, EAX ; ebx is preserved by callee, so it is safe to use
    DEC [ESP] ; decrement the value already on the stack
    CALL Fibonacci
    ADD EAX, EBX ; return value in eax
    ADD ESP, 4 ; remove value from stack
    POP EBX ; restore old value of ebx
exit:
ret
Fibonacci endp

你忘了在最后弹出
ebp
。此代码将始终返回堆栈上的某个位置。@ughoavgfhw:Yep,谢谢,已修复。我已经做了调整,但我的代码仍然不起作用。然而,这个回答似乎仍然是我所寻找的答案。我相信我的问题现在在别处。至于使用寄存器,我最初尝试过,但似乎没有效果。也许我会再试一次。谢谢@rar:我们已经发现专家无法正确编码:-}使用调试器和单步指令。您很快就会发现问题所在,而且体验是无价的。@rar:您确实选择了我根据ughoavgfw(哇)的观察结果制作的补丁?在使用了它之后,代码工作正常,但仍然在某个地方崩溃。开始调试-谢谢!
.386
.model Flat
public Fibonacci
include iosmacros.inc ;includes macros for outputting to the screen

.code
Fibonacci proc

    MOV EAX, [ESP+4]
    CMP EAX, 1
    JA Recurse
    MOV EAX, 1 ; return value in eax
    JMP exit

Recurse:
    PUSH EBX ; preserve value of ebx
    DEC EAX
    PUSH EAX
    CALL Fibonacci
    MOV EBX, EAX ; ebx is preserved by callee, so it is safe to use
    DEC [ESP] ; decrement the value already on the stack
    CALL Fibonacci
    ADD EAX, EBX ; return value in eax
    ADD ESP, 4 ; remove value from stack
    POP EBX ; restore old value of ebx
exit:
ret
Fibonacci endp