You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何可用jr $ra终止MIPS程序?是否依赖编译程序?

关于MIPS中jr $ra终止程序的疑问解答

嘿,这个问题问得特别到位——我刚上手MIPS汇编的时候,也对着这俩终止方式懵了好一阵!咱们一步步拆解:

为什么jr $ra能终止程序?

你得先搞懂MIPS程序的启动流程:当操作系统(或者模拟器比如MARS/SPIM)加载你的程序时,并不是直接跳到main执行的,而是先运行一段启动代码(runtime stub)。这段代码会帮你初始化栈指针、全局变量,然后通过jal main来调用你的主函数。

重点来了:jal指令会把下一条指令的地址(也就是启动代码里jal main之后的那条指令)存入$ra寄存器。而启动代码里jal main之后的逻辑,恰恰就是负责调用系统终止指令(比如li $v0,10; syscall)来结束程序的。

所以当你在main里执行jr $ra时,本质是回到启动代码的退出逻辑,由它帮你完成程序终止——相当于你把“收尾工作”交给了启动代码,而非自己直接调用系统指令。

是不是依赖编译/运行环境?

没错,确实依赖!不过不用太担心,绝大多数标准的MIPS开发环境(包括MARS、SPIM模拟器,以及交叉编译到硬件的GCC工具链)都会遵循这个启动逻辑:给main设置好指向启动代码退出点的$ra值。

举个例子,在MARS模拟器里,启动代码的大致流程是:

# 初始化栈、全局变量等
jal main       # 调用用户的main函数
li $v0, 10     # 准备终止程序的系统调用
syscall        # 执行终止

所以你在main里jr $ra,就会跳回jal main之后的li $v0,10那行,最终还是会执行终止操作。

结合你给出的代码片段看

你的代码里先做了addi $sp, $sp, -4和sw $ra, 0($sp),这一步非常关键!因为你接下来用jal exp调用了子函数,而jal会覆盖$ra的值(把jal exp之后的地址存进去)。如果不先把启动代码给的原始$ra保存到栈里,调用完exp后$ra就变成了回到main的地址,这时候jr $ra只会回到main里jal exp之后的位置,而不是退出程序。

所以正确的流程是:

  1. 保存原始$ra(启动代码的退出地址)到栈
  2. 调用子函数exp(此时$ra被覆盖为返回main的地址)
  3. 从栈恢复原始$ra
  4. jr $ra回到启动代码,完成退出

两种终止方式的区别

  • li $v0,10; syscall:属于直接硬终止,跳过启动代码的收尾逻辑,直接调用系统指令结束程序,适合简单的测试程序。
  • jr $ra:属于正常返回式终止,更贴近高级语言(比如C)中main函数返回的逻辑——C的main也是返回给runtime,由runtime处理后续的资源清理和退出。如果你的程序需要做一些收尾工作(比如释放动态内存),这种方式更安全。

内容的提问来源于stack exchange,提问作者Richie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:42:39