在大会递归斐波那契 [英] Recursive Fibonacci in Assembly

查看:140
本文介绍了在大会递归斐波那契的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图实现大会递归斐波那契程序。然而,我的程序崩溃,与未处理的异常,我似乎无法挑选出了问题。我不怀疑它涉及到我的不当使用堆栈,但我似乎无法指出哪里...

I'm attempting to implement a recursive Fibonacci program in Assembly. However, my program crashes, with an unhandled exception, and I can't seem to pick out the problem. I don't doubt that it involves my improper use of the stack, but I can't seem to point out where...

.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

另外,我推开,我使用来获得外部过程斐波那契值到堆栈数。任何想法,问题可能在于?

Also, I've pushed the number that I'm using to get the Fibonacci value to the stack in an external procedure. Any ideas where the problem might lie?

推荐答案

当您执行呼叫,下一个操作的地址推到堆栈作为返回值。当创建一个功能,它往往是习惯性地创造了堆​​栈帧。这个框架可以用来打印调用栈,以及用于局部变量和参数的偏移量。通过两个操作在函数的开始创建的框架:

When you perform a call, the address of the next operation is pushed to the stack as a return value. When creating a function, it is often customary to create a "stack frame". This frame can be used to print the call stack, as well as an offset for local variables and arguments. The frame is created through two operations at the beginning of the function:

push ebp
mov ebp, esp

在函数结束时,调用堆栈被删除使用离开,这等同于2操作相反。当使用堆栈帧的尤其存入 EBP ,使其指向名为栈上的位置值框架的基础。因为,这个地址上面还有 EBP 的旧值和返回地址,你可以使用通常得到的第一个参数 [EBP + 8] 。但是,您没有设置堆栈帧。这意味着 EBP 的旧值不压入栈,而 EBP 不能用当前值得到的参数,因为你不知道它在哪里。因此,你应该使用让您的论点 [ESP + 4]

At the end of the function, the call stack is removed using leave, which is equivalent to the reverse of those 2 operations. When using a stack frame, value of esp is stored into ebp, making it point to a location on the stack called the frame's base. Since, above this address, there are the old value of ebp and the return address, you would normally get the first argument using [ebp+8]. However, you did not set up a stack frame. This means that the old value of ebp was not pushed to the stack, and the current value of ebp cannot be used to get arguments because you don't know where it is. Therefore, you should get your argument using [esp+4].

此外,这是习惯的返回值被放置在 EAX EBX 是为preserved呼叫者。您code不符合其中任何一个公约。此外,技术上的功能并不需要preserved ECX EDX ,所以正常情况下你应该将它们推到调用另一个功能,如果你想让他们preserved前的堆栈。有了这个code, EDX EBX 将如果调用使用大于2的值覆盖,引起无效的结果。

Also, it is customary that return values are placed in eax and ebx be preserved for the caller. Your code does not follow either of these conventions. Also, technically functions aren't required to preserved ecx or edx, so normally you should push them to the stack before calling another function if you want them preserved. With this code, edx and ebx would be overwritten if called with a value greater than 2, causing an invalid result.

下面是一个完整的列表,其中包含所有我提到的修复。因为它是没有必要的,我没有创建栈帧的code没有。

Here is a full listing which includes all of the fixes I have mentioned. I did not create a stack frame as it is not necessary and your code didn't.

.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

这篇关于在大会递归斐波那契的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