【问题标题】:MIPS -- Tracing this codeMIPS——跟踪这段代码
【发布时间】:2014-06-03 23:55:41
【问题描述】:

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

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

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

还是每次保存$ra 时都会在内存中保留额外的 4 个字节,而不是一遍又一遍地覆盖相同的 4 个字节?如果是这种情况,当我们在堆栈上释放空间时,我们会“弹出”每个$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 

【问题讨论】:

标签: mips


【解决方案1】:

这是一个递归函数。在函数的每次迭代过程中,堆栈都会增加 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 的调用者,从而按预期运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多