ARM汇编指令集详解

ARM汇编指令集详解

简介:ARM(Advanced RISC Machines)处理器凭借其低功耗、高性能的特点,广泛应用于嵌入式系统、移动设备、物联网等领域。无论是做底层驱动开发、操作系统移植,还是嵌入式系统调试,掌握 ARM 汇编语言都是必不可少的基本功。本文将系统讲解 ARM 处理器架构、寄存器组织、寻址方式、数据处理指令、分支指令、加载存储指令、批量数据传送、状态寄存器操作、协处理器指令、异常处理等核心内容,配合详细的指令格式说明和代码示例,帮助你全面掌握 ARM 汇编编程。


一、ARM 处理器架构概述

1.1 处理器架构分类

常见的处理器架构包括:51/52、ARM、x86、PPC(Power PC)、MIPS 等。ARM 采用的是 RISC(精简指令集) 架构。

RISC 与 CISC 的区别

特性 RISC(精简指令集) CISC(复杂指令集)
指令长度 所有指令长度一致 指令长度不一致
指令数量 少,只保留常用指令 多,包含复杂指令
执行周期 大多数指令一个周期 指令执行周期不等
代表 ARM、MIPS、RISC-V x86

1.2 冯诺依曼体系结构

计算机的冯诺依曼体系结构由五大部分组成:

  • 输入(Input)
  • 输出(Output)
  • 存储器(Memory)
  • 运算器(ALU)
  • 控制器(CU)

计算机的三级存储设备:Cache -> 主存储器 -> 辅助存储器。其中寄存器和 Cache 集成在 CPU 内部,Cache 是高速缓冲存储器。

1.3 ARM 工作模式

ARM 处理器主要有两个工作模式(共8种):

  • User 模式:用户模式,应用代码在此模式下运行
  • SVC 模式:超级用户模式(特权模式),CPU 启动时进入此模式

其他模式包括:FIQ、IRQ、Abort、Undefined、System、Monitor 等。

ARM 的工作状态有三个:ARM 状态、Thumb 状态、Jazelle 状态。

1.4 ARM 流水线

ARM 采用3级流水线:取指令 -> 译码 -> 执行,并行执行。在执行当前指令时,可以同时取下一条指令。

重要概念 :PC(程序计数器)指向的是正在取址的指令地址,而不是正在执行的地址。所以:

复制代码
PC - 8 = 正在执行的指令地址(ARM状态下)

不论有多少级流水线,都是按照三级流水线执行。if-else 等跳转指令会打断流水线,而三目运算符不会跳转,所以在 ARM 编程中尽量使用三目运算符代替 if-else

图片占位符

1.5 ARM 指令集版本

ARM 指令集架构经历了多个版本的发展:v1、v2、v3、v4、v5、v6、v7、v8。Cortex-A 系列之前有 37 个寄存器,Cortex-A 之后有 40 个寄存器。


二、寄存器组

ARM 处理器拥有一个丰富的寄存器组,包括通用寄存器、程序计数器、程序状态寄存器等。

2.1 通用寄存器(R0-R15)

ARM 处理器共有 16 个通用寄存器(32位):

寄存器 名称 用途
R0-R3 通用寄存器 函数调用时默认用来传参
R4-R11 通用寄存器 保存变量,函数调用时需要保护
R12 IP(Intra-Procedure) 临时暂存寄存器
R13 SP(Stack Pointer) 栈指针,指向栈顶
R14 LR(Link Register) 链接寄存器,保存函数返回地址
R15 PC(Program Counter) 程序计数器,指向正在取址的指令

重要说明

  • R0-R3 默认用来传参,调用函数时参数通过这些寄存器传递
  • SP 在代码开始时必须初始化 ,例如:LDR SP, =0x4000000
  • LR 用于保存子程序的返回地址,在调用子程序时需将 LR 压栈
  • PC 的值是当前取址地址,正在执行的指令地址 = PC - 8

2.2 程序状态寄存器(CPSR/SPSR)

ARM 有一个 CPSR (当前程序状态寄存器)和最多 5 个 SPSR(备份程序状态寄存器,每种异常模式一个)。

CPSR 的 32 位分为 4 个 8 位的域:

复制代码
[31:24] 条件标志位域(用 f 表示)
[23:16] 状态位域(用 s 表示)
[15:8]  扩展位域(用 x 表示)
[7:0]   控制位域(用 c 表示)

