基本概念

ARM 体系结构是一种硬件规范,主要用来约定指令集,为了降低客户基于 ARM 体系结构开发处理器的难度,ARM 根据不同的应用开发需求开发出箭筒体系结构的处理器 IP,然后授权给客户,比如 ARMv8 体系结构开发出的处理器 IP 有:Cortex-A53, Cortex-A55, Cortex-A72, Cortex-A73,.

ARMv8 体系结构特性

  • 提供超过 4G 物理内存空间
  • 具有 64 位宽的虚拟地址空间,32 位宽的虚拟地址空间只能供 4GB 大小的虚拟空间访问,限制了桌面操作系统和服务器的应用。

ARMv8 体系结构包含多少个通用寄存器?

  • 提供 31 个 64 位宽的通用寄存器。分别是 X0~X30 。可以减少对栈的访问,从而提高性能。
  • 提供 16KB 和 64KB 的页面,有助于降低 TLB 的未命中率。
  • 具有全新的异常处理模型,降低操作系统和虚拟化的实现复杂度。

A64 指令集和 A32 指令集是不兼容的,它们是完全不一样的指令集,它们的指令编码时不一样的,另外 A64 指令集的指令宽度是 32 位,而不是 64 位。

ARMv8 处理器支持两种执行状态, AArch64 和 AArch32 ,当处理器在 AArch64 状态时,运行 A64 指令集,而处理器在 AArch32 状态时,运行 A32 和 T32 指令集,

AArch64 执行状态包含多少个异常等级?分页有什么作用?

AArch64 执行状态的异常等级确定了处理器当前运行的特权级别,类似特权等级。

  • EL0: 用户特权,用于运行普通用户程序
  • EL1: 系统特权,通常用于操作系统内核,如果系统使能了虚拟化扩展,运行虚拟机操作系统内核。
  • EL2: 运行虚拟化扩展的虚拟机监控器
  • EL3: 运行安全世界中的安全监控器

ARMv8 支持的数据宽度

  • 字节(byte): 8位
  • 半字(halfword): 16位
  • 字(word):32位
  • 双字(doubleword): 64位
  • 四字(quadword): 128位

ARMv8 寄存器

31个通用寄存器

在 AArch64 状态下,使用 X(X0、X30) 表示 64 位通用寄存器,另外可以使用 W 来表示低 32 位的数据,如 W0 表示 X0 寄存器的低 32 位数据, W1 表示 X1 寄存器的低 32 位数据。

处理器的状态

AArch64 体系结构使用 PSTATE 寄存器来保存当前处理器状态

条件标志位: N(负位) Z(零位) C(进位) V(溢出标志位)

特殊寄存器

  • 零寄存器

ARMv8 有两个零寄存器,这些寄存器的内容全是 0 ,可以用作源寄存器,也可以用作目标寄存器。WZR 是32位的零寄存器,XZR 是64位的零寄存器。

  • PC 指针寄存器

通常用来指向当前运行指令的下一条指令的地址,用于控制程序的运行顺序。

  • SP 寄存器

ARMv8 支持 4 个异常等级,每个异常等级都有一个 SP 寄存器

- SP_EL0: EL0 下的 SP 寄存器(最低等级)
- SP_EL1: EL1 下的 SP 寄存器
- SP_EL2: EL2 下的 SP 寄存器
- SP_EL3: EL3 下的 SP 寄存器

当处理器运行在 EL0 时,它只能访问 SP_EL0 ,不能访问其他高级的 SP 寄存器。

  • 备份程序状态寄存器

当我们运行一个异常处理程序时,处理器的备份程序会保存到备份程序状态寄存器(SPSR)里面,当异常要发生时,处理器会把 PSTATE 寄存器的值暂时保存到 SPSR 里,当异常处理完成返回时,再把 SPSR 寄存器的值恢复到 PSTATE 寄存器。

  • ELR

存放异常返回地址

  • CurrentEL 寄存器

表示 PSTATE 寄存器中的 EL 字段(当前异常等级),该寄存器保存了当前的异常等级,可以使用 MRS 指令读取当前异常等级。

  • DAIF 寄存器

表示 PSTATE 寄存器中的{D, A, I, F}字段(异常掩码标志位)。

  • SPSel 寄存器

表示 PSTATE 寄存器中的 SP 字段,用于选择某个 SP_ELn 寄存器。

  • PAN 寄存器

