下面我们来学习下ARM的常用汇编指令,这里我们参考了文档《ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition》(光盘目录:i.MX6UL终结者光盘资料\10_其它参考资料)。
MOV指令用于将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄存器里面,使用示例如下:
MOV R0,R1 @将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12 @将立即数 0X12 传递给 R0 寄存器,即 R0=0X12
MRS指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器,要读取特殊寄存器的数据只能使用MRS指令!使用示例如下:
MRS R0, CPSR @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR
MSR指令和MRS刚好相反,MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就是写特殊寄存器,写特殊寄存器只能使用MSR,使用示例如下:
MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,该指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,其寻址方式灵活多样。使用示例如下:
LDR R0,[R1] //将存储器地址为R1的字数据读入寄存器R0
LDR R0,[R1,R2] //将存储器地址为R1+R2的字数据读入寄存器R0
LDR R0,[R1,#8] //将存储器地址为R1+8的字数据读入寄存器R0
LDR R0,[R1],R2 //将存储器地址为R1的字数据读入寄存器R0,并将新地址R1 +R2写入R1
STR是将数据写入到存储器中,示例代码如下:
STR R1, [R0] //将R1中的值写入到 R0 中所保存的地址中
栈被定义为一种先进后出的数据结构,即最后进栈的元素将被最先弹出来.这很像许多人进入一条窄得只能容纳一个人通过的小道,如果要从这条道往回退出来的话,那么最先退出来的人是最后一个进入小道的人.所以栈具有后进先出的性质(LIFO)。我们使用push指令实现入栈,示例代码如下:
PUSH {R0~R3, R12} @将R0~R3和R12压栈
出栈指令使用POP,示例代码如下:
POP {R0~R3,R12} @在恢复 R0~R3,R12
跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:
1. 使用专门的跳转指令(B、BL、BX、BLX)
2. 直接向程序计数器 PC 写入跳转地址值
一般我们常用专门跳转指令实现程序的跳转,下面我们来看下跳转指令的使用:
B指令
B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是24位有符号数,左移两位后有符号扩展为32位,表示的有效偏移为26位(前后32MB的地址空间)。以下指令:
B Label ;程序无条件跳转到标号 Label 处执行
BL指令
跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。以下指令:
BL Label ;当程序无条件跳转到标号 Label 处执行时,同时将当前的 PC 值保存到 R14 中
BLX指令
从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态由ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14 值复制到PC 中来完成。指令格式如下:
BLX 目标地址
BX指令
跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thum指令,指令格式如下:
BX{条件} 目标地址
常用的逻辑运算符如下:
AND a, b //a = a & b 按位与
AND a, b, #c //a = b & #c 按位与
AND a, b, c //a = b & c 按位与
ORR a, b //a = a | b 按位或
ORR a, b, #c //a = b | #c 按位或
ORR a, b, c //a = b | c 按位或
BIC a, b //a = a & (~b) 位清除
BIC a, b, #c //a = b & (~#c) 位清除
BIC a, b, c //a = b & (~c) 位清除
ORN a, b //a = a | (b) 按位或非
ORN a, b, #c //a = b |(#c) 按位或非
ORN a, b, c //a = b |© 按位或非
EOR a, b //a = a ^b 按位异或
EOR a, b, #c //a = b ^ #c 按位异或
EOR a, b, c //a = b ^ c 按位异或
ADD, a, #b // a = a + #b 加法运算
ADD a, b, c //a = b + c 加法运算
ADD a, b, #c //a = b + #c 加法运算
SUB a, #b //a = a - #b 减法运算
SUB a, b, c //a = b - c 减法运算
SUB a, b, #c //a = b - #c 减法运算
MUL a, b, c //a = b * c 乘法运行算(32位)
UDIV a, b, c //a = b/c 无符号除法
SDIV a, b, c //a = b/c 有符号除法
本节主要讲解了一些最常用的指令,还有很多不常用的指令没有讲解,但是够我们后续学习用了。要想详细的学习ARM的所有指令请参考《 ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》和《ARM Cortex-A(armV7)编程手册 V4.0.pdf》这两份文档,他们分别在光盘资料的目录:i.MX6UL终结者光盘资料\10_其它参考资料。