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汇编语言

cs 复制代码
	area reset, readonly, code
	preserve8
	code32
	entry
	
	;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 loop

	ldr pc, =_start

_asm_max
	stmfd sp!, {r0-r12, lr}
	bl _asm_min
	ldmfd sp!, {r0-r12, lr} 
	cmp r0, r1
	movge r2, r0
	movlt r2, r1
	bx lr

	export _asm_min
_asm_min
	cmp r0, r1
	movle r2, r0
	movgt r2, r1
	mov r0, r2
	bx lr		

_start
	ldr sp, =0x40001000

	mrs r0, cpsr
   	;xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxx0 0000
	bic r0, r0, #0x1F
	orr r0, r0, #0x10 ;0001 0000
	msr	cpsr_c, r0

	ldr sp, =0x40001000
	sub sp, sp, #1024

	import main
	b 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, #22


finished
	b finished	
	end
相关推荐
Aczone287 小时前
硬件(六)arm指令
开发语言·汇编·arm开发·嵌入式硬件·算法
DebugKitty17 小时前
硬件开发2-ARM基本概要
arm开发·mmu·soc·指令集·计算机系统·alu
Aczone2817 小时前
硬件(五) 存储、ARM 架构与指令系统
arm开发·嵌入式硬件·架构
Skylar_.18 小时前
嵌入式 - ARM(2)汇编
汇编·arm开发
m0_5713728218 小时前
嵌入式ARM架构学习2——汇编
arm开发·学习
Skylar_.19 小时前
嵌入式 - ARM(1):ARM体系结构
arm开发
cui__OaO21 小时前
ARM -- 汇编语言
arm开发
sucool_lb1 天前
GEM5学习(5): ARM 架构功耗仿真
arm开发·学习
Joshua-a3 天前
macOS下arm编译缺少stdint.h等问题
arm开发·macos