ARM汇编指令集详解简介ARMAdvanced RISC Machines处理器凭借其低功耗、高性能的特点广泛应用于嵌入式系统、移动设备、物联网等领域。无论是做底层驱动开发、操作系统移植还是嵌入式系统调试掌握 ARM 汇编语言都是必不可少的基本功。本文将系统讲解 ARM 处理器架构、寄存器组织、寻址方式、数据处理指令、分支指令、加载存储指令、批量数据传送、状态寄存器操作、协处理器指令、异常处理等核心内容配合详细的指令格式说明和代码示例帮助你全面掌握 ARM 汇编编程。一、ARM 处理器架构概述1.1 处理器架构分类常见的处理器架构包括51/52、ARM、x86、PPCPower PC、MIPS 等。ARM 采用的是RISC精简指令集架构。RISC 与 CISC 的区别特性RISC精简指令集CISC复杂指令集指令长度所有指令长度一致指令长度不一致指令数量少只保留常用指令多包含复杂指令执行周期大多数指令一个周期指令执行周期不等代表ARM、MIPS、RISC-Vx861.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-R15ARM 处理器共有 16 个通用寄存器32位寄存器名称用途R0-R3通用寄存器函数调用时默认用来传参R4-R11通用寄存器保存变量函数调用时需要保护R12IPIntra-Procedure临时暂存寄存器R13SPStack Pointer栈指针指向栈顶R14LRLink Register链接寄存器保存函数返回地址R15PCProgram Counter程序计数器指向正在取址的指令重要说明R0-R3 默认用来传参调用函数时参数通过这些寄存器传递SP 在代码开始时必须初始化例如LDR SP, 0x4000000LR 用于保存子程序的返回地址在调用子程序时需将 LR 压栈PC 的值是当前取址地址正在执行的指令地址 PC - 82.2 程序状态寄存器CPSR/SPSRARM 有一个CPSR当前程序状态寄存器和最多 5 个SPSR备份程序状态寄存器每种异常模式一个。CPSR 的 32 位分为 4 个 8 位的域[31:24] 条件标志位域用 f 表示 [23:16] 状态位域用 s 表示 [15:8] 扩展位域用 x 表示 [7:0] 控制位域用 c 表示条件标志位位名称说明N负数标志运算结果为负数或小于时置 1Z零标志运算结果为零时置 1C进位/借位标志运算产生进位或借位时置 1V溢出标志运算结果发生溢出时置 1控制位位名称说明IIRQ 中断禁止1禁止, 0允许FFIQ 中断禁止1禁止, 0允许TThumb 状态标志1Thumb 状态M[4:0]模式标志指定当前处理器模式[图片占位符]三、寻址方式ARM 汇编指令的一般格式指令 {条件码}{S} Rd, Rn, shift_operand中的内容必须写{}中的内容可选操作数个数只能少不能多Rd 和 Rn 不能省略Rd目的操作数destinationRn第一个源操作数通用寄存器shift_operand第二个操作数可以是立即数、寄存器或移位码ARM 的第二操作数可以是ARM 通用寄存器、立即数、或移位码。关于立即数ARM 中的立即数是由一个 8 位的数左移或右移偶数位得到的所以不是所有的数都是立即数。如果不确定某个数是否为立即数可以使用伪指令LDR R0, 0xFFF ; 0xFFF 不是立即数但使用伪指令可以加载任意值四、数据处理指令4.1 MOV – 数据传送MOV {cond}{S} Rd, shift_operand将第二操作数可以是立即数或寄存器传送到目的寄存器。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将第二操作数取反后传送到目的寄存器。MVN R0, #0 ; R0 0xFFFFFFFF取反 MVN R0, #0x0F ; R0 0xFFFFFFF04.3 ADD / SUB – 加法 / 减法ADD {cond}{S} Rd, Rn, shift_operand SUB {cond}{S} Rd, Rn, shift_operandADD 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 - 104.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 位运算。; 64 位加法R1:R0 R3:R2 - R1:R0 ADDS R0, R0, R2 ; 低32位加法影响进位标志 ADC R1, R1, R3 ; 高32位加法 进位RSC 是反向相减可以实现常数减寄存器的值Rd shift_operand - Rn4.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 ; 位清除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 指令详解将第二个操作数取反后与第一个操作数相与实现指定位清零。BIC R0, R0, #0x1011 ; 将 0x1011 取反得 0xFFFFEFFE再与 R0 相与 ; 效果清除 R0 的 bit0, bit1, bit8, bit12EOR 的常见用途两个相同的数异或可以清零变量与 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, RdHiUMLAL无符号长整型乘法累加SMULL有符号长整型乘法SMLAL有符号长整型乘法累加; 格式UMULL RdLo, RdHi, Rm, Rs ; 64位结果RdHi:RdLo Rm * Rs UMULL R0, R1, R2, R3 ; R1:R0 R2 * R364位无符号乘法4.7 比较指令不保存结果只影响标志位CMP – 比较CMP {cond} Rd, shift_operand执行减法但不存储结果只更新 CPSR 的条件标志位。CMP R0, #10 ; 比较 R0 和 10实质是 R0 - 10 CMP R0, R1 ; 比较 R0 和 R1CMN – 取负比较CMN {cond} Rd, shift_operand与 CMP 类似但将操作数取负后比较用于与小负值进行比较。TST – 测试按位与TST {cond} Rd, shift_operand两个操作数相与不保存结果只更新标志位。常用于测试某个位是否被置位。; 测试 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 的标志位决定是否执行条件码后缀含义标志位状态0000EQ等于Z10001NE不等于Z00010CS/HS进位设置/无符号高于等于C10011CC/LO进位清除/无符号低于C00100MI负数N10101PL正数或零N00110VS溢出设置V10111VC溢出清除V01000HI无符号高于C1 且 Z01001LS无符号低于或等于C0 或 Z11010GE有符号大于等于NV1011LT有符号小于N!V1100GT有符号大于Z0 且 NV1101LE有符号小于等于Z1 或 N!V1110AL总是执行无条件默认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 的范围。B label ; 无条件跳转 BEQ equal_label ; 相等时跳转 BNE not_equal ; 不相等时跳转5.2 BL – 带链接的跳转BL {cond} 地址在跳转之前将当前 PC 的值下一条指令地址保存到R14LR中。可以通过将 R14 装载回 R15 来返回。BL subroutine ; 调用子程序LR 返回地址 ; ... subroutine: ; 子程序代码 MOV PC, LR ; 返回调用处BL 是实现子程序调用的基本但强大的机制。5.3 BX – 跳转并切换状态BX {cond} Rm跳转到 Rm 指定的地址并将 Rm 的 bit[0] 复制到 CPSR 的 T 标志位实现 ARM/Thumb 状态切换。Rm 的 [31:1] 位送入 PC。BX R0 ; 跳转到 R0 指定的地址根据 bit[0] 切换状态5.4 BLX – 带状态切换的链接跳转结合了 BL 和 BX 的功能保存返回地址的同时切换处理器状态。5.5 长跳转实现B/BL 只能跳转 -32MB ~ 32MB 范围要实现长跳转需要直接修改 PC 值MOV PC, #0x12345678 ; 直接设置 PC 值实现长跳转六、加载/存储指令Load/StoreLoad/Store 指令实现 ARM 寄存器和存储器之间的数据传输主要有三类6.1 单寄存器 Load/Store传输单项数据可以是字节、半字或字类型。LDR – 加载数据LDR {cond} Rd, 地址LDR R1, [R0] ; 将 R0 指向的内存数据加载到 R1 LDR R1, [R0, #4] ; 将 R04 地址的数据加载到 R1 LDR R1, [R0, R2] ; 将 R0R2 地址的数据加载到 R1 LDR R1, [R0, R2, LSL #2] ; 将 R0 R2*4 地址的数据加载到 R1 LDR R0, 0xFFF ; 伪指令加载任意常量STR – 存储数据STR {cond} Rd, 地址STR R1, [R0] ; 将 R1 的内容存储到 R0 指向的内存地址 STR R1, [R0, #4] ; 将 R1 存储到 R04 地址变体指令指令说明LDRB加载一个字节8位LDRH加载一个半字16位LDRBT在用户模式下加载一个字节STRB存储一个字节STRH存储一个半字寻址方式详解; 偏移寻址 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 46.2 多寄存器 Load/Store批量数据传送可以一次传送内存区域上的一块数据非常适合用于现场保护和恢复。LDM {cond}模式 Rn{!}, 寄存器列表{^} STM {cond}模式 Rn{!}, 寄存器列表{^}8 种模式前 4 种用于数据块传输后 4 种用于堆栈操作模式说明用途IA每次传送后地址加 4数据块传输IB每次传送前地址加 4数据块传输DA每次传送后地址减 4数据块传输DB每次传送前地址减 4数据块传输FD满递减堆栈堆栈操作FA满递增堆栈堆栈操作ED空递减堆栈堆栈操作EA空递增堆栈堆栈操作; 加载数据块 LDMIA R1!, {R2-R9} ; 加载 R1 指向地址上的多字数据到 R2~R9R1 值更新 ; 堆栈操作保护/恢复现场 STMFD SP!, {R3-R7, LR} ; 保护现场压栈 LDMFD SP!, {R3-R7, LR} ; 恢复现场出栈 ; 等价于STMFD SP!, {R3-R7, LR} / LDMFD SP!, {R3-R7, PC}压栈和出栈的本质压栈是将寄存器的数据存储到内存出栈是将内存的数据加载到寄存器。6.3 单寄存器交换指令SWPSWP {cond} Rd, Rm, [Rn]执行过程将内存地址 [Rn] 中的数据加载到 Rd将 Rm 中的数据存储到内存地址 [Rn]如果 Rd 和 Rm 为同一个寄存器则实现了寄存器和内存的数据交换。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 的值读入 Rd7.2 MSR – 从通用寄存器到状态寄存器MSR CPSR, Rd ; 将 Rd 的值写入 CPSR MSR SPSR, Rd ; 将 Rd 的值写入 SPSRCPSR 的 32 位分为 4 个域可以单独修改某个域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 使能/禁止中断; 禁止 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 寄存器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 ; 断点中断指令产生软件断点SWI 0x123456 ; 产生软中断中断号为 0x123456 BKPT 0x1234 ; 产生断点中断9.2 ARM 异常处理流程ARM 在遇到异常时会自动执行以下操作将下一条指令的地址保存到相应模式的 LR 中将 CPSR 的值保存到相应模式的 SPSR 中修改 CPSR 的模式位切换到对应的异常模式将 PC 设置为特定的异常向量地址异常向量表异常类型向量地址入口模式复位0x00000000SVC未定义指令0x00000004Undefined软中断SWI0x00000008SVC指令预取中止0x0000000CAbort数据访问中止0x00000010Abort保留0x00000014-IRQ普通中断0x00000018IRQFIQ快速中断0x0000001CFIQ9.3 异常返回异常处理完成后需要恢复现场并返回; 保护现场 STMFD SP!, {R0-R7, LR} ; 异常处理代码 ; ... ; 恢复现场并返回 LDMFD SP!, {R0-R7, PC}^ ; ^ 表示同时恢复 CPSRMOVS PC, LR也可以实现返回将 LR 的值赋给 PC并将 SPSR 的值恢复到 CPSR切换回原来的模式。9.4 函数编写规范在 ARM 中正确封装一个函数必须进行现场保护和恢复my_function: STMFD SP!, {R3-R7, LR} ; 保护现场保存用到的寄存器和返回地址 ; 函数体 ; ... LDMFD SP!, {R3-R7, PC} ; 恢复现场并返回十、ARM 汇编编程要点10.1 启动代码在 ARM 编程中一定要用汇编代码做初始化启动代码包括初始化向量表初始化栈指针SP初始化内存控制器跳转到 C 语言主函数; 典型的启动代码框架 LDR SP, 0x4000000 ; 初始化栈指针 ; 跳转到 main 函数 BL main ; 死循环 halt: B halt10.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 指令由汇编器处理LDR R0, 0xFFFF0000 ; 加载任意32位常量不是立即数也能用 LDR SP, 0x4000000 ; 加载地址常量10.4 PWM 注意事项PWM 的手动装载优先级高于自动装载。要使用自动装载时必须先关闭手动装载。十一、完整汇编程序示例以下是一个完整的 ARM 汇编程序示例演示了基本的程序结构; ; 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, #10MVN取反传送MVN R0, #0ADD加法ADD R0, R1, R2SUB减法SUB R0, R1, R2RSB反向减法RSB R0, R1, #0ADC带进位加法ADC R0, R1, R2SBC带借位减法SBC R0, R1, R2AND逻辑与AND R0, R0, #0xFFORR逻辑或ORR R0, R0, #0x0FEOR逻辑异或EOR R0, R0, R0BIC位清除BIC R0, R0, #0x0FMUL乘法MUL R0, R1, R2MLA乘加MLA R0, R1, R2, R3CMP比较CMP R0, #10CMN取负比较CMN R0, #1TST位测试TST R0, #0x01TEQ相等测试TEQ R0, R1分支指令指令功能示例B跳转B labelBL带链接跳转BL subroutineBX跳转并切换状态BX R0BLX带链接切换跳转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 汇编指令集的各个方面架构基础了解了 ARM 处理器的 RISC 架构特点、工作模式、流水线机制。理解 PC 与实际执行地址的关系PC - 8以及流水线对程序优化的影响。寄存器组织掌握了 R0-R15 的用途分工、CPSR/SPSR 的标志位和控制位含义。理解了函数调用时 R0-R3 传参、LR 保存返回地址、SP 栈指针管理的关键作用。数据处理指令学习了 MOV/MVN、ADD/SUB/ADC/SBC/RSC、AND/ORR/EOR/BIC、MUL/MLA 等运算指令以及 CMP/CMN/TST/TEQ 等测试指令。分支与控制掌握了 B/BL/BX/BLX 四种跳转指令理解了条件码的使用和长跳转的实现方法。存储器访问学习了 LDR/STR 单寄存器操作、LDM/STM 批量传送的 8 种模式、SWP 交换指令理解了压栈/出栈保护现场的原理。状态寄存器操作掌握了 MRS/MSR 指令的使用以及 CPSR 各域的独立操作方法。异常处理理解了 ARM 的异常向量表、异常处理流程、现场保护与恢复机制。ARM 汇编是嵌入式开发的底层基石熟练掌握后将为 Bootloader 开发、驱动编程、操作系统移植、性能优化等高级主题奠定坚实基础。原始笔记来源frasight/ARM笔记.asm