ARM-指令集全解析:从基础到高阶应用
一、ARM 指令集体系结构版本
ARM 公司定义了多个指令集版本:
ARMv1:原型机 ARM1,没有用于商业产品。
ARMv2:扩展 V1,包含 32 位乘法指令和协处理器指令。
ARMv3:第一个微处理器 ARM6 核心,支持 Cache、MMU、写缓冲。
ARMv4:应用最广泛的 ARM 指令集版本。
ARM7TDMI、ARM720T、ARM9TDMI、ARM940T、ARM920T、StrongARM。
ARMv5:
ARM9E-S、ARM966E-S、ARM1020E、ARM1022E、XScale → 基于 ARMv5TE。
ARM9EJ-S、ARM926EJ-S、ARM7EJ-S、ARM1026EJ-S → 基于 ARMv5EJ。
ARM10 也采用。
后缀含义:
E:增强型 DSP 指令集,算法和 16 位乘法操作。
J:支持 Java。
ARMv6:
ARM11 系列。
ARM1136J(F)-S:SIMD、Thumb、Jazelle、DBX、VFP、MMU。
ARM1156T2(F)-S:SIMD、Thumb-2、VFP、MPU。
ARM1176JZ(F)-S:增加 MMU、TrustZone。
ARM11 MPCore:支持 1~4 核 SMP、MMU。
ARMv7-A:Cortex A7 等。
二、常用指令
1. MOV 指令
- 加载立即数到寄存器或寄存器值传递。
mov r0, #2 ; 加载立即数 2 到寄存器 r0
mov r1, r0 ; 将 r0 的值加载到 r1
2. ADD / SUB 指令
ADD Rd, Rn, #const
ADD Rd, Rn, Rm, <shift>SUB Rd, Rn, #const
SUB Rd, Rn, Rm, <shift>
3. 移位操作
LSL:逻辑左移
LSR:逻辑右移
ASR:算术右移(保持符号位)
ROR:循环右移
RRX:带进位右移 1 位
移位可由立即数或寄存器指定,影响进位标志 C。
4. 立即数定义(imm12)
ARM 指令中的立即数并非任意 32 位数,而是 12 位立即数 (imm12),由以下规则决定:
条件 1:数值范围在 0~0xFF 之间时一定是立即数。
条件 2:把数写成二进制后,从最高位 1 到最低位 1 之间的位数 ≤ 8 位。
条件 3:补足 8 位后,右边必须是偶数个连续的 0。
实际上 ARM 将 imm12 编码为:
- 8 位常数 (0~255) + 4 位循环右移位数 (0~15)
- 旋转步长是 2,即可表示 0~30 偶数位的右移。
示例:
0x234 =
0000 0010 0011 0100
→ 符合条件,是立即数。0x3F4 =
0000 0011 1111 0100
→ 符合条件,是立即数。0x132 =
0000 0001 0011 0010
→ 末尾只有 1 个 0,不符合条件。0x7F8 =
0000 0111 1111 1000
→ 末尾 3 个 0,不满足条件。0xFAB4 =
1111 1010 1011 0100
→ 位宽超过 8 位,不是立即数。
5. LDR / STR 指令
- 加载和存储数据:
ldr r0, =0x2FAB4 ; 常量加载
ldr r0, [r1, #4] ; 偏移寻址
ldr r0, [r1], #8 ; 读后更新基址
ldr r0, [r1, #8]! ; 先更新基址再读str r0, [r1, #4] ; 存储数据
- 多寄存器操作:
ldmia r0!, {r1-r4} ; 从内存加载多个寄存器
stmfd sp!, {r0-r12, lr} ; 保存现场
6. BIC / ORR 指令
bic Rd, Rn, #const ; 清零
orr Rd, Rn, #const ; 置位
7. CMP 指令
- 比较两个数,更新标志位。
mov r0, #100
cmp r0, #100 ; Z=1 → 相等
8. 条件执行与条件码
指令可带条件码执行:
EQ:等于 (Z=1)
NE:不等于 (Z=0)
CS/HS:无符号大于等于 (C=1)
CC/LO:无符号小于 (C=0)
MI:负数 (N=1)
PL:正数 (N=0)
VS:溢出 (V=1)
VC:无溢出 (V=0)
HI:无符号大于 (C=1, Z=0)
LS:无符号小于等于 (C=0 或 Z=1)
GE:有符号大于等于 (N=V)
LT:有符号小于 (N≠V)
GT:有符号大于 (Z=0, N=V)
LE:有符号小于等于 (Z=1 或 N≠V)
AL:无条件执行
示例:
movcs r0, #100 ; 仅 C=1 时执行
9. B / BL / BX跳转指令
指令 | 功能描述 | PC 的变化 | LR 的变化 | 跳转目标 | 常见用途 |
---|---|---|---|---|---|
B | 无条件跳转(类似 goto ) | PC ← PC + 偏移量(立即数) | 不变 | 立即数偏移(label 地址) | 循环、分支、跳转到异常处理 |
BL | 跳转并保存返回地址(函数调用) | PC ← PC + 偏移量(立即数) | LR ← 调用点下一条指令的地址 | 立即数偏移(label 地址) | 子程序调用(函数调用) |
BX | 跳转到寄存器地址 | PC ← 指定寄存器的值 | 不变 | 任意寄存器(如 LR、R0) | 子程序返回(常见 bx lr ) |
三、栈操作
- ARM 采用 满减栈 (Full Descending)。
入栈
stmfd sp!, {r0, r1, r2, r3-r12, lr}
出栈
ldmfd sp!, {r0, r1, r2, r3-r12, lr}
栈的实现方式
空增:先写入数据,再自增
空减:先写入数据,再自减
满增:先自增,再写入数据
满减:先自减,再写入数据(ARM 采用)
类型 | 含义 | 压栈操作 | 出栈操作 | SP 指向 |
---|---|---|---|---|
满减栈 (Full Descending, FD) | 栈向低地址增长,SP 指向已用单元 | 先递减 SP → 写数据 | 读数据 → 递增 SP | 已用单元 |
满增栈 (Full Ascending, FA) | 栈向高地址增长,SP 指向已用单元 | 先递增 SP → 写数据 | 读数据 → 递减 SP | 已用单元 |
空减栈 (Empty Descending, ED) | 栈向低地址增长,SP 指向空单元 | 写数据 → 递减 SP | 递增 SP → 读数据 | 空单元 |
空增栈 (Empty Ascending, EA) | 栈向高地址增长,SP 指向空单元 | 写数据 → 递增 SP | 递减 SP → 读数据 | 空单元 |
四、函数与参数传递
汇编调用 C
import func_c
bl func_c
C 调用汇编
extern void func_asm(void);
func_asm();
参数传递规则
前 4 个参数 → r0 ~ r3
返回值 → r0
超过 4 个参数 → 栈传递
函数嵌套与现场保护
LR 会保存返回地址,但函数嵌套时 LR 会被覆盖。
解决方法:调用前使用栈保存 LR 和相关寄存器,返回时恢复。
五、模式切换与 CPSR
CPSR(Current Program Status Register)低 5 位决定工作模式:
- User、FIQ、IRQ、Supervisor、Abort、Undefined、System
指令
mrs r0, cpsr ; 读 CPSR
msr cpsr_c, r0 ; 写 CPSR
常见操作:
切换工作模式:修改低 5 位
开关中断:修改 I、F 位
六、ROM 类型分类
类型 | 是否可编程 | 是否可擦除 | 擦除方式 | 擦写次数 | 应用场景 |
---|---|---|---|---|---|
Mask ROM | 否 | 否 | 制造时固化 | 不可擦写 | 大批量固定程序 |
PROM | 一次 | 否 | 无 | 一次性 | 小批量定制程序 |
EPROM | 是 | 是 | 紫外线 | 少量(几十次) | 开发测试 |
EEPROM | 是 | 是 | 电擦除(字节级) | 10^5 ~ 10^6 | BIOS、配置数据 |
Flash ROM | 是 | 是 | 电擦除(块/扇区) | 10^4 ~ 10^5 | SSD、U盘、嵌入式系统 |
Flash ROM 分类总结表
类型 | 访问方式 | 读取速度 | 写入/擦除速度 | 容量范围 | 成本 | 常见应用 |
---|---|---|---|---|---|---|
NOR Flash | 随机访问(字节级/字寻址) | 快 | 慢 | MB ~ 数百 MB | 高 | 固件、Bootloader、系统代码存储 |
NAND Flash | 页/块访问 | 较慢 | 快 | GB 级 | 低 | U 盘、SSD、SD 卡、大容量数据存储 |
七、基本代码实现
ARM汇编语言
area reset, readonly, codepreserve8code32entry;ldr r0, =0x40000000;ldr r1, =0x3456781A;str r1, [r0, #4] ;*(r0 + 1) = r1 ;str r1, [r0], #4 ;*r0++ = r1;str r1, [r0, #4]! ;*++r0 = r1;ldr r0, =0x40000000;ldr r3, [r0];ldr r0, = 0x40000004;ldr r4, [r0];add r5, r3, r4;ldr r0, =0x40000008;str r5, [r0];mov r0, #0;orr r0, r0, #(1 << 7) ;0000 0000 0000 0000 0000 0000 1000 0000;ldr r0, =0x7FFFFFFF ;adds r0, r0, #1;mov r0, #3;mov r1, #5;mov r2, #4;cmp r0, r1;movls r3, r1;movge r3, r0;cmp r3, r2;movls r3, r2;b lable ;branch;mov r0, #3;mov r1, #5
;lable
; mov r0, #5
; mov r1, #3
; mov r2, #4
; cmp r0, r1
; bls less
; bgt great
;great
; mov r3, r0
; b lable
;less
; mov r3, r1 ;lable
; cmp r3, r2
; bgt finished
; mov r3, r2
; mov r0, #1 ;i
; mov r1, #0 ;sum;loop
; cmp r0, #100
; bgt finished
; add r1, r1, r0
; add r0, r0, #1
; b loopldr pc, =_start_asm_maxstmfd sp!, {r0-r12, lr}bl _asm_minldmfd sp!, {r0-r12, lr} cmp r0, r1movge r2, r0movlt r2, r1bx lrexport _asm_min
_asm_mincmp r0, r1movle r2, r0movgt r2, r1mov r0, r2bx lr _startldr sp, =0x40001000mrs r0, cpsr;xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx0 0000bic r0, r0, #0x1Forr r0, r0, #0x10 ;0001 0000msr cpsr_c, r0ldr sp, =0x40001000sub sp, sp, #1024import mainb main;stmfd sp!, {r0-r12, lr};import c_max;mov r0, #2;mov r1, #3;bl c_max;ldmfd sp!, {r0-r12, lr};mov r0, #11;mov r1, #22finishedb finished end