ARM 常用汇编指令
1. 数据传输指令
使用处理器做的最多事情就是在处理器内部来回的传递数据,常见的操作有:
- 将数据从一个寄存器传递到另外一个寄存器。
- 将数据从一个寄存器传递到特殊寄存器,如 CPSR 和 SPSR 寄存器。
- 将立即数传递到寄存器。
数据传输常用的指令有三个:MOV、MRS 和 MSR
MOV 指令用于将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄存器里面
MOV R0 R1 @将 R1 里面的数据复制到 R0 中
MRS 指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器,要读取特殊寄存器的数据只能使用 MRS 指令
MRS R0, CPSR @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR
MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就是写特殊寄存器,写特殊寄存器只能使用 MSR
MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0
2. 存储器访问指令
ARM 不能直接访问存储器,比如 RAM 中的数据。常用的存储器访问指令有两种:LDR 和 STR。
LDR 主要用于从存储加载数据到寄存器 Rx 中,LDR 也可以将一个立即数加载到寄存器 Rx中,LDR 加载立即数的时候要使用“=”,而不是“#”。在嵌入式开发中,LDR 最常用的就是读取 CPU 的寄存器值:
@LDR Rd, [Rn , #offset] 从存储器 Rn+offset 的位置读取数据存放到 Rd 中
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
STR 是将数据写入到存储器中:
@STR Rd, [Rn, #offset] 将 Rd 中的数据写入到存储器中的 Rn+offset 位置。
LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中
3. 压栈和出栈指令
通常在A 函数中调用 B 函数,当 B 函数执行完以后再回到 A 函数继续执行。
此过程必须先保存A函数中当前的数据(现场保护),等B函数执行结束后再进行恢复A函数数据(恢复现场)。在进行现场保护的时候需要进行压栈(入栈)操作,恢复现场就要进行出栈操作。压栈的指令为 PUSH,出栈的指令为 POP,PUSH 和 POP 是一种多存储和多加载指令,即可以一次操作多个寄存器数据,他们利用当前的栈指针 SP 来生成地址。注意:处理器的堆栈是向下增长的
PUSH 另一种写法为 STMFD SP!
@PUSH <reg list> 将寄存器列表存入栈中。
PUSH {R0~R3, R12} @将 R0~R3 和 R12 压栈
PUSH {LR} @将 LR 进行压栈
STMFD SP!,{R0~R3, R12} @R0~R3,R12 入栈
POP 另一种写法为 LDMFD SP!
@POP <reg list> 从栈中恢复寄存器列表。
POP {LR} @先恢复 LR
POP {R0~R3,R12} @在恢复 R0~R3,R12
LDMFD SP!, {R0~R3, R12} @再恢复 R0~R3, R12
STMFD 可以分为两部分:
STM 和 FD,同理,LDMFD 也可以分为 LDM 和 FD。看到 STM和 LDM 有没有觉得似曾相识,前面讲了 LDR 和 STR,这两个是数据加载和存储指令,但是每次只能读写存储器中的一个数据。STM 和 LDM 就是多存储和多加载,可以连续的读写存储器中的多个连续数据。
FD 是 Full Descending 的缩写,即满递减的意思。
4. 跳转指令
有多种跳转操作,比如:使用跳转指令 B、BL、BX 等。直接向 PC 寄存器里面写入数据。
B 指令会将 PC 寄存器的值设置为跳转目标地址, 一旦执行 B 指
令,ARM 处理器就会立即跳转到指定的目标地址
@B <label>
@跳转到 label,如果跳转范围超过了+/-2KB,可以指定 B.W <label>使用 32 位版本的跳转指令
_start:
ldr sp,=0X80200000 @设置栈指针
b main @跳转到 main 函数
BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,这是子程序调用一个基本但常用的手段。
@BL <label> 跳转到标号地址,并将返回地址保存在 LR 中。
push {r0, r1} @保存 r0,r1
cps #0x13 @进入 SVC 模式,允许其他中断再次进去
bl system_irqhandler @加载 C 语言中断处理函数到 r2 寄存器中
cps #0x12 @进入 IRQ 模式
pop {r0, r1}
str r0, [r1, #0X10] @中断执行完成,写 EOIR
5. 算术运算指令
指令 | 计算公式 | 描述 |
---|---|---|
ADD Rd, Rn, Rm(或#immed) | Rd = Rn + Rm(或#immed) | 加法运算,指令为 ADD |
ADC Rd, Rn, Rm(或#immed) | Rd = Rn + Rm(或#immed) + 进位 | 带进位加法运算,指令为 ADC |
SUB Rd, Rn, Rm(或#immed) | Rd = Rn - Rm(或#immed) | 减法运算,指令为 SUB |
SBC Rd, Rn, Rm(或#immed) | Rd = Rn - Rm(或#immed) - 借位 | 带借位减法运算,指令为 SBC |
MUL Rd, Rn, Rm | Rd = Rn * Rm | 乘法运算32位,指令为 MUL |
UDIV Rd, Rn, Rm | Rd = Rn / Rm | 无符号除法运算,指令为 UDIV |
SDIV Rd, Rn, Rm | Rd = Rn / Rm | 有符号除法运算,指令为 SDIV |
Rn Rm Rd 为寄存器 #immed为立即数,其中最常会用的就是加减指令,乘除基本用不到
6. 逻辑运算指令
指令 | 计算公式 | 描述 |
---|---|---|
AND Rd, Rn | Rd = Rd & Rn | |
AND Rd, Rn,#immed | Rd = Rn & #immed | 按位与,指令为 AND |
AND Rd, Rn,Rm | Rd = Rn & Rm | |
ORR Rd, Rn | Rd = Rd | Rn | |
ORR Rd, Rn,#immed | Rd = Rn | #immed | 按位或,指令为 ORR |
ORR Rd, Rn,Rm | Rd = Rn | Rm | |
BIC Rd, Rn | Rd = Rd & (~Rn) | |
BIC Rd, Rn,#immed | Rd = Rn & (~#immed) | 位清除,指令为 BIC |
BIC Rd, Rn,Rm | Rd = Rn & (~Rm) | |
ORN Rd, Rn,#immed | Rd = Rn | (~#immed) | 按位或非,指令为 ORN |
ORN Rd, Rn,Rm | Rd = Rn | (~Rm) | |
EOR Rd, Rn | Rd = Rd ^ Rn | |
EOR Rd, Rn,#immed | Rd = Rn ^ #immed | 按位异或,指令为 EOR |
EOR Rd, Rn,Rm | Rd = Rn ^ Rm |
若需了解汇编语法 请点击汇编基本语法