一.指令与伪指令
指令:CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。
伪指令:本质上不是指令(只是和指令代码一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。
二:ARM汇编特点:
2.1:LDR/STR架构
ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。
ldr(load register)指令将内存内容加载入通用寄存器
str(store register)指令将寄存器内容存入内存空间中
ldr/str组合用来实现ARM CPU和内存数据交换
2.2:8种寻址方式
寄存器寻址: 寄存器r2的值赋给r1
mov r1, r2
立即寻址: 把0xFF00给r0寄存器
mov r0, #0xFF00
寄存器移位寻址: 把r1左移三位后赋值给r0
mov r0, r1, lsl #3
寄存器间接寻址: r2类似一个指针,r2指向一个内存地址,[]类似于C间接寻址,将r2指向内存的值赋给r1寄存器
ldr r1, [r2]
基址变址寻址: r2所指向的地址偏移4位后的内存地址赋给r1
ldr r1, [r2, #4]
多寄存器寻址: r1里面放了内存地址,类似于数组,r1里面7个元素,依次放到寄存器里面
ldmia r1!, {r2-r7, r12}
堆栈寻址: sp栈指针,连续访问数据放到寄存器
stmfd sp!, {r2-r7, lr}
相对寻址: 标号跳转到标号执行
beq flag
flag:
2.3:条件后缀执行
mov r0,r1: 相当于C中的r0=r1
moveq r0,r1: 如果eq后缀成立,则直接执行mov r0,r1;如果eq本身不成立则本句代码直接作废,相当于没有。类似与C语言中的if(eq)(r0 = r1;)
条件后缀执行注意2点:
1、条件后缀是否成立,不是取决于本句代码,而是取决于这句代码之前的代码运行后的结果。
2、条件后缀决定了本句代码是否被执行,而不会影响上一句和下一句代码是否被执行
三:一些特殊指令
3.1 mvn:
mvn和mov用法一样,mov是原封不动的传递,而mvn是按位取反后传递
譬如r1=0xff ,然后mov r0,r1后,r0 = 0xff 但是mvn r0,r1后,r0=0xff000000
and 逻辑与
orr 逻辑或
eor 逻辑异或
3.2 bic位清除指令
bic r0,r1,#0x1f @将r1中的数bit0到bit4清零后赋值给r0
3.3 比较指令cmp,cmn
比较指令:
cmp cmp r0,r1 等价于 sub r2,r0,r1(r2 = r0 - r1)
cmn cmn r0,r1 等价于 add r0,r1
比较指令用来比较2个寄存器中的数
注意:比较指令不用后加s后缀就可以影响cpsr中的标志位
3.4 cpsr和spsr的区别和联系:
cpsr是程序状态寄存器,整个SoC中只有1个;而spsr有5个,分别在5种异常模式下,作用是当从普通模式进入异常模式时,用来保存之前普通模式下的cpsr的,以在返回普通模式时恢复原来的cpsr.
cpsr访问指令:
mrs & msr
mrs用来读psr,msr用来写
cpsr寄存器比较特殊,需要专门的指令访问,这就是mrs和msr.
举个例子:
@IRQ & FIQ disable
mrs r0,cpsr @cpsr读到r0
bic r0,r0,#0x1f @bit0到bit5清除
orr r0,r0,#0xd3 @位或0xd3 11010011 (I & F disable and 10011模式) 查看cpsr程序状态寄存器
msr cpsr,r0 @r0写进cpsr
3.5 跳转指令:
b直接跳转
bl(跳转前把返回地址放入lr中,以便返回,以便用于函数调用)跳转后返回
四:协处理器
格式:
mrc p15 ,0 ,r0 ,c1 ,c0,0 @把cp15协处理器里面 的c1值读到cpu寄存器r0
bic r0,r0 #0x00002000
.
.
.
mcr p15,0,r0,c1,c0,0 @把cpu寄存器r0里面的值写到cp15协处理器c1里面
如何看懂以上指令作用?
可百度查到相应寄存器的功能表,每一个bit位置为不同数,表示不同的实现功能。会看懂即可,没必要深究
五:多寄存器访问指令
ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm
ldm(load register mutiple)
stm(store register mutiple
举例:
stmia sp, {r0 - r12}
@将r0存入sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后地址再+4(指向0x30001008),将r2存入该地址······直到r12内容放入(0x3001030),指令完成。
一个访存周期同时完成13个寄存器的读写
8种后缀:
ia(increase after)先传输,再地址+4
ib(increase before)先地址+4,再传输
da(decrease after)先传输,再地址-4
db(decrease before)先地址-4,再传输
fd(full decrease)满递减堆栈
ed(empty decrease)空递减堆栈
fa(·······) 满递增堆栈
ea(·······)空递增堆栈
ia对应空增栈
ib对应满增栈
da对应空减栈
db对应满减栈
最常见的是stmia和stmfd
四种栈
空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出
满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针
增栈:栈指针移动时向地址增加的方向移动的栈
减栈:栈指针移动时向地址减小的方向移动的栈
谨记:操作栈时使用相同的后缀就不会出错,不管是满栈还是空栈、增栈还是减栈