假设我们正在检查函数f的MIPS汇编代码,只有一个局部变量x:
void f(void) {
int x;
...
}
我有两个问题:
f的函数序言和结尾对寄存器$ sp,$ ra和$ fp做了什么假设$ ra和$ fp是函数修改的唯一被调用者保存的寄存器。
< / LI>f的MIPS汇编代码如何访问变量x。
我的尝试: 函数序言将寄存器$ ra和$ fp保存到调用堆栈中。函数epilogue通过将它们从堆栈中弹出来恢复这些寄存器,并将控制权返回到$ ra中的地址。不确定MIPS如何访问变量x,但我知道局部变量也存储在堆栈中。
答案 0 :(得分:6)
(a)f函数的序言和结尾对寄存器$ sp,$ ra和$ fp做了什么假设$ ra和$ fp是函数修改的唯一被调用者保存的寄存器。强>
( $ fp 是'帧指针'也称为'基指针', $ sp 是'堆栈指针', $ ra 是'返回地址')
要解释如何访问“ int x ”,了解它的存储方式和位置非常重要。由于' int x '是一个局部变量,MIPS将通过减去字节数为堆栈上的整数分配适当的空间(或者如果空间使用了markgz所说的方法) 4)来自堆栈指针的32位整数。调用者的返回地址也被保存(另外4个字节),以便该函数可以链接回调用者:
sub $sp, $sp, 8 #4 bytes for $ra + 4 bytes for 'int x' = 8 bytes allocated
sw $ra, 4($sp) #note the order, $ra is always first
sw [int x], 0($sp)
OR
addi $sp, $sp, -8 #an alternate to the code above
sw $ra, 4($sp)
sw [int x], 0($sp)
同样,在函数调用结束时,函数将通过释放堆栈空间来将寄存器恢复到调用者:
lw [int x], 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8
我没有很多使用帧指针( $ fp )的经验,但是如果在程序中堆栈指针( $ sp )改变了值它不能再用作参考点,因此( $ fp )取代它($ sp只是另一个寄存器)。
(b)f的MIPS汇编代码如何访问变量x。
要访问“ int x ”,函数“ f ”可以将变量加载到临时寄存器中。
lw $t0, 0($sp) #it can be any temporary register
由于局部变量不会在函数调用中保留,因此它们可以存储在临时寄存器中。基本上,“推送”指令将是“ sw ”(“存储字词”),而“ pop ”指令将是“” lw '('加载字')。
另外,我知道MIPS可能会很痛苦,reference sheet确实帮助了我。
答案 1 :(得分:0)
查看MIPS调用约定here。通常,函数中的局部变量将保存在临时(调用者保存)寄存器$ t0 - $ t9中。如果函数本身调用函数,则局部变量将保存在堆栈中。
MIPS中没有push
或pop
指令,因此函数序言会通过足够的单词递减堆栈指针以允许函数的所有堆栈存储需求,并且函数结尾撤消这个。
答案 2 :(得分:0)
假设$ ra和$ fp是函数唯一修改的被调用者保存的寄存器,则f的函数序言和结尾对寄存器$ sp,$ ra和$ fp有什么作用。
$sp
-堆栈指针
$fp
-框架指针
$ra
-寄信人地址
函数序言和结语指的是在函数开始时将返回地址寄存器(以及所需的任何其他寄存器)保存到堆栈,并在函数结束时将值返回至各自的寄存器。
您可能已经注意到,MIPS架构没有堆栈,您必须创建堆栈(您可能要检查所用模拟器或特定处理器的手册,因为此方法的常规地址有所不同)。
您将在$ sp中指定的地址保存在主程序中:
daddi $sp, $sp, 0x400 # this is the convention address for WinMIPS64's stack
您可能出于多种原因而使用堆栈,例如:
$ra
)$fp
$s0-$s7
寄存器(如果在函数中使用它们的话)。按照惯例,使用时应始终将它们保存到堆栈中(在这种情况下不适用,但是其他人可能正在阅读,所以)。为此,您将像上面的用户一样使用代码(代码可能会有所不同,具体取决于您所使用的MIPS版本,请查看手册)。
要推送到堆栈,必须使用上面的代码模拟堆栈功能(为数据留出空间,将数据保存在堆栈上)。请记住,当您按上述方式压入堆栈时,还必须POP等量以将$sp
返回到其原始位置。您以相反的顺序进行操作(同样,如上面的用户所示)。
也:因为MIPS中的函数的调用指令(jal f-跳转和链接)自动将返回地址保存在单个寄存器中($ra
-返回地址,还记得吗?),所以您始终需要这样做如果您正在使用递归,或者从第一个函数调用第二个函数,则您将返回地址丢失给主程序,因为它在下一次调用时会被“踩”。
$fp
是帧指针,例如,如果您已将许多寄存器值保存到堆栈中,并且您想访问不同的操作数而无需移动将保留的$sp
指向堆栈的顶部。为此,您需要将$sp
的值加载到$fp
上,然后添加一个位移值来移动。
它允许您从堆栈中加载值,同时将$sp
保留在同一位置,因此可以跟踪推入和弹出操作。
f的MIPS汇编代码如何访问变量x。
按照惯例,MIPS具有用于参数和返回值的特定寄存器。在MIPS中,要传递给函数的参数保存在寄存器$a0-$a3
中,返回值保存在$v0-$v1
中。可以在函数内使用的临时寄存器为$t0-$t9
,但它们在函数返回时不会保留其值。但是,由于寄存器可能用完了,因此可能需要使用堆栈。按照惯例,$s0-$s7
是保存的寄存器,其值通过使用堆栈来保存。
P.S。 重要:我正在使用WinMIPS64模拟器。 MIPS汇编语言在寄存器大小,指令集和堆栈地址方面有所不同,请参考您的特定版本手册,并检查适用于您的情况的值,因为这会影响您的代码。