目录
[二、ARM 汇编常用伪操作](#二、ARM 汇编常用伪操作)
[三、ARM 汇编源程序基本结构](#三、ARM 汇编源程序基本结构)
[四、ARM 指令集(六大类,核心重点)](#四、ARM 指令集(六大类,核心重点))
[五、ARM 指令格式与符号说明](#五、ARM 指令格式与符号说明)
[1. 指令格式(通用格式)](#1. 指令格式(通用格式))
[1. 数据处理指令细节](#1. 数据处理指令细节)
[2. 条件码(核心重点)](#2. 条件码(核心重点))
[七、ARM 函数调用原理(核心难点)](#七、ARM 函数调用原理(核心难点))
[1. ARM 堆栈类型(延续之前栈结构知识)](#1. ARM 堆栈类型(延续之前栈结构知识))
[2. 栈操作核心指令](#2. 栈操作核心指令)
[3. 栈的初始化与使用](#3. 栈的初始化与使用)
[4. 跨文件汇编与混合编程](#4. 跨文件汇编与混合编程)
[八、更改 ARM 工作模式](#八、更改 ARM 工作模式)
[九、中断原理(重点:SWI 软中断)](#九、中断原理(重点:SWI 软中断))
[1. 软中断触发](#1. 软中断触发)
[2. 软中断处理函数核心步骤](#2. 软中断处理函数核心步骤)
一、C语言基础知识
1.数据类型

2.变量类型


**注:**定义一个变量,如果是全局的变量则默认就是0;如果是局部变量若不初始化为0,则默认是随机值。
二、ARM 汇编常用伪操作
伪操作是汇编源程序中用于辅助汇编、定义数据 / 符号的指令,不直接生成机器码,仅指导汇编器工作,常用核心伪操作:
- 数据定义伪操作:
DCB(定义字节)、DCW(定义半字)、DCD(定义字),用于在内存中分配空间并初始化数据。 - 符号定义伪操作:
EQU(等价定义,类似宏定义)、AREA(定义代码段 / 数据段)、ENTRY(指定程序入口)、END(指定程序结束)。 - 其他常用伪操作:
ALIGN(字节对齐,混合编程必备)、EXTERN(声明外部符号,跨文件调用使用)、EXPORT(导出符号,供其他文件调用)。
三、ARM 汇编源程序基本结构
汇编源程序采用 "段式结构",核心分为代码段和数据段,结构清晰、规范:
- 数据段(DATA):用于存放常量、变量等数据,使用
AREA伪操作定义,可通过数据定义伪操作初始化数据。 - 代码段(CODE):用于存放汇编指令,是程序执行的核心,需指定
ENTRY入口,END结束,指令按执行顺序编写。 - 基本框架:先定义数据段,再定义代码段,明确入口地址,指令遵循 ARM 指令格式,配合伪操作完成程序编写。

四、ARM 指令集(六大类,核心重点)
ARM 指令集属于 RISC 精简指令集,指令简洁、执行效率高,按功能分为六大类,重点掌握指令功能与适用场景:
- 数据处理指令:核心指令,用于数据运算、逻辑操作,如
MOV(数据传送)、ADD(加法)、SUB(减法)、AND(与运算)、ORR(或运算)、CMP(比较)。 - 数据加载与存储指令:用于实现寄存器与内存之间的数据传输,如
LDR(从内存加载数据到寄存器)、STR(将寄存器数据存储到内存)。 - 分支指令:用于控制程序执行流程,如
B(无条件跳转)、BL(带返回的跳转,用于函数调用)、BX(跳转并切换指令集)。 - 堆栈操作指令:用于栈的压栈、出栈,如
STMFD(满栈递减压栈)、LDMFD(满栈递减出栈),是函数调用、现场保存的核心。 - 异常处理指令:用于触发异常、中断返回,如
SWI(软中断指令)、BX LR(中断 / 函数返回)。 - 协处理器指令:用于操作协处理器(如浮点协处理器),日常裸机开发中使用较少。
五、ARM 指令格式与符号说明
1. 指令格式(通用格式)
指令助记符 {条件码} 目标操作数, 源操作数1, 源操作数2
- 指令助记符:指令核心功能(如
ADD、MOV)。 - 条件码:可选,用于条件执行(如
EQ相等、NE不相等),满足条件时指令才执行。 - 操作数:多为寄存器(如
R0、R1),部分指令支持立即数(如#0x10)、内存地址。

六、数据处理指令与条件码
1. 数据处理指令细节
- 核心功能:对寄存器中的数据进行算术、逻辑运算,运算结果通常存入目标寄存器。
- 重点指令:
CMP R1, R2:比较 R1 和 R2,结果不存入寄存器,仅更新 CPSR 中的条件标志位(N、Z、C、V)。MOV R0, #0x01:将立即数 0x01 传送到 R0 寄存器。ADD R0, R1, R2:R0 = R1 + R2,运算后更新 CPSR 标志位。

2. 条件码(核心重点)
条件码基于 CPSR 中的标志位,实现指令的条件执行,常用条件码:
| 条件码 | 含义 | 标志位要求 | 常用场景 |
|---|---|---|---|
| EQ | 相等 | Z=1 | 比较后相等时执行 |
| NE | 不相等 | Z=0 | 比较后不相等时执行 |
| GT | 大于(无符号) | C=1 且 Z=0 | 无符号数比较大于时执行 |
| LT | 小于(无符号) | C=0 且 Z=0 | 无符号数比较小于时执行 |
- 示例:
ADD EQ R0, R1, R2,仅当 Z=1(上一次比较相等)时,执行 R0=R1+R2。

七、ARM 函数调用原理(核心难点)
函数调用的核心是利用栈保存现场、传递参数、返回地址,结合 ARM 栈结构与指令实现,重点掌握以下内容:
1. ARM 堆栈类型(延续之前栈结构知识)
- 核心组合:减栈 + 满栈(ARM 默认),即压栈时 SP 向低地址递减,SP 指向栈中最后一个有效数据。
- ARM 最常用的是 满递减堆栈(FD, Full Descending) :满 :SP 指向最后压入的数据 (即栈顶)。递减 :压栈时 SP 向低地址移动(先减后存),出栈时向高地址移动(先取后加)。
2. 栈操作核心指令
STMFD SP!, {R0-R3, LR}:满栈递减压栈,将 R0~R3(函数参数)、LR(返回地址)压入栈中,保存现场。LDMFD SP!, {R0-R3, PC}:满栈递减出栈,将栈中数据恢复到 R0~R3、PC,恢复现场并返回。
3. 栈的初始化与使用
- 初始化栈 SP 寄存器:程序启动时,需指定栈的起始地址,将栈地址赋值给 SP(如
LDR SP, =0x80000000),确保栈有足够空间。 - 函数调用原理:
- 调用方:将函数参数存入 R0~R3(ARM 约定),使用
BL 函数名跳转,BL 会自动将返回地址存入 LR。 - 被调用方:用
STMFD压栈保存现场,执行函数逻辑,执行完成后用LDMFD出栈恢复现场,通过BX LR或出栈 PC 返回调用方。
- 调用方:将函数参数存入 R0~R3(ARM 约定),使用
4. 跨文件汇编与混合编程
- 跨文件汇编:通过
EXPORT导出被调用函数 / 符号,EXTERN声明外部函数 / 符号,实现不同汇编文件之间的调用。 - C 语言与汇编混合编译:
- 汇编调用 C 函数:C 函数名需用
EXPORT导出,汇编中通过BL 函数名调用,参数存入 R0~R3。 - C 调用汇编函数:汇编函数用
EXPORT导出,C 中用extern声明,直接调用即可。 - 关键要求:混合编程时,需通过
ALIGN伪操作实现字节对齐(通常 4 字节对齐),避免内存访问异常。
- 汇编调用 C 函数:C 函数名需用
八、更改 ARM 工作模式
工作模式切换的核心是修改 CPSR 中的模式位(M [4:0]),结合指令实现,常用两种方式:
- 通过异常 / 中断触发:如 SWI 软中断、IRQ 外部中断,自动切换到对应特权模式(如 SVC、IRQ 模式)。
- 通过指令手动切换:在特权模式下,通过
MSR指令修改 CPSR 的模式位,切换到目标模式(如从 SVC 模式切换到 User 模式)。
- 注意:只有特权模式才能手动切换工作模式,User 模式(非特权)无法修改 CPSR 模式位。
九、中断原理(重点:SWI 软中断)
中断是 ARM 处理器响应内部 / 外部事件的核心机制,本次重点学习 SWI 软中断(软件触发的中断),完整流程如下:
1. 软中断触发
通过 SWI #中断号 指令触发软中断(如 SWI #0x01),触发后处理器自动执行以下操作:
- 硬件自动保存现场:将当前 CPSR 存入 SVC 模式的 SPSR,将下一条指令地址存入 SVC 模式的 LR。
- 自动切换到 SVC 模式(管理模式),禁止 IRQ 中断(I=1)。
- 跳转到异常向量表的 SWI 异常入口地址(0x08),执行异常处理函数。
2. 软中断处理函数核心步骤
- 计算 SWI 指令地址:通过 LR 减去偏移量(因流水线影响),得到当前 SWI 指令的实际地址。
- 读取 SWI 指令:从计算出的地址中读取 SWI 指令(32 位)。
- 提取 24 位软件中断号:SWI 指令的低 24 位为中断号,通过指令运算提取(如屏蔽高 8 位)。
- 根据中断号执行对应处理逻辑:不同中断号对应不同的处理函数,实现多软中断区分。
- 恢复现场并返回:通过
LDMFD出栈恢复 CPSR(从 SPSR)和 PC(从 LR 修正后),回到中断触发前的程序位置继续执行。
cs
deal_swi
stmfd sp!, {r4-r12, lr} ; 保存现场
sub r0, lr, #4 ; 计算 SWI 指令的地址
ldr r1, [r0] ; 读取 SWI 指令本身
bic r0, r1, #(0xff << 24) ; 提取低 24 位(SWI 号)
import c_deal_swi ; 声明外部 C 函数
bl c_deal_swi ; 调用 C 函数,参数在 r0 中
ldmfd sp!, {r4-r12, pc}^ ; 恢复现场,切回用户模式,返回
逐行解释
1. deal_swi
- 这是 软中断异常处理函数的标签
- 当 CPU 执行到
SWI #xxx时,硬件会自动跳转到这里执行
2. stmfd sp!, {r4-r12, lr}
功能:压栈保存现场
stmfd:满栈递减方式压栈(ARM 标准栈)sp!:栈指针自动更新{r4-r12, lr}:把这些寄存器全部压入栈- **为什么要保存?**因为进入软中断后,这些寄存器的值会被覆盖,不保存的话,回到用户程序时数据就乱了。
- lr 这里保存的是:中断的返回地址
3. sub r0, lr, #4
功能:计算出真正的 SWI 指令地址
为什么要减 4?
因为 ARM 是 3 级流水线:
- 取指
- 译码
- 执行
当执行到 SWI 指令时,PC 已经指向下下一条指令硬件自动把返回地址存在 LR 里 = SWI地址 + 4
所以要得到 SWI 指令本身的地址,必须:
SWI指令地址 = LR - 4
结果存在 r0。
4. ldr r1, [r0]
功能:读取 SWI 指令的 32 位机器码
r0= SWI 指令的地址[r0]= 取该地址的 32 位数据- 读到
r1中
这条指令读取到的是:
0xEFXXXXXX (SWI 指令的机器码)
高 8 位是操作码,低 24 位是我们写的 SWI #编号
5. bic r0, r1, #(0xff << 24)
功能:提取 SWI 指令的低 24 位中断号
bic:位清除指令0xff <<24= 高 8 位(11111111 00000000 ...)- 作用:把高 8 位抹成 0,只保留低 24 位
最终:
r0 = SWI中断号(0~2^24-1)
6. import c_deal_swi
告诉汇编器:c_deal_swi 是外部 C 语言函数,不是本文件的
7. bl c_deal_swi
跳转到 C 语言函数处理软中断
ARM 规则:
- r0 存放第一个参数
- 所以 C 函数会收到
r0= SWI 中断号
C 函数原型:
void c_deal_swi(unsigned int swi_num);
8. ldmfd sp!, {r4-r12, pc}^
最重要一句:恢复现场 + 返回用户模式
逐部分解释:
① ldmfd
满栈递减出栈
② sp!
恢复栈指针
③ {r4-r12, pc}
- 恢复 r4~r12
- 把栈中保存的 LR 赋值给 PC
- 写
PC就会实现 函数返回
④ 最后的 ^ 符号(关键!)
作用: 恢复 SPSR 到 CPSR 自动从 SVC 模式切回 USER 模式
没有这个 ^,中断返回后 模式不会切换,程序直接崩溃!
整段代码执行流程总结
- 进入软中断
- 压栈保存所有寄存器(防止破坏用户现场)
- 计算 SWI 指令地址(LR - 4)
- 读取 32 位 SWI 指令
- 提取低 24 位作为中断号
- 把中断号放入 r0,调用 C 函数处理
- 出栈恢复所有寄存器
- 用
^符号恢复 CPSR,切回用户模式 - 跳回用户程序继续执行
一句话总结
这段代码就是软中断的标准底层处理:保存现场 → 取中断号 → 交给 C 语言处理 → 恢复现场并返回用户模式。
学习小结
今日重点掌握了 ARM 汇编伪操作、指令集、函数调用原理及 SWI 软中断机制,明确了汇编源程序结构、数据处理指令与条件码的使用,深入理解了栈在函数调用中的作用、混合编程的注意事项,以及软中断的完整处理流程。这些内容是 ARM 裸机开发、中断驱动编写的核心,需结合指令练习,巩固栈操作、现场保存与恢复的细节,为后续实操开发打下基础。