表示 PSTATE 寄存器中 PAN(特权禁止访问)字段。可以通过 MSR 和 MRS 指令来设置 PAN 寄存器,主要是为了防止内核态恶意访问用户态内存而新增的,所以需要调用内核提供的结构,比如 copy_from_user() 或者 copy_to_user() 函数。

  • 0: 表示在内核态可以访问用户态内存
  • 1: 表示在内核态访问用户态内存会触发一个访问权限异常
  • UAO 寄存器

表示 PSTAYE 寄存器中的 UAO (用户访问覆盖) 字段。同样可以使用 MSR 和 MRS 指令来设置,

UAO=1 时,表示在 EL1 和 EL2 执行非特权指令(例如 LDTR 和 STTR)的效果和特权指令(例如 LDR、STR)是一样的。

  • NACV 寄存器

表示 PSTATE 寄存器中的{N, Z, C, V}字段 (条件标志位)。

系统寄存器

系统寄存器支持不同的异常等级的访问,通常系统寄存器会使用“Reg_ELn"的方式来表示

  • Reg_EL1: 处理器处于 EL1、EL2 和 EL3 时可以访问该寄存器
  • Reg_EL2: 处理器处于 EL2 和 EL3 时可以访问该寄存器

除了 CTR_EL0 ,大部分系统寄存器不支持处理器处于 EL0 时范访问。


加载与存储指令

在 ARMv8 体系结构下,所以的数据都需要在通用寄存器中完成,而不能直接在内存中完成,因此,首先把待处理的数据从内存加载到通用寄存器,再进行数据处理,最后再把结果写入到内存中。

  • LDR 内存加载指令
  • STR 存储指令
LDR 目标基础漆,<存储器地址>   //把存储器地址中的数据加载到目标寄存器中
STR 源寄存器, <存储器地址>    //把源寄存器的数据存储到存储器中

基于基地址的寻址模式

基地址模式

  • 使用寄存器的值来表示一个地址
  • 把这个内存地址的内容加载到通用寄存器中
LDR Xt, [Xn]  //把 Xn 寄存器中的内容作为内存地址,并把这个内存地址的内容加载到 Xt 寄存器中STR xt, [Xn]  //把 Xt 寄存器中的内容存储到 Xn 寄存器的内存地址中

基地址+偏移地址模式

  • 基地址 + 偏移地址 = 内存地址
  • 把这个内存地址的值加载到通用寄存器中
