1.ARM的处理器模式
ARM体系结构支持7种处理器模式,分别是:用户、FIQ、IRQ、管理、中止(abort)、未定义和系统模式。除了用户模式外,其余都称之为特权模式。除了用户和系统模式外,其余都称之为异常模式。
2.ARM的存储器组织
ARM处理器总共有37个寄存器:包括31个通用寄存器、包括程序计数器(PC)、和6个状态寄存器。这些寄存器在不同模式下,不能被同时看到,有些名称是重叠的。分为三类:不分组寄存器,分组寄存器和程序计数器
1)不分组寄存器R0~R7
所有的处理模式下、它们都是访问同一个寄存器,因此只有8个不分组寄存器。
2)分组寄存器R8~R14
每一个访问的物理寄存器取决于当前的处理器模式,有些是共用的,而有些事分离的。具体可以查询相关资料。
R13就是堆栈寄存器SP,而R14就是链接寄存器LR
3)程序计数器R15
在ARM状态PC的位[1:0]为0,而在Thumb状态,位[0]为0.
4)程序状态寄存器CPSR和程序状态保存寄存器SPSR
CPSR只有一个,代表了当前的程序状态。而每个异常模式都有独立的一个SPSR,用于保存CPSR的状态。
2 N Z C V DNM(RAZ) I F T M4 M3 M2 M1 M0
3.ARM的常用汇编指令
1)基本寻址方式
包括有寄存器寻址、立即寻址、寄存器移位寻址、寄存器间寻址、变址寻址、多寄存器寻址、堆栈寻址、块复制寻址和相对寻址
2)条件执行
几乎所有的ARM指令都可以包含一个可选的条件码,句法中以{cond}来标识。可用的条件码如下面所示。几乎所有的ARM数据处理指令均可以根据执行结果来选择是否更新条件码标志,即在指令中包含后缀S。
2 0000 EQ Z置位 相等
3 0001 NE Z清零 不等
4 0010 CS / HS C置位 大于或等于(无符号 >= )
5 0011 CC / LO C清零 小于(无符号 < )
6 0100 MI N置位 负
7 0101 PL N清零 正或零
8 0110 VS V置位 溢出
9 0111 VC V清零 未溢出
10 1000 HI C置位且Z清零 大于(无符号 > )
11 1001 LS C清零或Z置位 小于或等于(无符号 <= )
12 1010 GE N和V相同 带符号 >=
13 1011 LT N和V不同 带符号 <
14 1100 GT Z清零且N和V相同 带符号 >
15 1101 LE Z置位或N和V不同 带符号 <=
16 1110 AL 任何 总是(通常省略)
3)存储器访问指令
3.1)LDR和STR(字与无符号字节)语法如下
1op {cond} {B} {T} Rd, [Rn]
2op {cond} {B} Rd, [Rn, Flexoffset] {!} //前索引偏移
3op {cond} {B} Rd, label
4op {cond} {B} {T} Rd, [Rn], Flexoffset //后索引偏移
其中:
op 是操作码即指令LDR或STR。
cond 就是上面所说的条件码,因此指令可以变成LDREQ或STRNE类似的名称,表示满足某些条件时该条指令才会执行。
B 可选后缀,表示传送Rd的最低有效字节,就是所谓的无符号字节传送,字节加载的时候是用'0'来扩展到32位的。
T 可选后缀,即使处理器是在特权模式下,存储系统也将访问看成是处理器在用户模式下。不能和前索引偏移一起使用。
Rd 用于加载或存储的ARM寄存器
Rn 存储器的基址寄存器。若指令是带写回的前索引或后索引(后索引都是写回的),则Rd和Rn不能相同
Flexoffset 加到Rn上的灵活的偏移量
label 程序相对偏移表达式。label必须是当前指令的+-4KB范围内
! 可选后缀,前索引写回标志,若Rn是R15,则不能用后缀!
Flexoffset的句法包括下面两种
1#expr
2{-} Rm {, shift}
- 是可选符号,表示从Rn中减去偏移量,否则是加
expr 表达式,取值范围-4095~+4095的整数
Rm 内含偏移量的寄存器。Rm不允许是R15
shift Rm的可选移位方法,可以是下列形式的任何一种
ASR n算术右移n位(1<=n<=32)
LSL n逻辑左移n位(0<=n<=31)
LSR n逻辑右移n位(1<=n<=32)
ROR n循环右移n位(1<=n<=31)
RRX 循环右移1位,带扩展
3.2)LDR和STR(半字和带符号字节)语法如下:
1op {cond} type Rd, [Rn]
2op {cond} type Rd, [Rn, offset] {!}
3op {cond} type Rd, label
4op {cond} type Rd, [Rn], offset
其中:
type 必须是以下所列其中之一
SH 对带符号半字(仅LDR)
H 对无符号半字
SB 对带符号字节(仅LDR)
label 程序相对偏移表达式。必须是当前指令+-255字节范围
offset 加在Rn上的偏移量,可以是以下两种形式之一
#expr //值为+-255范围内的整数。
{-} Rm
3.3)LDR和STR(双字)加载两个相邻的存储器和存储两个相邻的寄存器,语法如下:
1op {cond} D Rd, [Rn]
2op {cond} D Rd, [Rn, offset] {!}
3op {cond} D Rd, label
4op {cond} D Rd, [Rn], offset
其中:
Rd 加载或存储寄存器其中一个,另一个是R(d+1)。但Rd必须是偶数寄存器,且不能是R14。
Rn 除非指令为零偏移,或不带写回的前索引,否则Rn不允许与Rd和R(d+1)相同
offset 加在Rn上的偏移量
label 程序相对偏移表达式。必须是当前指令+-255字节范围
3.4)LDM和STM 加载多个寄存器或存储多个寄存器,可以传送R0~R15的任何组合
1op {cond} mode Rn{!}, reglist{^}
其中:
mode是下列情况中之一:
IA 每次传送后地址加1
IB 每次传送前地址加1
DA 每次传送后地址减1
DB 每次传送前地址减1
FD 满递减堆栈
ED 空递减堆栈
FA 满递增堆栈
EA 空递增堆栈
Rn 基址寄存器,传送数据的初始地址。不允许是R15
! 可选后缀。若有!,则最后的地址写回Rn
reglist 加载或存储的寄存器列表 可以写出如下形式
{R0, R2, R9}
{R3-R6, R11, R12}
{R0, R4-R7, LR}
3.4) SWP 在寄存器和存储器之间进行数据交换。
1SWP {cond} {B} Rd, Rm, [Rn]
其中:
B 可选后缀。若有B,则是交换字节,否则交换字
Rd 数据从存储器加载到Rd
Rm Rm的内容存储到存储器。如果Rm和Rd的相同,则是交换寄存器和存储器的内容
Rn Rn的内容指定要进行数据交换的存储器的地址。 Rn必须和Rm和Rd不同
4)ARM数据处理指令
4.1)灵活的第二操作数,在数据处理指令中会经常出现第二操作数,即Operand2,它有如下的两种可能形式。
1# immed_8r
2Rm{, shift}
其中:
immed_8r 取值为数字常量的表达式。常量必须对应8位位图在32位字中被循环移位偶数位(0,2,4,6,...,28,30)后的值
合法的常量有:0xFF,0x104,0xFF0,0xFF000,0xF0000000F等
非法的常量有:0x101,0x102,0xFF1,0xFF04等
Rm 存储第二操作数数据的寄存器,可以用各种方法对寄存器中的位图进行移位或循环移位,操作结果用于Operand2
但Rm本身不改变。
shift 对Rm的可选移位方法,可以是以下方法的任何一种
ASR n算术右移n位(1<=n<=32)
LSL n逻辑左移n位(0<=n<=31)
LSR n逻辑右移n位(1<=n<=32)
ROR n循环右移n位(1<=n<=31)
RRX 循环右移1位,带扩展
type Rs 其中type为上面ASR、LSL、LSR、ROR中的一种;Rs为提供移位量的寄存器,仅使用最低有效字节
4.2)ADD、SUB、RSB、ADC、SBC和RSC
1op {cond} {S} Rd, Rn, Operand2
其中:
op 是上面众多指令中的一个
S 可选后缀,会根据结果来更新条件码标志
Rd 结果寄存器
Rn 保存第一操作数的寄存器
Operand2 第二操作数
ADD 表示Rn加Operand2的值存到Rd
SUB 表示Rn减去Operand2
RSB 表示Operand2减去Rn
ADC 将Rn和Operand2相加后再加上进位标志
SBC 从Rn的值中减去Operand2的值,若进位标志是清零的,则结果减去1
RSC 从Operand2中减去Rn的值,若进位是清零的,则结果减去1
4.3)AND、ORR、EOR和BIC
1op {cond} {S} Rd, Rn, Operand2
其中:AND是与、ORR是或、EOR是异或和BIC是位清零
都是Rn和Operand2中的值做处理,然后结果保存在Rd中
BIC 用于将Rn中的位于Operand2中相应位的反码,进行与操作。
4.3)MOV和MVN 传送与传送非
1MOV {cond} {S} Rd,Operand2
2MVN {cond} {S} Rd,Operand2
MOV将Operand2中的值拷贝到Rd中
而MVN将Operand2的值进行按位逻辑非之后再传送到Rd
4.4)CMP和CMN 比较与比较反值
1CMP {cond} Rn, Operand2
2CMN {cond} Rn, Operand2
CMP比较大小,从Rn中减去Operand2的值,但丢弃结果,更新标志位,指令的主要目的是更新标志位
CMN是将Rn和Operand2相加,丢弃结果再更新标志位。
4.5)TST和TEQ 测试和测试相等
1TST {cond} Rn, Operand2
2TEQ {cond} Rn, Operand2
TST对Rn和Operand2的值进行按位与操作,更新标志位,丢弃结果
TEQ对Rn和Operand2的值进行异或操作,更新标志位,丢弃结果
4.6)CLZ 前导零计数
1CLZ {cond} Rd, Rm
Rd 结果寄存器,不允许是R15
Rm 操作数寄存器。CLZ对Rm中的前导零的个数进行计数,结果放在Rd中,若Rm全为0,则结果为32
若位[31]是1,则结果为0
4.7)MUL和MLA 乘法和乘加运算
1MUL {cond} {S} Rd,Rm,Rs
2MLA {cond} {S} Rd,Rm,Rs,Rn
其中:
Rd 结果寄存器,不能使R15
Rm,Rs,Rn 操作寄存器,不能是R15,Rd不能和Rm相同
MUL 将Rm和Rs相乘,并将最低有效32位结果放在Rd中
MLA 将Rm和Rs相乘,再加上Rn的值,将最低有效32位结果放在Rd中
4.8)UMULL、UMLAL、SMULL和SMLAL 无符号和带符号长整数乘法和乘加,结果是64位
1op {cond}{S} RdLo,RdHi,Rm,Rs
其中:
RdLo和RdHi 是结果寄存器
Rm和Rs 是操作数寄存器
UMULL 将Rm和Rs中的值解释为无符号整数。将两数相乘,并将结果的最低32位放RdLo中,高32位放RdHi中
UMLAL 将Rm和Rs中的值解释为无符号整数。将两数相乘,并将结果加回到RdLo和RdHi的64位无符号整数上。
SMULL 将Rm和Rs中的值解释为有符号补码整数。将两数相乘,并将结果的最低32位放RdLo中,高32位放RdHi中
SMLAL 将Rm和Rs中的值解释为有符号补码整数。并将结果加回到RdLo和RdHi的64位无符号整数上。
5)ARM转移指令
5.1)B和BL 跳转指令
1B {cond} label
2BL {cond} label
其中:
label 是程序相对偏移表达式。两条指令都会令程序转移到label上,而BL还会将原来的下一条指令地址保存在R14上
6)ARM协处理指令
7)其他指令
7.1)SWI 软件中断
7.2)MRS 将CPSR或SPSR的内容保存到寄存器中
1MRS {cond} Rd,psr
其中:
Rd 目标寄存器,Rd不允许为R15
psr CPSR或SPSR
7.3)MSR 将立即数或通用寄存器的内容加载到CPSR或SPSR的指定区域
1MSR {cond} <psr>_<fields>,#immed_8r
2MSR {cond} <psr>_<fields>,Rm
其中:
psr 即是CPSR或SPSR
fileds是制定传送区域,可以是
c 控制域屏蔽字节(PSR[7:0])
x 扩展域屏蔽字节(PSR[15:8])
s 状态域屏蔽字节(PSR[23:16])
f 标志域屏蔽字节(PSR[31:24])
8)伪指令
8.1)ADR 将程序的相对偏移或寄存器相对偏移地址加载到寄存器中
1ADR {cond} register,expr
其中:
register 是加载的寄存器
expr 是程序相对偏移或寄存器相对偏移表达式,取值可以是
非字节对齐地址-255~255
字节对齐地址-1020~1020
请注意,这条指令是用来获取相对偏移地址的。
即是用当前PC的值,去减去某一个适当的值(编译器自动计算),从而得到expr这个标号的相对地址,将这个标号的相对于当前pc的偏移地址存储到register中。正是因为这样,这条指令才是一条伪指令,这样的好处是可以绕过程序入口地址的影响,而始终能跳转到准确的地址,因为B这样的跳转指令是跳转到绝对地址上的,而ADR可以获取到一个相对于当前PC的地址,所以用处非常大。
8.2)LDR 用常量或地址加载寄存器
1LDR {cond} register,=[expr | label-expr]
其中:
register 加载寄存器
expr 赋值成数字常量
label-expr 程序相对偏移或外部表达式
汇编器可自动识别数字常量,从而完成对register赋值的操作。