ARM 汇编学习
一、立即数
1. 立即数的三个判断条件(以 12 为例)
ARM 的立即数并非任意数,而是通过 8 位数 + 偶数位旋转组合得到。
判断规则:
如果数值范围在
0 ~ 0xFF
之间,一定是立即数;把数写成二进制,从 最高位 1 到最低位 1 的位数不能超过 8 位;
凑够 8 位之后,其右边必须是 偶数个连续 0。
例如:
#255
是立即数
#0x80000000
也是立即数
#0x12345678
不是立即数
二、跳转与函数调用
1. B 指令
功能:无条件跳转,相当于 C 的 goto
。
本质:把目标地址装入 PC。
B loop
; 等价于
LDR PC, =loop
补充:B 指令也可用于函数调用。
2. BL 指令
功能:跳转并保存返回地址(下一条指令)到 LR。
区别:与 B
的区别就是 BL
会在 LR 中保存返回地址。
作用:函数调用。
3. BX 指令
功能:跳转到寄存器地址。
常用:BX LR
实现函数返回。
补充:可实现 ARM ↔ Thumb 状态切换(取决于地址最低位)。
三、栈(Stack)
1. 引入
函数调用会修改 R0、R1 以及 LR;嵌套调用时,LR 会丢失,无法回到正确位置。必须使用栈来保护现场、恢复现场。
2. 栈的四种方式
ARM 的栈操作方式:
空增:先写入数据,再 SP++
空减:先写入数据,再 SP--
满增:先 SP++,再写入数据
满减:先 SP--,再写入数据
ARM 体系采用 满减栈。
3. 栈初始化示例(S3C2440)
内部 RAM 大小 4KB,地址范围 [0x40000000~0x40000FFF]
:
LDR SP, =0x40001000 ; 设置栈底
4. 栈操作指令
入栈保护现场
STMFD SP!, {R0, R1, R2, R3-R12, LR}
出栈恢复现场
LDMFD SP!, {R0, R1, R2, R3-R12, LR}
四、数据传送指令
1. LDR(加载寄存器)
指令
LDR R0, =0x2FAB4
多用于加载常数。
基本寻址
LDR R0, [R1, #4] ; R0 ← *(R1+4)
#imm12
可省略。后变址寻址
LDR R0, [R1], #8 ; R0 ← *(R1), R1 ← R1+8
前变址并写回
LDR R0, [R1, #8]! ; R0 ← *(R1+8), R1 ← R1+8
2. STR(存储寄存器)
基本功能:把寄存器内容存入内存。
1.基本寻址
STR R1, [R0, #4] ; *(R0+4) = R1
2. 后变址(post-indexed)
STR R1, [R0], #4 ; *R0 = R1, 然后 R0 ← R0+4
; 对应 C 写法:*R0 = R1; R0++
3. 前变址(pre-indexed)
STR R1, [R0, #4]! ; R0 ← R0+4, *(R0) = R1
; 对应 C 写法:*++R0 = R1
4. 举例
MOV R0, #0x40000000
MOV R1, #0x55STR R1, [R0], #4 ; 存到 0x40000000,R0=0x40000004
STR R1, [R0, #4]! ; R0=0x40000008,存到 0x40000008
五、逻辑运算指令
1. BIC(按位清零)
MOV R0, 0xFFFFFFFF
BIC R0, R0, #3 ; 清除低 2 位 → 0xFFFFFFFC
BIC R0, R0, #(0x1F << 8) ; 清除连续 5 位
2. ORR(按位置 1)
MOV R0, #0
ORR R0, R0, #5 ; 低位 0b0101 置 1
ORR R0, R0, #(1 << 9) ; 第 9 位设 1
六、标志位与条件执行
1. {S} 后缀(更新 CPSR 标志位)
N:结果为负 → N=1
Z:结果为 0 → Z=1
C:无符号加法进位 / 减法借位
V:有符号加减法溢出
示例:
MOV R0, #0xFFFFFFFF ; 按有符号为 -1
ADDS R2, R0, #0 ; N=1
ADDS R1, R0, #1 ; Z=1, C=1
MOV R0, #0x7FFFFFFF
ADDS R1, R0, #1 ; N=1, C=1, V=1
2. 条件执行 <c>
例如:
MOVCS R0, #100 ; 仅在 C=1 时执行
七、比较指令
1. CMP 指令
功能:比较两个寄存器或寄存器与立即数,本质是 Rn - Operand2
,只更新 N、Z、C、V。
CMP R0, R1
BLT less
2. 最大值练习
(1) 两数取大:
CMP R0, R1
MOVGE R2, R0
MOVLT R2, R1
(2) 三数取大:
CMP R0, R1
MOVGE R3, R0
MOVLT R3, R1CMP R3, R2
MOVLT R3, R2
八、循环与练习
1. B 指令实现循环
B loop ; 相当于 LDR PC, =loop
2. while 循环:0+1+…+100
MOV R0, #0 ; sum
MOV R1, #0 ; i
MOV R2, #100loop:
CMP R1, R2
BGT end
ADD R0, R0, R1
ADD R1, R1, #1
B loopend:
; R0 = 5050
3. do-while 循环:0+1+…+100
MOV R0, #0
MOV R1, #0
MOV R2, #100loop:
ADD R0, R0, R1
ADD R1, R1, #1
CMP R1, R2
BLE loop
九、汇编与 C 的互调
1. 汇编调用 C 函数
IMPORT
声明函数BL
调用函数调用者负责保护现场、恢复现场
参数传递:
R0–R3 → 前 4 个参数
超过 4 个 → 栈传递
返回值:R0
示例:
IMPORT c_add ; 声明 C 函数
BL c_add ; 调用
2. C 调用汇编函数
C 文件中
extern
声明汇编文件中
EXPORT
导出参数、返回值与上面一致
调用者负责保护现场
十、模式切换
1. CPS 指令
直接修改模式:
CPS #<mode>
(Keil 不支持)
2. 使用 MRS / MSR 指令
MRS R0, CPSR
BIC R0, R0, #(0x1F) ; 清除低 5 位
ORR R0, R0, #0x10 ; 设置 User 模式 (10000b)
MSR CPSR_c, R0
LDR SP, =0x40001000 ; 设置栈指针