主页 > 游戏开发  > 

RISC-V汇编学习(二)——汇编语法

RISC-V汇编学习(二)——汇编语法

在具体汇编指令和汇编实战之前,还是有必要对RISC-V汇编进行下介绍,我一般称之为RISC-V汇编的“语法”,可能“语法”较少,也相对比较简单的原因,大部分的博主都是一笔带过,但本着循序渐进的原则,还是简单概述下,以便加深认识。

1 汇编“语法”概述

汇编文件一般后缀为.S或.s,.S包含了预处理的语句,.s就是纯粹的汇编语句。

1.1 汇编语句格式

和其他指令架构一样, 一个完整的RISC-V汇编程序有多条语句(statement)组成。一条典型的RISC-V汇编语言格式包括:RISC-V指令、操作符、标签以及GNU汇编语法定义。具体即:

[label:] opcode [operands] [;comment] # []内的部分可以省略

label(标签):GNU汇编中,任何以冒号结尾的标识符都被认为是一个标签,而不一定非要在一行的开始。

opcode (操作码):操作码部分有以下多种类型

instruction(指令):直接对应二进制机器指令的字符串pseudo-instruction(伪指令):一条伪指令在汇编时会生成多条实际的汇编指令,使用伪指令可提高代码的编写效率directive(指示/ 伪操作/宏):通过类似指令的形式(以“.”开头),通知汇编器如何控制代码的产生等,不对应具体的指令.macro:采用.macro/.endm自定义的宏

operands(操作数)操作码所需要的的参数,可以是符号、常量或者二者组成的表达式等

comment(注释):代码注释,一般以"#"或“;”开始到当前行结束;

1.2 简单示例: # ====== 伪操作(Directive) ====== .macro delay_loop cycles # 宏定义(Macro)开始 li t0, \cycles # 伪指令(Pseudo-instruction) 1: addi t0, t0, -1 # 基础指令(Instruction),"1:"为局部标签(Label) bnez t0, 1b # 基础指令(引用局部标签) .endm # 宏定义结束 # ====== 数据段定义 ====== .data # 伪操作(声明数据段) .align 2 # 伪操作(对齐控制) array_data: # 全局标签(Label,数据段地址标记) .word 0x1234, 0x5678 # 伪操作(定义32位数据) # ====== 代码段 ====== .text # 伪操作(声明代码段) .globl _start # 伪操作(符号全局化声明) _start: # 全局标签(Label,程序入口) la a0, array_data # 伪指令(实际展开为auipc+addi) lw a1, 0(a0) # 基础指令(内存加载) delay_loop 100 # 宏调用(Macro Expansion) li a7, 93 # 伪指令(加载立即数) ecall # 基础指令(系统调用触发)

说明:

标签(Label) 以冒号:结尾的符号(如array_data:)用于标记代码/数据位置,不生成机器码 伪指令(Pseudo-instruction) 用户友好的指令别名(如la=Load Address)汇编阶段会展开为实际指令序列 基础指令(Instruction) 直接映射到RISC-V ISA的机器码(如addi对应OP-IMM格式) 伪操作(Directive) 以.开头的控制命令(如.text)指导汇编器行为,不生成机器码 宏(Macro) 通过.macro定义的代码模板调用时展开为预定义的指令序列 2 汇编“语法”说明

前面已经简单示例,基本上已经可以算是入门了解了,下面稍微详细介绍下各部分

2.1 label标签

标签的本质是代表它所在的地址,因此标签可以当作变量或函数来使用。常见的标签分为文本标签和数字标签。 标签只能由a~z,A~Z,0~9,“.”,“_”这些点、字母、数字、下划线等字符组成,除数字标签外,不能以数字开头。

