1.ARM 工作状态
arm 支持大小端(默认小端 ,大端格式:高字节在低地址,低字节在高地址;小端格式:高字节在高地址,低字节在低地址;)、arm支持16bit thumb指令和32bit arm指令(默认arm指令),thumb2指令是16位与32位共存的。
2.ARM 工作工作模式
不同 工作模式 下 可访问的寄存器和指令集有差异,长度不一样,或者是功能不一样,主要用于区分运行权限保护系统(由运行异常、中断或者软件主动触发切换模式)
工作模式分类(7种):
1、用户模式(Usr):用于正常执行程序;
2、快速中断模式(FIQ):用于高速数据传输;
3、外部中断模式(IRQ):用于通常的中断处理;
4、管理模式(svc):操作系统使用的保护模式;
5、数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储以及存储保护;
6、系统模式(sys):运行具有特权的操作系统任务;
7、未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件。
注意:不是所有ARM架构的产品都是7种工作模式的
2.1.Arm的工作模式切换有两种方法:
被动切换:在arm运行的时候产生一些异常或者中断来自动进行模式切换
主动切换:通过软件改变,即软件设置寄存器来经行arm的模式切换,应为arm的工作模式都是可以通过相应寄存器的赋值来切换的。
Tips:当处理器运行在用户模式下,某些被保护的系统资源是不能被访问的。
除用户模式外,其余6种工作模式都属于特权模式;
特权模式中除了系统模式以外的其余5种模式称为异常模式;
大多数程序运行于用户模式;
进入特权模式是为了处理中断、异常、或者访问被保护的系统资源;-----保护机制
3.ARM 指令和 THUMB指令的关系:
THUMB 指令是 ARM 指令的子集,可以相互调用,只要遵循一定的调用规则
Thumb 指令 与 ARM 指令 的时间效率和空间效率关系为:
存储空间约为ARM代码的60%~70%
指令数比ARM代码多约30%~40%
存储器为32位时ARM代码比Thumb代码快约40%
存储器为16位时Thumb比ARM代码快约40~50%
使用Thumb代码,存储器的功耗会降低约30%
注:当处理器处于Thumb状态时发生异常(如IRQ、FIQ、Undef、Abort、SWI等),则异常处理返回时,自动切换到 Thumb 状态。ARM 处理器总是 从 ARM 工作状态开始执行的。因此,如果要在调试器重运行 Thumb 程序,必须为 该 Thumb 程序添加一个 ARM程序头,然后再切换到Thumb工作状态,调用该 Thumb程序。
3.1.Thumb与ARM状态切换
在实际系统中,内核状态需要经常的切换(Interworkong)来满足系统性能要求。具体的切换是通过 Branch Exchange,即 BX 指令来实现的。指令格式为:
Thumb 工作状态 BX Rn
ARM 工作状态 BX Rn
其中 Rn 可以是寄存器 R0 ~ R15 中的任意一个。指令可以通过将寄存器Rn的内容,拷贝到程序计数器 PC 来完成在 4GB地址空间中的绝对跳转,如果操作数寄存器的状态位 Bit0 = 0,则进入 ARM 工作状态;如果 Bit0 = 1,则进入 Thumb 工作状态。
ARM 处理器在两种工作状态之间可以切换,切换不影响处理器的模式或寄存器的内容。
- (1) 当操作数寄存器的状态位 ( 位[0] ) 为 1 时,执行 BX 指令进入 Thumb 状态。如果处理器在 Thumb 状态进入异常,则当异常处理 ( IRQ、FIQ、Undef、Abort 和 SWI ) 返回时,自动转换到 Thumb 状态。
- (2) 当操作数寄存器的状态位 ( 位[0] ) 为 0 时,执行 BX 指令进入ARM状态,处理器进行异常处理 ( IRQ、FIQ、Reset、Undef、Abort 和 SWI )。在此情况下,把PC放入异常模式链接寄存器中。从异常向量地址开始执行也可以进入ARM状态。
4.寄存器
Arm 处理器总共有 37 个寄存器,其可以分为以下 2 类:
- 1. 通用寄存器( 31 个)
1. 不分组寄存器( R0 — R7 ),共 8 个。
2. 分组寄存器( R8 — R14 )共22个(R8-R12,五个,一共5*2=10,R13-14,两个,一共是2*16=12,总共10+12=22个) - 3. PC 指针( R15 ),共1个
- 2. 程序状态寄存器( 6个 )
1. CPSR( 1个 )
2. SPSR( 5个 )
看图就可以算寄存器数量了,要看ARM指令的,不要看Thumb指令的。
所谓 不分组 就是在七种模式下的任意一种模式都访问同一个物理寄存器地址。就是不分组寄存器没有特权模式,任意一种模式都可以使用未分组寄存器。
5.ARM 框架 的 寄存器 解析
未分组寄存器:R0 - R7 R15 cpsr,cpu 在任何模式下看到的 这几个寄存器都是一样的。在所有的运行模式下,未分组寄存器都指向同一个物理寄存器,他们未被系统用作特殊的用途,因此,在中断或异常处理进行运行模式转换时,由于不同的处理器运行模式均使用相同的物理寄存器,可能会造成寄存器中数据的破坏,这一点在进行程序设计时应引起注意。分组寄存器 R8 - R14 在不同模式下看到的这几个寄存器是不一样的。
5.1.寄存器功能说明
- R0 - R12 存取数据,临时数据
- R13:sp 用于指向不同模式的栈顶。栈,每种模式都需要开辟一块内存,用于在该模式下 函数调用,临时分配的数据存放在此处。
Stack Pointer (SP)
,栈指针寄存器,该寄存器始终保存着一个指向栈顶的值,值得注意的地方;
SP寄存器的Bit[1:0](最低两位)始终为0,因此这个寄存器是按照字对齐的,也就是四个字节;M3有两个堆栈指针,并且同一时刻只能使用其中的一个;
主堆栈指针(MSP/SP_main):复位后默认使用的堆栈指针寄存器,用于操作系统内核以及异常处理例程(包括中断服务例程);
进程堆栈指针(PSP/SP_process):由用户的应用程序代码使用。
寄存器R13通常被用作堆栈指针寄存器,另外究竟使用哪个寄存器,由CPU的控制寄存器来决定;Handler mode :即系统发生异常(中断等)的情况会进入该模式,通常使用SP_main;
Thread mode:用户程序正常运行时处于该模式,可以选择使用SP_main 或 SP_process;
CPU的Configuration Control Register,如下图所示;。 - R14 : lr 程序跳转的时候,返回到的地址就保存到此处
- R15 :pc 要执行的下一条指令地址,就存放在此处,每次指令执行完,就自动+4
- CPSR:程序状态寄存器。程序执行的时候,有很多临时标记位,结果是0 是否溢出,是否有借位,是否有 进位,当前cpu模式,
- SPSR:用于模式切换,将切换前的 cpsr 保存到 新的模式的 spsr,模式切换回去的时候,再将spsr的内容还原到cpsr。
5.1.1寄存器分组说明
1. 未分组寄存器 R0 ~ R7,共 8 个。在所有的运行模式下都使用同一个物理寄存器,它们未被系统用作特殊的用途。
2. 分组寄存器 R8 ~ R12,R13 ~ R14
R8 ~ R12:( 总共10个 )
每次所访问的物理寄存器与处理器当前的运行模式有关,R8~R12:每个寄存器对应两个不同的物理寄存器
当使用fiq模式时,访问寄存器R8_fiq~R12_fiq,当使用除fiq模式以外的其他模式时,访问寄存器R8_usr~R12_usr。
其中 FIQ 模式有单独的一组 R8 ~ R12,共5个;( FIQ ( 快速中断模式 ) 时访问寄存器 R8_fiq ~ R12_fiq )
另外 6 种模式共用一组 R8 ~ R12,共5个;(当使用除 FIQ 模式以外的其他模式时,访问寄存器 R8 ~ R12)
R13 ~ R14:( 总共12个 )
其中 USR 和 SYS 模式(表格的第一列)共用一组 R13 ~ R14 共2个,
另外 5 种模式下各有独自的一组 R13 ~ R14,并采用以下记号来区分不同的物理寄存器,分别
为 fiq、irq、svc、abt、und。共10个。( mode为以下几种之一:usr、fiq、irq、svc、abt、und。 )
i. R13 在 ARM 指令中常用作堆栈指针 SP
特别注意:由于每一种模式都有自己的 R13,所以我们在自己初始化的时候 一般都要初始化每种模式下的R13,使其指向该运行模式的栈空间。
ii. R14 称为子程序链接寄存器 LR (Link Register)
有两个特殊功能,
一种是每一种模式下都可以用于 保存函数的返回地址,
另外就是异常处理后的返回地址,如中断处理之后的跳转
3. PC 指针( R15 )
R15 用作程序计数器 ( PC ),对应一个物理寄存器,由于 ARM 体系结构采用了多级流水线技术
对于 ARM 指令集而言,PC 总是指向当前指令的下两条指令的地址,可以通过向 pc 赋值,来控制程序跳转。即 PC 的值为当前指令的地址值加8个字节。(这里和我们正常学习的不一样,正常都是PC指向下一条指令,也就是地址值加4字节)。
4. CPSR (1 个 状态寄存器。CPSR 表示:当前程序状态寄存器 )-----重点
CPSR寄存器是32位寄存器。
- 0 ~ 7 位 : 控制
- 8 ~ 27 位: 保留
- 28 ~ 31位: 条件标志
所以我们只要研究控制位和条件位即可。
5. SPSR ( 5 个 备份状态寄存器 )
SPSR(备份的程序状态寄存器)
SPSR 除 usr、sys 外,对应用于异常保护的 CPSR 的备份,异常时,保存CPSR值,异常退出时,将该值恢复到CPSR,以保证程序的正常运行,每一中异常运行模式(除usr和sys)有各自的物理寄存器。
5.1.2.寄存器的作用
0 - r3 : 用作传入函数参数,传出函数返回值。在子程序调用之间,可以将 r0-r3 用于任何用途。被调用函数在返回之前不必恢复 r0-r3。如果调用函数需要再次使用 r0-r3 的内容,则它必须保留这些内容。
r4 - r11 : 被用来存放函数的局部变量。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。
r12 :是内部调用暂时寄存器 ip。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。 在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 r12。
r13 : 是栈指针 sp。它不能用于任何其它用途。sp 中存放的值在退出被调用函数时必须与进入时的值相同。
r14 : 是链接寄存器 lr。如果您保存了返回地址,则可以在调用之间将 r14 用于其它用途,程序返回时要恢复
r15 : 是程序计数器 PC。它不能用于任何其它用途。
注意:在中断程序中,所有的寄存器都必须保护,编译器会自动保护 R4~R11
寄存器编号 | 可选名字 | ATPCS寄存器用法 |
---|---|---|
R0~R3 | A1~A4 | 参数寄存器,在调用函数时,用来存放前4个函数参数和返回值,多出的存堆栈中。(易失的) |
R4~R8 | V1~V5 | 通用变量寄存器。(非易失性的) |
R9 | V6 sb | 通用变量寄存器。在与读/写位置无关的编译情况下,用作基址寄存器。(非易失性的) |
R10 | V7 sl | 通用变量寄存器。在使用堆栈边界检查的编译情况下,R10保存堆栈边界的地址。(非易失性的) |
R11 | V8 fp | 通用变量寄存器。在使用结构指针的情况下,必须保存这个寄存器中调用函数的变量值。(非易失性的) |
R12 | Ip | 通用临时过渡寄存器(易失的) |
R13 | sp | 堆栈指针,指向满递减堆栈 |
R14 | lr | 链接寄存器,在函数调用时用以保存返回地址 |
R15 | pc | 程序计数器 |
5.1.3.小结
37个寄存器是指 通用寄存器 和一些 状态寄存器,这是 ARM 架构定义好的寄存器,事实上 ARMv7 已经不止这些寄存器了,37 个 寄存器是 ARMv6 以前的架构,典型的就是基于 ARMv4T 的 ARM9 有这么多寄存器,之后 ARM 引入了 TrustZone 以及虚拟化就又引入了一些 banked 寄存器。现在到了 ARMv8,通用寄存器又不一样了,具体可以看 ARM 的 spec。
6.ARM 64 经常用到的汇编指令
MOV X1,X0 ;将寄存器X0的值传送到寄存器X1
ADD X0,X1,X2 ;寄存器X1和X2的值相加后传送到X0
SUB X0,X1,X2 ;寄存器X1和X2的值相减后传送到X0
AND X0,X0,#0xF ; X0的值与0xF相位与后的值传送到X0
ORR X0,X0,#9 ; X0的值与9相位或后的值传送到X0
EOR X0,X0,#0xF ; X0的值与0xF相异或后的值传送到X0
LDR X5,[X6,#0x08] ;X6寄存器加0x08的和的地址值内的数据传送到X5
STR X0, [SP, #0x8] ;X0寄存器的数据传送到SP+0x8地址值指向的存储空间
STP x29, x30, [sp, #0x10] ;入栈指令
LDP x29, x30, [sp, #0x10] ;出栈指令
CBZ ;比较(Compare),如果结果为零(Zero)就转移(只能跳到后面的指令)
CBNZ ;比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令)
CMP ;比较指令,相当于SUBS,影响程序状态寄存器CPSR
B/BL ;绝对跳转#imm, 返回地址保存到LR(X30)
RET ;子程序返回指令,返回地址默认保存在LR(X30)
其中 MOV
指令只能用于寄存器之间传值,寄存器和内存之间传值通过 LDR
和 STR
。b
是跳转指令
阿里社区也有一个很不错的整理,这里附上链接。
【ARM】常用指令集-阿里云开发者社区 (aliyun.com)
6.1.指令条件
ARM指令所有指令都是带有条件的,默认是AL
即无条件执行,当指令带有默认条件时不需要明确写出。
操作码 | 条件码助记符 | 标志 | 含义 |
---|---|---|---|
0000 | EQ | Z=1 | 相等 |
0001 | NE(Not Equal) | Z=0 | 不相等 |
0010 | CS/HS(Carry Set/High or Same) | C=1 | 无符号数大于或等于 |
0011 | CC/LO(Carry Clear/LOwer) | C=0 | 无符号数小于 |
0100 | MI(MInus) | N=1 | 负数 |
0101 | PL(PLus) | N=0 | 正数或零 |
0110 | VS(oVerflow set) | V=1 | 溢出 |
0111 | VC(oVerflow clear) | V=0 | 没有溢出 |
1000 | HI(HIgh) | C=1,Z=0 | 无符号数大于 |
1001 | LS(Lower or Same) | C=0,Z=1 | 无符号数小于或等于 |
1010 | GE(Greater or Equal) | N=V | 有符号数大于或等于 |
1011 | LT(Less Than) | N!=V | 有符号数小于 |
1100 | GT(Greater Than) | Z=0,N=V | 有符号数大于 |
1101 | LE(Less or Equal) | Z=1,N!=V | 有符号数小于或等于 |
1110 | AL | 任何 | 无条件执行(默认) |
1111 | NV | 任何 | 从不执行 |
参考链接:
ARM 寄存器 详解_擒贼先擒王的博客-CSDN博客_用于子程序或函数调用时保存返回地址、减少内存访问次数的寄存器是
【ARM】常用指令集-阿里云开发者社区 (aliyun.com)