一条简单的汇编指令格式(注释使用一个分号):
操作码 操作数 1, 操作数 2, … ;注释
下面表示寄存器移位存储方法,对于立即数必须要以#开头
MOV R0, #0x12 ; R0 -> 0x12
MOV R1, #’A’ ; R1 -> 字母 A 的 ASCII 码
EQU 指示字来定义常数
DCI 编译器指示字,用来表示某些汇编器无法识别的特殊指令助记符
DCB 来定义一串字节常数
DCD 来定义一串 32 位整数
DCI 0xBE00 ; 用于指代断点BKPT
DCD 0x123 ; 定义整数
DCB "heloworld",0 ; 定义字符串
统一汇编语言(UAL),是一个语法规则,用于支持 Thumb-2
你依然可以使用传统的 thumb 语法,这里不做介绍
ADD R0, R0, R1 ;等效R0=RO+R1
ANDS R0, R0, R1
ADDS.N R0, #1 ;指定使用 16 位指令(N=Narrow)
ADDS.W R0, #1 ;指定使用 32 位指令(W=Wide)
CM3 中的数据传送类型有如下几个
常用存储器访问指令
(LDR 加载指令,STR 存储指令)
LDRB Rd, [Rn, #offset]
从地址 Rn+offset 处读取一个字节送到 Rd
LDRD Rd1, Rd2, [Rn, #offset]
从地址 Rn+offset 处读取一个双字(64 位整数)送到 Rd1(低 32 位)和 Rd2(高 32 位)中
STR Rd, [Rn, #offset]
把 Rd 中的低字存储到地址 Rn+offset 处
感叹号的作用是:
STMIA.W R8!, {r0-R3} ; R8 值变为 0x8010,每存一次增一次,先存储后自增
)。增/减单位:字(4 字节)。例如,记R8=0x8000,则下面两
条指令:
STMDB.W R8, {R0-R3} ; R8 值的“一个内部复本”先自减后再存储数据,但 R8 的值不变```
带预索引的 LDR 和 STR
LDR.W R0, [R1, #20]!
该指令先把地址 R1+offset 处的值加载到 R0,然后,R1 <- R1+ 20
后索引:在后索引中,基址寄存器是无条件被更新,省略感叹号
STR.W R0 [R1], #-12
该指令是把 R0 的值存储到地址 R1 处的。在存储完毕后, R1 <- R1+(-12)
注:利用 LDR 和 STR 时,可以使用寄存器作为偏移值,而不用背立即数
但如果拿寄存器作偏移值就绝对不可以使用预索引和后索引了
LDR 伪指令和 ADR 伪指令
LDR r0, =address1
:将地址 address1 的立即数加载到寄存器 r0 中。
ADR r0, address1
:将标签 address1 的地址加载到寄存器 r0 中
ADD 指令有如下几个用法
ADD R0, R1
; R0 += R1ADD R0, #0x12
; R0 += 12ADD.W R0, R1, R2
; R0 = R1+R2除了 ADD 指令之外,CM3 中还包含 SUB, MUL, UDIV/SDIV
等用于算术四则运算
SUB Rd, Rm
常规减法,Rd -= Rn
SBC Rd, Rm
带错位的减法,Rd -= Rm+C
RSB.W Rd, Rn, #imm12
反向减法,Rd = imm12-Rn
MUL Rd, Rm
常规乘法,Rd *= Rm
移位以及循环指令
LSL Rd, Rn, #imm5 ; Rd = Rn<
LSR Rd, Rn, #imm5 ; Rd = Rn>>imm5
逻辑右移
ASR Rd, Rn, #imm5 ; Rd = Rn>>imm5
算数右移
其余指令出现频率很低,面试不会细分考察,我们仅需掌握重点简单的内容就好了,别为难自己
最基础的两个无条件跳转指令:
B Label
跳转到 Label 处对应的地址BX reg
跳转到由寄存器 reg 给出的地址BL Label
跳转到 Label 对应的地址,并且把跳转前的下条指令地址保存到 LRBLX reg
跳转到由寄存器 reg 给出的地址,并根据 REG 的 LSB 切换处理器状态,还要把转移前的下条指令地址保存到 LR在执行 BLX 时,必须置位 LSB=1,否则触发 fault
应用程序状态寄存器(APSR)中存在 5 个标志位
标志位用于表示程序执行过程中的状态信息和操作结果的特性
以下为 APSR 中的四个可被条件转移指令参考的标志位
下表展示了各种可供我们使用的跳转条件,当对应标志位置位后进入跳转流程
以上条件组合常配合无条件转移指令(B)使用,使之变成各式条件转移指令
BEQ label
表示当 z 被置位为 1 时跳转到位置 label
MOVGT R2, R1
条件跳转例子:
CMP
表示为两个数作差,并根据差的结果设置标志位z=1
R0==R1==0
时,触发 z=1
,此时 BEQ 检测到标志位置位,即进入跳转流程,跳转到 label 标注的位置CMP R0, R1
BEQ label
指令隔离(Instruction Barrier)指令是一种用于确保指令执行顺序和内存访问顺序的特殊指令,一般用于多核处理器和多线程环境
如果 CM3 缺少对应的隔离措施,就会发生所谓的“紊乱现象”
下面为 CM3 中的 3 条隔离指令
饱和运算类似于模电中的削顶失真,即通过使用 SSAT 指令,将大数据(32 位)截断为小数据(16 位)
SSAT.W Rd, #imm5, Rn, {,shift}
Rd
:目标寄存器,用于存储截断后的结果。#imm5
:一个立即数,表示要截断的位数,取值范围为 1 到 32。Rn
:源寄存器,包含要进行截断操作的原始数据。{,shift}
:可选参数,用于指定可选的移位操作,可以是 LSL(逻辑左移)、LSR(逻辑右移)、ASR(算术右移)或 ROR(循环右移)。这些指令从 ARMv6,ARMv7 才开始支持
这两条指令仅可以在以下两种情况下使用:
命令语法
MRS
加载特殊功能寄存器的值到 Rn
MSR
存储 Rn 的值到特殊功能寄存器
IF-THEN(IT)
指令围起一个块,里面最多有 4 条指令
其中 T 代表条件成立时执行的语句,E 代表条件不成立时执行的语句
E 对应指令必须和 T 对应指令相反!
下面展示了对应伪代码和使用方式
CBZ(Compare and Branch if Zero):CBZ 指令用于比较一个寄存器的值是否为零,如果为零,则执行跳转操作到指定的目标地址。
CBNZ 含义与 CBZ 相反
格式:
CBZ <寄存器>, <目标地址> ; 如果寄存器的值为零,则跳转到目标地址
CBNZ <寄存器>, <目标地址> ; 如果寄存器的值不为零,则跳转到目标地址
32 位硬件除法指令
SDIV.W Rd, Rn, Rm
UDIV.W Rd, Rn, Rm
REV 反转 32 位整数中的字节序,REVH 则以半字为单位反转,且只反转低半字
REV Rd, Rm
REVH Rd, Rm
REV16 Rd, Rm
REVSH Rd, Rm
RBIT 比前面的 REV 之流更精细,它是按位反转的,相当于把 32 位整数的二进制表示法水平旋
转 180 度
RBIT.W Rd, Rn
用于将数据宽度转换成带符号位 32 位整数长度
带 U 字头的表示高位清零
SXTB Rd, Rn
SXTH Rd, Rn
UXTB Rd, Rn
UXTH Rd, Rn
TBB(Table Branch Byte)
:TBB 指令用于通过查找表的方式进行跳转。它将一个字节大小的偏移量添加到基地址寄存器中,并跳转到所得到的目标地址。
TBB [<基地址寄存器> + <偏移量寄存器>]
TBH(Table Branch Halfword)
:相对应处理的就是半字数据
TBH [<基地址寄存器> + <偏移量寄存器> * 2]