MIPS——递归调用
嵌套过程
不调用其他过程的过程称为叶过程(leaf procedure)。如果所有过程都是叶过程,那么情况就很简单。但是某个过程可以调用其他过程,甚至调用的是自身的“克隆”。在调用非叶过程时使用寄存器需要十分小心。
例如,假设主程序将参数3存入寄存器a0,然后使用jal A调用过程A。再假设过程A通过jal B调用过程B,参数为7,同样存入a0。由于A尚未结束任务,所以在寄存器a0的使用上存在冲突。同样,在寄存器ra保存的返回地址也存在冲突,因为它现在保存着B的返回值。
我们必须采取措施阻止这类问题发生:
一个解决方法是将其他所有必须保存的寄存器压栈,就像将保存寄存器压栈一样。调用者将所有调用后还需的参数寄存器(a1~a3)或临时寄存器(t0~t9)压栈。被调用者将返回地址寄存器(ra)和被调用者使用的保存寄存器(a0~a7)都压栈。栈指针 sp 随这栈中的寄存器个数调整。到返回时,寄存器会从存储器中恢复,栈指针也会随着重新调整。
有关指令
jal function #set $ra to Program Counter(PC),then jump to statement at target addres
C语言代码
#include<stdio.h> int factorial(int n); int main()
{
int n;
scanf("%d", &n);
int res = factorial(n);
printf("%d\n",res);
return ;
} int factorial(int n)
{
if (n < ) return ;
else return n * factorial(n - );
}
虽然在C语言中函数定义可以在main函数前,也可以在main函数后,但定义在main函数后似乎更接近MIPS风格(看下面的代码你就知道了)
MIPS代码
.data
prompt1: .asciiz "Enter the number\n"
prompt2: .asciiz "The factorial of n is:\n" .text
# Print prompt1
li $v0,
la $a0, prompt1
syscall # Read integer
li $v0,
syscall # Call factorial
move $a0, $v0
jal factorial
move $a1, $v0 # save return value to a1 # Print prompt2
li $v0,
la $a0, prompt2
syscall # Print result
li $v0,
move $a0, $a1
syscall # Exit
li $v0,
syscall ## Function int factorial(int n)
factorial:
## YOUR CODE HERE
addi $sp,$sp,- #adjust stack for items
sw $ra,($sp) #save return address
sw $a0,($sp) #save the argument n slti $t0,$a0, #if n < 1,then set $t0 as 1
beq $t0,$zero,L1 #if equal,then jump L1
#above all,if n >= ,then jump L1
#if(n < 1)
addi $v0,$zero, #return
addi $sp,$sp, #pop items off stack
jr $ra #return to caller
#else
L1:
add $a0,$a0,- #argument :n -
jal factorial #call factorial with (n-) lw $a0,($sp) #restore argument n
lw $ra,($sp) #restore address
addi $sp,$sp,8 #adjust stack pionter
mul $v0,$a0,$v0 #return n * factorial(n-)
jr $ra return to caller
## END OF YOUR CODE
#jr $ra
手绘调用栈:


