Arm入门第四讲 Arm指令集学习上
一丶Arm汇编指令学习
1.1 Arm的加减汇编指令
Arm的加减汇编指令分为如下:
ADD 加法指令
ADC 带进位加法指令
SUB 减法指令
SBC 带借位的减法指令
RSB 逆向减法指令
RSC 带借位的逆向减法指令
ADD加法指令
ADD 指令,是用于把两个操作数相加,并且将结果放到目的寄存器中.
操作数1(op1)应是一个寄存器,操作数2可以是一个寄存器,也可以是一个立即数,也可以是一个移位寄存器.
ADD{条件}{S}<dest>,<op1>,<op2>
例子:
ADD R0,R1,R2 将R1 + R2赋值给R0 也就是 R0 = R1 + R2
ADD R0,R1,#2 寄存器与立即数之间的加法操作 R0 = R1 + 2
ADD R0,R2,R1,LSL@1 包含移位运算的加法操作.
先进性移位操作.在进行加法操作R0 = R2 + (R1 << 1)
指令中如果带有S后缀 那么就是要影响 ARM中的状态寄存器 状态寄存器 CPSR 也是一个32位 的寄存器. 主要就是保存程序的运行状态. 比如 第29位 是C标志 那么 如果 R0 = R1 + R2(目的寄存器 = 操作数1 + 操作数2) 两个32位数相加的结果超出了32位 就会产生进位 那么 C标志就会设置为1 否则C就设置为0 如果ADD指令中不加 S后缀的话.那么两数相加 结果是否产生进位都不会改变 CPSR寄存器
MOV R1,#0XF1000000MOV R2,0X800000000ADD R0,R1,R2
可以查看CPSR中的C位是否发生改变ADDS R0,R1,R2 可以查看CPSR中的C位是否发生了变化
溢出位的了解
C标志位 如果在加法运算中 产生了进位. 那么C = 1 这表示无符号运算发生了上溢出了. 其它情况则为0
C标志位 如果在减法运算中产生了借位. 那么C = 0. 简单理解就是C保存了进位.减法借位之后就没了.
这有个名词,意思就是表示无符号运算发生了下溢出. 其它情况下C为1. 正好与加法相反
ADC 带进位的32位书加法
和Add指令不同,此指令在相加的时候需要把进位标志加上 也就是 CPSR 标志位的C位
adc r1,r2,r3 r1 = r2 + r3 + C位
使用ADC指令还可以做64位数的加法。 可以把一个64位拆分为 高32位与低32位数
然后分别放到寄存器中。 如要实现 x + y x与y都是64位数。 那么可以把 x分为高32位和低32位
y也同理。 然后进行低位相加。 然后在使用ADC指令将他们的高位相加。 来实现一个64位数加法
mov r0,#0xFFFFFFFE x数的低32位
mov r1,#16 x数的高32位
mov r2,#5 y数的低32位
mov r3,#4 y数的高32位
adds r4,r0,r2 x的低32位+y的低32位
adc r5,r1,r3 r5 = r1 + r3 +C x的高32位+y的高32并且加上进位标志
请注意,这里的低32位加低32位的地方要使用 ADDS 不然不会影响标志位,但是如果结果溢出了进位了那么结果就错了。
SUB 减法指令
SUB指令用于把操作数1减去操作数2的结果 放到目的寄存器中. 操作数1 可以是寄存器. 操作数2 可以是
立即数 移位寄存器 (与ADD一样)
例子:
SUB{条件}{S}<dest>,<op1>,<op2>
SUB R0,R1,R2 R0 = R1 - R2
SUB R0,R1,#256 R0 = R1 - 256
SUB R2,R1,R3,LSL#1 R2 = R1 -(R3<<1)
SBC 带借位的减法
同样的与ADC加法一样,借位的时候需要减去C位
SUBS R0,R0,R2 R0 = R0-R2 并且设置标志位
SBC R1,R1,R3 R1 = R1 - R3 - C
RSB 反向减法指令
反向减法指令意思就是操作相反了。 变成了操作数2-操作数1了 并且将结果放置到目的寄存器中。
RSB R0,R1,R2 R0 = R2 - R1
RSB R0,R1,#256 R0 = 256-R1
RSB R0,R2,R3,LSL#1 R0 = (R3<<1)-R2
逆向减法可以在有符号或者无符号数上进行运算。
RSC 反向借位减法指令
原理与ADC SBC 一样,只不过是操作数互换了。
64位例子 对一个64位数进行取反
RSBS R2,R0 ,#0RSC R3,R1,#0
1.2 数据传送指令
Mov 数据传送指令
MOV指令可以完成从另一个寄存器,或者一个被移位寄存器,或者一个立即数。 加载到目的寄存器。
也就是可以把一个操作数的值给拷贝一份给另一个操作数。 其中要拷贝的操作数 可以是移位寄存器 立即数 寄存器等等。如果带有S选项那么就会影响CPSR中标志位的值。如果没有则不影响。
MOV{条件}{S} 目的寄存器,源操作数
MOV R0,#0X100 ;把立即数0x100拷贝到R0寄存器中。或者说是载入到R0中
MOV R1,R0 ;把寄存器R0中的数据载入到R1中。
MVN 数据取反传送指令
MVN指令和MOV一样,都是拷贝一个值到目的寄存器。唯一不同的就是MVN拷贝的时候会把要拷贝的值进行取反。取反后拷贝给目的寄存器. 可加S
MVN R0,#0 ;把0 取反后载入到R0寄存器中。 0取反= 0xFFFFFFFF 也就是-1
MVN R1,0XFFFFFF00 ;把0xFFXX00取反的值(0x000000FF)赋值给R1
1.3 比较指令
CMP 数据比较指令
CMP指令是用于把一个寄存器的内容和另一个寄存器的内容或者立即数进行比较。
然后设置CPSR中条件标志位的值。 该指令本质就是进行一次减法操作。但是不存储结果。只适用于修改标志位的。
标志位表示的是操作数1 与 操作数2的关系 也就是 大 小 相等。 比如如果操作数1 > 操作数2 那么后面就会跟着跳转指令(如GT)
CMP{条件} 操作数1,操作数2
CMP R1,R0 R1 - R0 并且根据结果设置标志位CMP R1,#100 R1-100 结果设置标志位
CMN 比较反值指令
看到带有N的大概也能猜到意思了。 就是按照取反之后的值进行比较了。 而唯一不同的是他们完成的实际是
操作数1+操作数2. 并且根据结果更改条件标志位
CMN{条件} 操作数1,操作数2
CMN R1,R0 R1 + R0 结果设置标志位CMN R1,#100 R1 + 100 设置标志位
TST 位测试指令
TST指令是用于把一个寄存器的内容和另一个寄存器的内容或者立即数进行 按位 的与运算。
并且根据运算结果来设置CPSR中条件标志位的值。 操作数1则是要测试的数据。而操作数2则是一个位掩码。 该指令一般用来检测是否设置了特定的位
TST{条件} 操作数1,操作数2
TST R1,#0X1 ;先进行and运算。
TEQ 相等指令
TEQ指令用于把一个寄存器的内容和另一个寄存器(立即数)的内容进行按位的异或运算,并且根据运算的结果来更新标志位CPSR中的条件标志位。 该指令通常用于比较操作数1和操作数2是否相等。
TEQ{条件} 操作数1,操作数2
TEQ R1,R2 比较R1 R2是否相等
1.4 位操作指令
ADN 逻辑与指令
AND指令试讲两个操作数进行逻辑与运算,并且讲结果放置到目的寄存器当中。 操作数1可以是一个寄存器,操作数2可以是寄存器(立即数,移位寄存器)
AND{条件}{S}<DEST><OP1><OP2>
MOV R0,#0X02 ;设置R0 = 2
AND R0,R0,#0X01 ;R0 = R0 & 0X1 取出低位
MOV R1,#0X7 ;R1 = 0x7
MOV R3,#0X05 ;R3 = 0x5AND R2,R1,R3 ;R2 = R1 & R3 = 7 & 5
AND 指令可以用于提取寄存器中某些位的值。 具体做法是设置一个掩码值,然后将这个值对应寄存器中欲要提取的位设为1. 其他值设置为0. 然后寄存器的值与掩码值进行操作泽科提取出你想要的值。
ORR 逻辑或指令
ORR是将两个操作数进行逻辑或,一般用于设置值。 把结果放置到目的寄存器中,对设置的特定的位有用。 操作数1是一个寄存器,操作数2 (寄存器,移位寄存器,立即数)都可以
ORR{条件}{S}<DEST><OP1><OP2>
MOV R0,#0XF0ORR R0,R0,#0X0F R0 = R0 | 0XF 低四位都设置为1
EOR 逻辑异或指令
EOR也就是异或指令,跟x86平台上的XOR指令一样。相同为假,不同为真。作用就是对两个操作数进行异或,结果放到目的寄存器中。
EOR{条件}{S}<DEST><OP1><OP2>
EOR R1,R1,#0XF R1 = R1 ^ 0XF 也就是将R1的低四位取反EOR R2,R1,R0 R2 = R1 ^ R0
BIC位清除指令
ORR指令是逻辑或指令,是设置一位的。但是BIC指令正好与其相反。是清除这一位的。如果设置的位数与之对应,那么则清除这一位。
BIC{条件}{S}<DEST><OP1><OP2>
BIC R1,R1,#0X0F 将R1的低四位清0,其它保持不变。
1.5 移位操作指令
移位操作在ARM指令集中不可以作为单独的指令使用,他只能作为指令格式中的一个字段。
在汇编语言中表示为指令的中的选项。 例如数据处理指令的第二个操作数为寄存器的时候,就可以加入移位操作选项对它进行各项移位操作。
移位操作有以下六中类型 其中LSL ASL等价
LSL: 逻辑左移
ASL: 算数左移
LSR: 逻辑右移
ASR: 算数右移
ROR: 循环右移
RRX: 带扩展的循环右移
左移操作
左移操作是可以完成对通用寄存器中的内容进行逻辑(算数)的左移操作,按照操作数所指定的数量向左移位,低位则用零来进行填充,其中操作数可以是通用寄存器,也可以是立即数(0-31)。
在高级语言中左移一位相当于*2的操作
如:
0100 (4) <<1 = 1000(8)
通用寄存器,LSR(ASL) 操作数
MOV R0,R1,LSR#2 ; R0 = (R1 << 2) 对R1进行左移2位然后结果给R0
LSR 右移指令
LSR可以完成对通用寄存器中的内容右移操作。 按照高级语言来说 右移1位相当于/2操作。 LSR右移的时候左端用0进行填充。 其中操作数可以是通用寄存器 也可以是立即数 (0~31)
通用寄存器,LSR 操作数
MOV R0,R1,LSR#2; RO = (R1 >> 2)
ASR 符号右移
ASR和LSR一样都是完成右移操作。唯一不同的就是左边高位填充值的不同,LSR左边就是用0填充。 ASR则是以右端的第一位(左端的第31位)来进行填充的。 操作数数可以是立即数或者通用寄存器
通用寄存器,ASR 操作数
MOV R0,R1,ASR#2 ; R0 = (R1 >>2)
0001 >> 1位 = 1000 (8) 这是ASR
0001 >> 1位 = 0000 (0) 这是LSR
ROR循环右移指令
ROR指令是循环右移指令,是按照操作数给的位数进行循环移位。何为循环,循环的意思就是移出的哪位并没有丢弃。而是作为值补充到高位了,这点与ASR很相似。 但是ASR不同的是就是最后一位为1高位才会为1
通用寄存器,ROR 操作数
MOV R0,R1,ROR#2 ; RO = (R1 >> 2)(>>是循环移位的代替)
例子:
0011 循环右移2位 = 1100
RRX循环扩展右移指令
与ROR一样都是循环右移指令。 唯一不同的就是他是以C位(条件标志位)来填充高位的值。而不是直接和R0R指令一样使用移出位来填充了。
通用寄存器, RRX 操作数
MOV R0,R1,RRX#2 ;将R1的值进行扩展循环右移两位 结果给R0存储