以下是我用来解决问题的代码:
%include "io.mac"
section .data
msg1 db "Enter a positive number: ",0
msg2 db "fibonacci number is: ",0
space db " ",0
section .bss
section .text
global _start
_start:
PutStr msg1
GetLInt EBX
mov EDX,EBX
cmp EBX,1
jge result
jmp _start
result:
PutLInt EBX
PutStr space
PutStr msg2
call fibo
PutLInt EAX
nwln
.EXIT
fibo:
cmp EBX,2
jg fibo_helper
mov EAX,1
ret
fibo_helper:
dec EBX
call fibo
mov ECX,EAX
dec EBX
call fibo
ADD EAX,ECX
ret
但是这段代码只为n <5而输出正确的方法。其余只输出n-1。
有人可以帮我吗?
答案 0 :(得分:2)
你的算法是递归的,但是你使用寄存器来存储C中的局部变量等中间值,因此大致会发生这种情况(从头部写入,使用调试器和单步执行指令来验证我是否正确):
- fibo(ebx = 5): jumps to fibo_helper, ebx = 4 (--ebx), call fibo(ebx=4)
- fibo(ebx=4): -> helper -> call fibo(ebx=3)
- fibo(ebx=3): -> helper -> call fibo(ebx=2)
- fibo(ebx=2), eax=1, ret
- in helper after first call: ecx=1, --ebx, call fibo(ebx=1)
- fibo(ebx=1), eax=1, ret
- eax = 1 + ecx(1) = 2, ret
- in helper after first call: ecx=2, --ebx, call fibo(ebx=0)
- fibo(ebx=0), eax=1, ret
- eax = 1 + ecx(2) = 3, ret
- in helper after first call: ecx=3, --ebx, call fibo(ebx=-1)
- fibo(ebx=-1), eax=1, ret
- eax = 1 + ecx(3) = 4, ret
寄存器就像“超级全局”,如果你想创建递归算法,你必须保留所需的所有值(动态地,最有可能在堆栈上),这必须在递归调用中存活。
谷歌的一些工作x86的例子(而不是例子,看看即使这样简单的实现可能会有所不同),必须有大量的这些东西,即使在这里也是如此...并检查一些堆栈使用与递归教程以获得更好想法如何/何时保留价值观。编辑:如果你足够聪明并且可以自由地为递归函数设计自定义调用约定,那么通常可以通过巧妙的设计来最小化堆栈内存需求。
在这种情况下,您可以通过这种方式设计fibo
函数,它将值添加到eax
(运行总和),在ebx = n
中输入,这将是保留(返回未修改的值)。因此eax
将作为函数的输入和输出。
然后,您必须先将eax
清零,然后再致电:
... set ebx to "n" ...
xor eax,eax
call fibo
递归函数本身将是:
fibo:
cmp ebx,2
jg fibo_helper
inc eax ; sum += 1 (fib(1) = fib(2) = 1)
ret
fibo_helper:
dec ebx
call fibo ; sum += fib(n-1)
dec ebx
call fibo ; sum += fib(n-2)
add ebx,2 ; restore ebx to original value
ret
然后堆栈存储器仅用于跟踪call+ret
对,即递归深度,不需要使用它来保存值。