MIPS——递归调用的更多相关文章
- Python-函数的递归调用
递归调用顾名思义即在函数内部调用函数(自己调用自己),通常用它来计算阶乘,累加等 注意: - 必须有最后的默认结果 if n ==0,(不能一直调用自己,如果没有可能会造成死循环) - 递归参数必 ...
- 关于C++的递归调用(n的阶乘为例)
C++,是入门编程界的一门初期的语言.今天我们浅谈一下有关C++的递归调用. 在没有继承,多态,封装之前,C++几乎看成是C语言,除了一些简单的输出和头文件. 具体代码实现如下: #include&l ...
- java中父类与子类, 不同的两个类中的因为构造函数由于递归调用导致栈溢出问题
/* 对于类中对成员变量的初始化和代码块中的代码全部都挪到了构造函数中, 并且是按照java源文件的初始化顺序依次对成员变量进行初始化的,而原构造函数中的代码则移到了构造函数的最后执行 */ impo ...
- 玩坏JVM很简单--toString的递归调用
在JVM的内存管理机制下很少发生内存溢出的情况.至少我碰见的少,好像在SSH我多次发布项目时候出现过一次.今天看见一个特简单的方法让内存溢出(好吧,我似乎作死了--!): public class I ...
- 关于static 的研究 与递归调用的输出
static的作用 :1.保存上次执行的结果 2.static int m; 这里默认m的初始值为0,即默认 值是0 #include "stdio.h" int fun(int ...
- C#函数式编程之递归调用
关于递归相信大家已经熟悉的不能再熟悉了,所以笔者在这里就不多费口舌,不懂的读者们可以在博客园中找到很多与之相关的博客.下面我们直接切入正题,开始介绍尾递归. 尾递归 普通递归和尾递归如果仅仅只是从代码 ...
- c++11 lambda递归调用写法
偶然想到要在函数内部使用lambda递归调用,以下是可行的写法,可参考 std::function<void(Node * container,const BlendFunc &blen ...
- 使用Map辅助拼装树状结构,消除递归调用
目前菜单或其他树状结构在数据库中的存储,多数是以一个parentid作为关联字段,以一维形式存储.使用时全部查询出来,然后在内存中拼装成树状结构.现在主要涉及的是拼装方法的问题. 一般可以进行 递归调 ...
- php之递归调用,递归创建目录
/* 递归自身调用自身,每次调用把问题简化,直到问题解决 即:把大的任务拆成相同性质的多个小任务完成 */ /* function recsum($n){ if($n>1){ return $n ...
随机推荐
- CSS3 制作魔方 - 相关立体样式
最好的实践,就是给定一个实践的目标去实践. 目标:利用 CSS3 的一些特性,绘制一个魔方,要可以玩转的那种,即上下左右每一层都可以独立旋转.效果如下: 为了完成此效果,将使用到以下相关概念和样式:坐 ...
- C#、Unity网络通信中基于字节码的自定义协议解码,C#版ByteBuffer
http://www.oschina.net/code/snippet_42170_37516 C#.Unity基于字节的网络通信中字节码解析类,类似java中的ByteBuffer,不过这个实现是参 ...
- 浅谈C# String对象
本文介绍C#中的string是一个引用类型,C# String对象是存放在堆上,而不是堆栈上的,因此,当把一个字符串变量赋给另一个字符串时,会得到对内存中同一个字符串的两个引用. AD:WOT2015 ...
- jzoj5987. 【WC2019模拟2019.1.4】仙人掌毒题 (树链剖分+概率期望+容斥)
题面 题解 又一道全场切的题目我连题目都没看懂--细节真多-- 先考虑怎么维护仙人掌.在线可以用LCT,或者像我代码里先离线,并按时间求出一棵最小生成树(或者一个森林),然后树链剖分.如果一条边不是生 ...
- [Xcode 实际操作]八、网络与多线程-(23)多线程的同步与异步的区别
目录:[Swift]Xcode实际操作 本文将演示线程的同步与异步的区别. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] 异步线程的运行,是没有按照顺序执行的. ...
- vant搜索框问题
最近使用vant搜索框时发现,当输入内容点击一次搜索有数据,点击错号把内容去掉再点击搜索,都没进入点击搜索方法. 解决方法:把bindtop改成bindtouchstart <van-searc ...
- dumpe2fs: Bad magic number in super-block
今天使用tune2fs和dumpe2fs来查看文件系统信息,出现如下图所示错误提示: 解决方法: 1.原来tune2fs和dumpe2fs只能打开ext3/ext4等文件类型. dumpe2fs - ...
- 可以提升3倍开发效率的 Intellij IDEA快捷键大全汇总(2019)
整理了一下IDEA的常用快捷键,可以打印出来或者弄成图片设置为桌面,为广大的程序员们节省更多的时间去谈恋爱. 常用快捷键1 Ctrl+Shift + Enter,语句完成 “!”,否定完成,输入表达式 ...
- 黑马函数式接口学习 Stream流 函数式接口 Lambda表达式 方法引用
- JTextArea设置滚动条
应将JTextArea置于JScrollPanel中 若要使只有垂直滚动条而没有水平滚动条,使用JTextArea.setLineWrap(true),自动换行. 以下摘自[url]http:// ...