条件操作码
在pstate寄存器中有4个条件标志位,即N、Z、C、V
条件标志位 | 描述 |
---|---|
N | 负数标志,上一次运算结果为负值 |
Z | 零结果标志,上一次运算结果为零 |
C | 进位标志,上一次运算结果发生了无符号数溢出 |
V | 溢出标志,上一次运算结果发生了有符号数溢出 |
加法与减法指令
ADD指令
普通的加法指令有以下几种用法:
-
使用立即数的加法:
ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}
它的作用是把Xn/SP寄存器的值再加上立即数imm,把结果写入Xd/SP寄存器里。
-
使用寄存器的加法:
ADD <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}
这条指令的作用是先把Rm寄存器做一些扩展,例如左移操作,然后再加上Xn/SP寄存器 的值,把结果写入Xd/SP寄存器中。
-
使用移位操作的加法:
ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
这条指令的作用是先把Xm寄存器做一些移位操作,然后再加上Xn寄存器的值,结果写
入Xd寄存器中。
ADDS指令是ADD指令的变种,唯一的区别是指令执行结果会影响PSTATE寄存器的N、Z、
C、V标志位,例如当计算结果发生无符号数溢出时,C=1。
ADC是进位的加法指令,最终的计算结果需要考虑PSTATE寄存器的C标志位。
SUB指令
普通的减法指令与加法指令类似,也有下面几种用法:
-
使用立即数的减法指令:
SUB <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}
它的作用是把Xn|SP寄存器的值减去立即数imm,结果写入Xd|SP寄存器里。
-
使用寄存器的减法指令:
SUB <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>})
这条指令的作用是先对寄存器做一些扩展,例如左移操作,然后Xn|SP寄存器的值减Rm寄存器的值,把结果写入Xd|SP寄存器中。
-
使用移位操作的减法指令:
SUB <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
这条指令的作用是先把Xm寄存器做一些移位操作,然后使Xn寄存器中的值减去Xm寄存器中的值,把结果写入Xd寄存器中。
SUBS指令是SUB指令的变种,唯一的区别是指令执行结果会影响PSTATE寄存器的N、Z、C、V标志位。SUBS指令判断是否影响N、Z、C、丫标志位的方法比较特别,对应的伪代码如下。
operand2 = NOT(imm);
(result, nzcv) = AddWithCarry(operand1, operand2, '1');
PSTATE.<N,Z,C,V> = nzcv;
首先,把第二个操作数做取反操作。然后,根据operand 1 + NOT(operand2) + 1进行计算。NOT(operand2)表示把operand2按位取反。在这个计算过程中要考虑是否影响N、Z、C、V
标志位。当计算结果发生无符号数溢出时,C=1;当计算结果为负数时,N=1。
CMP指令
CMP指令用来比较两个数的大小。在A64指令集的实现中,CMP指令内部调用SUBS指令来实现。
-
使用立即数的cmp指令:
CMP <Xn|SP>, #<imm>{, <shift>} //等同于如下subs指令 SUBS XZR, <Xn|SP>, #<imm> {, <shift>}
-
使用寄存器的cmp指令:
CMP <Xn|SP>, <R><m>{, <extend> {#<amount>}} SUBS XZR, <Xn|SP>, <R><m>{, <extend> {#<amount>}}
-
使用移位操作的cmp指令:
CMP <Xn>, <Xm>{, <shift> #<amount>} SUB XZR, <Xn>, <Xm>{, <shift> #<amount>}
CMP指令常常和跳转指令与条件操作后缀搭配使用,例如条件操作后缀CS表示是否发生了无符号数溢出,即C标志位是否置位,CC表示C标志位没有置位。
my_test:
mov xl, #3
mov x2, #2
1:
cmp xl, x2
b.ls 1b
ret
在比较Xl和X2寄存器的值大小时,判断条件为LS,表示无符号数小于或者等于。那么,这个比较过程中,我们就不需要判断C标忘位了,直接判断X1寄存器的值是否小于或者等于 X2寄存器的值即可,因此这里b指令不会跳转到标签1处。
移位指令
常见的移位指令如下。
- LSL:逻辑左移指令,最高位会被丢弃,最低位补0
- LSR:逻辑右移指令,最高位补0,最低位会被丢弃
- ASR:算术右移指令,最低位会被丢弃,最高位会按照符号进行扩展
- ROR:循环右移指令,最低位会移动到最高位
位操作指令
与操作
-
AND指令:
AND <Xd|SP>, <Xn>, #<imm> AND <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
AND指令支持两种方式。
- 立即数方式:对Xn寄存器的值和立即数imm进行与操作,把结果写入Xd|SP寄存器中。
- 寄存器方式:先对Xm寄存器的值移位操作,然后再与Xn寄存器的值进行与操作,把结果写入Xd|SP寄存器中。shift表示移位操作,支持LSL、LSR、ASR以及ROR。amount表示移位数量,取值范围为0~63。
-
ANDS指令:与AND指令不一样的地方是它会根据计算结果来影响PSTATE寄存器的N、Z、C、V 标志位。
或操作
ORR (或)操作指令的格式如下。
ORR <Xd|SP>, <Xn>, #<imm>
ORR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
EOR (异或)操作指令的格式如下。
EOR <Xd|SP>, <Xn>, #<imm>
EOR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
位清除操作
BIC (位清除操作)指令的格式如下。
BIC <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
位段操作指令
位段插入
BFI指令的格式如下。
BFI <Xd>, <Xn>, #<lsb>, #<width>
BFI指令的作用是用Xn寄存器中的Bit[0, width-1]替换Xd寄存器中的Bit[lsb, Isb + width-1], Xd寄存器中的其他位不变。BFI指令常用于设置寄存器的字段。
位段提取
UBFX指令的格式如下。
UBFX <Xd>, <Xn>, #<lsb>, #<width>
UBFX指令的作用是提取Xn寄存器的Bit[lsb, lsb+width-1],然后存储到Xd寄存器中。
UBFX还有一个变种指令SBFX,它们之间的区别在于:SBFX会进行符号扩展,例如,如果Bit[lsb+width-1]为1,那么写到Xd寄存器之后,所有的高位都必须写1,以实现符号 扩展。UBFX和SBFX指令常常用于读取寄存器的某些字段。