C语言编译成RISC-V汇编代码后的执行步骤

qq_43204385 2022-05-16 21:52:11

目录

  • 引言
  • 1. 寄存器布局
  • 2. 指令特点
  • 3. 常用指令
  • 3.1 存取指令
  • 3.2 运算指令
  • 3.3 堆栈指令
  • 3.4 跳转指令
  • 3.5 C语言与对应的RISC-V汇编语言

引言

​ 本文在学习了x86和ARM6两种指令集架构之后,以ISA的寄存器、寻址方式、常用指令、堆栈操作等为基础,从程序员的角度介绍RISC-V指令集架构的基础工作流程。对一个指令集架构学习的流程一般分为两个部分:寄存器布局和指令集。

1. 寄存器布局

​ 与x86和ARM64不同的是,对于RV32I、RV64I、RV128I,RISC-V都定义了32个通用寄存器,名称以及用法如下图所示。

​ RISC-V软件将19个寄存器分为两组:x5-x7以及x28-x31是临时寄存器,在过程调用中不被被调用者保存;x8-x9以及x18-x27是保存寄存器,在过程调用中必须被保存。而x10-x17八个参数寄存器,用于传递参数或返回值,x1一个返回地址寄存器,用于返回到起始点。

img

2. 指令特点

​ 与x86和ARM64不同的是,RISC-V的指令是定长的,都为32位,且只有6种类型,这样做简化了指令解码。具体六种指令格式如下,其中,

  • R类型用于寄存器-寄存器操作;

  • I类型用于短立即数和访存load操作;

  • S类型用于访存store操作;

  • B类型用于条件跳转操作;

  • U类型用于长立即数;

  • J类型用于无条件跳转。

其中R、I、S和U类型是四种基础指令,B和J类型都只包含一条指令,具体指令格式如下:

img

3. 常用指令

​ 接下来介绍RISC-V中一些常用指令,后面将给出一个简单的C语言程序与其对应的RISC-V汇编语言伪代码。

3.1 存取指令

​ 内存和寄存器之间传输数据的指令,称为数据传输指令。

取双字

​ 取内存中的A[8]至寄存器x9,字节寻址8×8偏移地址为64

ld    x9, 64(x22)    //x22存放内存中数组的基址,偏移64,取出的数据A[8]存放至寄存器x9

存双字

​ 将寄存器x9中数据存至内存的A[12],字节寻址8×12偏移地址为96

sd    x9, 96(x22)     //x22存放内存中数组的基址,偏移96,寄存器x9的数据存至A[12]

3.2 运算指令

立即数加法

addi    x22, x22,4                //x22 = x22 + 4

寄存器加法

add     x10,x5,x6                //x10=x5+x6,结果保存在x10

3.3 堆栈指令

​ 在使用需要保存的寄存器时进行参数传递等操作时(例如x1用来保存函数的返回地址),需要先把寄存器的当前值换出到栈中保存,再用寄存器进行函数调用,调用结束后,换回寄存器的旧值。

​ RISC-V中,寄存器x2用来保存栈指针,别名也叫做sp。栈的增长方向是由高地址向低地址方向增长。

//例如现在需要将x1和x10两个寄存器的值保存在栈中
addi sp,sp,-16    //sp增长16位,用来保存x1和x10的旧值
sd x1,8(sp)        //保存x1的值
sd x10,0(sp)    //保存x10的值

ld x10,0(sp)    //恢复x10的值
ld x1,8(sp)        //恢复x1的值
addi sp,sp,16    //恢复栈针

3.4 跳转指令

无条件跳转

jalr x0, 0(x1)     //返回x1存储的地址

jal x0, func    //跳转到函数func,返回地址保存在x1中

3.5 C语言与对应的RISC-V汇编语言

C语言程序

int g(int x)
{
    return x+3;
}
int f(int x)
{
    return g(x);
}
int main(void)
{
    return f(8)+1;
}

RISC-V汇编语言程序

g:
addi x10,x10,3  //x10=x10+3,传入的参数加3
jalr x0,0(x1)   //函数返回

f:
jal x1,g        //调用函数g
jalr x0,0(x1)    //返回

main:
addi sp,sp,-16    //sp增长16位,用来保存x1和x10的旧值
sd x1,8(sp)        //保存x1的值
sd x10,0(sp)    //保存x10的值
addi x10,x0,8    //x10=0+8,将立即数8放入寄存器x10中
jal x1,f        //调用函数f,返回地址存在x1    

addi x10,x10,1  //x10=x10+1,即f(8)+1
ld x10,0(sp)    //恢复x10的值
ld x1,8(sp)        //恢复x1的值
addi sp,sp,16    //恢复栈针

252

...全文
262 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

571

社区成员

发帖
与我相关
我的任务
社区描述
软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
软件工程 高校
社区管理员
  • 码农孟宁
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