一、开发环境与学习意义
开发环境:Keil4,参考 ARMv7 架构手册
学习核心 :ARM汇编不用于写业务代码,核心用途是编写启动代码。启动代码在C程序运行前执行,负责初始化硬件与运行环境,最终引导进入 main 函数。
二、ARM启动代码五大核心任务
处理器复位后,启动代码依次完成:
-
初始化异常向量表
-
初始化各模式栈指针(SP)
-
开启内核中断
-
切换系统为 User 用户模式
-
初始化硬件,跳转执行 C 语言 main 函数
三、汇编伪操作(编译器指令)
伪操作不被CPU执行,仅用于指导汇编器编译规则。
AREA reset, CODE, READONLY
CODE32
ENTRY
END
-
AREA:定义代码段/数据段,reset 为复位启动段
-
CODE:当前段为可执行代码段
-
READONLY:代码段只读
-
CODE32:使用32位 ARM 指令集
-
THUMB:使用16位 Thumb 指令集
-
ENTRY:标记程序入口
-
END:汇编文件结束
四、ARM核心常用指令
4.1 MOV 传送指令
用于寄存器赋值、立即数加载,支持移位操作,是最基础的数据搬运指令。
MOV{S}<c> <Rd>, #<const>
MOV{S}<c> <Rd>, <Rm>
常用移位:LSL左移、LSR右移、ASR算术右移、ROR循环右移、RRX扩展右移
MOV r0, #0x8
MOV r1, r0
MOV r6, r0, LSL #31
4.2 ADD / SUB 加减指令
完成加减运算,带 S 可更新 CPSR 标志位,支持移位运算。
ADD Rd, Rn, #const
ADD Rd, Rn, Rm, LSL #n
SUB Rd, Rn, #const
SUB Rd, Rn, Rm
注意:ARM 不支持两个立即数直接运算,常量计算由编译器预处理完成。
4.3 12位合法立即数(必考)
ARM 数据指令仅支持 12 位立即数,并非任意32位数都能直接 MOV。
判定规则 :数值可由8位基数 + 循环右移偶数位(0~30) 得到,即为合法立即数。
使用原则:合法立即数用 MOV,非法立即数必须用 LDR 伪指令加载。
示例:0x80000000(合法)、0x40001000(非法)
4.4 LDR / STR 读写内存指令
MOV 只能操作寄存器,LDR/STR 是唯一内存读写指令。
-
LDR:内存 → 寄存器,可加载超大/非法立即数
-
STR:寄存器 → 内存,保存数据
LDR sp, =0x40001000 ; 初始化栈指针(非法立即数,必须LDR)
4.5 位操作指令(MVN / BIC / ORR)
-
MVN:按位取反后赋值
-
BIC:位清零,指定位置0
-
ORR:位置1,用于寄存器位配置
4.6 CMP 比较指令与 NZCV 标志位
CMP Rn, Rm:等价 SUBS,只更新标志位,不保存结果
CPSR 四大标志位:
-
N:结果为负(最高位为1)置1
-
Z:结果为0置1
-
C:加法进位/减法无借位置1
-
V:有符号数运算溢出置1
常用条件码:EQ相等、NE不等、GT大于、LT小于、GE大于等于、LE小于等于
4.7 跳转指令 B / BL / BX
-
B:纯跳转,不保存返回地址,用于循环、分支
-
BL:带链接跳转,保存下一条指令地址到 LR,用于函数调用
-
BX:寄存器跳转,可切换 ARM/Thumb 状态,用于函数返回(BX LR)
五、汇编循环结构
汇编循环依靠 CMP + 条件跳转 实现
do-while 循环示例:
MOV r0, #0 ; i
MOV r1, #0 ; sum
loop
ADD r1, r1, r0
ADD r0, r0, #1
CMP r0, #100
BLE loop ; 小于等于则继续循环
六、函数调用与栈保护
6.1 PC 与 LR 寄存器
-
PC(R15):程序计数器,指向当前执行指令
-
LR(R14):链接寄存器,保存函数返回地址
函数调用:BL 保存返回地址到 LR;函数返回:BX LR
6.2 栈与现场保护
ARM 默认使用 满减栈(FD)。函数嵌套会覆盖寄存器与 LR,必须压栈保护现场、弹栈恢复现场。
-
STMFD:压栈,保护寄存器与LR
-
LDMFD:出栈,恢复寄存器与PC
STMFD sp!, {r0-r12, lr} ; 保护现场
BL func1 ; 调用子函数
LDMFD sp!, {r0-r12, pc} ; 恢复现场并返回
七、汇编与C语言混合编程
7.1 汇编调用C函数
-
汇编中 IMPORT 导入C函数
-
前4个参数放入 R0~R3,多余参数压栈
-
调用前 STMFD 保护现场,调用后恢复
-
添加 PRESERVE8 保证8字节栈对齐,避免编译报错
7.2 C语言调用汇编函数
-
汇编中 EXPORT 导出函数
-
C语言中 extern 声明函数
-
参数 R0~R3 传递,返回值存放在 R0
八、内核工作模式切换与异常
通过 MRS/MSR 读写 CPSR 寄存器,修改M域可切换内核工作模式。
MRS :读状态寄存器;MSR:写状态寄存器
SWI:软中断指令,用于触发软件中断异常
九、高频面试/作业简答题(汇总)
1、什么是12位立即数?如何判断非法立即数?
ARM数据指令的立即数由8位基数+4位循环移位组成。能通过8位数循环右移偶数位得到为合法立即数,反之是非法立即数,需用LDR加载。
2、B、BL、BX区别?
B普通跳转;BL跳转并保存返回地址到LR,用于函数调用;BX带指令集切换,用于函数返回。
3、ARM默认栈类型?
满递减栈(FD),先减指针、后存数据,搭配 STMFD/LDMFD 使用。
4、NZCV标志位置位条件?
N负、Z零、C进位/无借位、V有符号溢出。
5、汇编与C互调用参数规则?
前4参R0-R3,多参压栈,返回值R0;汇编调C需栈对齐,C调汇编需EXPORT/extern声明。
十、总结
本篇笔记精简覆盖 ARM 汇编核心:启动代码工作流程、伪操作、全部常用指令、立即数规则、栈帧保护、循环与函数调用、C与汇编混合编程、模式切换与异常,是嵌入式底层、启动代码开发、面试复习的核心干货。