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

relj7zay  于 2023-01-17  发布在  其他
关注(0)|答案(2)|浏览(183)

我是一个开始学习MIPS的学生。
我一直在网上搜索$ra(返回地址)是否被调用方保存(保留),有些表格说它是被调用方保存的,而有些表格说它不是。
我认为$ra不是被调用者保存的寄存器,这意味着它是调用者保存的寄存器。
因为如果$ra是被调用方保存的寄存器,我相信会有问题,如果我们通过jal调用一个函数(子例程),被调用方函数不可能保留以前的$ra值,因为在jal指令之后$ra会变成PC +4;调用者函数应该事先在堆栈中保存$ra。2因此,考虑到这种情况,$ra将是调用者保存的寄存器。
我说的对吗?

9ceoxa92

9ceoxa921#

我说的对吗?
正如您已经发现的,$ra是一个非常特殊的情况:
jal指令在进入被调用的函数之前已经向$ra写入了一个值,因此调用函数已经"销毁"了$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修改了这些寄存器)。

vlurs2pr

vlurs2pr2#

正如上面唯一的另一个答案(马丁·罗森瑙)所指出的,$ra是一个例外。
被调用方的工作是将在函数中被覆盖的重要寄存器保存到堆栈中。然而,正如你(OP)指出的,这对$ra来说是不可能的,这使得它成为规则的例外,并迫使调用方在跳转到函数之前将$ra保存到堆栈中。
为什么被调用方E的工作是充当推送和弹出所有内容(除了$ra)的管家呢?想象一下,不管出于什么原因,您决定删除函数,因为您不再需要它。您可以简单地删除函数中的所有内容,而无需担心其他任何事情(除了$ra)。
然而,如果调用者的工作是从堆栈/内存中保存和恢复值,那么你就需要担心函数之外的额外开销,推送和弹出是否是由于被删除的函数或稍后出现的一些事情,这就不太清楚了。

相关问题