ARM汇编语言是嵌入式系统开发的基石,它直接与处理器硬件交互,提供了对计算资源的精确控制。与高级语言不同,汇编程序需要开发者手动管理寄存器分配、内存访问和程序流程,这种精细控制带来了极高的执行效率,特别适合以下场景:
ARM处理器支持两种指令集状态:
处理器通过BX/BLX等指令在两种状态间切换。例如:
armasm复制 ADR r0, thumb_code + 1 ; +1表示切换到Thumb状态
BX r0 ; 切换状态并跳转
thumb_code:
.thumb ; 声明后续为Thumb指令
MOV r1, #0x55 ; Thumb指令
典型的ARM开发环境包括:
安装RealView Development Suite (RVDS)或GNU Toolchain for ARM后,可通过命令行编译:
bash复制armasm --cpu=Cortex-M3 -o startup.o startup.s
armlink --map startup.o -o firmware.elf
数据处理指令完成算术逻辑运算,基本格式为:
OP{cond}{S} Rd, Rn, Operand2
典型指令示例:
armasm复制 MOV r0, #0x1000 ; 立即数加载
ADD r1, r1, r2, LSL #2 ; r1 = r1 + (r2<<2)
ANDS r3, r3, #0xFF ; 按位与并更新标志位
操作数技巧:
MOV r0, r1, ROR #4ARM采用Load/Store架构,只有LDR/STR指令可访问内存:
| 指令格式 | 说明 | 示例 |
|---|---|---|
| LDR Rd, [Rn] | 字加载 | LDR r0, [r1] |
| LDRB Rd, [Rn] | 字节加载 | LDRB r0, [r1] |
| LDRD Rd1,Rd2,[Rn] | 双字加载 | LDRD r0,r1,[r2] |
| STR Rd, [Rn] | 字存储 | STR r0, [r1] |
| STMIA Rn!, | 多寄存器存储(后递增) | STMIA r0!, |
地址模式详解:
armasm复制 LDR r0, [r1, #4]! ; 前变址:r1=r1+4后加载,!表示更新基址
STR r2, [r3], #-8 ; 后变址:存储后r3=r3-8
LDMIA sp!, {r0-r2, pc} ; 批量加载并恢复上下文
关键点:ARMv5及以上架构要求STRD/LDRD指令访问8字节对齐地址,否则会产生对齐异常。使用
ALIGN 8确保数据对齐。
条件执行机制:
ARM指令可带条件后缀(如EQ/NE/GT等),只有CPSR条件标志满足时才执行。结合CMP/TEST指令实现高效分支:
armasm复制 CMP r0, #10 ; 计算r0-10并设置标志位
MOVGT r1, #1 ; r0>10时执行
MOVLE r1, #0 ; r0<=10时执行
分支指令对比:
B label:相对跳转,±32MB范围BL label:带返回地址保存的子程序调用BX Rm:支持状态切换的跳转BLX Rm:带链接和状态切换的调用AREA指令定义代码/数据段属性:
armasm复制 AREA Reset, CODE, READONLY ; 定义只读代码段
ENTRY ; 程序入口点声明
start
LDR sp, =0x20004000 ; 初始化栈指针
BL main ; 跳转到C入口
END ; 汇编文件结束
ENTRY使用要点:
EQU定义常量:
armasm复制NVIC_Base EQU 0xE000E000 ; 定义外设基址
Priority_Offset EQU 0x400 ; 偏移量常量
EXPORT全局符号:
armasm复制 EXPORT SystemInit ; 导出函数供外部调用
SystemInit
... ; 初始化代码
EXPORTAS别名导出:
armasm复制 EXPORTAS User_ISR, IRQ_Handler ; 内部用User_ISR,外部显示为IRQ_Handler
GET指令包含文件:
armasm复制 GET cortex_m3.s ; 包含处理器定义文件
GET project/defs.inc ; 包含自定义宏
条件汇编示例:
armasm复制 IF :DEF:DEBUG_VERSION
MOV r0, #0xDEADBEEF ; 调试标记
ENDIF
典型启动代码流程:
armasm复制 AREA RESET, CODE, READONLY
EXPORT __Vectors
__Vectors
DCD 0x20001000 ; 主栈指针初始值
DCD Reset_Handler ; 复位向量
... ; 其他异常向量
Reset_Handler
LDR r0, =0xE000ED08 ; VTOR寄存器地址
LDR r1, =__Vectors
STR r1, [r0] ; 设置向量表偏移
... ; 其他初始化
AAPCS调用约定要点:
C调用汇编示例:
c复制// C声明
extern void ASM_Func(uint32_t param);
armasm复制 AREA AsmCode, CODE, READONLY
EXPORT ASM_Func
PRESERVE8 ; 保持8字节栈对齐
ASM_Func
PUSH {r4-r6, lr} ; 保存寄存器
... ; 函数体
POP {r4-r6, pc} ; 恢复寄存器并返回
指令调度原则:
循环展开示例:
armasm复制; 原始循环
MOV r0, #100
loop
SUBS r0, #1
BNE loop
; 展开4次迭代
MOV r0, #25 ; 100/4
unrolled_loop
SUBS r0, #1
[其他3条处理指令]
BNE unrolled_loop
对齐错误:
armasm复制AREA MyData, DATA
ALIGN 8 ; 确保8字节对齐
buffer DCD 0,0 ; 双字数据
寄存器冲突:
armasm复制; 错误示例:破坏链接寄存器
BL sub1
MOV lr, #0 ; 覆盖了返回地址
; 正确做法
BL sub1
MOV r5, #0 ; 使用非关键寄存器
使用KEEP保留局部符号:
armasm复制 AREA Debug, CODE, READONLY
func1
KEEP ; 保留func1符号
... ; 函数体
栈检查宏:
armasm复制 MACRO
CHECK_STACK $req_size
LDR r0, =__initial_sp
SUB r0, r0, $req_size
CMP r0, sp
BLLT Stack_Overflow_Handler
MEND
CHECK_STACK 256 ; 检查至少256字节栈空间
掌握ARM汇编需要理论与实践相结合。建议从简单的外设驱动开始,逐步深入到RTOS移植、DSP算法优化等高级应用场景。记住:优秀的汇编程序员不是写出最复杂的代码,而是用最恰当的指令实现最高效的控制。