在此函数的第一个迭代中,我们可以执行recur:
并执行以下行:sw $ra, 0($sp)
,这是在任何jal
语句之前完成的。据我了解,jal
(跳转和链接)语句将输入到$ra
寄存器中,即直接位于jal
之后的位置。那么,如果$ra
中还没有存储任何内容,示例中会发生什么?
这是一个功能;在条目$ra
上保留呼叫者希望您跳回的回信地址。
伴随$ a0 .. $ a3中的前4个整数args,这是调用方和被调用方之间的合同的一部分,这对于它们达成一致以使函数调用起作用是必需的。 calling Convention的这一部分当然是围绕MIPS jal
指令设计的,因此每个函数的调用/返回都可以用一条指令完成。这就是$31
具有符号名$ra
=返回地址的原因。
寄存器不能保存“ nothing”,它始终是32位值。
如果某些代码将$ra
设置为0或某个无效的地址,并使用j
而不是jal
跳转到此函数,则返回时它将崩溃,这将是调用者的错误。您的函数可以简单地假设$ra
在函数入口上拥有有效的返回地址,无论是来自递归调用还是来自其他调用者。
(这是递归函数的要点,您实际上只是在对该函数进行函数调用,而从哪里调用都没有关系。)
请注意,程序中的顶级标签(例如,MARS模拟器中的标签)严格地是[[not函数。
[在MARS中,尽管事实上main
保留有垃圾或$ra
,但通常仍将其称为0
,因此必须通过退出系统调用退出; jr $ra
会崩溃。((在C中,main
是一个真正的函数,通常是从_start
入口点到达的,该入口点在调用main之前进行了设置。在C中,main
本身可以递归,没有任何特殊技巧。可以在真实的操作系统(而不是MARS模拟的玩具系统)下运行,通常可以使用_start:
标签作为内核的真实入口点,或者您只需编写一个main并链接由C库提供的启动代码,该启动代码调用[ C0]。)