ARM汇编知识点总结
学习目标:编写ARM启动代码,CPU复位后搭建C语言运行环境,最终跳转到C语言main函数执行。 启动代码五大任务
- 初始化异常向量表
- 初始化各个处理器模式的栈指针SP
- 配置内核中断
- 设置处理器工作模式(User模式)
- 跳转进入C语言main函数
一、伪操作(给汇编器看,不是CPU机器指令)
| 伪操作 | 功能 |
|---|---|
AREA reset,CODE,READONLY |
定义段;段名reset,代码段,只读;复位代码放在该段 |
CODE32 |
后续使用32位ARM指令集;THUMB代表16位Thumb指令集 |
ENTRY |
标记程序入口,复位从此处开始执行 |
END |
汇编源文件结束标记 |
IMPORT |
声明外部符号(外部C函数),相当于C的extern |
EXPORT |
导出汇编标号,供C语言调用 |
PRESERVE8 |
保证栈8字节对齐,解决汇编调用C的编译报错 |
二、核心汇编指令
1.数据传送指令
-
MOV :数据拷贝,寄存器‑寄存器、寄存器‑合法立即数;支持移位操作(LSL/LSR/ASR/ROR/RRX);
{S}后缀影响CPSR标志位。注意:
mov sp,#0x40001000报错,地址大多不是合法立即数,改用ldr sp,=0x40001000。 -
MVN:按位取反后传送。
2.算术运算
- ADD{S} :加法;
S后缀会更新NZCV标志。 - SUB{S} :减法。 格式:
ADD Rd,Rn,Rm{,移位},第二操作数支持:立即数、寄存器、寄存器移位。 ⚠错误写法:add r0,#3,#2,汇编指令只能一个立即数。
3.位操作指令
- BIC:位清零,掩码中为1的bit清零目标寄存器。
- ORR:位置1,掩码中为1的bit置1目标寄存器。
4.比较指令
CMP Rn,操作数 :等价于SUBS Rn,操作数,做减法,只更新CPSR的NZCV标志,不保存运算结果,配合条件码使用(EQ/NE/GT/LT/GE/LE/AL无条件)。
5.跳转指令 B / BL / BX
B label:无条件跳转;修改PC,不保存返回地址LR,不能返回。BL label:带链接跳转;跳转前把下一条指令地址存入LR(R14),用于函数调用;返回用BX LR。BX Rm:跳转到Rm保存的地址;同时根据Rm最低bit切换ARM/Thumb指令集。 对比:MOV PC,LR仅跳转,不能切换指令集 ;BX LR既返回又切换指令集。
6.加载存储
LDR Rt,<label>:伪指令,把地址/常量加载进寄存器;处理无法用mov加载的大数/地址。LDMFD / STMFD:满递减栈批量读写寄存器STMFD SP!,{reglist}:保护现场 ,寄存器压栈;!表示自动更新SP。LDMFD SP!,{reglist}:恢复现场,寄存器出栈。
7.访问CPSR程序状态寄存器(修改处理器模式)
MRS Rd,CPSR:读状态寄存器,CPSR→通用寄存器。MSR CPSR,Rn:写状态寄存器,通用寄存器→CPSR。 修改工作模式套路:MRS读CPSR → BIC清空M位 → ORR设置模式码 → MSR写回CPSR。
8.软中断
SWI #n:触发软中断异常。
三、12位立即数(imm12)
- 立即数:编码写在指令内部的常数,不需要访问内存。
- 编码组成:8位基础数imm8 +4位循环移位控制;实际是把8位数**循环右移偶数次(0,2...30)**得到32位数值。
- 判断:32位数字,是否可以由一个0‑255的8位数循环右移偶数位得到;能=合法立即数;否则非法。 非法立即数不能用mov,要用ldr伪指令加载。
四、CPSR标志位 NZCV
- N(负标志):运算结果bit31=1(视为有符号负数),N=1。
- Z(零标志):运算结果全0,Z=1。
- C(进位/借位,无符号数) -加法:最高位进位C=1; -减法:无借位C=1,发生借位C=0。
- V(溢出,有符号数):有符号运算溢出则V=1;两正相加结果负、两负相加结果正就是溢出。
五、栈相关
- ARM默认:满递减栈 FD(Full Descending) -满:SP指向最后压入的有效数据; -递减:栈向低地址增长;压栈先SP自减,再写数据;出栈先读数据,SP再加。
- 四种栈类型:满递减FD、满递增FA、空递减ED、空递增EA。
- 栈初始化:
ldr sp,=栈起始地址。 - 函数嵌套必须保护现场:把用到的通用寄存器+LR压栈;返回前出栈恢复。

