MIPS 汇编语言,函数调用后是否保留 $ra 寄存器?

MIPS assembly language, is $ra register preserved after function call?

我是一个刚开始学习MIPS的学生

我一直在网上搜索$ra(return address) 是否被调用者保存(保留)。一些表声明它是一个被保存的被调用者,而另一些声明它不是。

我认为 $ra 不是被调用者保存的寄存器,这意味着它是调用者保存的寄存器。

因为如果$ra是一个callee saved register,我相信是有问题的。如果我们通过 jal 调用函数(子例程),被调用函数无法保留之前的 $ra 值,因为 $ra 在 jal 指令之后将更改为 PC+4;调用函数应该事先将 $ra 保存在堆栈中。因此,考虑到这种情况,$ra 将是调用者保存的寄存器。

我说的对吗?

Am I correct?

您已经发现 $ra 是一个非常特殊的情况:

jal 指令在进入被调用函数之前已经将值写入 $ra 。所以调用函数已经 "destroy" $ra 注册。

但是有人已经问了一个与你的问题非常相似的问题:

一个回答指出被调用函数被允许修改$ra寄存器所以调用函数不能假设 $ra 确实包含 return 地址。该答案中给出的示例是:

move $v0,$ra
li   $ra,0
jr   $v0

Besides the jal instruction, does syscall instruction always preserve the $ra register?

在模拟器(SPIM、MARS 等)上,syscall 指令是一个单独的 CPU 指令,它不访问任何寄存器,但记录在案。

在真正的 MIPS CPU 上,syscall 指令导致 x86 CPUs 上所谓的 "software interrupt"。软件中断是函数调用的一种特殊形式。

然而,与 jal 指令不同,syscall 指令不会将 return 地址写入 $ra 寄存器,而是写入一个特殊寄存器(名为 EPC 在 MIPS R4400 CPUs) 上,只能使用特殊指令访问。

被调用的函数("exception handler")当然会修改寄存器。如果该函数调用其他函数,它将修改 $ra 寄存器。

但是我认为几乎所有操作系统都会保留 所有 寄存器,但根据文档明确修改的那些(在 Linux $v0, $v1$a3syscall).

修改