最近在学RISC-V的汇编,这里我就以上次作业gcd函数为例,分享一下如何写汇编程序。
C语言版的如下。不多介绍了。
int gcd(int a,int b){
if(b==0)
return a;
return gcd(b,a%b);
}
RISCV汇编的代码如下。
.text
.globl gcd
.type gcd, @function
gcd:
addi sp,sp,-32 #调整栈指针
sd ra,24(sp) #保存函数返回地址
sd s0,16(sp) #保存帧指针(FP)
addi s0,sp,32 #指向栈顶
mv a4,a0 #第一个参数a放在a0中,移到a4
mv a5,a1 #第二个参数b放在a1中,移到a5
#将其保存到堆栈中
sw a4,-20(s0)
sw a5,-24(s0)
bne a5,zero,.return #如果第二个参数b!=0,再调用一次
lw a4,-20(s0) #如果为0,取出参数a,返回
j .end
.return:
remw a1,a4,a5
mv a0,a5
call gcd
mv a4,a0 #将返回参数保存到a4
.end:
mv a0,a4 #返回参数a
ld ra,24(sp) #恢复返回地址
ld s0,16(sp) #恢复帧指针(FP)
addi sp,sp,32 #恢复栈指针
ret
基本指令介绍:
sd=store doubleword,存储双字(8个字节)
ld=load doubleword,加载双字
sw,lw,同理(4个字节)
addi,立即数加
bne=not equal 不等则跳转
j 无条件跳转
mv 寄存器存储到寄存器
ret 返回ra的地址,一般为程序的最后一条指令
一个汇编程序的开头和结尾:
程序的最开始需要
调整栈指针sp
保存返回地址ra
保存帧指针s0(FP)
让s0指向栈顶
相应的,程序的结尾需要
将返回参数写入a0
恢复返回地址ra
恢复帧指针s0(FP)
恢复栈指针sp
ret返回
调用子程序用call指令,需要注意:一般将传入的参数写在a0,a1,a2,,,等寄存器中,将返回的参数写在a0中
关于调用堆栈的内容,参考软件课的课件。
(复旦大学周学功老师版权所有)
我们程序中每次调用的sp调整就是开一个新的frame,程序最后的恢复就是释放掉这一段空间。
我们用s0寄存器(帧指针FP)来确定数据在这一帧中的位置
见除了开头和结尾的所有sd、ld、sw、lw中的基址寄存器,都是用的s0

喜欢的朋友点个关注欢迎大家踊跃转发