C语言转写成MIPS指令集汇编以及MIPS指令集汇编中函数调用时栈的变化
一、问候语
二、C语言代码分析
这段C语言代码共有3个函数组成。set_array函数传入1个int类型的变量num,并创建了1个int类型临时变量i和1个临时int类型数组array,里面含有10个单位,此函数主要目的是调用compare函数,并将num和i传入该函数中,得到其函数返回值并将该值赋值给array[i],共循环10次,由于set_array函数是void类型,故无需返回值;compare函数传入2个int类型的变量a和b,无临时变量创建,调用sub函数,并将a和b传入该函数中,得到其函数返回值判断是否大于等于0,如果该值大于等于0,则compare函数返回1,否则返回0;sub函数传入2个int类型的变量a和b,无临时变量创建,无函数调用,sub函数返回a-b。综上我们可以看出这3个函数实现了为数组array初始化的功能,i赋值从0到9,循环判断num的值是否大于等于i,如果大于等于则array[i]=1,否则array[i]=0。
我们可以看出set_array函数有1个变量传入,有临时变量创建,有函数调用,无返回值;compare函数有2个变量传入,无临时变量创建,有函数调用,有返回值;sub函数有2个变量传入,无临时变量创建,无函数调用,有返回值;
三、MIPS指令集汇编知识点
1、叶子函数和非叶子函数
在一个函数中如果这个函数里面有调用其他的函数,则我们称这个函数为非叶子函数,需要分配空间;在一个函数中如果这个函数里面没有调用其他的函数,则我们称这个函数为叶子函数,无需分配空间。故set_array函数和compare函数是非叶子函数,sub函数是叶子函数
2、大端模式和小端模式
小端模式下高字节存放高地址,低字节存放低地址;大端模式下低字节存放高地址,高字节存放低地址,上图就是不同模式下存放12345678这个数据的空间不同之处,其中1234为高字节,5678为低字节。在MIPS指令集汇编中是采用大端模式,而在X86指令集汇编中则是采用小端模式
3、函数传入的值在MIPS中的表示
我们用$a0到$a3来传递函数传入前4个非浮点参数,从左到右,超过4个参数使用任务栈传递,此时从右往左依次压栈。例如在sub函数中传入a和b,则在MIPS汇编中$a0就是a,$a1就是b。我们在某个函数中调用其他函数时,需要传参,此时也是用的$a0到$a3
4、函数返回的值在MIPS中的表示
如果是在一个函数中调用其他函数的返回值,则我们用$v0到$v1来表示,例如在compare函数中调用sub函数返回值,则这个函数返回值就是$v0。如果我们要将这个函数最终的返回值调用给其他函数,我们需要用$v0来保存。无论是叶子函数还是非叶子函数结束时都需要jr $ra表示函数结束
5、函数中临时变量和永久变量在MIPS中的表示
我们一般用$t0到t9来存放临时变量,当调用子函数时,这些寄存器中的值可以被随意更改,无需保存。例如set_array函数中的临时变量i就用t0来表示。我们一般用$s0到$s7存放永久变量,所谓的永久变量可以理解为全局变量,或者函数调用结束后依然存在的变量
6、MIPS中开辟空间
MIPS中一个栈帧空间为32位,也就是4个字节。栈帧中除了保留所用的保存寄存器外,还必须保留返回地址$ra,是否保存$fp要看具体情况。如果确保后面都用不到$fp,则可以不保存,但为了保证$fp的值不被后面的过程覆盖,通常应该保存$fp的值,初始化$fp时,$fp总是指向当前栈帧前一个字或者当前栈帧第一个字的起始位置,一般是sw $ra, ?($sp)和addi $fp, $sp,?连用,其中?表示某个数值。除了数组以外的临时变量不用开辟空间,全局变量需要开辟空间。叶子函数不用开辟返回地址$ra空间和帧指针$fp空间,而非叶子函数需要两个都开辟
四、将C语言代码转换成MIPS指令集汇编代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具