MIPS - 跟踪此代码

时间:2014-06-03 23:55:41

标签: mips

我得到了下面的代码示例。

代码从$a0(作为参数传递)中的任何数字计数/打印到0。除了$ra所做的事情之外,我可以关注所有事情。那部分令我困惑。

我知道我们何时使用jal $ra跟踪返回地址(因此程序知道返回的位置)。尽管在$ra处追踪代码仍保存在堆栈中,并设置为在函数执行完毕后返回的位置。但是,每次再次调用printnums时,都不会创建新的$ra值?然后该值将保存在内存中。这意味着当我们jr结束时,它会跳转到保存的$ra的最后一个值(指向ret:之后的jal printnums)?

或者每次保存$ra时,是否在内存中保留了4个额外字节而不是反复覆盖相同的4个字节?如果是这种情况,那么当我们在堆栈上释放空间时,我们就会“弹出”#39;每个$ra,直到我们点击保存的第一个并返回到函数的正确位置。那是对的吗?

我只是想确保我正确理解这一点。谢谢您的帮助。

printnums:              # $a0 has value
addi $sp, $sp, -4         # reserve room for return address
sw $ra, ($sp)             # save return address
beq $a0, $0, ret          # check ending condition
addi $v0, $0, 1           # set command to print int
syscall                 # print value in $a0
addi $a0, $a0, -1         # decrement value
jal printnums           # call printnums again
ret:
lw $ra, ($sp)             # restore $ra
addi $sp, $sp, 4          # deallocate space on stack
jr  $ra              # return 

1 个答案:

答案 0 :(得分:3)

这是一个递归函数。在函数的每次迭代期间,堆栈增加4个字节以保存返回地址,并打印一个数字。

想象一下,我们有这段代码调用printnums:

caller:
    li  $a0 4
    jal printnums

这是每次调用后堆栈的样子(都有$a0的不同值)

      ╔════════╦════════╦════════╦════════╗
  $a0:║   4    ║   3    ║   2    ║ 1      ║
      ╠════════╬════════╬════════╬════════╣
stack:║ caller ║ caller ║ caller ║ caller ║
      ║        ║ ret    ║ ret    ║ ret    ║
      ║        ║        ║ ret    ║ ret    ║
      ║        ║        ║        ║ ret    ║
      ╚════════╩════════╩════════╩════════╝

$a0达到值0时,堆栈开始展开,每次printnums的调用开始返回时,每个值都会逐个弹出。最近的四次调用将从堆栈中恢复$ra并返回ret,但最后一次将弹出返回值caller并返回printnums的调用者按预期运作。