登录后台

页面导航

本文编写于 481 天前,最后修改于 450 天前,其中某些信息可能已经过时。

条件操作码

在pstate寄存器中有4个条件标志位,即N、Z、C、V

条件标志位 描述
N 负数标志,上一次运算结果为负值
Z 零结果标志,上一次运算结果为零
C 进位标志,上一次运算结果发生了无符号数溢出
V 溢出标志,上一次运算结果发生了有符号数溢出

image-20230611182150177

加法与减法指令

ADD指令

普通的加法指令有以下几种用法:

  1. 使用立即数的加法:

    ADD <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}

    它的作用是把Xn/SP寄存器的值再加上立即数imm,把结果写入Xd/SP寄存器里。

  2. 使用寄存器的加法:

    ADD <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}

    这条指令的作用是先把Rm寄存器做一些扩展,例如左移操作,然后再加上Xn/SP寄存器 的值,把结果写入Xd/SP寄存器中。

  3. 使用移位操作的加法:

    ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}

    这条指令的作用是先把Xm寄存器做一些移位操作,然后再加上Xn寄存器的值,结果写
    入Xd寄存器中。

ADDS指令是ADD指令的变种,唯一的区别是指令执行结果会影响PSTATE寄存器的N、Z、
C、V标志位,例如当计算结果发生无符号数溢出时,C=1。

ADC是进位的加法指令,最终的计算结果需要考虑PSTATE寄存器的C标志位。

SUB指令

普通的减法指令与加法指令类似,也有下面几种用法:

  1. 使用立即数的减法指令:

    SUB <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}

    它的作用是把Xn|SP寄存器的值减去立即数imm,结果写入Xd|SP寄存器里。

  2. 使用寄存器的减法指令:

    SUB <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>})

    这条指令的作用是先对寄存器做一些扩展,例如左移操作,然后Xn|SP寄存器的值减Rm寄存器的值,把结果写入Xd|SP寄存器中。

  3. 使用移位操作的减法指令:

    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指令来实现。

  1. 使用立即数的cmp指令:

    CMP <Xn|SP>, #<imm>{, <shift>}
    //等同于如下subs指令
    SUBS XZR, <Xn|SP>, #<imm> {, <shift>}
  2. 使用寄存器的cmp指令:

    CMP <Xn|SP>, <R><m>{, <extend> {#<amount>}}
    SUBS XZR, <Xn|SP>, <R><m>{, <extend> {#<amount>}}
  3. 使用移位操作的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:循环右移指令,最低位会移动到最高位

image-20230612213132906

位操作指令

与操作

  1. 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。
  2. 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指令常常用于读取寄存器的某些字段。