(1)文件标签在程序文件中是全局可见的,所以在定义是不可重复。文本标签通常被作为分支或跳转指令的目标地址,如: loop: # 定义一个loop标签 ... j loop # 跳转到loop标签处 (2)数字标签属于一种局部标签,可重复定义,通常用0~9之间的数字定义。在被引用时,数字标签通常需要带上字母“f”或“b”字母后缀, f:指示编译器向前搜索,即代码行数增加的方向b:指示编译器向后搜索,即代码行数减少的方向 如: j 1f # 向前寻找并跳转至第一个数字为1的标签处 ... 1: #数字标签1 ... j 1b # 向后寻找并跳转至第一个数字为1的标签处 2.2 汇编指令和伪指令

汇编程序的最基本元素是指令,指令集是处理器架构的最基本要素。因此RISC-V汇编语言的最基本元素便是一条条的RISC-V指令;除了普通的指令,RISC-V还定义了伪指令以便于用户编写汇编程序。但是这一部分呢,是RISC-V的核心,所以后续将另开一篇介绍。

2.3 伪操作

伪操作通常以“.”开头,在汇编程序中的作用是指导汇编器处理汇编程序的行为,仅在汇编过程中起作用。

(1).file filename .file 伪操作,指示汇编器该汇编程序的逻辑文件名

(2).global symbol_name或.globl symbol_name .global和.globl伪操作,用于定义一个全局的符号,使得其他文件也可调用该symbol_name

(3).local symbol_name .local伪操作,用于定义局部符号,使得该symbol_name对其他文件不可见

(4).weak symbol_name 在汇编程序中,符号的默认属性为强(strong),.weak伪操作用于设置符号的属性为弱(weak)

(5).type name,type description .type伪操作用于定义符号的类型。如“.type symbol,@function”表示将名为symbol的符号定义为一个函数(function)

(6).align integer .align伪操作,用于定义接下来的地址按照2的integer次方对齐。如“.align 2”表示按照4字节对齐。

(7).byte expression [,expression]* .byte伪操作将从当前PC地址处开始分配若干个字节(byte)的空间,每个字节填充的值由分号分隔开的expression指定。

(8) .float 或者 .double expression [, expression]*

(1).float伪操作将从当前PC地址处开始分配若干个单精度浮点数(32位)的空间,每个单精度浮点数填充的值由分号分隔开的expression指定。空间分配的地址一定与32位对齐。(2).double伪操作将从当前PC地址处开始分配若干个双精度浮点数(64位)的空间,每个双精度浮点数填充的值由分号分隔开的expression指定。空间分配的地址一定与64位对齐。

(9).section name [,subsection] .section伪操作指示将接下来的代码汇编链接到名为name的段中(Section),还可以指定可选的子段(Subsection),常见的段有.text、.data、.bss.

“.section .text” 将接下来的代码汇编链接到.text段中“.section .data” 将接下来的代码汇编链接到.data段中“.section .bss” 将接下来的代码汇编链接到.bss段中

(10).macro和.endm宏定义

.macro和.endm用于定义宏,可以将一段汇编代码定义为一个宏(可以类比于C的宏函数)使用方式如下: .macro mutil_add a,b,c #定义一个名为mutil_add的宏,参数为a、b、c add t0,a,b #将a和b相加,值写入t0寄存器 add c,c,t0 #加t0和c相加,值写入c .endm #宏定义结束 mutil_add x1,x2,x3 #调用mutil_add

还有更多比如:.half .word .option等等,不再详细一一列举了,使用到或者感兴趣,可以自行搜索学习。

关于RISC-V的基本语法格式介绍完毕,后续在汇编实战中使用到时再做学习。

参考 RISC-V (二)汇编语言编程 RISC-V嵌入式开发入门篇2:RISC-V汇编语言程序设计(上) RISC-V嵌入式开发入门篇2:RISC-V汇编语言程序设计(中) RISC-V嵌入式开发入门篇2:RISC-V汇编语言程序设计(下)

标签:

RISC-V汇编学习(二)——汇编语法由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“RISC-V汇编学习(二)——汇编语法