基础篇(三).A64指令集

A64指令集


本篇只对A64指令集进行总结。

1.A64汇编指令简介

  • A64指令只能运行在AARCH64环境中
  • 所有A64汇编指令都是32bit位宽
  • A64支持全部大写或全部小写的书写方式
  • 寄存器命名:
    在这里插入图片描述
    A64指令分类
     内存加载和存储指令
     多字节内存加载和存储
     算术和移位指令
     移位操作
     位操作指令
     条件操作
     跳转指令
     独占访存指令
     内存屏障指令
     异常处理指令
     系统寄存器访问指令

2.存储和加载指令

ldr指令和str指令:

ARMv8、ARMv9架构也是基于加载和存储架构。

加载和存储指令的格式:

  1. LDR 目标寄存器, <存储器地址> //把存储器地址的数据加载到目标寄存器中
  2. STR 源寄存器, <存储器地址> //把源寄存器的值存储到存储器中

关于“<存储器地址>”的表示,有很多种方式。

[1].ldr指令寻址方式1:地址偏移模式(unsigned offset)

地址偏移模式,通常使用寄存器的值来表示一个地址,或者基于寄存器的值做一些偏移来计算出内存地址,并且把这个内存地址的值加载到通用寄存器中。偏移量可以是正数,也可以是负数。

ldr Xd, [Xn, $offset]

首先在Xn寄存器的内容上加一个offset偏移量后作为内存地址,加载此地址的内容到Xd寄存器。

在这里插入图片描述
实践:

1 首先使用mov指令把 0x80000加载到x1寄存器, 使用mov指令把16数值加载到x3寄存器
2. 使用ldr指令读取0x80000地址的值。
3. 使用ldr指令来读取0x80008地址的值。
4. 使用ldr指令来读取 (x1 + x3)寄存器的值。
5. 使用ldr指令来读取(x1+ x3<<3) 地址的值

将代码写成如下这样:

.global ldr_test

ldr_test:
    mov x1, 0x80000
    mov x3, 16
    //使用ldr指令读取0x80000地址的值
    ldr x0, [x1]
    //使用ldr指令来读取0x80008地址的值。
    ldr x0, [x1, #8]
    //使用ldr指令来读取 (x1 + x3)寄存器的值。
    ldr x0, [x1, x3]
    //使用ldr指令来读取(x1+ x3<<3) 地址的值
    ldr x0, [x1, x3,lsl #3] 

需要注意的是这里的lsl 移位指令,后面的数字只能是0或3
在这里插入图片描述

[2].ldr指令寻址方式2:变基模式

变基模式主要有两种:
 前变基模式(pre-index模式),先更新偏移地址然后再访问内存。
 后变基模式(post-index模式),先访问内存地址然后再更新偏移地址。

LDR X0, [X1, #8]!	//前变基模式。先更新X1的值为X1+8,然后以新的X1值为地址,加载内存的值到X0

LDR X0, [X1], #8 //后变基模式。以X1的值为地址,加载该内存地址的值到X0,然后再更新X1寄存器为X1+8

[3].ldr指令寻址方式3:标签模式(literal)

标签模式,也叫pc相对寻址。本质是:读取(PC值+ label offset) 这个地址的值**

ldr ,

<label>的位置必须在当前指令地址的1MB范围之内。超出这个范围,编译器会报错。

在这里插入图片描述

例1:
其中x6和x7寄存器的值分别是多少?

#define MY_LABEL 0x20 
ldr x6, MY_LABEL
ldr x7, =MY_LABEL

区别在于“=”.

  • 前者属于pc位置相对寻址,将(pc+MY_LABEL)地址处的值加载都x6。
  • 后者是一个伪指令。表示将MY_LABEL的值加载到x7。

例2:
其中x6,x7, x8寄存器的值分别是多少?

data:
	.word 0x40
	
ldr x6,data  //
ldr x7,=data
ldr x8, [x7]

标签data定义了一个数据,data实际上代表的是一个地址,而该地址处数据的值是0x40。
第一句,是普通的加载指令。读取到的是data标签位置的值,0x40。
第二句,是伪指令。读取的是标签本身代表的值,也就是data对应的地址。它没有地址范围的限制。
第三局,普通加载指令。读取的是[x7]代表的地址处的值,因此结果是0x40。

[4]加载指令4:mov

mov指令是最简单和最原始的指令。
在这里插入图片描述

Mov指令加载有限制:

  1. 16位立即数
  2. 或者16位立即数 左移 16,32,48位

[5]多字节加载(ldp)\存储(stp)指令

  • 在A32指令集中通过ldm和stm指令来加载和存储多个字节内存
  • 而在A64指令集中,使用ldp和stp作为多字节内存加载和存储
  • ldp和stp 一条指令可以加载和存储16个字节
    在这里插入图片描述

LDP X3, X7, [X0] //以X0的值为地址,加载此地址的值到X3寄存器,以X0+8为地址,加载此地址的值到X7寄存器
STP X1, X2, [X4] //存储X1的值到地址为X4的内存中,然后存储X2的值到地址为X4+8的内存中。

[6]加载和存储指令练习

1.加载一个很大的数值到通用寄存器,例如0xffff_000_ffff_ffff

//伪指令允许加载很大的数。mov有限制。
ldr x1, =0xffff_000_ffff_ffff
  1. 加载一个寄存器的值,例如sctrl_el1寄存器。
//mov只支持16位数局,左移0,16,32,48 位。对于超出16bit任意数无能为了。
//mov x1, (1 << 0) | (1 << 2) | (1<< 20) | (1<< 40) | (1<<55)
ldr x1, = (1 << 0) | (1 << 2) | (1<< 20) | (1<< 40) | (1<<55)
  1. 下面的代码,x0和x1分别是多少?
string1:
.string "Booting at EL“

ldr x0, string1 
ldr x1, =string1

x0 为string1变量的值代表的地址处的值,即为字符串的ASCII码值。
x1为string1变量的值,本身是个地址。

[7]加载和存储指令的变种

根据单字节,半字,字,有符号数和无符号数,有ldr和str有如下变种。
在这里插入图片描述
注意:访问和存储4个字节和8个字节都是用ldr和str,只不过目标寄存器使用wn或者xn。

3.算数和移位指令

条件操作码

在处理器状态PSTATE中有NZCV特殊寄存器表示4个状态码。
在这里插入图片描述
在这里插入图片描述

3.1 加法指令

[1] 普通加法指令add

1.使用立即数的加法指令

add <Xd|SP>, <Xn|SP>, #{, shift}

  • Xd|SP, 目标寄存器,可以是通用寄存器或栈地址寄存器。
  • Xn|SP,源寄存器,可以是通用寄存器或栈地址寄存器。
  • imm:立即数。是一个无符号立即数,范围在0~4095.
  • shift, 可选项,用来表示算术左移操作。只能是LSL 0或LSL 12.
add x0, x1, #1
add x0, x1, #1, LSL #12

下面是错误做法,编译器会报错。

add x0, x1, #4096
add x0, x1, #1, LSL #1

2. 使用寄存器的加法

add <Xd|SP>, <Xn|SP>, {, {#{amount}}}

这条指令是把Rn寄存器做一些扩展,例如左移操作,然后再加上 <Xn|SP>寄存器的值,把结果写道<Xd|SP>寄存器

  • Xd|SP, 目标寄存器,可以是通用寄存器或栈地址寄存器。
  • Xn|SP,源寄存器,可以是通用寄存器或栈地址寄存器。
  • R:表示第2个操作数是32位还是64位通用操作器。

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

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老衲不依

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值