目录
位测试指令:TST{cond} Rn, shifter_operand
1 移位指令(5种)
LSL logical shift left 逻辑左移 进行移位操作之后, 空出来的位添0
两种使用方法:
<Rn>, LSL #<shift imm>
<Rn>, LSL <Rs> 移位的个数由Rs寄存器的bit[7:0]决定
LSR logical shift right 逻辑右移 进行移位操作之后, 空出来的位添0
<Rn>, LSR #<shift imm>
<Rn>, LSR <Rs> 移位的个数由Rs寄存器的bit[7:0]决定
ASR Arithmetic Shift right 算数右移 进行移位操作之后, 最高位补符号位
ROR 循环右移 最低位变为了最高位
RRX 带扩展位的循环右移 新的最高位由cpsr的C位决定 最低位更新cpsr的C位
2 数据传输指令
MOV{cond}{S} <Rd>, <shifter_operand>
cond 表示条件执行 EQ NEQ CC CS ...
S 会影响cpsr的NZCV位
例:
mov r0, #10 @ r0 = 10
movs r0, #10 @ r0 = 10 N = 0 Z = 0
Rd 一定是通用寄存器
shifter_operand 有三种表现形式
即可以是立即数, 也可是通用寄存器, 或通用寄存器移位之后的值
mov r0, #10
注意立即数的合法性
存在一个8bit的立即数能够循环右移偶数位得到, 这个立即数就是合法的
mov r0, r2 @ r0 = r2
mov r0, r2, lsl #2 @ r2 <<= 2 , r0 = r2
moveqs r0, r1 @ if (CPSR.Z == 1)
movs r0, r1 @ r0 = r1, if (r0 == 0) 则 Z = 1 else Z = 0
@ N = r0[31]
MVN{cond}{S} <Rd>, <shifter_operand>
数据取反: 将数据的反码存放的目标寄存器中
MVNEQ R0, #0x80 @ if (cpsr.Z == 1)
r0 = 0x7f
3 算术运算指令
加法指令:ADD{cond}{S} <Rd>, <Rn>, <shifter_operand>
cond 可以条件执行
s 操作结果影响cpsr的nzcv位
N = Rd[31]
if (Rd == 0) Z == 1 else Z == 0
最高位有进位 C == 1 else C == 0
Rd 目标寄存器
Rn 一定是通用寄存器
operand 有三种表现形式
立即数 | add r0, r1, #1 @ r0 = r1 + 1 |
通用寄存器 | add r0, r1, r2 @ r0 = r1 +r2 |
通用寄存器移位之后的值 | add r0, r1, r2, lsl #3 @ r0 = r1 + r2 << 3 |
例:
ADDS R0, R1, R2 @ r0 = r1 + r2
N = R0[31]
if R0 == 0 , Z == 1, else Z == 0
C == Carryfrom(r1 +r2)
V == Overflowfrom (r1 + r2)
ADDS PC, R1, #0 @ pc = r1 + 0
带C标志位的加法指令:ADC{cond}{S} <Rd>, <Rn>, <shifter_operand>
默认会影响C位
例:
adc r0, r1, r2 @ r0 = r1 + r2 + C C就是CPSR寄存器的bit[29]
ADC R0, R1, #0x80 @ r0 = r1 + 0x80 + C
减法指令:SUB{cond}{S} <Rd>, <Rn>, <shifter_operand>
S 注意对C位的影响
Rn > operand C = 1, 反之 C = 0
例:
SUB R0, R1, #0x80 @ r0 = r1 - 0x80
SUBNE R0, R1, R3 @ if (cpsr.Z == 0) r0 = r1 - r3
SUBS R0, R1, R2
N = Rd[31]
Z = if Rd == 0 then 1 else 0
C = NOT BorrowFrom(Rn - shifter_operand)
V = OverflowFrom(Rn - shifter_operand)
SUBS PC, R14, #04 @ pc = r14 - 0x04
带C标志位的减法指令:SBC{cond}{S} <Rd>, <Rn>, <shifter_operand>
sbc r0, r1, r2 @ r0 = r1 - r2 - NOT(C) @ 出现负负得正的效果
subs r9, r5, r7 @ if (r5 > r7) C = 1
sbc r8, r4, r6 @ r8 = r4 - r6 - NOT(C)
逆向减法指令:RSB{cond}{S} <Rd>, <Rn>, <shifter_operand>
rsb r0, r1, r2 @ r0 = r2 - r1
rsb r0, r1, #8 @ r0 = 8 - r1
rsb r0, #8, r1 @ 注意语法错误
rsb r0, r0, #0 @ 取相反数
4 位运算指令
(按位与 &)AND{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
AND R0, R1, #0x80 @ r0 = r1 & 0x80
ANDNE R0, R1, R3 @ if (cpsr.z == 0) r0 = r1 & r3
ANDS R0, R1, R2
N = Rd[31]
Z = if Rd == 0 then 1 else 0
C= shifter_carry_out
ANDS PC, R1, #0xFFFFFFFF
(按位或 |)ORR{<cond>}{S} <Rd>, <Rn>, <shifter_operand>、
ORR R0, R1, #0x80 @ r0 = r1 | 0x80
ORRNE R0, R1, R3 @ if (cpsr.z == 0) r0 = r1 | r3
ORRS R0, R1, R2
N = Rd[31]
Z = if Rd == 0 then 1 else 0
C= shifter_carry_out
ORRS PC, R1, #0x0 @R1清零赋给PC
orrgts r0, r1, r2 @ if (Z == 0 && N == V) r0 = r1 | r2,
N = r0[31]
Z = if r0 == 0 then 1 else 0
C V 不影响
(按位异或 ^)EOR{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
EOR R0, R1, #0x80 @ r0 = r1 ^ 0x80
EOREQ R0, R1, R3 @ if (cpsr.z == 1) r0 = r1 ^ r3
EORS R0, R1, R2 @ r0 = r1 ^ r2
N = Rd[31]
Z = if Rd == 0 then 1 else 0
C= shifter_carry_out
EORS PC, R1, #0x0 @ pc = r1 ^ 0
如何取反32位整型变量的 BIT15?
mov r1, #1
eor r0, r0, r1, lsl #15
(位清除指令)BIC{cond}{S} <Rd>, <Rn>, <shifter_operand>
看第二个操作数, 如果perand对应的位中为1, 则结果为0
如果op2对应的位中为0, 则结果不变 (Rn)
或者换一种理解方式:将operand按位取反,然后与(Rn)做按位与操作,赋给(Rd)
BIC R0, R1, #0x80 @ 最高位置为0, 其他位不变 结果给r0
BICEQ R0, R1, R3 @ if (cpsr.z == 1) r0 = r1 bic r3
BICS R0, R1, R2 @ r0 = r1 bic r2
N = Rd[31]
Z = if Rd == 0 then 1 else 0
C= shifter_carry_out
BICS PC, R1, #0x0 @ pc = r1
如何清除一个32bit的寄存器中的第7位?
mov r1, #1
bic r0, r0, r1, lsl #7
5 比较测试指令
比较指令:CMP{cond} <Rn>, <shifter_operand>
Rn和operand做减法,操作结果不保存,不需要加S,默认影响NZCV位
CMP R0, #0x80
@ alu_out = r0 - 0x80
@ r0 > 0x80 C = 1
@ r0 == 0x80 Z = 1
@ r0 < 0x80 C = 0
CMPEQ R0, R3
N=ALU_out[31]
Z = if ALU_out == 0 then 1 else 0
C=NOT BorrowFrom(Rn - shifter_operand)
V=OverflowFrom(Rn - shifter_operand)
位测试指令:TST{cond} Rn, shifter_operand
按位与运算,只与操作数对应的位做与运算,操作结果不保存,默认影响NZCV位
TST R0, #0x80
@ 测试bit7是否为0
@ alu_out == 0 , Z = 1 else Z = 0
TSTEQ R0, R3
N=ALU_out[31]
Z = if ALU_out == 0 then 1 else 0
C = shifter_carry_out
相等测试指令:TEQ{cond} <Rn>, <shifter_operand>
判断Rn和operand是否相等,会对Z位产生影响
6 加载存储指令LDR 、STR
在ARM中所有的运算都是在通用寄存器中完成的
store load
存储 加载
操作对象: 内存(包含内存条和特殊功能寄存器)
通用寄存器
1、LDR
例:
mov r1, #0x48000000
ldr r0, [r1] @ 将内存0x48000000开始的4字节的数据加载到r0中
r0 = *((int *)0x48000000)
ldrb r0, [r1] @ 将内存0x48000000开始的1字节的数据加载到r0中 (byte)
@ *((unsigned char *)0x48000000) 取出来的8bit 存放到r0寄存器的低8个bit
高24bit补0
ldrsb r0, [r1] @ 将内存0x48000000开始的1字节的数据加载到r0中, r0的高24bit补符号位
ldrh r0, [r1] @ 将内存0x48000000开始的2字节的数据加载到r0中, r0的高16bit补0
ldrsh r0, [r1] @ 将内存0x48000000开始的2字节的数据加载到r0中, r0的高16bit补符号位
实例:
ldr r0, [r1, #0x08] @ [r1 + 0x08] ---> r0
ldr r0, [r1, r2] @ [r1 + r2] ---> r0
ldr r0, [r1, r2, lsl #2] @ [r1 + r2 << 2] ---> r0
------------------------------------------------------------------------
注意:加!表示更新基址
ldr r0, [r1, #0x08]! @ [r1 + 0x08] ---> r0 , r1 = r1 + 0x08
ldr r0, [r1, r2]! @ [r1 + r2] ----> r0 , r1 = r1 + r2
ldr r0, [r1, r2, lsl #3]! @ [r1 + r2 * 8] ---> r0 , r1 = r1 + r2 * 8
------------------------------------------------------------------------
ldr r0, [r1], #0x08 @ [r1] ---> r0 , r1 = r1 + 0x08
ldr r0, [r1], r2 @ [r1] ---> r0, r1 = r1 + r2
ldr r0, [r1], r2, lsl #0x2 @ [r1] ---> r0, r1 = r1 + r2 * 4
2、STR
例:
mov r1, #0x48000000
str r0, [r1] @将r0中的4字节数据写入到0x48000000指向的内存中
strb r0, [r1] @将r0中的1字节(低8bit)数据写入到0x48000000指向的内存中
strh r0, [r1] @将r0中的2字节(低16bit)数据写入到0x48000000指向的内存中
str r0, [r1] @ r0 ---> [r1]
str r0, [r1, #0x08] @ r0 ---> [r1+0x08]
str r0, [r1, r2] @ r0 ---> [r1+r2]
str r0, [r1, r2, lsl #2] @ r0 ---> [r1 + r2 * 4]
--------------------------
str r0, [r1, #0x08]! @ r0 ---> [r1 + 0x08] r1 = r1 + 0x08
str r0, [r1, r2]! @ r0 ---> [r1 + r2] r1 = r1 + r2
str r0, [r1, r2, lsl #3]! @ r0 ---> [r1 + r2 * 8] r1 = r1 + r2 * 8
--------------------------
str r0, [r1], #0x08 @ r0 ---> [r1] r1 = r1 + 0x08
str r0, [r1], r2 @ r0 ---> [r1] r1 = r1 + r2
str r0, [r1], r2, lsl #3 @ r0 ---> [r1] r1 = r1 + r2 * 8