| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> ARMv7和ARMv8中关于内存访问的汇编指令总结对比 -> 正文阅读 |
|
[系统运维]ARMv7和ARMv8中关于内存访问的汇编指令总结对比 |
ARMv7和ARMv8中关于内存访问的汇编指令总结对比文章目录前言ARM处理器是精简指令集计算机 (Reduced Instruction Set Computer,RISC) 处理器,复杂指令集计算机(Complex Instruction Set Computer,CISC)处理器,比如X86,具有丰富的指令集,能够用单个指令执行复杂的操作。这种处理器通常具有大量的内部逻辑,用于将机器指令解码为内部操作序列(微码,microcode )。相比之下,RISC架构具有较少数量的更通用的指令,这些指令可使用更少的晶体管执行,从而节省生产成本并且更节能。与其他RISC架构一样,ARM的内核具有大量通用寄存器,许多指令在单个周期(cycle)内执行。它具有简单的寻址模式,其中所有加载/存储的地址都可以从寄存器内容和指令字段中确定。 ARM 指令集通常被认为是简单、合乎逻辑和高效的。但是,它不能直接在内存上执行数据处理操作:比如,要递增某个内存位置中的值,必须先将该值加载到 ARM 寄存器,在寄存器中递增,并且需要第三条指令才能将更新的值再写回内存当中。 与 x86(但与 68K 不同)一样,ARM 指令通常采用两个或三个操作数格式,在大多数情况下,第一个操作数指定结果的目标(多加载/多存储例外)。相比之下,68K 将目标作为最后一个操作数。对于 ARM 指令,通常对哪些寄存器可用作操作数没有限制。下面给出了不同汇编语言之间差异的风格:
ARMv7和ARMv8都是 加载/存储 架构,这意味着它们不能直接对内存中的数据进行处理, 只有加载和存储指令才能访问内存。所以需要通过通用寄存器(GPR),先将内存中的数据加载到寄存器中,处理完成后,再存储回内存中。此外,ARMv8具有A64模式和A32模式,也就是64bits模式和32bits模式,32bits模式的指令集和ARMv7的指令集几乎一致。所以在学习ARMv7指令集的同时,也是相当于在学习ARMv8的A32模式的指令集。 笔者最近在做ARMv8下的内存拷贝实验,需要在A64模式和A32模式下进行,所以对ARMv7和ARMv8下的内存访问汇编指令进行总结和对比。 在文章开始前有必要对ARMv7和ARMv8寄存器的位宽进行简单说明。一般情况下,ARMv8中用X表示A64下的64bits寄存器,W则是32bits寄存器。此外还有 B、H、S、D 以及 Q 寄存器,它们的位宽如下图所示。在ARMv7中通用寄存器则是用R表示,它与ARMv8下的W是一致的。 ARMv7下的内存访问指令ARM 内核仅在寄存器上执行算术逻辑单元 (ALU) 操作。唯一支持的内存操作是加载(LOAD,LDR,将数据从内存读取到寄存器)或存储(STORE,STR,将数据从寄存器写入内存)。 用户可以通过在指令中附加 B 表示 Byte(8位)、H 表示Halfword ,半字(16位)、或 D表示doubleword ,双字(64 位),来指定加载或存储传输的大小,例如 LDRB。仅对于加载LDR,还可以使用额外的 S 来指示有符号字节或半字(SB 表示有符号字节,SH 表示有符号半字)。附加的类型可以是:
这种方法可能很有用,因为如果将 8 位或 16 位加载到 32 位寄存器中,则必须决定如何处理寄存器中的符号位。无符号数字是零扩展的(即寄存器最重要的16或24位设置为零),但对于有符号数字,必须将符号位(字节的位[7]或半字的位[15])复制到寄存器的前16位(或24位)。 寻址模式LDR和STR有多种寻址模式,如下示例:
方式(1)为寄存器寻址(Register addressing)方式,从R1中保存的数据为地址,将该地址上的数据加载到R0。 方式(2)和(3)为前下标寻址(Pre-indexed addressing),在内存访问之前添加基址寄存器的偏移量,基本的形式为: 方式(4)为前下标寻址+写回(Pre-indexed with write-back),它指令的最后使用了一个感叹号 方式(5)为后下标+写回(Post-index with write-back),偏移量在方括号之外,表示先进行数据加载,即先从R1处加载,然后更新 R1为R1 + 32。 多加载/存储多加载和存储(LDM/STM)使连续的字(word,4字节)可以从存储器中读取或写入。这些对于堆栈操作和内存复制非常有用。只有word可以以这种方式操作,并且必须使用与word对齐的地址。如下指令:
操作数是一个基址寄存器(带有可选的 !表示基址寄存器的回写,即更新基址寄存器),大括号之间有一个寄存器列表。寄存器列表以逗号分隔,连字符 如上示例指令,大括号内有R0,R1,R2,R3和R12五个目标寄存器,基址寄存器为R10,则该指令会进行如下操作:
由于加了 该指令还必须指定如何从基址寄存器 Rd 中继续操作。有四种情况:
这些也可以使用后缀(FD,FA,ED和EA),这些后缀是从栈stack的角度工作的,ARM7支持四种堆栈模式:满递减(FD)、满递增(FA)、空递减(ED)、空递增(EA),并指定栈指针是指向栈的完整(Full)顶部还是空(Empty)的顶部,以及栈在内存中是上升(Ascend)还是下降(Descend)。
按照惯例,只有(FD) 选项是用于基于 ARM 处理器系统中的栈。这意味着栈指针指向栈内存中最后填充的位置,并且将随着压入到栈的每个新数据项而递减。
下图展示了将R1和R2压入一个FD栈中,在执行 STMFD (PUSH) 指令之前,栈指针SP指向栈中最后一个占用的word。指令完成后,栈指针SP递减 8(两个word),两个寄存器的内容已写入内存,由于内存地址是向上递增,并且按照编号最低的寄存器将写入最低的内存地址的规则,所以R2在R1的上方。 ARMv8下的内存访问指令与所有以前的 ARM 处理器一样,ARMv8 架构是加载/存储架构。程序必须指定地址、要传输的数据的大小以及源或目标寄存器。ARMv8还有其他加载和存储指令,提供了更多选项,例如非临时加载/存储(non-temporal Load/Store )、加载/存储独占项(Load/Store exclusives),和获取/释放(Acquire/Release)。 加载和存储指令格式ARMv8中的加载和存储指令和ARMv7中的相同:
当加载整数寄存器时,可选择数据大小进行加载,例如,要加载小于指定寄存器值的大小,可将以下后缀之一追加到 LDR 指令中:
还有未缩放的偏移形式,例如LDUR,程序员通常不需要显式使用 LDUR形式,因为大多数汇编程序可以根据使用的偏移量选择适当的版本。 用户不需要指定对 X 寄存器的零扩展加载,因为写入 W 寄存器实际上为零会扩展到整个寄存器宽度。 下图为指令 下图为指令 下图为指令 此外,如果要存储的数据大小可能小于寄存器,可以通过向 STR 添加 B 或 H 后缀来指定此项。 浮点和 NEON 标量加载和存储加载和存储指令还可以访问浮点/NEON 寄存器。大小仅由正在加载或存储的寄存器确定,寄存器可以是任何 B、H、S、D 或 Q 寄存器。并且浮点和标量 NEON 的加载和存储,使用与整数寄存器加载和存储相同的寻址模式。 需要注意的是,符号扩展(sign-extension)并不支持加载到 FP/SIMD 寄存器中。此类加载的地址仍使用通用寄存器指定。比如:
D寄存器也为64位(doubleword ,8字节),上述指令会将地址X0+X1上的数据加载到D0寄存器当中。 指定加载或存储指令的地址A64 可用的寻址模式与 A32 和 T32 中的寻址模式类似。有一些额外的限制以及一些新功能,但对于熟悉A32或T32的人来说,A64可用的寻址模式并不陌生。 在 A64 中,地址操作数的基本寄存器必须始终是 X 寄存器。但是,有几条指令支持零扩展或符号扩展,因此可以提供 32 位偏移量作为 W 寄存器。 偏移模式偏移寻址模式将立即数或可选的修改的寄存器值添加到 64 位基址寄存器以生成地址。
通常,在指定移位或扩展选项时,移位量可以是访问大小的 0(默认值)或 log2(以字节为单位)(以便 Rn << 将 Rn 乘以访问大小)。 以下是一段C程序的示例:
索引模式索引模式类似于偏移模式,但它们会更新基址寄存器。语法与 A32 和 T32 中的语法相同,但操作集的限制性更强。通常,只能为索引模式提供立即数偏移量。同ARMv7一样,有两种变体:前索引模式(在访问内存之前应用偏移量)和后索引模式(在访问内存后应用偏移量):
C语言示例:
访问多个内存位置A64 不包括 A32 和 T32 代码可用的多加载 (LDM) 或多存储(STM) 指令。 在 A64 代码中,有成对加载(Load Pair ,LDP) 和存储对(Store Pair,STP)。与 A32中的LDRD 和 STRD 指令不同,LDP/STP可以读取或写入任何两个整数寄存器。数据被读取或写入到相邻的内存位置或从相邻的内存位置写入。为这些指令提供的寻址模式选项比其他内存访问指令更具限制性。 LDP 和 STP 指令只能使用具有缩放的 7 位有符号立即数的基址寄存器,并具有可选的预增量或后增量。与 32 位 LDRD 和 STRD 不同,LDP 和 STP 可以进行未对齐的访问。
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 17:32:38- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |