目录
伪操作:汇编程序中一些特殊指令助记符,作用是完成汇编程序的各种准备工作。伪操作只在源程序进行汇编时被汇编程序处理,不会生成机器码。
符号定义
全局变量定义
格式:GBLA(GBLL/GBLS) 变量名
作用:用于定义一个全局变量并进行初始化。
三条伪操作介绍如下:
伪操作 | 作用 |
---|---|
GBLA | 定义全局的数值变量,并初始化为0 |
GBLL | 定义全局的逻辑变量,并初始化为假 |
GBLS | 定义全局的字符串变量,并初始化为空 |
示例:
GBLA NUM ;定义一个全局的数值变量,变量名为NUM
GBLL LOGIC ;定义一个全局的逻辑变量,变量名为LOGIC
GBLS STRING ;定义一个全局的字符串变量,变量名为STRING
局部变量定义
与全局变量定义中的三条指令类似,LCLA、LCLL和LCLS分别用于定义局部的数值变量、逻辑变量及字符串变量,局部的意思在于,此种变量只能在宏中定义:宏MACRO介绍。
示例(这里在MACRO等前面添加了大量空格,但实际上只需要不顶格即可):
MACRO
$label message $a
LCLS err
err SETS "error no: "
$label
INFO 0, "err":CC::STR:$a
MEND
变量赋值
格式:变量名 SETA(SETL/SETS) 相应值
作用:用于定义一个全局变量并进行初始化。三条伪操作介绍如下:
伪操作 | 作用 |
---|---|
SETA | 为数值变量赋值 |
SETL | 为逻辑变量赋值 |
SETS | 为字符串变量赋值 |
示例:
NUM SETA 4 ;将数值变量NUM赋值为4
LOGIC SETL {TRUE} ;将逻辑变量LOGIC赋值为真(不可改为1)
STRING SETS "nhfgtnhgfdb" ;将字符串变量STRING赋值为相应字符串
寄存器列表名称定义
格式:寄存器列表名 RLIST 寄存器列表
作用:为多个寄存器命名为一个名称以方便使用。
示例:
reglist RLIST {R5-R8}
LDMIA R0!,reglist ;这两句等效于LDMIA R0!,{R5-R8}
数据定义
简单数据定义
格式:标号 伪操作名 表达式
伪操作 | 作用 | 注意事项 |
---|---|---|
DCB | 分配一片连续的字节存储单元并初始化 | 表达式可为0 ~ 255的数值或字符串(可以用“=”代替) |
DCW(DCWU) | 分配一片连续的半字存储单元并初始化 | 表达式为程序标号或数值表达式(DCW分配的字存储单元是半字对齐,而DCWU不是) |
DCD(DCDU) | 分配一片连续的字存储单元并初始化 | 表达式为程序标号或数值表达式(DCD分配的字存储单元是字对齐,而DCDU不是) |
DCDO | 分配一片按字对齐的字内存单元,并将每个字单元的内容初始化 | 表达式一般为程序标号,初始化内容为标号相对于R9内容的偏移量 |
DCI | 分配一片字对齐(ARM)或半字对齐(Thumb)内存单元并初始化 | Thumb示例 |
DCQ(DCQU) | 分配一片以8字节为单位的连续的存储单元并初始化 | (DCQ分配的存储单元是字对齐,而DCQU不是) |
DCFS( DCFSU) | 为单精度浮点数分配一片连续的字存储单元并初始化 | 每个单精度浮点数占据1个字单元,DCFS分配的字存储单元是字对齐,而DCFSU不是) |
DCFD( DCFDU) | 为双精度浮点数分配一片连续的字存储单元并初始化 | 每个双精度浮点数占据2个字单元,DCFS分配的字存储单元是字对齐,而DCFSU不是) |
SPACE | 分配一片连续的存储单元并初始化为0 | 表达式为分配的字节数(可以用“%”代替) |
NUM_B DCB 11 ;定义变量(标号)NUM_B,并为这个地址赋值为11,即0x0B
DCB 25 ;为NUM_B+1这个地址赋值为25,即0x19
;上两行代码等效于:NUM_B DCB 11,25
LDR R0, =NUM_B ;将NUM的地址赋给R0
LDRB R1, [R0] ;读出NUM的值(一字节)并赋给R1,此时R1=11
LDRB R1, [R0,#1] ;R1=25
NUM_D DCD 11 ;定义变量(标号)NUM_D
DCD 25
LDR R0, =NUM_D ;将NUM的地址赋给R0
LDRB R1, [R0] ;读R1=11
LDRB R1, [R0,#4] ;R1=25
DCDO操作在验证时,以下代码:
NUM DCDO 4
出现错误error: A1144E: DCDO directive not supported for non-RWPI format output,未解决,如果有大佬知道怎么用的话求教。
NUM DCI 3,28;DCB 定义一个连续字节内存空间,0是指字符串结束标记,也可以加0dh回车,0ah换行
DCI 25
LDR R0, =NUM ;(应该是因为半字节对齐才导致从-1开始?)
LDRB R1, [R0,#-1] ;R1=3
LDRB R1, [R0,#0] ;R1=0
LDRB R1, [R0,#1] ;R1=28
LDRB R1, [R0,#2] ;R1=0
LDRB R1, [R0,#3] ;R1=25
特殊结构定义
伪操作 | 语法 | 作用 | 注意事项 |
---|---|---|---|
MAP | MAP 表达式,寄存器 | 定义一个结构化内存表的首地址为表达式+寄存器的值 | 表达式可以是数值或标号,寄存器可为R1 ~ R15,并且可省略,此时首地址为表达式。MAP可用"^"代替 |
FIELD | 标号 伪操作名 表达式 | 定义一个结构化内存表的数据域,表达式为当前数据域在内存表中占的字节数 | FIELD可用"#"代替,内存表示例 |
LTORG | LTORG | 定义一个数据缓冲池( (literal pool)的开始,防止使用LDR之类指令时数据缓冲区使用越界 | 一般在无条件跳转指令或子程序返回指令之后使用 |
MAP 0x10 ;定义结构化内存表首地址为0x10
NUM_1 FIELD 3 ;定义NUM_1的大小为3字节,其地址为0x10
NUM_2 FIELD 6 ;定义NUM_2的大小为6字节,其地址为0x10+3
NUM_3 FIELD 9 ;定义NUM_3的大小为9字节,其地址为0x10+3+6
汇编控制
需要注意的是,下面的伪操作在汇编语言中被视为预编译命令,即if等同于C语言的#if
分支(IF、ELSE、 ENDIF)
IF 逻辑表达式
分支语句1
ELSE
分支语句2
ENDIF
循环(WHILE、WEND)
作为预编译命令,WHILE的作用是将一个代码段按照一定格式拷贝N遍,并进行展开
WHILE 逻辑表达式
循环语句
WEND
下面的示例可以用但不建议使用,WHILE在汇编程序中毕竟是预编译命令:
GBLA count
count SETA 1
WHILE count <= 4
count SETA count+1
WEND
宏定义(MACRO、MEND、MEXIT)
宏定义的编写:
MACRO
$label name $p1,$p2 ;label为后面调用时使用的名称,name为这个宏的名称,p1、p2为参数,可以为标号,相当于C语言的函数形参
; code
$label.loop1 ; 宏中的标号(可省略)
; code
BGE $label.loop1 ;进行标号跳转,具体可以不用BGE而是使用B等其它指令
MEND
宏的调用:宏在被调用时会展开成定义的样子。
自定义的调用名称 name p1,p2 ;name为调用的宏的名称,p1和p2为具体参数名
示例:
;简单的宏定义
MACRO
$label MOVing $p1
MOV R1=$p1
MEND
;宏调用
GBLA para
aaa MOVing para
;调用后的代码在编译时会被当成:
aaa MOVing para
MOV R1=para
信息报告
ASSERT
作用:检查相关条件是否满足,若不满足则报告并终止汇编。
格式:
ASSERT 逻辑表达式
示例:
GBLA subr1
GBLA de
ASSERT subr1 > de
像上述示例,相关条件不满足时,在编译时会弹出错误提示:error: A1312E: Assertion failed
如果满足条件则会正常运行。
INFO
作用:显示用户自定义的错误信息。当数值表达式为0,将字符串表达式以warning的形式打印,为1时,以error的形式打印。
格式:
INFO 数值表达式,字符串表达式
OPT
作用:改变编译器生成的常规列表文件相应的默认选项。
格式:
OPT n
n的取值范围和效果如下表所示:
n值 | 选项含义 |
---|---|
1 | 设置常规列表选项 |
2 | 关闭常规列表选项 |
4 | 设置分页符,在新的一页开始显示 |
8 | 将行号重新设置为0 |
16 | 设置选项,显示SET、GBL、LCL伪操作 |
32 | 设置选项,不显示SET、GBL、LCL伪操作 |
64 | 设置选项,显示展开宏 |
128 | 设置选项,不显示展开宏 |
256 | 设置选项,显示宏调用 |
512 | 设置选项,不显示宏调用 |
1024 | 设置选项,显示第1遍扫描列表 |
2048 | 设置选项,不显示第1遍扫描列表 |
4096 | 设置选项,显示条件汇编伪操作 |
8192 | 设置选项,不显示条件汇编伪操作 |
16384 | 设置选项,显示MEND伪操作 |
32768 | 设置选项,不显示MEND伪操作 |
TTL和SUBT
作用:TTL伪操作在列表文件的页顶部显示一个标题。SUBT伪操作在列表文件页标题的下面显示一个子标题。
如果要在列表文件的第一页显示标题或子标题,应将TTL或SUBT放在源程序的第一行。通过TTL或 SUBT改变页标题时,新的标题将在下一页开始起作用。
其它
AREA
作用:定义代码段、数据段或特定属性的段。其中,段名若以数值开头,则该段名需用"|"括起来,如|1test|。
格式:
AREA 段名,属性1,属性2,……
其中常用属性的有效值及介绍如下表:
有效值 | 作用 |
---|---|
CODE | 定义代码段,默认为READONLY(可以通过添加其它属性进行修改) |
DATA | 定义数据段,默认为READWRITE |
READONLY | 指定本段属性为只读 |
READWRITE | 指定本段为可读可写 |
ALIGN n | n的取值范围为0~31,对应的对齐方式为2n,默认按字对齐 |
COMMON | 定义一个通用数据段,各个源文件中同名的COMMON段共享一段存储单元,该段不可用于定义代码或数据(变量) |
ALIGN
作用:使代码或数据按一定的边界对齐。
格式:
ALIGN [表达式[,偏移量]]
在Cortex-M3、M4内核中,由于使用Thumb汇编,一般会使用
ALIGN 4
使得代码按4字节对齐
CODE16、CODE32
作用:指示汇编器将后面的指令解释为16位的Thumb指令或32位的ARM指令。
格式:
CODE16
CODE32
ENTRY
作用:指定汇编程序的入口点,每个文件里最多只能有一个,当只有一个时,系统复位后会将该入口作为程序起始点,因此一般在启动文件使用。
格式:
ENTRY
END
作用:指示编译器文件结束,一般汇编文件的结尾都会使用
格式:
END
EQU
作用:可用于定义常量,类似C语言中的define。
格式:
名称 EQU 表达式
EXPORT(/GLOBAL)
作用:声明一个全局的标号,该标号可在其他的文件中引用,可用 GLOBAI代替。
格式:
EXPORT 标号{[WEAK]}
{[WEAK]}表示可以在标号后加入[WEAK]选项,声明其他的同名标号优先于该标号被引用,下同。
IMPORT
作用:指示编译器该标号在其它文件定义,无论后续是否引用该标号,该标号均会被加入到当前源文件的符号表中。
格式:
IMPORT 标号{[WEAK]}
EXTERN
作用:类似IMPORT,但后续未应用则不将其加入到当前源文件的符号表。
格式::
EXTERN 标号{[WEAK]}
GET(/INCLUDE)
作用:将一个源文件(.s)包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理。可以使用 INCLUDE代替GET。
格式:
GET 文件名
注意汇编语言的包含和C语言包含的区别,C语言进行文件包含是通过include包含.h文件,主要作用是调用其中声明的函数,但这部分功能在汇编程序中通过EXPORT和IMPORT完成,因此汇编程序中通过GET包含文件一般是包含那些将某些宏指令、常量或结构化的数据类型统一放的源文件
INCBIN
作用:将一个目标文件或数据文件(比如.txt文件)包含到当前的源文件中,被包含的文件不做任何变动地存放在当前文件中,编译器从其后开始继续处理。
格式:
INCBIN 文件名
RN
作用:给寄存器定义一个别名,方便记忆该寄存器的功能。
格式:
名称 RN 表达式
示例:
Temp RN R0 ;这之后可以通过别名Temp使用寄存器R0
ROUT
作用:为局部变量定义作用范围,未使用时局部变量的作用范围为所在的整个AREA,使用后局部变量的作用范围为当前ROUT和下一个ROUT之间。
格式:
局部变量名 ROUT