六、汇编循环(翻译C循环)
-
do‑while:先执行循环体,再判断条件跳转。
-
while/for:先判断条件,满足才执行循环体。
;while(i<=100) sum+=i;i++
mov r0,#0 ;i
mov r1,#0 ;sum
loop
cmp r0,#100
bgt finish
add r1,r1,r0
add r0,r0,#1
b loop
finish
b finish
七、函数调用 & ATPCS规则(C与汇编互相调用)
1.汇编调用C函数
- 汇编中
IMPORT c_add声明外部C函数。 PRESERVE8保证栈8字节对齐。- 参数传递:前4个参数用 R0,R1,R2,R3 ;第5个及以后参数压栈传递。
- 返回值存放在 R0(64位返回值R0存低32位,R1存高32位)。
- 调用前保护现场
stmfd sp!,{r0‑r12,lr};bl c_add调用;调用完恢复现场。
2.C调用汇编函数
- 汇编使用
EXPORT func_name导出函数标号。 - C语言写
extern int func(int a,int b);声明。 - 汇编函数用
BX LR返回;返回值放R0。
寄存器约定:
- r0‑r3:传前4参数,返回值,调用方保存;
- r4‑r11:被调用函数必须保存,使用前压栈,返回前恢复;
- r13=SP栈指针;r14=LR链接寄存器(返回地址);r15=PC程序计数器。
问答题:
- 什么是立即数?如何判断某数是不是合法12位立即数? 立即数是直接编码在指令内部的常量,不用访问内存。12位立即数由一个8位无符号数循环右移偶数次得到;把数字写成32位二进制,若能找到0‑255的8位数,循环右移偶数次等于该数,则合法,否则非法。
- b,bl,bx指令的区别是什么?
- B:无条件跳转,修改PC,不保存返回地址LR,无法返回。
- BL:带链接跳转,跳转前将返回地址保存到LR,用于函数调用。
- BX:跳转到寄存器保存的地址,同时根据寄存器bit0切换ARM/Thumb指令集;常用
BX LR做函数返回。
- ARM内核采用的栈是哪种栈? ARM默认使用满递减栈FD。SP指向最后入栈有效元素;栈向低地址增长;压栈SP先减小,出栈SP后增大。
- CPSR中条件标志位,分别在什么情况下被置位
- N:运算结果最高位bit31为1,N置1;
- Z:运算结果等于0,Z置1;
- C:加法最高位进位 / 减法无借位时C置1;减法借位C清0;用于无符号数;
- V:有符号数运算溢出时V置1。
- ARM汇编调用C语言函数以及C语言调用汇编编写的函数,函数参数和返回值如何处理? 遵循ATPCS调用约定: ①参数:前4个参数依次放在R0、R1、R2、R3;超过4个的参数通过栈传递。 ②返回值:32位返回值存放在R0;64位返回值低32位R0,高32位R1。 ③汇编调用C:IMPORT声明C函数,PRESERVE8栈对齐,保护现场,BL调用; ④C调用汇编:汇编EXPORT导出函数,C用extern声明函数原型;汇编函数最后BX LR返回。