当前位置: 首页 > news >正文

汇编基础介绍——ARMv8指令集(四)

一、CMP 指令

CMP 指令用来比较两个数的大小。在 A64 指令集的实现中,CMP 指令内部调用 SUBS 指令来实现。

1.1、使用立即数的 CMP 指令

使用立即数的 CMP 指令的格式如下。

CMP <Xn|SP>, #<imm>{, <shift>}

上述指令等同于如下指令。

SUBS XZR, <Xn|SP>, #<imm> {, <shift>}

1.2、使用寄存器的 CMP 指令

使用寄存器的 CMP 指令的格式如下。

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

上述指令等同于如下指令。

SUBS XZR, <Xn|SP>, <R><m>{, <extend> {#<amount>}}

1.3、使用移位操作的 CMP 指令

使用移位操作的 CMP 指令的格式如下。

CMP <Xn>, <Xm>{, <shift> #<amount>}

上述指令等同于如下指令。

SUBS XZR, <Xn>, <Xm> {, <shift> #<amount>}

1.4、CMP 指令与条件操作后缀

CMP 指令常常和跳转指令与条件操作后缀搭配使用,例如条件操作后缀 CS 表示是否发生了无符号数溢出,即 C 标志位是否置位,0 表示 C 标志位没有置位。

如下代码使用 CMP 指令来比较如下两个寄存器。

cmp x1, x2
b.cs label

CMP 指令判断两个寄存器是否触发无符号溢出的计算公式与 SUBS 指令类似:

X1 + NOT(X2) + 1 

如果上述过程中发生了无符号数溢出,那么 C 标志位会置 1,则 b.cs 指令将会跳转到 label 处。

下面的代码用来比较 3 和 2 两个立即数。

my_test:mov x1, #3mov x2, #21:cmp x1, x2b.cs 1bret

至于如何比较,需要根据 b 指令后面的条件操作后缀来定。CS 表示判断是否发生无符号数溢出。根据 CMP 指令的运算公式可得,3 + NOT(2) +1,其中 NOT(2)把立即数 2 按位取反,取反后为 0xFFFFFFFFFFFFFFFD。 3 + 0xFFFFFFFFFFFFFFFD + 1 的最终结果为 1,这个过程中发生了无符号数溢出,C 标志位为 1。所以,b.cs 的判断条件成立,跳转到标签 1 处,继续执行。

二、移位指令

常见的移位指令如下。

  • LSL:逻辑左移指令,最高位会被丢弃,最低位补 0,如下(a)图所示。
  • LSR:逻辑右移指令,最高位补 0,最低位会被丢弃,如下(b)图所示。
  • ASR:算术右移指令,最低位会被丢弃,最高位会按照符号进行扩展,如下(c)图所示。
  • ROR:循环右移指令,最低位会移动到最高位,如下(d)图所示。

如下代码使用了 ASR 和 LSR 指令。

ldr w1, =0x8000008a
asr w2, w1, 1
lsr w3, w1, 1

在上述代码中,ASR 是算术右移指令,把 0x8000008A 右移一位并且对最高位进行有符号扩展,最后结果为 0xC0000045。LSR 是逻辑右移指令,把 0x8000008A 右移一位并且在最高位补 0,最后结果为 0x40000045。

三、位操作指令

3.1、与操作指令

与操作主要有两条指令。

  • AND:按位与操作。
  • ANDS:带条件标志位的与操作,影响 Z 标志位。

3.1.1、AND 指令

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。

3.1.2、ANDS指令

ANDS 指令的格式如下。

ANDS <Xd>, <Xn>, #<imm>
ANDS <Xd>, <Xn>, <Xm>{, <shift> #<amount>}

ANDS 指令支持两种方式。

  • 立即数方式:对 Xn 寄存器的值和立即数 imm 进行与操作,把结果写入 Xd/SP 寄存器中。
  • 寄存器方式:先对 Xm 寄存器的值做移位操作,然后再与 Xn 寄存器的值进行与操作,把结果写入 Xd/SP 寄存器中。

指令参数说明如下。

shift 表示移位操作,支持 LSL、LSR、ASR 以及 ROR。

amount 表示移位数量,取值范围为 0~63。

与 AND 指令不一样的地方是它会根据计算结果来影响 PSTATE 寄存器的 N、 Z、 C、 V 标志位。

如下代码使用 ANDS 指令来对 0x3 和 0 做“与”操作。

mov x1, #0x3
mov x2, #0ands x3, x1, x2
mrs x0, nzcv

“与”操作的结果为 0。通过读取 NZCV 寄存器,我们可以看到其中的 Z 标志位置位了。

3.2、或操作指令

3.2.1、ORR指令

ORR(或)操作指令的格式如下。

ORR <Xd|SP>, <Xn>, #<imm>
ORR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}

ORR 指令支持两种方式。

  • 立即数方式:对 寄存器的值与立即数 Xn imm 进行或操作。
  • 寄存器方式:先对 Xm 寄存器的值做移位操作,然后再与 Xn 寄存器的值进行或操作。

指令参数说明如下。

shift 表示移位操作,支持 LSL 、LSR 、ASR 以及 ROR。

amount 表示移位数量,取值范围为 0~63。

3.2.2、EOR指令

EOR (异或)操作指令的格式如下。

EOR <Xd|SP>, <Xn>, #<imm>
EOR <Xd>, <Xn>, <Xm>{, <shift> #<amount>}

EOR 指令支持两种方式。

  • 立即数方式:对 Xn 寄存器的值与立即数 imm 进行异或操作。
  • 寄存器方式:先对 Xm 寄存器的值做移位操作,然后再与 Xn 寄存器的值进行异或操作。

指令参数说明如下。

shift 表示移位操作,支持 LSL 、LSR 、ASR 以及 ROR。

amount 表示移位数量,取值范围为 0~63。

异或操作的真值表如下。

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

从上述真值表可以发现 3 个特点。

  • 0 异或任何数 = 任何数。
  • 1 异或任何数 = 任何数取反。
  • 任何数异或自己都等于 。

利用上述特点,异或操作有如下几个非常常用的场景。

使某些特定的位翻转。

例如, 想把 0b10100001 的第 2 位和第 3 位翻转, 则可以对该数与 0b00000110 进行按位异或运算。

10100001 ^ 00000110 = 10100111

交换两个数。

例如,交换两个整数 a=0b10100001 和 b=0b00000110 的值可通过下列语句实现。

a = a^b; //a=10100111
b = b^a; //b=10100001
a = a^b; //a=00000110

在汇编程序里把变量设置为 。

eor x0, x0

判断两个整数是否相等。

bool is_identical(int a, int b)
{return ((a ^ b) == 0);
}

3.3、位清除操作指令

BIC (位清除操作)指令指令用于将寄存器中的某些位清零,而保持其他位不变。其核心作用是选择性地清除(置 0)特定位置的位,常用于权限屏蔽、标志位清除等场景。其格式如下。

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

BIC 指令支持寄存器方式: 先对 Xm 寄存器的值做移位操作, 然后再与 Xn 寄存器的值进行位清除操作。

指令参数说明如下。

shift 表示移位操作,支持 LSL 、LSR 、ASR 以及 ROR。

amount 表示移位数量,取值范围为 0~63。

BIC 指令的本质是:

Xd = Xn & (~Xm)
  • 将掩码 Xm 按位取反。
  • 将源寄存器(Xn)与取反后的掩码进行按位与操作。

掩码中为 1 的位会清除对应位,为 0 的位保持不变。

3.4、CLZ 指令

CLZ 指令的格式如下。

CLZ <Xd>, <Xn>

CLZ 指令计算为 1 的最高位前面有几个为 0 的位。

如下代码使用了 CLZ 指令。

ldr x1, =0x1100000034578000
clz x0, x1

X1 寄存器里为 1 的最高位是第 60 位,前面还有 3 个为 0 的位,最终 X0 寄存器的值为 3。

四、位段操作指令

4.1、位段插入操作指令

BFI 指令的格式如下。

BFI <Xd>, <Xn>, #<lsb>, #<width>

BFI 指令的作用是用 Xn 寄存器中的 Bit[0, width - 1]替换 Xd 寄存器中的 Bit[lsb, lsb + width - 1], 寄存器中的其他位不变。

BFI 指令常用于设置寄存器的字段。

如下代码将寄存器 X1 的低 4 位插入到寄存器 X0 的第 8~11 位(共 4 位)。

BFI X0, X1, #8, #4  ; 将X1的低4位插入到X0的第8~11位

步骤解析

  • 假设初始值
    • X0 = 0xFFFFFFFFFFFFFFFF(全 1)。
    • X1 = 0x000000000000000F(低 4 位为 1,其余为 0)。
  • 提取源位段
    • X1 的低 4 位为 0b1111
  • 清除目标位段
    • X0 的第 8~11 位被清零,变为 0xFFFFFFF0FFFFFF
  • 插入位段
    • 源位段 0b1111 左移 8 位后为 0x0000000000000F00
    • 合并后 X0 = 0xFFFFFFF0FFFFFF | 0x0000000000000F00 = 0xFFFFFFF0FFFFFFFF

4.2、位段提取操作指令

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

如下代码从寄存器 X1 的第 8~15 位(共 8 位)提取值,并零扩展到 X0。

UBFX X0, X1, #8, #8  ; 提取X1的第8~15位,存入X0

步骤解析

  • 假设初始值
    • X1 = 0x0000000000FF00FF(二进制 0b0000...0000111111110000000011111111)。
  • 提取位段
    • 第 8~15 位为 0b00000000(值为 0)。
  • 零扩展
    • 提取的 8 位右移至最低位,左侧补零,结果为 0x0000000000000000
  • 存入目标寄存器
    • X0 = 0x0000000000000000

http://www.dtcms.com/a/262746.html

相关文章:

  • 【c/c++1】数据类型/指针/结构体,static/extern/makefile/文件
  • 【c/c++3】类和对象,vector容器,类继承和多态,systemd,stdboost
  • Ragflow本地部署和基于知识库的智能问答测试
  • 机器学习在智能电网中的应用:负荷预测与能源管理
  • 【鸿蒙中级】
  • 面试复盘6.0
  • 「Java案例」输出24个希腊字母
  • 深入理解 Dubbo 负载均衡:原理、源码与实践
  • Redis Cluster Gossip 协议
  • 指针篇(6)- sizeof和strlen,数组和指针笔试题
  • 免费SSL证书一键申请与自动续期
  • MySQL-复合查询
  • 暴力风扇方案介绍
  • AlpineLinux安装部署MariaDB
  • 微信小程序接入腾讯云短信验证码流程
  • 用户行为序列建模(篇十)-【加州大学圣地亚哥分校】SASRec
  • 在Linux系统中部署Java项目
  • Unity Catalog 三大升级:Data+AI 时代的统一治理再进化
  • Re:从0开始的 空闲磁盘块管理(考研向)
  • HybridCLR热更新实例项目及改造流程
  • 人工智能之数学基础:如何判断正定矩阵和负定矩阵?
  • JVM基础--JVM的组成
  • Transformer超详细全解!含代码实战
  • Java面试宝典:基础三
  • 新生代潜力股刘小北:演艺路上的璀璨新星
  • 用户行为序列建模(篇七)-【阿里】DIN
  • Linux下基于C++11的socket网络编程(基础)个人总结版
  • 学习日志02 ETF 基础数据可视化分析与简易管理系统
  • BERT 模型详解:结构、原理解析
  • 视频跳帧播放器设计与实现