1.数据传送指令
【MOV指令】:它的传送指令只能是把一个寄存器的值(要能用立即数表示)赋给另一个寄存器,或者将一个常量赋给寄存器,将后边的量赋给前边的量
MOV指令的格式为:MOV{条件}{S} 目的寄存器,源操作数
MOV r1,r0 ; 将寄存器r0的值传送到寄存器r1---->(r0 = r1)
MOV pc,r14 ; 将寄存器r14的值传送到pc,常用于子程序返回---->(PC = r14)
MOV r1, r0, LSL#3 ; 将寄存器r0的值左移3位后传送到---->r1(r1 = r0 << 3)
MOVS pc, r14 ; 将寄存器r14的值传送到pc中,返回到调用代码并恢复标志位
【MVN指令】:MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值
MVN指令的格式为:MVN{条件}{S} 目的寄存器,源操作数
; 将操作数的反码 传送到 目标寄存器
MOV r1, #0xf0 ; r1 = ~(0xf0) ==> r1 = 0xffffff0f
2.算术运算指令
【ADD指令】:ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中
ADD指令的格式为:ADD{条件}{S} 目的寄存器,操作数1,操作数2
ADD r0, r1, r2 ; r0 = r1 + r2
ADD r0, r1, #3 ; r0 = r1 + 3
ADD r0, r1, r2, lsl #3 ; r0 = r1 + r2 << 3;
ADDEQS r0, r1, r2 ;如果上一条指令结果为0,那么就进行相加运算的同时还会去更新cpsr中flag位
【SUB指令】:SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中
SUB指令的格式为:SUB{条件}{S} 目的寄存器,操作数1,操作数2
SUB r0, r1, r2 ; r0 = r1 - r2
SUB r0, r1, #256 ; r0 = r1 - 256
SUB r0, r2, r3, LSL#1 ; r0 = r2 - (r3 << 1)
SUB r0, #0, r1 ; (错误) 立即数不能放在前面
RSB(Reverse Subtract翻转减):
RSB r0, r1, r2 ; r0 = r2 - r1
RSB r0, r1, #0 ; r0 = 0 - r1
3.比较指令
【CMP指令】:CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中条件标志位的值。该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作操作数2,则此后的有GT 后缀的指令将可以执行
CMP指令的格式为:CMP{条件} 操作数1,操作数2
CMP r1,r0 ; 将寄存器r1的值与寄存器r0的值相减,并根据结果设置CPSR的标志位
CMP r1,#100 ; 将寄存器r1的值与立即数100相减,并根据结果设置CPSR的标志位
4.逻辑运算指令
【AND指令】:AND指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中
AND指令的格式为:AND{条件}{S} 目的寄存器,操作数1,操作数2
; 1 & ? = ? , 0 & ? = 0
AND r0, r1, r2 ==> r0 = r1 & r2
; 需求:判断某个寄存器中的第5bit是否为1
AND r0, r1, #(1<<5) ==> r0 = r1 & (1<<5)
【ORR指令】:ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中
ORR指令的格式为:ORR{条件}{S} 目的寄存器,操作数1,操作数2
; 1 | ? = 1, 0 | ? = ?
ORR r0, r1, r2 ; r0 = r1 | r2
; 需求:将某个寄存器中的第5bit和7bit是设置为1
ORR r1, r1, #(5<<5) ; r1 = r1 | (5<<5) 或者: r1 |= 5<<5
【BIC指令】:BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中
BIC指令的格式为:BIC{条件}{S} 目的寄存器,操作数1,操作数2
BIC r0, r1, r2 ; r0 = r1 & ~r2
; 清寄存器的低三位
BIC r0, r0, #(0x7) ; r0 = r0 & ~(0x7) 或者: r0 &= ~(0x7)
; 需求:将某个寄存器中的第5bit,6bit, 7bit是设置为 101
;先要清零:
BIC r0, r0, #(0x7<<5)
;或运算
ORR r0, r0, #(0x5<<5)
【EOR指令】:EOR指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中
EOR指令的格式为:EOR{条件}{S} 目的寄存器,操作数1,操作数2
; 相同为0, 不同为1
EOR r0, r1, r2 ; r0 = r1 ^ r2
;翻转:
EOR r1, r1, #0xf ; r1 = r1 ^ 0xf
5.测试指令
【TST指令】:TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值
TST指令的格式为:TST{条件} 操作数1,操作数2
TST r1, #%1 ; 用于测试在寄存器r1中是否设置了最低位(%表示二进制数)
TST r1, #0xffe ; 将寄存器r1的值与立即数0xffe按位与,并根据结果设置CPSR的标志位
【TEQ指令】:TEQ指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的异或运算,并根据运算结果更新CPSR中条件标志位的值。该指令通常用于比较操作数1和操作数2是否相等
TEQ指令的格式为:TEQ{条件} 操作数1,操作数2
TEQ r0, r1 ;r0 ^ r1,如果相同,结果为0
条件码:
EQ : 如果相等
NE : 如果不相同
GT : great than : 大于
LT : less than : 小于
GE : 大于或者的等于
LE : 小于或者的等于
【TEQ指令】:其实IT指令的结构就是“IF-Then-(Else)”,语法都是由字母“T”和“E”构成:
- IT:If-Then(下一条指令是条件的);
- ITT:If-Then-Then(后两条指令是条件的);
- ITE:If-Then-Else(后两条指令是条件的);
- ITTE:If-Then-Then-Else(后三条指令是条件的);
- ITTEE:If-Then-Then-Else-Else(后四条指令是条件的);
IT块中的每条指令必须指定相同或逻辑相反的条件后缀。意思是,如果使用ITE,那么前两个指令必须有相同的后缀,而第三个必须是逻辑相反的后缀。下面是 ARM 参考手册中的一些示例,说明了这些逻辑:
ITTE NE ; 接下来的3条指令都是有条件的。
ANDNE R0, R0, R1 ; ANDNE不更新条件标志。
ADDSNE R2, R2, #1 ; ADDSNE更新条件标志。
MOVEQ R2, R3 ; 有条件的移动
ITE GT ; 接下来的2条指令都是有条件的。
ADDGT R1, R0, #55 ; 条件满足大于时进行相加。
ADDLE R1, R0, #48 ; 条件不满足大于时进行相加。
ITTEE EQ ; 接下来的4条指令都是有条件的。
MOVEQ R0, R1 ; 有条件的MOV
ADDEQ R2, R2, #10 ; 有条件的ADD
ANDNE R3, R3, #1 ; 有条件的AND
BNE.W dloop ; 分支指令只能在IT块的最后一个指令中使用。
6.跳转指令
【跳转指令】 跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:
-
— B 跳转指令
-
— BL 带返回的跳转指令
-
— BLX 带返回和状态切换的跳转指令
-
— BX 带状态切换的跳转指令
B Label ; 程序无条件跳转到标号Label处执行
BL Label ; 当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中
7.状态寄存器访问指令
【MRS指令】:MRS指令用于将程序状态寄存器的内容传送到通用寄存器中
MRS指令的格式为: MRS{条件} 通用寄存器,程序状态寄存器
;当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
;当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
MRS r0, psp ; 传送psp的内容到r0
【MSR指令】:MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中
MSR指令的格式为: MSR{条件} 程序状态寄存器,操作数
; 指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域
MSR psp, r0 ; 传送r0的内容到psp
8.汇编加载存储指令
【LDR指令】:LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中
LDR指令的格式为:LDR{条件} 目的寄存器,<存储器地址>
; 用法1: 赋值立即数
LDR r0, =0x20000000
; 用法2: 从内存中获取数据
LDR r0, =0x30000000
LDR r1, [r0]
; 用法3:获取一个标签的地址
LDR r0, =myfunc ; 将myfunc地址赋值给r0
myfunc
xxxxx
xxxxxx
; 用法4:获取一个标签的地址中值
LDR r0, myarray ; 将myfunc地址赋值给r0, r0的值为0x1
myarray
dcd 0x1
; 前索引和后索引(注意区分):
; 前索引:先计算地址,再运算
LDR r1, =0x30008000 ; 假如0x30008000存了0x1b, 0x30008008存了0x2b
LDR r0,[r1,#8] ; r0==0x2b,此处r1==0x30008000
LDR r0,[r1,r2] ; 将存储器地址为r1+r2的字数据读入寄存器r0
LDR r0,[r1,r2,LSL#2] ; 将存储器地址为r1+r2×4的字数据读入寄存器r0
LDR r0, [R1, R2] ! ; 将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
; 后索引: 先运算, 后计算地址(基地址会发生变化)
LDR R0, [R1], #8 ; r0==0x1b, r1==0x30008008
LDR R0, [R1], R2 ; 将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
【STR指令】:STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。
STR指令的格式为:STR{条件} 源寄存器,<存储器地址>
STR r0,[r1] ; 将r0中的字数据写入以r1为地址的存储器中。
STR r0,[r1], #8 ; 将r0中的字数据写入以r1为地址的存储器中,并将新地址r1+8写入r1。
STR r0,[r1, #8] ; 将r0中的字数据写入以r1+8为地址的存储器中。
【LDM(或STM)指令】:LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
; IA 每次传送后地址加1
; IB 每次传送前地址加1
; DA 每次传送后地址减1
; DB 每次传送前地址减1
; FD 满递减堆栈
; ED 空递减堆栈
; FA 满递增堆栈
; EA 空递增堆栈
LDMIA r0, {r1-r3, r5} ; r0表示一个内存的基准地址,从基准地址内存中获取到4个数据,赋值给r1-r3, r5,内容高地址交给高寄存器
STMIA r0, {r0-r3, r5} ; 存储寄存器r0,r1,r2,r3,r5到目标地址(r0存储的地址)
;栈操作:
STMFD sp!, {r0-r7} ;压栈
LDMFD sp!, {r0-r7} ;出栈
STMFD r13!,{r0,r4-r12,lr} ;将寄存器列表中的寄存器(r0,r4到r12,lr)存入堆栈。
LDMFD r13!,{r0,r4-r12,pc} ;将堆栈内容恢复到寄存器(r0,r4到r12,pc)。