无论是数据运算还是逻辑运算,需要满足如下格式:
<操作码> <目标寄存器> <第一操作寄存器> <第二操作数>
- 操作码: 表示执行哪种操作(加减乘)
- 目标寄存器: 用于存储运算的结果
- 第一操作寄存器: 存储第一个参与运算的数据(只能写寄存器)
- 第二操作数: 第二个参与运算的数据(可以是寄存器也可以是立即数)
目录
默认情况下,执行指令不会改变CPSR寄存器的状态位,若想改变CPSR寄存器的状态,需要在原指令的后面加上‘ S ’,比如ADD要想在进位时将进位状态保存到CPSR,需要使用指令ADDS。
一、数据运算指令
1、加法指令
(1) 加法指令 ADD (相加时不考虑进位)
ADD在做加法运算时,不考虑任何进位,包含了两方面。
- ADD 运算产生的进位,会忽略(CPSR寄存器的C状态位不会改变)
- 如果要记录产生的进位,需改为 ADDS 指令
- 上一次运算产生的进位,也会忽略
- 如果要考虑上一次的进位,需改为 ADC 指令
ADD R1, R2, R3 @ R1 = R2 + R3
ADD R1, R2, #5 @ R1 = R2 + 5
ADD R1, #7, #5 @ 非法
ADD R1, #7, R2 @ 非法
注意:正常情况下使用的指令都是ADD,寄存器一次可以处理32bit,如果是处理64bit 的数才会需要用到ADDS 和 ADC。
(2) 加法指令ADDS(保留进位状态)
默认情况下,ADD不会改变CPSR寄存器的状态位置,如果要改变CPSR,需要在原指令的后面加上‘ S ’,也就是指令ADDS。
使用格式和ADD完全一样:
ADDS R1, R2, R3 @ R1 = R2 + R3
(3) 带进位加法指令 ADC(相加时考虑进位)
ADC在做加法运算时,会考虑上一次运算产生的进位。
ADC R1, R2, R3 @ R1 = R2 + R3 + CPSR的C状态位
2、减法指令
(1) 减法指令 SUB
SUB和上面ADD类似,在做减法运算时,不考虑任何借位:
- SUB 运算产生的借位,会忽略(CPSR寄存器的C状态位不会改变)
- 如果要记录产生的借位,需改为 SUBS 指令
- 上一次运算产生的借位,也会忽略
- 如果要考虑上一次的借位,需改为 SBC 指令
SUB R1, R2, R3 @ R1 = R2 - R3
SUB R1, R2, #1 @ R1 = R2 - 1
(2) 减法指令SUBS(保留借位状态)
SUB产生的借位,默认不保存,即不会更新到CPSR寄存器;如果要更新到CPSR寄存器,需要使用指令SUBS。
SUBS R1, R2, R3 @ R1 = R2 - R3
(3) 带借位减法指令 SBC
SBC 在做减法运算时,会考虑上一次运算产生的借位
SBC R1, R2, R3 @ R1 = R2 - R3 - (!CPSR的C状态位)
(4) 逆向减法指令 RSB
减法指令ADD只能是一个寄存器减去一个立即数,逆向减法指令可以让一个立即数减去一个寄存器。但是依然不能违背最初的格式。
RSB R1, R2, #5 @R1 = 5 - R2
3、乘法指令 MUL
乘法指令比较特殊,只能是两个寄存器相乘
MUL R1, R2, R3 @R1 = R2 * R3
二、逻辑运算指令
1、按位与指令 AND
AND R1, R2, R3 @ R1 = R2 & R3
2、按位或指令 ORR
ORR R1, R2, R3 @ R1 = R2 | R3
3、按位异或指令 EOR
EOR R1, R2, R3 @ R1 = R2 ^ R3
4、左移指令 LSL
LSL R1, R2, 1 @ R1 = R2 << 1
5、右移指令 LSR
LSR R1, R2, 1 @ R1 = R2 >> 1
三、拓展指令
上述指令都是可以在C语言中找到对应的,汇编语言也存在自己独有的指令
1、位清零指令 BIC
位清零可以将 “指定比特位” 置 0
MOV R2, #0xFF @ R2 = 0xFF
BIC R1, R2, #0x0F @ 将R2后四位清零,结果放入 R1 =》 R1 = R2 & (~0x0F)
R2 中保存的是 0xFF,转化成二进制:1111 1111
0x0F 转换成二进制形式: 0000 1111
最终结果: 1111 0000
0x0F后四位是1,说明要把R2后四位置 0,得到的运算结果放入 R1(0xF0)
2、运算指令与其他指令的混合使用
MOV R1, R2, LSL #1
MOV 的格式是 MOV <目标寄存器> <第一操作数>
- 目标寄存器:R1
- 第一操作数:R2, LSL #1
- 这里已经可以猜出个大概了,其实就是LSL将R2寄存器左移1位,其结果作为第一操作数