汇编中的递归斐波那契
我正在尝试在汇编中实现递归斐波那契程序。但是,我的程序崩溃了,出现未处理的异常,而且我似乎无法找出问题所在。我不怀疑这涉及我对堆栈的不当使用,但我似乎无法指出在哪里......
.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
此外,我已将用于获取斐波那契值的数字推送到堆栈中一个外部过程。有什么想法可能是问题出在哪里吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您执行
调用
时,下一个操作的地址将作为返回值推送到堆栈。创建函数时,通常习惯创建“堆栈框架”。该帧可用于打印调用堆栈以及局部变量和参数的偏移量。该帧是通过函数开头的两个操作创建的:在函数结束时,使用
leave
删除调用堆栈,这相当于这两个操作的相反操作。使用堆栈帧时,esp
的值存储到ebp
中,使其指向堆栈上称为帧基址的位置。由于在此地址之上有ebp
的旧值和返回地址,因此您通常会使用[ebp+8]
获取第一个参数。但是,您没有设置堆栈框架。这意味着ebp
的旧值没有被压入堆栈,并且ebp
的当前值不能用于获取参数,因为你不知道它在哪里。因此,您应该使用[esp+4]
来获取参数。此外,通常将返回值放置在
eax
和ebx
中为调用者保留。您的代码不遵循这些约定。此外,从技术上讲,函数不需要保留ecx
或edx
,因此,如果您希望保留它们,通常应该在调用另一个函数之前将它们推送到堆栈。使用此代码,如果使用大于 2 的值调用,edx
和ebx
将被覆盖,从而导致无效结果。这是一个完整的列表,其中包括我提到的所有修复。我没有创建堆栈框架,因为它不是必需的,并且您的代码也没有。
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: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 ofesp
is stored intoebp
, making it point to a location on the stack called the frame's base. Since, above this address, there are the old value ofebp
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 ofebp
was not pushed to the stack, and the current value ofebp
cannot be used to get arguments because you don't know where it is. Therefore, you should get your argument using[esp+4]
.Also, it is customary that return values are placed in
eax
andebx
be preserved for the caller. Your code does not follow either of these conventions. Also, technically functions aren't required to preservedecx
oredx
, so normally you should push them to the stack before calling another function if you want them preserved. With this code,edx
andebx
would be overwritten if called with a value greater than 2, causing an invalid result.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.
几个问题:
这就是我的想法想要,假设您在堆栈上传递参数(最好为每个指令添加注释
明确你的想法):
但是你不必在堆栈上传递参数。使用寄存器更有效:
Several problems:
Here's what I think you wanted, assuming you are passing parameters on the stack (best to add a comment to each instruction
making it clear what you think it does):
But you don't have to pass the parameters on the stack. It is more efficient to use the registers: