当今,强大的编译器将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
5cd ~
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