条件标志位

名称 说明
N 负数标志 运算结果为负数或小于时置 1
Z 零标志 运算结果为零时置 1
C 进位/借位标志 运算产生进位或借位时置 1
V 溢出标志 运算结果发生溢出时置 1

控制位

名称 说明
I IRQ 中断禁止 1=禁止, 0=允许
F FIQ 中断禁止 1=禁止, 0=允许
T Thumb 状态标志 1=Thumb 状态
M4:0 模式标志 指定当前处理器模式

图片占位符


三、寻址方式

ARM 汇编指令的一般格式:

复制代码
指令 {<条件码>}{S} <Rd>, <Rn>, <shift_operand>
  • <> 中的内容必须写
  • {} 中的内容可选
  • 操作数个数只能少,不能多(Rd 和 Rn 不能省略)
  • Rd:目的操作数(destination)
  • Rn:第一个源操作数(通用寄存器)
  • shift_operand:第二个操作数,可以是立即数、寄存器或移位码

ARM 的第二操作数可以是:ARM 通用寄存器、立即数、或移位码。

关于立即数:ARM 中的立即数是由一个 8 位的数左移或右移偶数位得到的,所以不是所有的数都是立即数。如果不确定某个数是否为立即数,可以使用伪指令:

asm 复制代码
LDR R0, =0xFFF    ; 0xFFF 不是立即数,但使用伪指令可以加载任意值

四、数据处理指令

4.1 MOV -- 数据传送

复制代码
MOV {<cond>}{S} <Rd>, <shift_operand>

将第二操作数(可以是立即数或寄存器)传送到目的寄存器。

asm 复制代码
MOV R0, #0         ; R0 = 0
MOV R1, R2         ; R1 = R2
MOV R0, R0         ; 无操作(NOP)
MOVS R0, #0xFFFFFFFB  ; 设置标志位,CPSR 的 N 位置1(结果为负)

注意:操作数最多只能有两个。

4.2 MVN -- 取反传送

复制代码
MVN {<cond>}{S} <Rd>, <shift_operand>

将第二操作数取反后传送到目的寄存器。

asm 复制代码
MVN R0, #0         ; R0 = 0xFFFFFFFF(取反)
MVN R0, #0x0F      ; R0 = 0xFFFFFFF0

4.3 ADD / SUB -- 加法 / 减法

复制代码
ADD {<cond>}{S} <Rd>, <Rn>, <shift_operand>
SUB {<cond>}{S} <Rd>, <Rn>, <shift_operand>
asm 复制代码
ADD R0, R1, R2     ; R0 = R1 + R2
ADD R0, R1, #5     ; R0 = R1 + 5
SUB R0, R1, R2     ; R0 = R1 - R2
SUB R0, R1, #10    ; R0 = R1 - 10

4.4 ADC / SBC / RSC -- 带进位的运算

