RISC-V汇编快速入门

Creative Commons
本作品采用知识共享署名

本文简单介绍RISC-V的汇编。

当今,强大的编译器将C或者更高级的语言编译成机器码后,其效能损失已经很小了,再加上芯片的性能越来越强,让汇编语言显得可有可无。但对于嵌入式来说至少在下面两种情况还需要汇编:1是启动代码,2是OS的上下文切换。另外在极端情况下使用汇编提高效率也是有必要的,例如芯片内核非常新编译器优化不够好可以在非常清楚CPU的微结构下进行指令集编码提高性能。因此学习一种新的体系结构,了解其汇编语言是非常有必要的。

实例

将Zephyr开发环境做为RISC-V的实验环境一文中,贴出了一段非常简单的RISC-V汇编,这里进行分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# __start被放入到.txt.entry段,位于.text的最开始
.section .text.entry
.globl __start
# 上电后ROM从__start开始运行:初始化$sp,栈是负增长,所以sp指向boot_stack_top,然后跳回到__start
__start:
la sp, boot_stack_top
j __start

# 要将stack放到bss后面,这里声明字段 .bss.stack 作为启动时的栈
.section .bss.stack
.global boot_stack
boot_stack:
# 4K 启动栈大小
.space 4096 * 4
.global boot_stack_top
boot_stack_top:
# 栈结尾

上面这段代码中:
.section .globl .space叫汇编指示符,是汇编器的命令,用于告诉汇编器代码和数据的位置,指定程序中特定的数据常量。
la, j 叫做汇编指令,用于告诉CPU要执行什么样的动作
__start, boot_stack, boot_statck_top,叫做lable,用于代码或者数据的位置表示

汇编指示符

RISC-V的汇编指示符和作用如下

指示符 作用
.text 代码段,之后跟的符号都在.text内
.data 数据段,之后跟的符号都在.data内
.bss 未初始化数据段,之后跟的符号都在.bss中
.section .foo 自定义段,之后跟的符号都在.foo段中,.foo段名可以做修改
.align n 按2的n次幂字节对齐
.balign n 按n字节对齐
.globl sym 声明sym未全局符号,其它文件可以访问
.string “str” 将字符串str放入内存
.byte b1,…,bn 在内存中连续存储n个单字节
.half w1,…,wn 在内存中连续存储n个半字(2字节)
.word w1,…,wn 在内存中连续存储n个字(4字节)
.dword w1,…,wn 在内存中连续存储n个双字(8字节)
.float f1,…,fn 在内存中连续存储n个单精度浮点数
.double d1,…,dn 在内存中连续存储n个双精度浮点数
.option rvc 使用压缩指令(risc-v c)
.option norvc 不压缩指令
.option relax 允许链接器松弛(linker relaxation,链接时多次扫描代码,尽可能将跳转两条指令替换为一条)
.option norelax 不允许链接松弛
.option pic 与位置无关代码段
.option nopic 与位置有关代码段
.option push 将所有.option设置存入栈
.option pop 从栈中弹出上次存入的.option设置

汇编指令

RISC-V指令

RISC-V的汇编器可以直接识别RISC-V指令集中所有的指令,例如在RISC-V指令集体系结构-RV32I指令集概览里面列出来的RV32I。实际读写汇编的时候可以参考riscv-card,https://github.com/jameslzhu/riscv-card 下面摘要了rv32i的card:

RISC-V伪WEI指令

RISC-V的汇编器也可以直接识别RISC-V伪指令。在之前的文章我们曾经提到过RISC-V的指令非常精简,一些功能指令(例如取反)可由其它指令组成,在实际写汇编的RISC-V的汇编器也可以直接识别RISC-V过程中我们要是靠人脑去组合,写代码的WEI效率会很低,因此汇编器提供一组伪指令,在汇编的时候汇编器会将伪指令翻RISC-V的汇编器也可以直接识别RISC-V译为RISC-V的指令组合,RISC-V spec Chatper 25规定的伪指令如下:



第一栏为伪指令,第二栏为基础指令,第三栏说明伪指令的作用。基础指令是RISC-V处理器支持的指令,伪指令由基础指令组成,在汇编的时候由汇编器将伪指令转换为基础指令。

指令速查

虽然RISC-V的汇编指令不多,但能用的场合也不多,少用则易忘。因此我们可以将risc-card和RISC-V spec Chapter 25的伪指令列表打印出来,写汇编或者读汇编代码的时候参考。另外我有将RV32I和伪指令做成tldr文件,大家可以下载安装后直接进行查询, Linux下的安装方法:

1
2
3
4
5
cd ~ 
git clone https://github.com/lgl88911/riscv_tldr.git
sudo apt-get install tldr
cp riscv_tldr/rv32i/* ~/.tldr/tldr/pages/common/
cp riscv_tldr/pseudo/* ~/.tldr/tldr/pages/common/

使用和tldr一样

tldr met

如果没有查找到指令,请尝试缩短查找词,只找有意义的关键词例如

tldr addi
找不到就用
tldr add

参考

http://crva.io/documents/RISC-V-Reader-Chinese-v2p1.pdf
https://github.com/riscv/riscv-isa-manual/releases