ARM指令集可以分为数据处理指令、跳转指令、Load/Store指令、程序状态寄存器传输指令、协处理器指令和异常中断产生指令。根据使用的指令类型不同,指令的寻址方式分为数据处理指令寻址方式和内存访问指令寻址方式。
数据处理指令寻址方式
概述:数据操作指令是指对存放在寄存器中的数据进行操作的指令。主要包括数据传送指令、算术指令、逻辑指令、比较与测试指令及乘法指令。如果在数据处理指令后使用“S”后缀,指令的执行结果将会影响CPSR中的标志位。数据处理指令的基本语法格式如下:
1.MOV指令
MOV是最简单的ARM指令,MOV指令是将《shifter_operand》表示的数据传送到目标寄存器《Rd》中,其中《shifter_operand》可以是寄存器,也可以使立即数,并根据操作的结果更新CPSR中相应的条件标志位。
语法格式:
MOV { <cond> } { S } <Rd>,<shifter_operand>
指令举例:
MOV R0,#0xFF ; //R0=0xFF
MOV R0,RO ; //R0=R0.....NOP指令
MOV RO,RO,LSL#3; //RO=RO<<3
当R15作为目标寄存器Rd出现时常用于子函数的返回,方法是将连接寄存器LR中保存的返回地址通过该指令传送给PC。
MOV PC,R14; //退出到调用者,用于普通函数返回,PC即R15
MOVS PC,R14; //退出到调用者并恢复标志位,用于异常函数返回
指令功能:
- 将数据从一个寄存器传送到另一个寄存器。
- 将一个常数值传送到另一个寄存器。
- 实现单纯的移位操作,比如操作数除以2^n可以用右移n位来实现。
- 当PC(R15)用作目标寄存器Rd时,可以实现程序跳转,如“MOV PC,LR”。这种跳转可以实现子程序条用及从子程序返回。
- 当PC作为目标寄存器Rd且指令中有后缀“S”时,则指令在执行跳转操作的同时,将当前处理器模式的SPSR寄存器的内容复制到CPSR中。这种指令“MOVS PC,LR”,可以实现从某些异常中断中返回。
2.MVN指令
MVN是数据取反传送指令,指令将《shifter_operand》表示的数据的反码传送到目标寄存器《Rd》,并根据操作的结果更新CPSR中相应的条件标志位。
语法格式:
MVN { <cond> } { S } <Rd>,<shifter_operand>
指令举例:
MVN指令和MOV指令相同,《shifter_operand》可以是立即数,也可以是寄存器。
MVN R0,#4; //R0=~(4)
MVN R0,#0; //RO=~(1)
指令功能:
- 想寄存器中传送一个负数。
- 生成位掩码。
- 求一个数的反码。
3.ADD指令
ADD指令将《shifter_operand》表示的数据加上寄存器《Rn》的值,将结果保存到目标寄存器《Rd》中,并根据指令的执行结果更新CPSR中相应的条件标志位。
语法格式:
ADD { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例:
ADD R0,R1,R2; //R0=R1+R2
ADD R0,R1,#0xFF; //R0=R1+0xFF
ADD R0,R2,R3,LSL#1; //R0=R2+(R3<<1)
指令功能:
- 主要完成两个数的相加。
4.ADC指令
ADC指令将《shifter_operand》表示的值加上寄存器《Rn》的值,再加上CPSR中的C条件标志位的值,将结果保存到目标寄存器《Rd》中,并根据指令的执行结果更新CPSR中相应的条件标志位。
语法格式:
ADC { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例:
ADC指令把两个操作数加起来,并把结果放置到目标寄存器《Rd》中。它使用CPSR中的进位标志位,这样就可以做比32位大的加法。
下面的例子将两个128位的数相加。
128位结果:寄存器R0、R1、R2和R3.
第1个128位数:寄存器R4、R5、R6和R7
第2个128位数:寄存器R8、R9、R10和R11
ADDS R0,R4,R8; //加低端的字
ADCS R1,R5,R9; //加下一个字,带进位
ADCS R2,R6,R10; //加第3个字,带进位
ADCS R3,R7,R11; //加高端的字,带进位
指令功能:
ADC指令常与ADD指令联合使用,可以实现两个64位数的相加。
5.SUB 指令
SUB指令的作用是将寄存器《Rn》中的数值减去《shifter_operand》所表示的数值,将运算结果保存到目标寄存器《Rd》中,并根据指令的执行结果更新CPSR中的条件标志位。
语法格式:
SUB { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例:
SUB R0,R1,R2; //R0=R1-R2
SUB R0,R1,#0xff; //R=R1-0xff
SUB R0,R2,R3,LSL#1; //R0=R2-(R3<<1)
指令功能:
SUB指令常用于实现两个数的减法。
6.AND指令
AND指令将《shifter_operand》表示的数值与寄存器《Rn》的值按位做“与”操作,并将结果保存到目标寄存器《Rd》中,同时根据操作的结果更新CPSR寄存器中的条件标志位。
语法格式:
ADD { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例
AND R0,R0,#0x03; //r0寄存器的0、1位不变,其他位清零
AND R2,R1,R3; //R2=R1 & R3
AND R0,R0,#0x01; //R0=R0 & 0X01
7.EOR指令
EOR指令将寄存器《Rn》中的值和《shifter_operand》表示的值进行按位“异或”操作,并将执行结果存储到目标寄存器《Rd》中,同时根据指令的执行结果更新CPSR中相应的条件标志位。
语法格式:
EOR { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例:
EOR R0,R0,#3; //反转R0中的第0和1位
EOR R1,R1R,#0x0F; //将R1的低4位取反
EOR R2,R1,R0; //R2=R1^R0
EORS R0,R5,#0X01; //将R5和0x01进行逻辑异或,结果保存到R0,并根据执行结果更新标志位。
8.BIC指令
BIC位清零指令,将寄存器《Rn》的值与第2个源操作数《shifter_operand》的值的反码按位做“逻辑与”操作,结果保存到寄存器《Rd》中。
语法格式:
BIC { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例:
BIC R0,R0,#0X1011; //清除R0中的位0、1和3,保持其余不变
BIC R1,R2,R3; //将R3的反码和R2逻辑与,结果保存到R1中
9.CMP指令
CMP指令的实质是使用寄存器《Rn》的值减去《shifter_operand》表示的值,根据操作的结果更新 CPSR 中相应的条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。
语法格式:
CMP { <cond> } { S } <Rd>,<Rn>, <shifter_operand>
指令举例:
CMP指令允许把一个寄存器的内容与另一个寄存器的内容或立即数进行比较,比较结果将更改状态寄存器中对应的标志从而之后的指令可以进行条件执行。它的实质是进行了一次减法,但不存储结果,而是更改条件标志位。标志位表示的是操作数1与操作数2比较的结果(其值可能为大、小、相等)。比如操作数1大于操作数2,则此后的有GT后缀的指令将可以执行。
显然,CMP不需要显式地指定S后缀来更改状态标志。
CMP R1.#10 ; //比较R1和立即数10并更新相关的标志位
CMP R1.R2 ; //比较寄存器R1和R2中的值并设置相关的标志位
通过上面的例子可以看出,CMP 指令与SUBS 指令的区别在于 CMP指令不保存运算结果,在进行两个数据大小判断时,常用CMP指令及相应的条件码来进行操作.