技术笔记!
一、计算机基础知识
1.计算机的组成
输入设备:
把其他信号转换成计算机能识别和处理的信号并送入计算机中,如键盘、鼠标、摄像头等。
输出设备:
把运算结果以人或其他设备所能接受的形式送出计算机外,如显示器、音响、打印机等。
存储器:
存储器是用来存储程序和数据的部件,是实现"存储程序控制"的基础,如内存、硬盘等。
运算器:
CPU中负责进行算数运算和逻辑运算的部件,其核心是算术逻辑单元ALU。
控制器:
控制器是CPU的指挥中心,其控制着整个CPU执行程序的逻辑过程。
注:运算器和控制器共同组成了CPU。
2.总线
总线:
总线是计算机中各个部件之间传送信息的公共通信干线, 在物理上就是一束导线按照其传递信,的类型可以分为数据总线、地址总线、控制总线。
DMA总线:
DMA(Direct Memory Access)即直接存储器访问,使用DMA总线可以不通过CPU直接在存储器之间进行数据传递。
3.三级存储结构
Cache:
速度最快、价格最贵、容量最小、断电数据丢失、cpu可直接访问,存储当前正在执行的程序中的活跃部分,以便快速地向CPU提供指令和数据。
主存储器:
速度、价格、容量介于Cache与辅存之间、断电数据丢失、cpu可直接访问,存储当前正在执行的程序和数据。
辅助存储器:
速度最慢、价格最低、容量最大、断电数据不丢失、cpu不可直接访问,存储暂时不运行的程序和数据,需要时再传送到主存。
注:使用三级存储结构是为了兼顾速度、容量、价格。
4.地址空间
一个处理器能够访问(读写)的存储空间是有限的,我们称这个空间为它的地址空间(寻址空间),一般来说N位地址总线的处理器的地址空间是2的N次方。
5.CPU工作原理
一条指令的执行分为三个阶段:
1.取址:
CPU将PC寄存器中的地址发送给内存,内存将其地址中对应的指令返回到CPU中的指令寄存器(IR)。
2.译码:
译码器对IR中的指令进行识别,将指令(机器码)解析成具体的运算。
3.执行:
控制器控制运算器中对应的运算单元进行运算,运算结果写入寄存器。
每执行一条指令后PC的值会自动增加指向下一条指令。
二、ARM处理器概述
1. ARM产品系列
早先经典处理器
包括ARM7、ARM9、ARM11家族。
Cortex-A系列
针对开放式操作系统的高性能处理器,应用于智能手机、数字电视、智能本等高端运用 。
Cortex-R系列
针对实时系统、满足实时性的控制需求,应于汽车制动系统、动力系统等。
Cortex-M系列
为单片机驱动的系统提供了低成本优化方案,应用于传统的微控制器市场、智能传感器、汽车周边等。
2. RISC处理器
RISC处理器(精简指令集)
只保留常用的的简单指令,硬件结构简单,复杂操作一般通过简单指令的组合实现,一般指令长度固定,且多为单周期指令。
RISC处理器在功耗、体积、价格等方面有很大优势,所以在嵌入式移动终端领域应用极为泛。
CISC处理器(复杂指令集)
不仅包含了常用指令,还包含了很多不常用的特殊指令,硬件结构复杂,指令条数较多,一般指令长度和周期都不固定。
CISC处理器在性能上有很大优势,多用于PC及服务器等领域。
3.SOC( System on Chip)
即片上系统,将一个系统中所需要的全部部件集成在一个芯片中在体积、功耗、价格上有很大优势。
4.指令和指令集
4.1 指令
能够指示处理器执行某种运算的命令称为指令(如加、减、乘 ...)
指令在内存中以机器码(二进制)的方式存在;
每一条指令都对应一条汇编;
程序是指令的有序集合。
4.2 指令集
处理器能识别的指令的集合称为指令集;
不同架构的处理器指令集不同;
指令集是处理器对开发者提供的接口。
4.3 ARM指令集
大多数ARM处理器都支持两种指令集:
ARM指令集
所有指令(机器码)都占用32bit存储空间;
代码灵活度高、简化了解码复杂度;
执行ARM指令集时PC值每次自增4。
Thumb指令集
所有指令(机器码)都占用16bit存储空间;
代码密度高、节省存储空间;
执行Thumb指令集时PC值每次自增2。
5.编译原理
机器码(二进制)是处理器能直接识别的语言,不同的机器码代表不同的运算指令,处理器能够识别哪些机器码是由处理器的硬件设计所决定的,不同的处理器机器码不同,所以机器码不可移植。
汇编语言是机器码的符号化,即汇编就是用一个符号来代替一条机器码,所以不同的处理器汇编也不一样,即汇编语言也不可移植。
C语言在编译时我们可以使用不同的编译器将C源码编译成不同架构处理器的汇编,所以C语言可以移植。
6.ARM 存储模型
6.1 ARM 数据类型
ARM采用32位架构,基本数据类型有以下三种
Byte(字节) 8bits
Halfword (半字) 16bits
Word(字) 32bits
数据存储
Word型数据在内存的起始地址必须是4的整数倍
Halfword型数据在内存的起始地址必须是2的整数倍
注:即数据本身是多少位在内存存储时就应该多少位对齐
6.2 字节序
大端对齐
低地址存放高位,高地址存放低位
a = 0x12345678;
小端对齐
低地址存放低位,高地址存放高位
a = 0x12345678;
注:ARM一般使用小端对齐
6.3 ARM指令存储
处理器处于ARM状态时
所有指令在内存的起始地址必须是4的整数倍
PC值由其[31:2]决定,[1:0]位未定义
处理器处于Thumb状态时
所有指令在内存的起始地址必须是2的整数倍
PC值由其[31:1]决定,[0]位未定义
注:即指令本身是多少位在内存存储时就应该多少位对齐
数据类型 大小端 指令存储
7. ARM 工作模式
7.1 ARM有8个基本的工作模式
User(用户模式) 非特权模式,一般在执行上层的应用程序时ARM处于该模式。
FIQ (快速中断) 当一个高优先级中断产生后ARM将进入这种模式。
IRQ (普通终端) 当一个低优先级中断产生后ARM将进入这种模式。
SVC 当复位或执行软中断指令后ARM将进入这种模式。
Abort 当产生存取异常时ARM将进入这种模式。
Undef 当执行未定义的指令时ARM将进入这种模式。
System 使用和User模式相同寄存器集的特权模式。
Monitor 为了安全而扩展出的用于执行安全监控代码的模式。
工作模式的理解:
不同模式拥有不同权限;不同模式执行不同代码;不同模式完成不同的功能。
7.2 ARM工作模式分类
按照权限
User为非特权模式(权限较低),防止用户对系统做不必要的更改,起保护系统作用,其余模式均为特权模式(权限较高)。
按照状态
FIQ、IRQ、SVC、Abort、Undef属于异常模式,即当处理器遇到异常后会进入对应的模。
8. ARM寄存器组织
8.1 寄存器
1.概念
寄存器是处理器内部的存储器,没有地址。
2.作用
一般用于暂时存放参与运算的数据和运算结果。
3.分类
包括通用寄存器、专用寄存器、控制寄存器。
8.2 ARM寄存器
注:
在上方ARM寄存器一共有40个,其中17个通用寄存器,23个特殊寄存器(有三角形下标的是特殊寄存器), 在某个特定模式下只能使用当前模式下的寄存器,一个模式下特有的寄存器其他模式下不可使用。
8.3 专用寄存器
1. R15(PC,Program Counter)
程序计数器,用于存储当前取址指令的地址
2. R14(LR,Link Register)
链接寄存器,一般有以下两种用途:
> 执行跳转指令(BL/BLX)时,LR会自动保存跳转指令下一条指令的地址,程序需要返回时将LR的值复制到PC即可实现。
> 产生异常时,对应异常模式下的LR会自动保存被异常打断的指令的下 一条指令的地址,异常处理结束后将LR的值复制到PC可实现程序返回。
3. R13(SP,Stack Pointer)
栈指针,用于存储当前模式下的栈顶地址。
8.4 CPSR 寄存器(Current Program Status Register)当前程序状态寄存器
CPSR寄存器分为四个域,[31:24]为条件域用F表示、[23:16]为状态域用S表示、[15:8]为预留域用X表示、[8:0]为控制域用C表示 。
每个比特位对应的作用:
Bit[4:0] ——模式位
[10000]User [10001]FIQ [10010]IRQ [10011]SVC
[10111]Abort [11011]Undef [11111]System [10110]Monitor
Bit[5] ——状态位
[0]ARM状态 [1]Thumb状态
Bit[6] ——FIQ禁止位
[0]开启FIQ [1]禁止FIQ
Bit[7] ——IRQ禁止位
[0]开启IRQ [1]禁止IRQ
Bit[28] ——溢出位 V
> 当运算器中进行加法运算且产生符号位进位时该位自动置1,否则为0;
> 当运算器中进行减法运算且产生符号位借位时该位自动置0,否则为1。
Bit[29] ——进位或错位扩展位 C
> 当运算器中进行加法运算且产生进位时该位自动置1,否则为0;
> 当运算器中进行减法运算且产生借位时该位自动置0,否则为1。
Bit[30] ——零 Z
当运算器中产生了0的结果该位自动置1,否则为0;
Bit[31] ——负数 N
当运算器中产生了负数的结果该位自动置1,否则为0;
9. ARM异常处理
9.1 异常
概念:
处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生,这时处理器就要将当前的程序暂停下来转而去处理这个异常的事件,异常事件处理完成之后再返回到被异常打断的点继续执行程序。
9.2 异常处理机制
概念:
不同的处理器对异常的处理的流程大体相似,但是不同的处理器在具体实现的机制上有所不同;比如处理器遇到哪些事件认为是异常事件遇到异常事件之后处理器有哪些动作、处理器如何跳转到异常处理程序如何处理异常、处理完异常之后又如何返回到被打断的程序继续执行等我们将这些细节的实现称为处理器的异常处理机制。
9.3 ARM 异常源
概念:
导致异常产生的事件称为异常源。
ARM异常源:
FIQ 快速中断请求引脚有效
IRQ 外部中断请求引脚有效
Reset 复位电平有效
Software Interrupt 执行swi指令
Data Abort 数据终止
Prefetch Abort 指令预取终止
Undefined Instruction 遇到不能处理的指令
异常模式:
在ARM的基本工作模式中有5个属于异常模式,即ARM遇到异常后会切换成对应的异常模式。
ARM异常响应:
ARM产生异常后的动作(自动完成)
1.拷贝CPSR中的内容到对应异常模式下的SPSR_<mode>
2.修改CPSR的值
2.1.修改中断禁止位禁止相应的中断
2.2.修改模式位进入相应的异常模式 产生异常
2.3.修改状态位进入ARM状态
3.保存返回地址到对应异常模式下的LR_<mode>
4.设置PC为相应的异常向量(异常向量表对应的地址)
异常向量表:
异常返回:
ARM异常返回的动作(自己编写)
1.将SPSR_<mode>的值复制给CPSR
使处理器恢复之前的状态
2.将LR_<mode>的值复制给PC
使程序跳转回被打断的地址继续执行
IQR异常示例:
注:整个过程CPSR保存的永远是当前程序运行状态,SPSR只是异常时对原来的CPSR进行备份。
多个异常同时产生时的服务顺序:
Reset
Data Abort
FIQ
IRQ
Prefetch Abort
Software Interrupt
Undefined instruction
FIQ的响应速度比IRQ快:
1. FIQ在异常向量表位于最末
可直接把异常处理写在异常向量表之后,省去跳转。
2. FIQ模式有5个私有寄存器(R8-R12)
执行中断处理程序前无需压栈保存寄存器,可直接处理中断。
3. FIQ的优先级高于IRQ
3.1 两个中断同时发生时先响应FIQ。
3.2 FIQ可以打断RIQ,但RIQ不能打断FIQ。
三、ARM指令集
1.ARM汇编——精简指令集(cpu不能直接识别)
1.1 汇编中的符号
@ 1.指令: 能够编译生成一条32位的机器码,且能被CPU识别和执行
@ 2.伪指令:本身不是指令,编译器可以将其替换成若干条等效指令
@ 3.伪操作:不会生成代码,只是在编译之前告诉编译器怎么编译
1.2 ARM指令
1.2.1 数据处理指令(数学运算、逻辑运算等)
1.数据搬移指令
MOV(汇编不区分大小写)
.text @表示当前段为代码段
.global _start @声明start为全局符号
_start @汇编程序的入口
MOV R1, #1 @将1搬移至R1寄存器
@ R1 = 1
MOV R2, R1 @将R1的数据搬移至R2
@R2 = R1
.end @汇编程序的结束
MVN(数据取反再搬移)
MVN R0, #0xFF @MVN也属于搬移指令的一种,将数据取反后搬移至寄存器中
@R0 = ~0xFF
立即数:本质就是包含指令当中的数,属于指令的一部分。
立即数的优点:取指的时候就可以将其督导CPU,不用单独去内存读取,速度快。
立即数的缺点:不能是任意的32位的数字,有局限性。
MOV R0, #0x12345678 @这行代码不能正常运行
MOV R0, #0x12 @0x12 = 0x00000012
机械码:0x00000004 E3A02012 MOV R2,#0x00000012
E3A0 指令对应的值
20 寄存器
12 值
数据运算指令基本格式:
@ 《操作码》《目标寄存器》《第一操作寄存器》 《第二操作数》
@ 操作码: 指示执行哪种代码
@ 目标寄存器: 存储计算结果
@ 第一操作寄存器: 第一个参与运算的数据(只能是寄存器)
@ 第二操作数: 第二个参与运算的数据(可以是寄存器或立即数
2. 加法指令 ADD
MOV R2, #5
MOV R3, #3
@ADD R1, R2, R3
@R1 = R2 + R2
@ADD R1,R2, #5
@R1 = R2 + 5
3. 减法指令 SUB
@ SUB R1, R2, R3
@ R1 = R2 - R3
@SUB R1, R2, #2
@ R1 = R2 - 2
@ 逆向减法指令 RSB
RSB R1, R2, #2
@ R1 = 2 - R2
4. 乘法指令 MUL
MUL R1, R2, R3
@R1 = R2 * R3
@乘法指令只能是两个寄存器相乘
5. 按位与指令 AND
AND R1, R2, R3
@ R1 = R2 & R3
6. 按位或指令 ORR
ORR R1, R2, R3
@R1 = R2 | R3
7. 按位异或指令 EOR
EOR R1, R2, R3
@ R1 = R2 ^ R3
8. 左移指令 LSL
LSL R1, R2, R3
@R1 = (R2 << R3)
9. 右移指令 LSR
LSR R1, R2, R3
@R1 = (R2 >> R3)
10. 位清零指令 BIC
MOV R4, #0xFF
BIC R1, R4, #0x0F
@第二操作数中的哪一位为1,就将第一操作寄存器的中哪一位清零,然后将结果写入R1
11. 格式扩展
MOV R1, R2, LSL #1 //看作一个整体
@R1 = (R2 << 1)
12. 带进位的加法指令
两个64位的数据做加法运算,将数据拆分成两部分,分为高低位:
@ 数据运算指令对条件位(N、Z、C、V)的影响
@ 默认情况下数据运算不会对条件位产生影响,在指令后加后缀”S“才可以影响
@ 第一个数的低32位放在R1
@ 第一个数的高32位放在R2
@ 第二个数的低32位放在R3
@ 第二个数的高32位放在R4
@ 运算结果的低32位放在R5
@ 运算结果的高32位放在R6
@ 第一个数
@ 0x00000001 FFFFFFFF
@ 第二个数
@ 0x00000002 00000005
MOV R1, #FFFFFFFF
MOV R2, #0x00000001
MOV R3, #0x00000005
MOV R4, #0x00000002
ADDS R5, R1, R3 @低位两数相加产生进位,C位置1
ADC R6, R2, R4
@本质:R6 = R2 + R4 + 'C'
13, 带借位的减法指令
@ 第一个数
@ 0x00000002 00000001
@ 第二个数
@ 0x00000001 00000005
MOV R1, #0x00000001
MOV R2, #0x00000002
MOV R3, #0x00000005
MOV R4, #0x00000001
SUBS R5, R1, R3 @低位两数相减产生借位,C位置0
SBC R6, R2, R4
@本质:R6 = R2 - R4 -'!C'
1.2. 2 跳转指令(实现程序的跳转,本质就是修改了PC寄存器)
1. 直接修改PC寄存器的值(不建议使用,需要自己计算目标指令的绝对地址。
MAIN:
MOV R1, #1
MOV R2, #2
MOV R3, #3
MOV PC, #0x18 @修改pc寄存器
MOV R4, #4
MOV R5, #5
FUNC:
MOV R6, #6
MOV R7, #7
2. B :不带返回的跳转指令,本质就是将PC寄存器的值修改成跳转标号下指令的地址。
MAIN:
MOV R1, #1
MOV R2, #2
MOV R3, #3
B FUNC @跳转至FUNC标号
MOV R4, #4
MOV R5, #5
FUNC:
MOV R6, #6
MOV R7, #7
3. BL : 带返回的跳转指令,本质就是将PC寄存器的修改为跳转标签下指令地址,同时将跳转指令的下一条指令存放到LR寄存器中。
MAIN:
MOV R1, #1
MOV R2, #2
MOV R3, #3
BL FUNC @修改pc寄存器
MOV R4, #4
MOV R5, #5
FUNC:
MOV R6, #6
MOV R7, #7
MOV PC, LR
@程序返回
1.2.3 ARM指令的条件码(大多数指令后可衔接条件码后缀)
1. 比较指令(CMP)
CMP指令的本质就是一条减法指令(SUBS),只是没有将运算结果保存到目标寄存器。
MOV R1, #1
MOV R2, #2
CMP R1, R2
BEQ FUNC
@执行逻辑: if(EQ){B FUNC} 本质:if(Z == 1){B func}
BNE FUNC
@执行逻辑: if(NQ){B FUNC} 本质:if(z == 0){B func}
MOV R3, #3
MOV R4, #4
FUNC:
MOV R5, #5
MOV R6, #6
ARM指令集中大多数指令都可以带条件码后缀
MOV R1, #1
MOV R2, #2
CMP R1, R2
MOVGT R3, #3
1.2.4 Load/Srore指令(访问(读写)内存)
1. 写内存(STR)
MOV R1, #0xFF000000
MOV R2, #0x40000000
STR R1, [R2]
@将R1寄存器中的数据写入到R2指向的内存空间
2. 读内存(LDR)
LDR R3, [R2]
@将R2指向的内存空间中的数据读取到R3寄存器中
3. 读/写指定的数据类型
MOV R1, #0xFFFFFFFF
MOV R2, #0x40000000
STRB R1, [R2] @写一个字节byte
@将R1寄存器中的数据的Bit[7:0]写入到R2指向的内存空间
STRH R1, [R2]
@将R1寄存器中的数据Bit[15,0]写入到R2指向的内存空间中
STR R1, [R2]
@将R1寄存器中的数据的Bit[31:0]写入到R2指向的内存空间
LDR指令同样支持以上后缀!
1.2.5 寻址方式
寻址方式就是CPU取寻找操作数的方式
1. 立即(数)寻址
MOV R1, #1
MOV R1, R2, #1
2. 寄存器寻址
ADD R1, R2, R3
3. 寄存器移位寻址
MOV R1, R2, LSL #1
4. 基地址加变址寻址
MOV R1, #0xFFFFFFFF
MOV R2, #0x40000000
MOV R3, #4
STR R1, [R2,R3]
@将R1寄存器中的数据写入到R2+R3指向的内存空间
STR R1, [R2, R3, LSL #1]
@将R1寄存器中的数据写入到R2+(R3<<1)指向的内存空间
5. 基址加变址寻址的索引方式
前索引
MOV R1, #0xFFFFFFFF
MOV R2, #0X40000000
STR R1, [R2,#8]
@将R1寄存器中的数据写入到R2+8指向的内存空间
后索引
MOV R1, #0xFFFFFFFF
MOV R2, #0x40000000
STR R1, [R2], #8
@将R1寄存器中的数据写入到R2指向的内存空间
自动索引
MOV R1, #0xFFFFFFFF
MOV R2, #0x40000000
STR R1, [R2,#8]!
@将R1寄存器中的数据写入到R2+8指向的内存空间,然后R2增8
LDR指令同样支持以上后缀!
6. 多寄存器内存访问
@ MOV R1, #1
@ MOV R2, #2
@ MOV R3, #3
@ MOV R4, #4
@ MOV R11,#0x40000020
@ STM R11,{R1-R4}
@ 将R1-R4寄存器中的数据写入到以R11为起始地址的内存空间中
@ LDM R11,{R6-R9}
@ 将以R11为起始地址的内存空间中的数据读取到R6-R9寄存器中
@ 当寄存器编号不连续时,使用逗号分隔
@ STM R11,{R1,R2,R4}
@ 不管寄存器列表中的顺序如何,存取时永远是低地址对应小编号的寄存器
@ STM R11,{R3,R1,R4,R2}
@ 自动索引照样适用于多寄存器内存访问指令
@ STM R11!,{R1-R4}
7. 多寄存器内存访问指令的寻址方式
@ MOV R1, #1
@ MOV R2, #2
@ MOV R3, #3
@ MOV R4, #4
@ MOV R11,#0x40000020
@ STMIA R11!,{R1-R4}
@ 先存储数据,后增长地址
@ STMIB R11!,{R1-R4}
@ 先增长地址,后存储数据
@ STMDA R11!,{R1-R4}
@ 先存储数据,后递减地址
@ STMDB R11!,{R1-R4}
@ 先递减地址,后存储数据
8. 栈的种类与使用
栈的分类:
增栈:压栈时栈指针越来越大,出栈时栈指针越来越小;
减栈:压栈时栈指针越来越大,出栈时栈指针越来越小;
满栈:栈指针指向最后一次压入到栈中的数据,压栈时需要先移动栈指针到相邻位置然后再压栈;
空栈:栈指针指向最后一次压入到栈中的数据的相邻位置,压栈时可直接压栈,之后需要将栈指针移动到相邻位置;
栈分为空增(EA)、空减(ED)、满增(FA)、满减(FD)四种ARM处理器一般使用满减栈;
@ MOV R1, #1
@ MOV R2, #2
@ MOV R3, #3
@ MOV R4, #4
@ MOV R11,#0x40000020
@ STMFD R11!,{R1-R4}
@ LDMFD R11!,{R6-R9}
9. 栈的应用举例
叶子函数的调用过程:
@ 初始化栈指针
@ MOV SP, #0x40000020
@ MIAN:
@ MOV R1, #3
@ MOV R2, #5
@ BL FUNC
@ ADD R3, R1, R2
@ B STOP
@ FUNC:
@ 压栈保护现场
@ STMFD SP!, {R1,R2}
@ MOV R1, #10
@ MOV R2, #20
@ SUB R3, R2, R1
@ 出栈恢复现场
@ LDMFD SP!, {R1,R2}
@ MOV PC, LR
非叶子函数的调用过程:
@ MOV SP, #0x40000020
@ MIAN:
@ MOV R1, #3
@ MOV R2, #5
@ BL FUNC1
@ ADD R3, R1, R2
@ B STOP
@ FUNC1:
@ STMFD SP!, {R1,R2,LR}
@ MOV R1, #10
@ MOV R2, #20
@ BL FUNC2
@ SUB R3, R2, R1
@ LDMFD SP!, {R1,R2,LR}
@ MOV PC, LR
@ FUNC2:
@ STMFD SP!, {R1,R2}
@ MOV R1, #7
@ MOV R2, #8
@ MUL R3, R1, R2
@ LDMFD SP!, {R1,R2}
@ MOV PC, LR
执行叶子函数时不需要对LR压栈保护,执行非叶子函数时需要对LR压栈保护!
1.2.6 状态寄存器传送指令MSR(访问(读写)CPSR寄存器)
1. 读CPSR
MRS R1, CPSR
@ R1 = CPSR
2.写CPSR
@ MSR CPSR, #0x10
@ CPSR = 0x10
在USER模式下不能随意修改CPSR,因为USER模式属于非特权模式
@ MSR CPSR, #0xD3
1.2.7 软中断指令(触发软中断异常)
@异常向量表
B MAIN
B .
B SWI_HANDLER
B .
B .
B .
B .
B .
@应用程序
@ MIAN:
MOV SP, #0x400000020
@初始化SVC模式下的栈指针
MSR CPSR, #0x01
@切换成user模式,开启FIQ, IRQ
MOV R1, #1
MOV R2, #2
SWI #1
@触发软中断异常
ADD R3, R2, R1
B STOP
@异常处理程序
@SWI_HANDLER:
STMFD SP!,{R1,R2,LR}
@压栈保护现场
MOV R1, #10
MOV R2, #20
SUB R3, R2, R1
LDMFD SP!, {R1, R2, PC}^
@出栈恢复现场
@'^'表示出栈的同时将SPSR的值传递给CPSR,实现CPU状态的恢复
1.2.8 协处理器指令(操控协处理器的指令)
@1.协处理器数据运算指令
@ CDP
@2.协处理器存储器访问指令
@ STC 将协处理器中的数据写入到存储器
@ LDC 将存储器中的数据读取到协处理器
@3. 协处理器寄存器传送指令
@ MRC 将协处理器中寄存器中的数据传送到arm处理器中的寄存器
@ MCR 将arm处理器中寄存器中的数据传送到协处理器中的寄存器
1.2.9 伪指令(本身不是指令,编译器可以将其替换成若干条等效指令)
@ 空指令
@ NOP
@ 指令
@ LDR R1, [R2]
@ 将R2指向的内存空间中的数据读取到R1寄存器
@ 伪指令
@ LDR R1, =0x12345678
@ R1 = 0x12345678
@ LDR伪指令可以将任意一个32位的数据放到一个寄存器
@ LDR R1, =STOP
@ 将STOP表示的地址写入R1寄存器
@ LDR R1, STOP
@ 将STOP地址中的内容写入R1寄存器
1.2.10 伪操作(不会生成代码,只是在编译之前告诉编译器怎么编译)
@GNU 的伪操作一般都以'.'开头
@.global symbol
@将symbol声明成全局符号
@.local symbol
@将symbol声明成局部符号
@.equ DATA, 0xFF
@MOV R1, #DATA
@类似于C语言中的宏定义
@.macro FUNC
@MOV R1, #1
@MOV R2, #2
@.endm
@FUNC
@类似C中的子程序调用,注意伪操作符号是一对存在的
@.if 1
@MOV R1, #1
@MOV R2, #2
@.endif
@类似C中的条件编译
@.rept 3 @将循环体中的内容执行3遍
@MOV R1, #1
@MOV R2, #2
@.endr
@类似于C中的循环
@.weak symbol
@ 弱化一个符号, 即告诉编译器即便没有这个符号也不要报错
@.weak func
@B func
@.word VALUE
@在当前地址申请一个字的空间并将其初始化为VALUE
@MOV R1, #1
@.word 0xFFFFFFFF
@MOV R2, #2
@.byte VALUE
@ 在当前地址申请一个字节的空间并将其初始化为VALUE
@MOV R1, #1
@.byte 0xFF
@ .align N
@ 告诉编译器后续的代码以2的N次方对齐
@.align 2
@MOV R2, #2
@ .arm
@ 告诉编译器后续的代码是ARM指令
@ .thumb
@ 告诉编译器后续的代码是Thumb指令
@ .text
@ 定义一个代码段
@ .data
@ 定义一个数据段
@ .space N, VALUE
@ 在当前地址申请N个字节的空间并将其初始化为VALUE
@MOV R1, #1
@.space 12, 0x12
@MOV R2, #2
@不同的编译器伪操作的语法不同
1.3 C和汇编的混合编程
@C和汇编的混合编程原则:在哪种语言环境下符合哪种语言的语法规则
@ 1. 在汇编中将C中的函数当作标号处理
@ 2. 在C中将汇编中的标号当作函数处理
@ 3. 在C中内联的汇编当作C的语句来处理
@ 1. 方式一:汇编语言调用(跳转)C语言
MOV R1, #1
MOV R2, #2
BL func_c
MOV R3, #3
@ 2. 方式二:C语言调用(跳转)汇编
.global FUNC_ASM
FUNC_ASM:
MOV R1, #1
MOV R2, #2
@3. 方式三:
C内联(内嵌)汇编
asm
(
"MOV R6, #6\n"
"MOV R7, #7\n"
);
1.4 ATPCS协议(ARM-THUMB Procedure Call Standard)
ATPCS协议主要内容:
@ 1. 栈的种类
@ 1.1 使用满减栈
@ 2. 寄存器的使用
@ 2.1 R15用作程序计数器,不能作其他用途
@ 2.2 R14用作链接寄存疲,不能做其他用途
@ 2.3 R13用作栈指针,不能做其他用途
@ 2.4 当函数的参数不多于4个时使用R0-R3传递
@ 2.5 函数的返回值使用R0传递
@ 2.6 其他寄存器主要用于存储局部变量