前提 MIPS 中的堆栈的工作原理与任何其他架构中的堆栈一样,因此您只需 Google 即可。
假设堆栈指向内存的任意位置:
| xxx | xxx = Undefined
| xxx | <- $sp
| |
| | | Free area, stack moves down
| | V
现在只需模拟对fact(3) 的调用。
您粘贴了代码的图像,因此此处不会显示任何代码。一个可复制粘贴的代码会使这个答案更清楚。
fact 的每次调用都会按此顺序推送返回地址和参数。
假设 fact 位于 0x1000,而对 fact 的调用位于 0x1ffc。
fact(3)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | <- $sp Argument of fact(3)
| |
fact(2) called from fact(3)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | Argument of fact(3)
| 0x1028 | Return address to L1+8 label
| 2 | <- $sp Argument of fact(2)
fact(1) called from fact(2)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | Argument of fact(3)
| 0x1028 | Return address to L1+8 label
| 2 | Argument of fact(2)
| 0x1028 | Return address to L1+8 label
| 1 | <- $sp Argument of fact(1)
fact(0) called from fact(1)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | Argument of fact(3)
| 0x1028 | Return address to L1+8 label
| 2 | Argument of fact(2)
| 0x1028 | Return address to L1+8 label
| 1 | Argument of fact(1)
| 0x1028 | Return address to L1+8 label
| 0 | <- $sp Argument of fact(0)
fact(0) 返回 1 并从堆栈中删除两项。
fact(0) 是叶调用,即最后一次调用,因此没有其他调用更改$ra,此外$a0(参数)是不需要,因此保存在堆栈中的这两个值只是通过递增$sp 来丢弃。
Just before "jr $ra" in fact(0)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | Argument of fact(3)
| 0x1028 | Return address to L1+8 label
| 2 | Argument of fact(2)
| 0x1028 | Return address to L1+8 label
| 1 | <- $sp Argument of fact(1)
其他返回从堆栈中恢复$a0和$ra的值以计算n*fact(n-1)并返回给它们的调用者。
Just before "jr $ra" in fact(1)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | Argument of fact(3)
| 0x1028 | Return address to L1+8 label
| 2 | <- $sp Argument of fact(2)
Just before "jr $ra" in fact(2)
| xxx |
| xxx |
| 0x2000 | Return address to caller of fact(3)
| 3 | <- $sp Argument of fact(3)
Just before "jr $ra" in fact(3)
| xxx |
| xxx | <- $sp
注意堆栈是如何返回到递归链末尾的原始位置的。