MIPS——追踪这段代码

标签 mips

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

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

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

或者是每次保存 $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 

最佳答案

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

关于MIPS——追踪这段代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24026888/

相关文章:

mips - 为什么 MIPS 中有(加载字节无符号)和(加载字节)指令,但只有(存储字节)?

string - MIPS - 检查数组的元素是否为空终止字符

c - 将 C 代码转换为 Mips 汇编

io - MIPS 文件打开

linux - 尝试在 Linux 上打开文件时,MARS MIPS 模拟器卡住

c - 如何计算MIPS中两个值之间的偶数之和?

assembly - 什么是分行摊位?

arrays - MIPS 钻石分选

linux - 以 OpenWrt 作为操作系统为 MIPS 交叉编译 Snap7

c - 使用自定义 __start 的 GCC/LD 的异常输出