Risc-V的汇编指令
32位的RV称为RV32,64位为RV64
寄存器
RV中有32个寄存器,容量只有128B,x0~x31,其中x0始终保持0值,只读。
add x1,x2,x3 #其中第一个寄存器是存储结果,表示x1=x2+x3
sub x1,x1,x3 #x1=x1-x3
addi x3,x4,10 #包含立即数的加法,没有立即数减法指令,使用负数实现
其中高级语言中的连续加减会被分解为几条汇编语言
寄存器数据传输速度很快,而访问存储空间传输速度慢
但寄存器存储空间小,只有128B,而DRAM有GB以上的容量
存储空间
32位的字是由4个Byte组成的,RV存储系统中是以Byte为单位寻址,每一个字地址可以拆分到4个字节地址。
小端系统中(低字节存放在低地址上),字地址与最低位字节地址相同。
Load Word指令lw:将数据从存储器装载到寄存器
Store Word指令sw:将数据从寄存器保存到存储器
lw x10,12(x15)#将x15指向的地址加上偏移量12B的数据取出,存到x10中
sw x10,40(x15)#将x10存到地址(x15)+偏移40B的地方去
lb和sb对单个字节进行存储访问操作,取得的数据会经过符号扩展,即将字节最高位复制到所有字的高比特位(8-31)。
lbu,无符号扩展,全0填充
分支转移指令
条件判断分支转移/无条件转移指令
beq register1,register2,L1
bne register1,register2,L1#不相等跳转
blt reg1,reg2,label#less than 小于跳转指令
bltu reg1,reg2,label#无符号小于跳转指令
bge reg1,reg2,label#大于等于跳转指令
j label#无条件跳转指令
可以组成各种高级语言循环语句
逻辑运算指令
and x1,x2,x3#按位与
andi x1,x2,3#与立即数按位与
slli x11,x12,2#逻辑左移(立即数)
srl#逻辑右移
sra#算数右移
常用语掩码操作,分离字节数据
RV中没有逻辑非指令,通过与全1进行xor异或可以实现非
算数移位与逻辑移位区别:算数移位的空位由最高位扩展填充。
伪指令
mv rd,rs#等价于addi rd,rs,0
li rd,13#=addi rd,x0,13
函数调用与跳转
RV的每个指令都是以32位机器码存储在程序空间中
PC寄存器:程序计数器,存放下一条待执行的程序
一般情况下指令顺序执行,更新的PC+4
a0-a7,即x10-x17寄存器,用来向调用函数传递参数,a0,a1寄存器常常用于传递返回值
ra,即x1寄存器,用来保存返回时的地址值
s0-s11,对应编号x8-x9和x18-x27的寄存器用来作为保存寄存器,保存原来进程中的关键数据避免在函数调用过程中被破坏,也用于保存函数中的值。
jr指令,用于函数返回。
jr ra#jump &return ra记录返回地址
ret指令可以只待jr ra
jal指令,相比j而言,jump&link可以自动保存返回地址至ra
addi ra,x0,1016
j sum
##以上代码等价于
jal sum
栈的使用
栈LIFO也是存储系统的一部分,需要一个指向它的寄存器来保存它的基地址。
sp(栈指针寄存器)
栈是按照一定结构组织在一起的,栈中的内容分为许多帧(frame),为栈帧,在内存中为连续块状存储空间
caller:发起调用的函数
callee:被调用的函数
函数调用时的保留寄存器:sp,gop,tp,s0-s11,callee一般不会使用,即便使用也会提前保存好原值
**函数调用不保留寄存器:**可能会被调用函数更改的寄存器,有参数与返回值寄存器a0-a7,返回地址寄存器ra,临时寄存器t0-t6。需要调用函数在调用前对用到的寄存器值进行保存,需要进行压栈弹栈保存。
静态区:保存程序中只声明一次的全局变量
堆区:使用malloc函数申请的动态存储空间
栈区:程序中发生函数调用时用于保存寄存器值的存储空间
RV32中,栈区从0xbfff_fff0开始向低地址扩展,向下存放,以每16B为界进行对齐
堆区位于静态数据的上方,向高地址扩展。
RV32中的程序段从0x0001_1000到0x1000_0000向上存放