复制代码
ADC {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 加法 + 进位标志C
SBC {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 减法 - 进位标志C
RSC {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 反向减法

ADC 和 SBC 要加上或减去 CPSR 中的 C 条件标志位,常用于实现 64 位运算。

asm 复制代码
; 64 位加法:R1:R0 + R3:R2 -> R1:R0
ADDS R0, R0, R2    ; 低32位加法,影响进位标志
ADC  R1, R1, R3    ; 高32位加法 + 进位

RSC 是反向相减,可以实现常数减寄存器的值:Rd = shift_operand - Rn

4.5 AND / ORR / EOR / BIC -- 逻辑运算

复制代码
AND {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 逻辑与
ORR {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 逻辑或
EOR {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 逻辑异或
BIC {<cond>}{S} <Rd>, <Rn>, <shift_operand>  ; 位清除
asm 复制代码
AND R0, R0, #0xFF     ; R0 = R0 & 0xFF(取低8位)
ORR R0, R0, #0x0F     ; R0 = R0 | 0x0F(置低4位)
EOR R0, R0, R0        ; R0 = 0(自身异或清零)
BIC R0, R0, #0x0F     ; 将R0的低4位清零

BIC 指令详解:将第二个操作数取反后与第一个操作数相与,实现指定位清零。

asm 复制代码
BIC R0, R0, #0x1011   ; 将 0x1011 取反得 0xFFFFEFFE,再与 R0 相与
                      ; 效果:清除 R0 的 bit0, bit1, bit8, bit12

EOR 的常见用途

  • 两个相同的数异或可以清零变量
  • 与 1 异或取反码
  • 与 0 异或保持不变
  • 交换两个值不需要中间变量

4.6 MUL / MLA -- 乘法

复制代码
MUL {<cond>}{S} <Rd>, <Rn>, <Rm>           ; Rd = Rn * Rm
MLA {<cond>}{S} <Rd>, <Rn>, <Rm>, <Rs>     ; Rd = Rn * Rm + Rs

以上两个只保存低 32 位的值。

64 位乘法指令

指令 说明
UMULL 无符号长整型乘法,结果64位存入 RdLo, RdHi
UMLAL 无符号长整型乘法累加
SMULL 有符号长整型乘法
SMLAL 有符号长整型乘法累加
asm 复制代码
; 格式:UMULL <RdLo>, <RdHi>, <Rm>, <Rs>
; 64位结果:RdHi:RdLo = Rm * Rs
UMULL R0, R1, R2, R3  ; R1:R0 = R2 * R3(64位无符号乘法)

4.7 比较指令(不保存结果,只影响标志位)

CMP -- 比较

复制代码
CMP {<cond>} <Rd>, <shift_operand>

执行减法但不存储结果,只更新 CPSR 的条件标志位。

asm 复制代码
CMP R0, #10      ; 比较 R0 和 10(实质是 R0 - 10)
CMP R0, R1       ; 比较 R0 和 R1

CMN -- 取负比较

复制代码
CMN {<cond>} <Rd>, <shift_operand>

与 CMP 类似,但将操作数取负后比较,用于与小负值进行比较。

TST -- 测试(按位与)

复制代码
TST {<cond>} <Rd>, <shift_operand>

两个操作数相与,不保存结果,只更新标志位。常用于测试某个位是否被置位。

asm 复制代码
; 测试 R0 的 bit0 是否为 1
MOV R0, #0xFFFFFFFC
TST R0, #0x1
; 0xFFFFFFFC & 0x00000001 = 0
; CPSR 的 Z 标志位置 1(结果为零)

TEQ -- 测试等价(按位异或)

复制代码
TEQ {<cond>} <Rd>, <shift_operand>

两个操作数异或,不保存结果,只更新标志位。可用于判断两个值是否相等,且不影响进位标志。

比较指令的特点:这些指令不需要 S 后缀就会更新标志位。

4.8 条件码

所有 ARM 指令都可以附加条件码,根据 CPSR 的标志位决定是否执行:

条件码 后缀 含义 标志位状态
0000 EQ 等于 Z=1
0001 NE 不等于 Z=0
0010 CS/HS 进位设置/无符号高于等于 C=1
0011 CC/LO 进位清除/无符号低于 C=0
0100 MI 负数 N=1
0101 PL 正数或零 N=0
0110 VS 溢出设置 V=1
0111 VC 溢出清除 V=0
1000 HI 无符号高于 C=1 且 Z=0
1001 LS 无符号低于或等于 C=0 或 Z=1
1010 GE 有符号大于等于 N=V
1011 LT 有符号小于 N!=V
1100 GT 有符号大于 Z=0 且 N=V
1101 LE 有符号小于等于 Z=1 或 N!=V
1110 AL 总是执行 无条件(默认)
asm 复制代码
MOVEQ R0, #1       ; 如果相等则 R0 = 1
MOVNE R0, #0       ; 如果不相等则 R0 = 0
CMP   R0, #10
ADDGT R1, R1, #1   ; 如果 R0 > 10,则 R1 = R1 + 1

五、分支指令

5.1 B -- 跳转指令

复制代码
B {<cond>} <地址>

最简单的分支指令,处理器立即跳转到给定地址继续执行。存储在分支指令中的实际值是相对于当前 PC 的偏移量,不是绝对地址,由汇编器计算。

限制:B 指令只能跳转 -32MB 到 +32MB 的范围。

asm 复制代码
B   label        ; 无条件跳转
BEQ equal_label  ; 相等时跳转
BNE not_equal    ; 不相等时跳转

5.2 BL -- 带链接的跳转

复制代码
BL {<cond>} <地址>

在跳转之前,将当前 PC 的值(下一条指令地址)保存到 R14(LR) 中。可以通过将 R14 装载回 R15 来返回。

asm 复制代码
BL  subroutine    ; 调用子程序,LR = 返回地址
; ...
subroutine:
    ; 子程序代码
    MOV PC, LR    ; 返回调用处

BL 是实现子程序调用的基本但强大的机制。

5.3 BX -- 跳转并切换状态

复制代码
BX {<cond>} <Rm>

跳转到 Rm 指定的地址,并将 Rm 的 bit0 复制到 CPSR 的 T 标志位,实现 ARM/Thumb 状态切换。Rm 的 31:1 位送入 PC。

asm 复制代码
BX R0    ; 跳转到 R0 指定的地址,根据 bit[0] 切换状态

5.4 BLX -- 带状态切换的链接跳转

结合了 BL 和 BX 的功能:保存返回地址的同时切换处理器状态。

5.5 长跳转实现

B/BL 只能跳转 -32MB ~ +32MB 范围,要实现长跳转需要直接修改 PC 值:

asm 复制代码
MOV PC, #0x12345678    ; 直接设置 PC 值实现长跳转

六、加载/存储指令(Load/Store)

Load/Store 指令实现 ARM 寄存器和存储器之间的数据传输,主要有三类:

6.1 单寄存器 Load/Store

传输单项数据,可以是字节、半字或字类型。

LDR -- 加载数据

复制代码
LDR {<cond>} <Rd>, <地址>
asm 复制代码
LDR R1, [R0]          ; 将 R0 指向的内存数据加载到 R1
LDR R1, [R0, #4]      ; 将 R0+4 地址的数据加载到 R1
LDR R1, [R0, R2]      ; 将 R0+R2 地址的数据加载到 R1
LDR R1, [R0, R2, LSL #2]  ; 将 R0 + R2*4 地址的数据加载到 R1
LDR R0, =0xFFF        ; 伪指令,加载任意常量

STR -- 存储数据

复制代码
STR {<cond>} <Rd>, <地址>
asm 复制代码
STR R1, [R0]          ; 将 R1 的内容存储到 R0 指向的内存地址
STR R1, [R0, #4]      ; 将 R1 存储到 R0+4 地址

变体指令

指令 说明
LDRB 加载一个字节(8位)
LDRH 加载一个半字(16位)
LDRBT 在用户模式下加载一个字节
STRB 存储一个字节
STRH 存储一个半字

寻址方式详解

asm 复制代码
; 偏移寻址
LDR R0, [R1]           ; 零偏移
LDR R0, [R1, #4]       ; 立即数偏移
LDR R0, [R1, R2]       ; 寄存器偏移
LDR R0, [R1, R2, LSL #2]  ; 寄存器偏移 + 移位

; 前索引寻址(先更新基址再访问)
LDR R0, [R1, #4]!      ; R1 = R1 + 4, 然后加载

; 后索引寻址(先访问再更新基址)
LDR R0, [R1], #4       ; 先加载 R1 指向的数据, 然后 R1 = R1 + 4

6.2 多寄存器 Load/Store(批量数据传送)

可以一次传送内存区域上的一块数据,非常适合用于现场保护和恢复。

复制代码
LDM {<cond>}<模式> Rn{!}, <寄存器列表>{^}
STM {<cond>}<模式> Rn{!}, <寄存器列表>{^}

8 种模式(前 4 种用于数据块传输,后 4 种用于堆栈操作):

模式 说明 用途
IA 每次传送后地址加 4 数据块传输
IB 每次传送前地址加 4 数据块传输
DA 每次传送后地址减 4 数据块传输
DB 每次传送前地址减 4 数据块传输
FD 满递减堆栈 堆栈操作
FA 满递增堆栈 堆栈操作
ED 空递减堆栈 堆栈操作
EA 空递增堆栈 堆栈操作
asm 复制代码
; 加载数据块
LDMIA R1!, {R2-R9}    ; 加载 R1 指向地址上的多字数据到 R2~R9,R1 值更新

; 堆栈操作(保护/恢复现场)
STMFD SP!, {R3-R7, LR}    ; 保护现场(压栈)
LDMFD SP!, {R3-R7, LR}    ; 恢复现场(出栈)
; 等价于:STMFD SP!, {R3-R7, LR} / LDMFD SP!, {R3-R7, PC}

压栈和出栈的本质:压栈是将寄存器的数据存储到内存,出栈是将内存的数据加载到寄存器。

6.3 单寄存器交换指令(SWP)

复制代码
SWP {<cond>} <Rd>, <Rm>, [<Rn>]

执行过程:

  1. 将内存地址 Rn 中的数据加载到 Rd
  2. 将 Rm 中的数据存储到内存地址 Rn

如果 Rd 和 Rm 为同一个寄存器,则实现了寄存器和内存的数据交换。

asm 复制代码
SWP R0, R1, [R2]     ; 将 [R2] 的数据加载到 R0,将 R1 存储到 [R2]
SWP R0, R0, [R1]     ; R0 与 [R1] 交换数据
SWPB R0, R1, [R2]    ; 字节交换

七、状态寄存器操作指令

7.1 MRS -- 从状态寄存器到通用寄存器

复制代码
MRS <Rd>, CPSR     ; 将 CPSR 的值读入 Rd
MRS <Rd>, SPSR     ; 将 SPSR 的值读入 Rd

7.2 MSR -- 从通用寄存器到状态寄存器

复制代码
MSR CPSR, <Rd>     ; 将 Rd 的值写入 CPSR
MSR SPSR, <Rd>     ; 将 Rd 的值写入 SPSR

CPSR 的 32 位分为 4 个域,可以单独修改某个域:

asm 复制代码
MSR CPSR_c, #0x03    ; 只修改控制位域 [7:0]
MSR CPSR_f, R0       ; 只修改条件标志位域 [31:24]
MSR CPSR_cxsf, R0    ; 修改所有域

域标识

  • c:控制位域 7:0
  • x:扩展位域 15:8
  • s:状态位域 23:16
  • f:条件标志位域 31:24

7.3 使能/禁止中断

asm 复制代码
; 禁止 IRQ 中断
MRS R0, CPSR
ORR R0, R0, #0x80       ; 设置 I 位(bit7)
MSR CPSR_c, R0

; 使能 IRQ 中断
MRS R0, CPSR
BIC R0, R0, #0x80       ; 清除 I 位
MSR CPSR_c, R0

八、协处理器指令

ARM 处理器支持协处理器(如 MMU、FPU 等),通过以下指令与协处理器交互:

指令 说明
CDP 协处理器数据操作
LDC 从存储器加载协处理器寄存器
STC 将协处理器寄存器存储到存储器
MCR 从 ARM 寄存器传数据到协处理器寄存器
MRC 从协处理器寄存器传数据到 ARM 寄存器
asm 复制代码
MCR p15, 0, R0, c1, c0, 0   ; 将 R0 的值传送到协处理器 p15 的 c1 寄存器
MRC p15, 0, R0, c0, c0, 0   ; 从协处理器 p15 的 c0 寄存器读取到 R0

协处理器指令在系统级编程(如配置 MMU、Cache、TLB 等)中非常重要。


九、异常处理

9.1 异常产生指令

复制代码
SWI {<cond>} <immed_24>    ; 软件中断,产生软中断,处理器进入 SVC 模式
BKPT <immed_16>            ; 断点中断指令,产生软件断点
asm 复制代码
SWI 0x123456    ; 产生软中断,中断号为 0x123456
BKPT 0x1234     ; 产生断点中断

9.2 ARM 异常处理流程

ARM 在遇到异常时,会自动执行以下操作:

  1. 将下一条指令的地址保存到相应模式的 LR 中
  2. 将 CPSR 的值保存到相应模式的 SPSR 中
  3. 修改 CPSR 的模式位,切换到对应的异常模式
  4. 将 PC 设置为特定的异常向量地址

异常向量表

异常类型 向量地址 入口模式
复位 0x00000000 SVC
未定义指令 0x00000004 Undefined
软中断(SWI) 0x00000008 SVC
指令预取中止 0x0000000C Abort
数据访问中止 0x00000010 Abort
保留 0x00000014 -
IRQ(普通中断) 0x00000018 IRQ
FIQ(快速中断) 0x0000001C FIQ

9.3 异常返回

异常处理完成后,需要恢复现场并返回:

asm 复制代码
; 保护现场
STMFD SP!, {R0-R7, LR}

; 异常处理代码
; ...

; 恢复现场并返回
LDMFD SP!, {R0-R7, PC}^    ; ^ 表示同时恢复 CPSR

MOVS PC, LR 也可以实现返回:将 LR 的值赋给 PC,并将 SPSR 的值恢复到 CPSR,切换回原来的模式。

9.4 函数编写规范

在 ARM 中正确封装一个函数,必须进行现场保护恢复

asm 复制代码
my_function:
    STMFD SP!, {R3-R7, LR}     ; 保护现场(保存用到的寄存器和返回地址)

    ; 函数体
    ; ...

    LDMFD SP!, {R3-R7, PC}     ; 恢复现场并返回

十、ARM 汇编编程要点

10.1 启动代码

在 ARM 编程中,一定要用汇编代码做初始化启动代码,包括:

  1. 初始化向量表
  2. 初始化栈指针(SP)
  3. 初始化内存控制器
  4. 跳转到 C 语言主函数
asm 复制代码
; 典型的启动代码框架
    LDR SP, =0x4000000       ; 初始化栈指针

    ; 跳转到 main 函数
    BL  main

    ; 死循环
halt:
    B   halt

10.2 ARM 指令机器码格式

ARM 指令固定为 32 位,其机器码格式如下:

复制代码
|31|30|29|28|27-25|24|23-22|21|20|19-16|15-12|11-0|
|  cond   | 001 |  | opcode |S |  Rn  |  Rd  |shift_operand |
  • 31:28:条件码
  • 27:26:指令类型标识
  • 24:21:操作码
  • 20:S 标志位
  • 19:16:第一操作数寄存器 Rn
  • 15:12:目的寄存器 Rd
  • 11:0:第二操作数(立即数/移位码)

10.3 伪指令

伪指令不是真正的 ARM 指令,由汇编器处理:

asm 复制代码
LDR R0, =0xFFFF0000   ; 加载任意32位常量(不是立即数也能用)
LDR SP, =0x4000000    ; 加载地址常量

10.4 PWM 注意事项

PWM 的手动装载优先级高于自动装载。要使用自动装载时,必须先关闭手动装载。


十一、完整汇编程序示例

以下是一个完整的 ARM 汇编程序示例,演示了基本的程序结构:

asm 复制代码
; ==============================
; ARM 汇编程序示例
; 功能:简单的算术运算和子程序调用
; ==============================

    AREA example, CODE, READONLY
    ENTRY

start
    ; 初始化栈指针
    LDR SP, =0x4000000

    ; 基本算术运算
    MOV R0, #10          ; R0 = 10
    MOV R1, #20          ; R1 = 20
    ADD R2, R0, R1       ; R2 = R0 + R1 = 30
    SUB R3, R1, R0       ; R3 = R1 - R0 = 10

    ; 逻辑运算
    AND R4, R0, #0xFF    ; R4 = R0 & 0xFF
    ORR R5, R0, #0x0F    ; R5 = R0 | 0x0F

    ; 调用子程序
    MOV R0, #5
    MOV R1, #3
    BL  multiply         ; 调用乘法子程序

    ; 条件执行
    CMP R0, #10
    MOVEQ R0, #100       ; 如果相等则 R0 = 100
    MOVNE R0, #200       ; 如果不等则 R0 = 200

    ; 死循环
loop
    B loop

; ==============================
; 子程序:乘法(简单实现)
; 输入:R0 = 被乘数, R1 = 乘数
; 输出:R2 = 积
; ==============================
multiply
    STMFD SP!, {R3, LR}  ; 保护现场

    MOV R2, #0           ; 结果清零
    MOV R3, #0           ; 计数器清零

mul_loop
    CMP R3, R1           ; 计数器 < 乘数?
    BGE mul_done
    ADD R2, R2, R0       ; 累加被乘数
    ADD R3, R3, #1       ; 计数器 +1
    B   mul_loop

mul_done
    LDMFD SP!, {R3, PC}  ; 恢复现场并返回

    END

十二、指令速查表

数据处理指令

指令 功能 示例
MOV 数据传送 MOV R0, #10
MVN 取反传送 MVN R0, #0
ADD 加法 ADD R0, R1, R2
SUB 减法 SUB R0, R1, R2
RSB 反向减法 RSB R0, R1, #0
ADC 带进位加法 ADC R0, R1, R2
SBC 带借位减法 SBC R0, R1, R2
AND 逻辑与 AND R0, R0, #0xFF
ORR 逻辑或 ORR R0, R0, #0x0F
EOR 逻辑异或 EOR R0, R0, R0
BIC 位清除 BIC R0, R0, #0x0F
MUL 乘法 MUL R0, R1, R2
MLA 乘加 MLA R0, R1, R2, R3
CMP 比较 CMP R0, #10
CMN 取负比较 CMN R0, #1
TST 位测试 TST R0, #0x01
TEQ 相等测试 TEQ R0, R1

分支指令

指令 功能 示例
B 跳转 B label
BL 带链接跳转 BL subroutine
BX 跳转并切换状态 BX R0
BLX 带链接切换跳转 BLX R0

加载/存储指令

指令 功能 示例
LDR 加载字 LDR R0, R1
STR 存储字 STR R0, R1
LDRB 加载字节 LDRB R0, R1
STRB 存储字节 STRB R0, R1
LDRH 加载半字 LDRH R0, R1
LDM 批量加载 LDMIA R0!, {R1-R5}
STM 批量存储 STMFD SP!, {R1-R5, LR}
SWP 数据交换 SWP R0, R1, R2

总结

本文全面系统地介绍了 ARM 汇编指令集的各个方面:

  1. 架构基础:了解了 ARM 处理器的 RISC 架构特点、工作模式、流水线机制。理解 PC 与实际执行地址的关系(PC - 8),以及流水线对程序优化的影响。
  2. 寄存器组织:掌握了 R0-R15 的用途分工、CPSR/SPSR 的标志位和控制位含义。理解了函数调用时 R0-R3 传参、LR 保存返回地址、SP 栈指针管理的关键作用。
  3. 数据处理指令:学习了 MOV/MVN、ADD/SUB/ADC/SBC/RSC、AND/ORR/EOR/BIC、MUL/MLA 等运算指令,以及 CMP/CMN/TST/TEQ 等测试指令。
  4. 分支与控制:掌握了 B/BL/BX/BLX 四种跳转指令,理解了条件码的使用和长跳转的实现方法。
  5. 存储器访问:学习了 LDR/STR 单寄存器操作、LDM/STM 批量传送的 8 种模式、SWP 交换指令,理解了压栈/出栈保护现场的原理。
  6. 状态寄存器操作:掌握了 MRS/MSR 指令的使用,以及 CPSR 各域的独立操作方法。
  7. 异常处理:理解了 ARM 的异常向量表、异常处理流程、现场保护与恢复机制。

ARM 汇编是嵌入式开发的底层基石,熟练掌握后,将为 Bootloader 开发、驱动编程、操作系统移植、性能优化等高级主题奠定坚实基础。


原始笔记来源:frasight/ARM笔记.asm

相关推荐
AndyHeee2 天前
【SVC、PendSV(系统异常) 与 外设 IRQ 、NVIC笔记】
arm开发
暮云星影2 天前
瑞芯微rk3588利用Rockchip NPU运行大语言模型(LLM)
arm开发·人工智能·语言模型·自然语言处理
techdashen2 天前
绕过系统 ICMP:用 rawsock、Npcap 和 WMI 找到默认网卡
开发语言·arm开发·rust
ThornArmor2 天前
【工具篇·番外】跨语言生态的主权回收:基于 ISA 说明书的 4-bit 双向汇编系统全线封顶
c语言·开发语言·汇编·c++·重构·架构
振南的单片机世界2 天前
ARM中断比51快在哪?硬件压栈+NVIC集中管理
arm开发·stm32·单片机·嵌入式硬件
墨绿色的摆渡人2 天前
论文笔记(一百三十七)Learning Dual-Arm Push and Grasp Synergy in Dense Clutter
arm开发·论文阅读
暮云星影3 天前
全志linux开发屏幕适配(一)屏幕参数设置说明
linux·arm开发
是星辰吖~3 天前
WIN32_线程(下)
汇编
m0_547486663 天前
《ARM Cortex-M4嵌入式应用技术——基于STM32F407、STM32CubeMX与Proteus》全套PPT课件
arm开发·stm32·proteus
Lanceli_van3 天前
SQLite 3.45.2(sqlite-autoconf-3450200)ARM 交叉编译完整步骤
arm开发·sqlite