LDR Xt, [Xn. #offset] //Xn寄存器中的内容加一个偏移量(offset 必须是 8 的倍数),以相加的结果作为内存地址,加载这个内存地址的内容到 Xt 寄存器中。STR Xt,[Xn. #offset]  //把 Xt 寄存器的值存储到以 Xn 寄存器的值加一个偏移量表示的内存地址中

基地址扩展模式

LDR <Xt>, [<Xn>, (<Xm>) {, <extend> {<amount>}}]STR <Xt>, [<Xn>, (<Xm>) {, <extend> {<amount>}}]
  • Xt: 目标寄存器
  • Xn:基地址寄存器
  • Xm,偏移的寄存器
  • extend:扩展/移位 指示符,默认是 LSL(逻辑左移),UXTW(从寄存器中提取32位,其余高位填充0),SXTW(从寄存器中提取32位,其余高位须有符号扩展),SXTX(从寄存器中提取64位数据)
  • amount:索引偏移量,当 extend 不是 LSL 时有效
LDR X0, [X1, X2 LSL #3]   //内存地址为 X1 寄存器的值(X2 寄存器的值<<3),加载这个内存地址的值到 X0 寄存器LDR X0, [X1, W2, SXTW, #3]  //先对 W2 的值做有效符号扩展,然后左移 3 位,和 X1 寄存器的值相加后得到内存地址,加载这个内存地址的值到 X0 寄存器

变基模式

  • 前变基模式:先更新偏移量地址,后访问内存地址
  • 后变基模式:先访问内存地址,后更新偏移量地址
前变基模式

内存加载指令

LDR Xt, [<Xn|SP>, #<simm>]
  • 首先,Xn/SP 寄存器的值 = Xn/SP 寄存器的值 + simm
  • 以新的 Xn/SP 寄存器的值作为内存地址,并加载这个内存地址的值到 Xt 寄存器

存储指令

STR Xt, [<Xn|SP>, #<simm>]
  • 首先,Xn/SP 寄存器的值 = Xn/SP 寄存器的值 + simm
  • 以新的 Xn/SP 寄存器的值作为内存地址,然后把 Xt 寄存器的值存储到这个内存单元中
后变基模式

内存加载指令

LDR Xt, [<Xn|SP>, #<simm>]
  • 首先,加载 Xn/SP 寄存器的值到 Xt 寄存器
  • 然后更新,Xn/SP 寄存器的值 = Xn/SP 寄存器的值 + simm

存储指令

STR Xt, [<Xn|SP>, $<simm>]
  • 首先,将 Xt 寄存器的值加载到 Xn/SP 寄存器的值为内存地址的内存单元中
  • 然后更新,Xn/SP 寄存器的值 = Xn/SP 寄存器的值 + simm

易混例子

//(X1的值不变)
LDR X0, [X1, #8]    //内存地址为 X1的值+8,加载此内存地址的值到 X0 寄存器//(X1的值改变)
LDR X0, [X1, #8]!    //前变基模式,先更新 X1 寄存器的值 = X1 寄存器的值 + 8,然后将 X0 的值加载到新的 X1 寄存器值对应的内存单元中//(X1的值改变)
LDR X0, [X1], #8     //后变基模式,以 X1 的值作为内存地址,加载该内存地址的值到 X0 中,然后更新 X1 寄存器的值 = X1 寄存器的值 + 8STP X0, X1, [SP, #-16]!   //把 X0 和 X1 寄存器的值压回栈中LDP X0, X1, [SP], #16     //把 X0 和 X1 寄存器的值抬出栈

PC相对地址模式

可以使用 lable 标签来标记代码片段,LDR 指令可以访问标签的地址

LDR Xt <label>

读取 label 所在内存地址的内存到 Xt 寄存器中,但是这个 label 必须在当前 PC地址后 1MB 的范围内,否则会报错。

my_data:.word 0x40
ldr x0, my_data  // 最终 X0 寄存器的值为 0x40

假设当前 PC 的地址是 0x806E4, 那么这条 LDR 指令读取 0x806E4 + 0x20 地址的内容到 X6 寄存器中。

#define MY_LABEL 0x20
ldr x6, MY_LABEL// error 0x100000 的偏移量超超出 1MB 范围
#define MY_LABEL_1 0x100000
ldr x6, MY_LABEL_1

LDR 伪指令

伪指令是对汇编器发出的指令,伪指令可以分解为几条指令的集合。

LDR 指令既可以在大范围内加载地址的伪指令,也可以是普通的内存访问指令。当第二个参数前面有 “=” 时,表示伪指令,否则表示普通的内存访问指令。

LDR Xt, =<label>  //把label标记的地址加载到 Xt 寄存器#define MY_LABEL 0x20
ldr x6, =MY_LABEL
//这里的 ldr 是一条伪指令,它会把 MY_LABEL 宏的值加载到 X6 寄存器中my_data1:.quad 0x8
ldr x5, =my_data1
ldr x6, [x5]
//my_data1 定义了一个数据为 0x8,第一条 LDR 是伪指令,它把 my_data1 对应的地址加载到 X5 寄存器中
//第二条 LDR 是普通的内存访问指令,以 X5 寄存器的值为内存地址,加载这个地址的内容到 X6 中

简而言之,伪指令是把地址给目标寄存器,而普通指令是把地址的值给目标指令

linux 内核的 head.S 中,启动 MMU 之后就使用这个特性实现从运行地址定位到链接地址。

secondary_startup:   bl  __cpu_secondary_check52bitvabl  __cpu_setup  // initialise processorbl  __enable_mmu  ldr x8, =__secondary_switched  //跳转到__secondary_switched函数,该函数的地址是链接地址(内核空间的虚拟地址),// 在这之前CPU运行在实际物理地址上,实现了地址重定位功能br  x8
ENDPROC(secondary_startup)

ARM64体系结构编程1-加载与存储指令相关推荐

  1. 单寄存器加载与存储指令

    这种指令用于把单一的数  传入或者传出一个寄存器.支持的数据类型有字(32 位 ) .半字(16 位)  和字节.常用的单寄存器加载与存储指令包括: LDR/STR            字数据加载/ ...

  2. 深入理解Java虚拟机——加载和存储指令

    目录 一.加载和存储指令的概述 二.加载和存储指令的内容 三.加载和存储指令的示例 一.加载和存储指令的概述 加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输. 二.加载和存储指令的 ...

  3. ARMv8体系结构基础03:加载和存储指令

    目录 1 A64指令集概述 1.1 A64指令集特征 1.1.1 指令定长 1.1.2 可使用64位指针 1.1.3 使用一致的编码结构(consistent encoding scheme) 1.1 ...

  4. 《利用python进行数据分析》——第6章 数据加载、存储与文件格式——读书笔记

    第6章 数据加载.存储与文件格式 6.1 读写文本格式的数据 pandas提供了一些用于将表格型数据读取为DataFrame对象的函数. 其中read_csv和read_talbe用得最多 panda ...

  5. 借由ARM CORTEX-M芯片分析C程序加载和存储模型

    https://zhuanlan.zhihu.com/p/22048373 写文章 借由ARM CORTEX-M芯片分析C程序加载和存储模型 王小军 1 年前 阿军最近在忙着血氧手环嵌入式系统的技术预 ...

  6. Python之pandas数据加载、存储

    Python之pandas数据加载.存储 0. 输入与输出大致可分为三类: 0.1 读取文本文件和其他更好效的磁盘存储格式 2.2 使用数据库中的数据 0.3 利用Web API操作网络资源 1. 读 ...

  7. python观察日志(part28)--数据的加载与存储

    学习笔记,仅供参考,有错必究 参考文献:编码问题:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb3 in position; 数据的加载 ...

  8. xp系统打开计算机配置文件,浅析xp系统如何解决开机出现“Windows不能加载本地存储的配置文件“...

    对于打开电脑出现"Windows不能加载本地存储的配置文件"的问题,之前小编有跟大家分享通过用户配置文件设置来解决这个问题.可是有部分xp系统用户反馈设置完之后问题还是没有得到解决 ...

  9. 《利用Python进行数据分析·第2版》第6章 数据加载、存储与文件格式

    第1章 准备工作 第2章 Python语法基础,IPython和Jupyter 第3章 Python的数据结构.函数和文件 第4章 NumPy基础:数组和矢量计算 第5章 pandas入门 第6章 数 ...

  10. python数据分析实例_python数据分析实例3-商铺数据加载及存储

    商铺数据加载及存储 在data文件夹存放有商铺数据.csv文件,路径:path = '../data/商铺数据.csv' 要求: 1.成功读取"商铺数据.csv"文件,并展示打印出 ...

最新文章

  1. android释放acitity内存,Android 内存泄漏分析与解决方法
  2. 关于Cocoa Pods的升级安装和使用说明
  3. 最火的前端开发框架Bootstrap使用教程学习!
  4. java中的异常及其处理
  5. UA MATH564 概率论VI 数理统计基础3 卡方分布的正态近似
  6. NAT的全然分析及其UDP穿透的全然解决方式
  7. Java四大函数式接口
  8. OpenGL版本与OpenGL扩展机制
  9. 【Excel】统计不重复数据的个数,设置单元格不允许出现重复数据
  10. 程序员面试题100题第28题——全排列
  11. 决策报表服务器安装_无服务器流处理如何使决策更加容易
  12. fullcalendar自定义搜索框_??这款搜索神器,真希望你早点使用,越早越好!有效提升学习和生活的幸福感!
  13. Intellij IDEA 配置
  14. ROS 控制台:rqt_console 因为比较简单。。。
  15. java 解析/操作 xml 几种常用方式 xml的增加/删除/修改
  16. L1-066 猫是液体 (5 分)-PAT 团体程序设计天梯赛 GPLT
  17. notepad格式化html代码快捷键,Notepad++中代码格式化插件NppAStyle使用介绍
  18. 计算机显示器刷新率怎么调,电脑显示器刷新率怎么调
  19. 世 界 上 最 经 典 的 25 句 话 (带卡通图说明)
  20. MATLAB | 绘制复指数函数 y = exp(j*w*n)的三维图像

热门文章

  1. java开发软件Myeclipse汉化教程
  2. Mac好用的RSS阅读器Reeder使用方法
  3. cass等距离等分线段的命令键_cad等分快捷键(cad等分线段快捷键命令)
  4. bean的生命周期(最全最细讲解)
  5. 双层PDF—OCR文字识别系统
  6. winform安装包签名
  7. 药品信息管理系统php,医药行业信息化管理系统
  8. 工具介绍(3)- TS 视频文件分析工具神器
  9. 明解c语言答案第11章,《明解C语言第3版.入门篇》练习代码 第11章
  10. [unity3d插件]插件效果以及下载