【问题标题】:Recursive Fibonacci in MASM AssemblyMASM 汇编中的递归斐波那契
【发布时间】:2014-06-24 01:13:51
【问题描述】:

所以我正在创建一个程序来给出斐波那契数列的第 n 项。我应该使用递归 MASM 程序集来实现以下逻辑。

int fib(int n){ 
 if ((n == 1) || (n == 2)) 
     return n - 1; 
 else 
     return fib(n-1) + fib(n-2); 
}

我似乎遇到的问题是在程序循环直到达到 1 时保留这些值。我对递归相当缺乏经验,我觉得我在这方面遗漏了一些东西。我不确定如何保留这些值以添加它们。

.code
main PROC
    mov ecx,0
    push 4          ; calculate the nth fib
    call Fib            ; calculate fib (eax)
    call WriteDec
    call Crlf
    exit
main ENDP

Fib PROC
    add ecx,1
    push ebp
    mov  ebp,esp
    mov  eax,[ebp+8]    ; get n
    cmp  eax,2      ; n == 2?
    je   exception2     
    cmp  eax,1      ; n == 1?
    je   exception2         
    dec eax
    push eax            ; Fib(n-1)
    call fib

    add eax,
    jmp Quit


Exception2:
    dec eax
Quit:
    pop  ebp            ; return EAX
    ret  4          ; clean up stack
Fib ENDP

END main

【问题讨论】:

  • 使用堆栈存储您即将修改但需要稍后恢复的寄存器的值。
  • 我无法从堆栈中访问它们。我使用 push 和 [ebp] 但如果我在错误的位置推送寄存器,它会崩溃。尝试访问堆栈中以前的值只会提供随机数据,因为 ret 4 在完成一轮 fib 时会清除堆栈。
  • 每个push需要有一个对应的pop(或add esp,nret n,...)。如果没有确切地看到你在做什么,就很难说出问题所在。

标签: assembly recursion masm fibonacci irvine32


【解决方案1】:

在过程结束时,您必须恢复 ESP 而不仅仅是 EBP

ret 4 (stdcall) 在这种情况下不方便,因为您可以将堆栈上的值重用于第二次调用。

对于第一次调用的结果,您可以使用将在“当前”堆栈上创建的局部变量。

即使 OPTION 指令允许,也不要在符号中混合大小写!

我相应地更改了您的代码:

include Irvine32.inc

.code
main PROC
    mov ecx,0
    push 10             ; calculate the nth fib
    call fib            ; calculate fib (eax)
    add esp, 4          ; clean up the stack

    call WriteDec
    call Crlf
    exit
main ENDP

fib PROC C
    add ecx,1
    push ebp
    mov  ebp,esp
    sub  esp, 4         ; space for a local dword [ebp-4]
    mov  eax,[ebp+8]    ; get n

    ; if ((n == 1) || (n == 2)) return 1;
    cmp  eax,2          ; n == 2?
    je   exception2
    cmp  eax,1          ; n == 1?
    je   exception2

    ;else return fib(n-1) + fib(n-2);
    dec eax
    push eax            ; Fib(n-1)
    call fib
    mov [ebp-4], eax    ; store first result

    dec dword ptr [esp] ; (n-1) on the stack -> (n-2)
    call fib
    add esp, 4          ; clean up stack

    add eax, [ebp-4]    ; add result and stored first result

    jmp Quit

exception2:
    mov eax, 1          ; start values: 1, 1
    ; dec eax           ; start values: 0, 1
Quit:
    mov esp, ebp        ; restore esp
    pop ebp             ; restore ebp

    ret                 ; return EAX, stack not cleaned up
fib ENDP

END main

【讨论】:

  • 感谢您的深入回复!尽管我对自己感到非常沮丧,因为在我废弃的先前版本中我非常接近这一点。它根本没有正确保存变量,因为我试图使用 [ebp+20] 之类的东西来访问它们。我没有考虑减少esp。我仍然需要研究堆栈在汇编中是如何工作的。再次感谢您的回复!如果可以的话,我会支持它,但我还没有足够的声誉。
【解决方案2】:

在 VS 中组装

.686p

        .xmm

        .model  flat, c

includelib  libcmtd

printf      proto   :vararg

scanf       proto   :vararg

Fibo        proto   :dword

        .data
guid_msg    db  ' Number of protest? ', 00h

doc_form_1  db  '%d', 00h

doc_form_2  db  ' %d ', 00h

        .data?

num_i       dd  ?

num_j       dd  ?

        .code

main        proc

        invoke  printf, addr guid_msg

        invoke  scanf, addr doc_form_1, addr num_j

        mov edi, 0

     .while edi < num_j

        invoke  Fibo, edi

        invoke  printf, addr doc_form_2, eax

        inc edi

    .endw

        ret 0

main        endp

Fibo        proc    uses edx esi, num_n:dword

        mov edx, num_n

    .if         edx < 1

        xor eax, eax

     .elseif   edx < 2

        mov eax, 1

    .else

        sub edx, 1

        invoke  Fibo, edx

        mov esi, eax

        sub     edx, 1

        invoke  Fibo, edx

        add eax, esi

    .endif

        ret 0

Fibo        endp

        end

【讨论】:

  • 请正确格式化您的答案。这完全难以辨认
猜你喜欢
  • 2011-08-02
  • 2012-11-06
  • 2013-10-13
  • 2021-07-18
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 2020-08-11
  • 2010-12-03
相关资源
最近更新 更多