我是一名开始学习MIPS的学生。
我一直在网上搜索$ ra(返回地址)是否被保存(保留)被调用者。有些表说它是一个被保存的被叫者而另一些表示它不是。
我认为$ ra不是被叫方保存的注册表,这意味着它是一个来电者保存的注册表。
这是因为如果$ ra是被调用者保存的寄存器,我相信存在问题。如果我们通过jal调用一个函数(子例程),则callee函数无法保留之前的$ ra值,因为$ ra将在jal指令之后更改为PC + 4;调用函数应事先在栈中保存$ ra。因此,考虑到这种情况,$ ra将成为调用者保存的寄存器。
我说错了吗?
答案 0 :(得分:2)
我说错了吗?
正如您已经发现$ra
是一个非常特殊的情况:
jal
指令在输入被调用函数之前已经将值写入$ra
。所以调用函数已经" destroy" $ra
注册。
然而有人已经提出了一个与你非常相似的问题:
Whether $ra register callee saved or caller saved in mips?
一个答案指出被调用函数允许修改$ra
寄存器,因此调用函数不能假设 $ra
真正包含退货地址。该答案中给出的例子是:
move $v0,$ra
li $ra,0
jr $v0
除了jal指令外,syscall指令是否始终保留$ ra寄存器?
在模拟器(SPIM,MARS,...)上,syscall
指令是一条单CPU指令,它不访问任何寄存器,但记录了这些寄存器。
在真正的MIPS CPU上,syscall
指令会导致所谓的"软件中断"在x86 CPU上。软件中断是函数调用的一种特殊形式。
然而,与jal
指令不同,syscall
指令不会将返回地址写入$ra
寄存器,而是写入特殊寄存器(MIPS R4400 CPU上名为EPC
) ,只能使用特殊说明访问。
被调用的函数("异常处理程序")当然会修改寄存器。如果该函数调用其他函数,它将修改$ra
寄存器。
但是我认为几乎所有操作系统都会保留所有寄存器,但是根据文档明确修改的那些(在Linux $v0
的情况下,$v1
和$a3
由syscall
修改。