返回
Featured image of post ARMv8基础

ARMv8基础

一拳打碎v8区

ARMv8

建议关闭暗色模式阅读

ARMv8官方文档

Fundamentals of ARMv8

异常等级(Exception levels)

在ARMv8中,执行发生在4个执行级别之一。执行级别提供了适用于ARMv8体系结构的所有操作状态的软件执行权限的逻辑分离。它类似于并支持计算机科学中常见的分层保护域的概念。

  • EL0 普通用户应用程序
  • EL1 操作系统内核通常被描述为特权(privileged)
  • EL2 虚拟机管理程序
  • EL3 低级固件,包括安全监视器

异常等级
异常等级

安全状态(security states)

ARMv8提供了两种安装状态:保护(Secure)和非保护(Non-secure),非保护状态又被称为 Normal World,具体见下图:

安全状态
安全状态

关于图中各部分具体内容见ARM文档

执行状态(Execution states)

ARMv8定义了两种执行状态:AArch64 和 AArch32

AArch32 state
The ARM 32-bit execution state that uses 32-bit general-purpose registers, and a 32-bit Program Counter (PC), Stack Pointer (SP), and Link Register (LR). AArch32 execution state provides a choice of two instruction sets, A32 and T32, previously called the ARM and Thumb instruction sets.
AArch64 state
The ARM 64-bit execution state that uses 64-bit general-purpose registers, and a 64-bit Program Counter (PC), Stack Pointer (SP), and Exception Link Registers (ELR). AArch64 execution state provides a single instruction set, A64.

ARMv8寄存器

通用寄存器

AArch64状态提供了 $31*64bit$通用寄存器,所用时间和异常级别均可访问。每一个寄存器都是64bit,编号X0 - X30.

