assembly 使用堆栈帧推入参数,以计算Fibbonnacci序列,但始终获得1作为返回值

x33g5p2x  于 2022-12-13  发布在  其他
关注(0)|答案(1)|浏览(129)

我正在开发一个程序,它使用堆栈帧来递归地调用函数,以帮助计算fibonnacci序列的第n项。这是我目前所拥有的,但输出(程序停止运行时,它将位于寄存器$t7中)返回1。这是我目前的进展

.text
    .globl main
    
main:

    li  $v0, 4
    la  $a0, prompt
    syscall
    
    li  $v0, 5
    syscall




    addiu   $sp, $sp, -4
    sw  $t0, ($sp)
    addiu   $sp, $sp, -4
    sw  $t1, ($sp)
    addiu   $sp, $sp, -4            # space for parameters
    
    sw  $v0, ($sp)          # pushing parameter
    jal fib
    
    addiu   $sp, $sp, 4
    lw  $t1, ($sp)
    addiu   $sp, $sp, 4
    lw  $t0, ($sp)
    addiu   $sp, $sp, 4
    
    
    move    $t7, $v0
    
    li  $v0, 10
    syscall
    
fib:
    addiu   $sp, $sp, -4
    sw  $ra, ($sp)
    addiu   $sp, $sp, -4
    sw  $fp, ($sp)
    addiu   $sp, $sp, -4
    sw  $s0, ($sp)
    addiu   $sp, $sp, -4
    sw  $s1, ($sp)
    addiu   $fp, $sp, -8
    move    $sp, $fp
    
    lw  $t3, 24($fp)            # t3 = n of fib(int n)
    
    move    $s0, $t3
    li  $v0, 1              # return value 
    ble     $s0, 1, epilog          # 
    addi    $s0, $s0, -1            # setting up fib(n-1)
    jal fib
    move    $s0, $v0            # store fib(n-1)
    addi    $s0, $s0, -2            # set up fib(n-2)
    jal fib
    add     $v0, $s1, $v0           # add fib(n-1) and fib(n-2)
    
epilog:
    addiu   $sp, $fp, 8         # 
    lw  $s1, ($sp)
    addiu   $sp, $sp, 4
    lw  $s0, ($sp)
    addiu   $sp, $sp, 4
    lw  $fp, ($sp)
    addiu   $sp, $sp, 4
    lw  $ra, ($sp)
    jr  $ra
    
    
    
    li  $v0, 10
    syscall
    
    
    
    
    
    
    
    
    
    .data
    
prompt: .asciiz "enter a number dingus \n"

我觉得这是我的递归函数在身体的子例程,但我一直盯着这个过去几个小时,仍然不知道我做错了什么,任何提示将不胜感激,谢谢。

gmxoilav

gmxoilav1#

第一次输入fib时,在函数序言中压入寄存器后,堆栈如下所示:

fp xx sp                         ;what values fp and sp point to. xx = nothing
xx xx s1 s0 fp ra t0 t1 v0       ;what registers were pushed. xx = nothing
00 04 08 12 16 20 24 28 32       ;offset n for "lw $r_,n($fp)

这张图表并没有在任何地方被标准化,但是它是我喜欢用来可视化函数的堆栈帧的工具。
然后,函数从24(fp)加载$s024(fp)对应于开始时推的$t0。这一切都很好,但fib(n-1)的情况会发生什么?函数被再次调用,第二次执行序言。现在堆栈如下所示:

fp xx sp 
xx xx s1 s0 fp ra xx xx s1 s0 fp ra t0 t1 v0
00 04 08 12 16 20 24 28 32 36 40 44 48 52 56

你现在看到问题了吗?偏移量24(fp)不再指向你的前一个参数。所以当你递归时,你不再加载你推的$s0。相反,你加载的是谁知道的东西。
现在,如果将这一部分移到函数 * 内部 *,则将从临时变量的正确偏移量加载。

addiu   $sp, $sp, -4
    sw  $t0, ($sp)
    addiu   $sp, $sp, -4
    sw  $t1, ($sp)
    addiu   $sp, $sp, -4            # space for parameters 
    sw  $v0, ($sp)          # pushing parameter

相关问题