问题描述
我是 MIPS 的新手,我有一个给定的 MIPS 递归代码,我必须将其应用于特定数字(例如数字 3) Bellow 是给定的 MIPS 代码,如果我要通过 ex,我应该写。函数中的第 3 号对于所述第 3 号的递归,注册表和缓存中的更改是什么? 我试图在一张纸上一步一步地做,但一无所获。
fact:
addi $sp,$sp,-8
sw $ra,4($sp)
sw $a0,0($sp)
slti $t0,$a0,1
beq $t0,$zero,L1
addi $v0,1
addi $sp,8
jr $ra
Ll:addi $a0,-1
jal fact
lw $a0,0($sp)
lw $ra,4($sp)
addi $sp,8
mul $v0,$v0
jr $ra
解决方法
始终首先使用尽可能小的输入来测试您的代码。如果你尝试使用 0,并且单步执行大约 8 条指令,你可以观察到你的代码没有返回给它的调用者使用正确的堆栈指针值——函数的一个重要部分是保留必须为调用者保留的寄存器,包括堆栈指针。通常,堆栈指针的恢复方式是释放任何已分配的空间,只要平衡,$sp
的保留规则就得到遵守。
由于堆栈指针不正确,调用者搞砸了。这会让你感到困惑,然后是调用者试图返回给调用者的时候。可能这对于 MARS 上的 main
b/c 不是问题,例如,我们通常通过 exit 系统调用退出 main
。但是,如果您执行 fact(2)
,您会看到它执行的第一个 return 工作正常,但之后调用者(事实上,递归调用者)不起作用——它无法返回到它的调用者,因为它无法正确恢复其先前保存的$ra
,因为堆栈指针已被终端案例不平衡。
我们需要平衡序言和尾声:不仅是静态的,而且是动态的。
您的代码在所有情况下都在分配堆栈空间,但在终端情况下,您的代码省略了堆栈的释放,因此变得不平衡。
在终端案例中添加堆栈调整(解除分配),或者在分配堆栈空间之前测试终端案例(因此您不必在该终端案例中分配或取消分配)。