通用寄存器
通用寄存器
每一个64bit通用寄存器(X0-X30)同时具有32bit形式((W0-W30),如下图:
寄存器格式
寄存器格式
(不想翻译了,开贴)
The 32-bit W register forms the lower half of the corresponding 64-bit X register. That is, W0 maps onto the lower word of X0, and W1 maps onto the lower word of X1.

Reads from W registers disregard the higher 32 bits of the corresponding X register and leave them unchanged. Writes to W registers set the higher 32 bits of the X register to zero. That is, writing 0xFFFFFFFF into W0 sets X0 to 0x00000000FFFFFFFF.

(一句话说就是W寄存器是X寄存器的低32位)

特殊寄存器

AArch64提供以下特殊寄存器:

特殊寄存器
特殊寄存器

Note There is no register called X31 or W31. Many instructions are encoded such that the number 31 represents the zero register, ZR (WZR/XZR). There is also a restricted group of instructions where one or more of the arguments are encoded such that number 31 represents the Stack Pointer (SP).

当访问零寄存器时,所有写入被忽略,所以读取均返回0。注意:SP寄存器前没有X。

Name Size Description
WZR 32bits Zero register
XZR 64bits Zero register
WSP 32bits Current stack pointer
SP 64bits Current stack pointer
PC 64bits Program counter

在AArch64模式下,异常返回状态(exception return state)被保存每个异常等级的下列专用寄存器中:

  • Exception Link Register (ELR).
  • Saved Processor State Register (SPSR).

每个异常级别都有一个专用的SP,但它不用于保存返回状态。

EL0 EL1 EL2 EL3
Stack Pointer (SP) SP_EL0 SP_EL1 SP_EL2 SP_EL3
Exception Link Register (ELR) ELR_EL1 ELR_EL2 ELR_EL3
Saved Process Status Register (SPSR) SPSR_EL1 SPSR_EL2 SPSR_EL3

Zero register

当用作源寄存器时,零寄存器读取为零,当用作目标寄存器时,零寄存器丢弃结果。你可以在大多数指令中使用零寄存器,但不是所有指令。

Stack pointer

在ARMv8架构中,堆栈指针的选择在某种程度上与异常级别分开. 默认情况下,当前异常级别为ELn则选择SP_ELn。例如,异常等级为EL1则选择SP_EL1. 每一个异常状态均有对应的SP寄存器,SP_EL0, SP_EL1, SP_EL2, and SP_EL3. 当在AArch64中处于除EL0之外的异常级别时,处理器可以使用任何一种:

  • A dedicated 64-bit stack pointer associated with that Exception level (SP_ELn).
  • The stack pointer associated with EL0 (SP_EL0).
    EL0只能访问SP_EL0

注意 SP不能被大多数指令引用 。然而,一些形式的算术指令,例如ADD指令,可以读写当前堆栈指针来调整函数中的堆栈指针。例如:

 ADD SP, SP, #0x10      // Adjust SP to be 0x10 bytes before its current value

Program Counter

ARMv8中删除了对PC的直接访问。作为专用寄存器,PC永远不被允许访问。它的使用是隐含的某些指令,例如PC相对负载和地址生成。不能将PC指定为数据处理指令或加载指令的目的寄存器。

异常链接寄存器保存异常返回地址。

Saved Process Status Register(程序状态寄存器)

当出现异常时,处理器状态存储在相关的已保存程序状态寄存器(SPSR)中,类似于ARMv7中的CPSR。SPSR在接受异常之前保存PSTATE的值,并用于在执行异常返回时恢复PSTATE的值。

程序状态寄存器
程序状态寄存器

各位含义如下:

N

Negative result (N flag).负结果

Z

Zero result (Z flag). 0结果

C

Carry out (C flag). 进位(maybe)

V

Overflow (V flag). 溢出

SS

Software Step. Indicates whether software step was enabled when an exception was taken. 指示在发生异常时是否启用软件步骤.

IL

Illegal Execution State bit. Shows the value of PSTATE.IL immediately before the exception was taken. 如何计算PSTATE的值。在异常taken之前。

D

Process state Debug mask. Indicates whether debug exceptions from watchpoint, breakpoint, and software step debug events that are targeted at the Exception level the exception occurred in were masked or not. 指示来自观察点、断点和软件步骤调试事件的调试异常是否被屏蔽,这些事件的目标是发生异常的Exception级别。

A

SError (System Error) mask bit.

I

IRQ mask bit. IRQ:中断请求,通常用于外部中断。

F

FIQ mask bit. FIQ:一种中断类型(以前是快速中断)。

M[4]

Execution state that the exception was taken from. A value of 0 indicates AArch64. 执行状态,从其中获取异常。0表示“AArch64”。

M[3:0]

Mode or Exception level that an exception was taken from.

在ARMv8中,SPSR取决于异常级别。如果在EL1中产生异常,则使用SPSR EL1。如果在EL2中产生异常,则使用SPSR EL2;如果在EL3中产生异常,则使用SPSR EL3。核心在接受异常时填充SPSR。

Processor state(处理机状态)

在AArch64中,传统CPSR的组件作为可以独立访问的字段提供。这些统称为Processor State(PSTATE)。
AArch64的处理器状态(PSTATE)字段有以下定义:

Name Description
N Negative condition flag.
Z Zero condition flag.
C Carry condition flag.
V oVerflow condition flag.
D Debug mask bit.
A SError mask bit.
I IRQ mask bit.
F FIQ mask bit.
SS Software Step bit.
IL Illegal execution state bit.
EL(2) Exception level.
nRW Execution state [0=64bit] [1=32bit]
SP Stack Pointer selector. [0=SP_EL0] [1=SP_ELn]

在AArch64中,通过执行ERET指令从异常返回,这将导致SPSR\_ELn被复制到PSTATE中。这将恢复ALU标志、执行状态、异常级别和处理器分支。从这里开始,从ELR_ELn中的地址继续执行。
PSTATE{N, Z, C, V}字段可以在EL0处访问。所有其他PSTATE字段都可以在EL1或更高级别执行,而在EL0时未定义。

System registers

在AArch64中,系统配置通过系统寄存器进行控制,并使用MSRMRS指令进行访问。这与ARMv7-A不同,在ARMv7-A中,这些寄存器通常通过协处理器15 (CP15)操作来访问。寄存器的名称告诉您可以从哪里访问它的最低Exception级别。

例如:

  • TTBR0_EL1 is accessible from EL1, EL2, and EL3.
  • TTBR0_EL2 is accessible from EL2 and EL3.

后缀为ELn的寄存器在某些或所有级别中都有一个单独的存储副本,但通常不是EL0。很少有系统寄存器可以从EL0访问.尽管Cache Type Register (CTR EL0)是一个可以访问的例子。

访问系统寄存器的代码采用以下形式:

MRS  x0, TTBR0_EL1          // Move TTBR0_EL1 into x0

MSR  TTBR0_EL1, x0          // Move x0 into TTBR0_EL1

更多System registers参见ARMv8文档

The system control register

系统控制寄存器(SCTLR)是一个寄存器,它控制标准内存、系统功能,并为核心中实现的功能提供状态信息。具体内容见The system control register

A64指令集

注意 ARMv8文档有一大章讲A64和A32指令集区别,感兴趣的自己查看A32和A64的区别

指令助记符

A64汇编语言重载指令助记符,并根据操作数寄存器名区分指令的不同形式。例如,下面的ADD指令都有不同的编码,但你只需要记住一个助记符,汇编器就会根据操作数自动选择正确的编码。

ADD W0, W1, W2             // add 32-bit registers
ADD X0, X1, X2             // add 64-bit registers
ADD X0, X1, W2, SXTW       // add sign extended 32-bit register to 64-bit extended 
ADD X0, X1, #42            // add immediate to 64-bit register
ADD V0.8H, V1.8H, V2.8H    // NEON 16-bit add, in each of 8 lanes

数据处理指令

这些是处理器的基本算术和逻辑操作,并对通用寄存器中的值或寄存器和直接值进行操作。乘法和除法 指令可以被认为是这些指令的特殊情况。

数据处理指令大多使用一个目标寄存器和两个源操作数。一般格式可以认为是指令,后面跟着操作数,如下所示:

  Instruction Rd, Rn, Operand2

第二个操作数可以是一个寄存器、一个变址寄存器或一个立即值。R的使用表明它可以是X寄存器或W寄存器。
数据处理操作包括:

  • 算术和逻辑操作
  • 移动和移位操作。
  • 符号和零扩展的说明。
  • 位和位域操作。
  • 条件比较和数据处理。

Arithmetic and logical operations

Type Instructions
Arithmetic ADD, SUB, ADC, SBC, NEG
Logical AND, BIC, ORR, ORN, EOR, EON
Comparison CMP, CMN, TST
Move MOV, MVN

有些指令还有S后缀,表示该指令设置了标志。在表6.1中的指令中,包括ADDSSUBSADCSSBCSANDSBICS。还有其他标志设置指令,尤其是CMPCMNTST,但这些指令不带S后缀。

ADCSBC表示带进位的加减法。

ADC{S}: Rd = Rn + Rm + C
SBC{S}: Rd = Rn - Rm - 1 + C
ADD W0, W1, W2, LSL #3                 // W0 = W1 + (W2 << 3)
SUBS X0, X4, X3, ASR #2                // X0 = X4 - (X3 >> 2), set flags
MOV X0, X1                             // Copy X1 to X0
CMP W3, W4                             // Set flags based on W3 - W4
ADD W0, W5, #27                        // W0 = W5 + 27

BIC(逐位清除)指令对目标寄存器之后的第一个寄存器与第二个操作数的值的相反数执行AND运算。例如,要清除寄存器X0的[11]位,可以使用:

MOV X1, #0x800
BIC X0, X0, X1

ORN and EON perform an OR or EOR respectively with a bitwise-NOT of the second operand.

比较指令只修改标志,没有其他效果。 这些指令的 立即数的范围是12bit ,并且这个值可以向左移动12位。

Multiply and divide instructions

乘除指令太复杂了,感兴趣的可以自己看文档Multiply and divide instructions

这里给出简单示例:

MUL X0, X1, X2           // X0 = X1 * X2
MNEG X0, X1, X2           // X0 = -(X1 * X2)
UDIV W0, W1, W2          // W0 = W1 / W2 (unsigned, 32-bit divide)
SDIV X0, X1, X2          // X0 = X1 / X2 (signed, 64-bit divide)

溢出和被零除法不会被限制:

  • 任何整数除以零返回零。
  • Overflow can only occur in SDIV:
    • INT_MIN / -1 returns INT_MIN, where INT_MIN is the smallest negative number that can be encoded in the registers used for the operation. The result is always rounded towards zero, as in most C/C++ dialects.

Shift operations

有以下移位操作:

  • Logical Shift Left逻辑左移 (LSL). The LSL instruction performs multiplication by a power of 2.
  • Logical Shift Right逻辑右移 (LSR). The LSR instruction performs division by a power of 2.
  • Arithmetic Shift Right算数右移 (ASR). The ASR instruction performs division by a power of 2, preserving the sign bit.
  • Rotate right 循环右移(ROR). The ROR instruction performs a bitwise rotation, wrapping the bits rotated from the LSB into the MSB.

被移位的寄存器可以是 32 位或 64 位。 要移位的量可以指定为立即数,值最多寄存器位数大小减一,或者由一个寄存器指定,其中该值仅寄存器的低5bit(模 32)或6bit(模 64)中获取。

数据传输指令

在x86架构中,不管是寄存器之间,还是寄存器和内存之间,都可以使用MOV指令,并且直接操作内存单元上的数据是被允许的。

在ARM架构中,寄存器间传送数据的指令依然是MOV,比如MOV Ra Rb 就是把Rb里存放的数据传送给Ra,但内存单元上的数据不允许被直接操作,而是必须先放到寄存器中,为此就有了把内存的内容传送到寄存器的指令LDR(Load),以及把寄存器的内容传送回内存的指令STR(Store)

传送的时候,内存单元的地址存放在一个寄存器中(比如R1),用[R1]表示,"[]“表示取地址里的内容。假设R1里存放的是0x200,内存中地址0x200处的内容是0x5,那么ldr r0, [r1]就是将0x5放入r0中。

通用寄存器的数量一共就那么多,直接用寄存器的值来获取内存地址的数量实在太有限了,更多的时候,是通过寄存器的值(基址)加上一个偏移/索引(offset/index)来指向内存对应的单元,索引的大小可以由立即数提供,也可以由寄存器存储的值提供:

STR  R0,[R1, #12]  // R0 --> [R1+12]
LDR  R4,[R5, R6]  // R4 <-- [R5+R6]

如果索引对基址的更改发生在数据传输之前,则称为"预索引”(pre-index),传输前后寄存器R1的值都不会改变。

如果索引对基址的更改发生在数据传输之后(注意下图"[]“位置的改变),则称为"后索引”(post-index),传输后寄存器R1的内容将变为加上其原来的值加上索引后的值。“后索引"其实算是一种二合一的指令,比如str r0, [r1], #12就等同于str r0, [r1]加上r1 = r1+12

如果一次传送的不是8个字节,那么64位的寄存器是填不满的,为了保持负数的数值不变,这剩余的字节可能就需要进行符号位扩展(Signed),由后缀"S"表示,其配合"W"使用表示只进行低32位空余字节的扩展,配合"X"则表示进行整个64位的符号位扩展:

符号扩展
符号扩展

woc,太多了,看不完,QAQ

指令集就到这吧,用的时候查文档吧 lOl

————————————————————————————————————

ARM汇编

Licensed under CC BY-NC-SA 4.0