[1]arm64架构学习
介绍
ARM架构也曾经叫做进阶精简机器指令集,早期是一个32位的处理器架构,目前为止占据了32位嵌入式处理器的75%,成为全世界最多数的32位架构。arm架构主要用于低性能或一般性能的嵌入式操作系统,对于一些高级的比如计算机或者服务器,取决于CPU的架构,如AMD的AMD64或Intel的x64架构等等,他们是相似但不相同的。不过由于市面上绝大部分架构都是从arm演变过来的,所以学ARM架构就足够了。
ARM的第一代产品在1985年推出,使用了RISC架构,史称ARM架构。arm不同版本有不同的功能:
| 版本 | 特点 |
| —— | ——————————————— |
| v1 | 26位地址 |
| v2 | 乘法和加法指令,支持协处理器 |
| v3 | 地址扩展到32位 |
| v4 | 增加Thumb指令集 |
| v5 | 增加Jazelle和VFPv2指令 |
| v6 | 增加SIMD、Thumb-v2扩展 |
| v7 | 增强Neon和VFPvs/v4扩展 |
| v8 | 同时支持32位和64位指令集处理器 |
| v9 | 支持矢量扩展计算 |
基本寄存器
通用寄存器:X0~X30,用于保存基本数据,每个寄存器有64位,W可以用于表示X的低32位的数据
PSTATE寄存器:
- N:负数标志位
- Z:0标志位
- C:进位标志位
- V:溢出标志位
- SS:软件单步
- IL:异常标志位
- nRW:架构模式,可以判断寄存器数(0有32个通用寄存器,1有16个通用寄存器)
- EL:异常等级标志位
- SP:选择异常处理寄存器
- D:调试位
- A:屏蔽错误
- I:屏蔽中断(IRQ)
- F:屏蔽快速中断(FIQ)
- PAN:特权模式禁止访问位(异常等级跨界访问置为1)
- UAO:访问覆盖标志位(无特权访问地址指令置为1)
除了上述之外还有很多寄存器,这里就不一一列举了。
PC寄存器是程序运行的指针,但是无法访问。SP是异常等级指针。
SP寄存器中有:SP_EL0,也就是EL0的寄存器,同理还有EL1,EL2,EL3寄存器。这些寄存器都是被穷举出来的,也就是说不可变。
简单指令集
加载指令:LDR
- LDR Xt, [Xn, #偏移量] 加载Xn+偏移量处(不写就不偏)的值存储进Xt
存储指令:STR
- STR Xt, [Xn, #偏移量] 保存Xt的值进入Xn+偏移量处(不写就不偏)
前变基:先偏移后取值
- LDR Xt, [Xn, #8] 先移动8位然后加载值进入Xt
后变基:先取值后偏移
- LDR Xt, [Xn], #8 先加载Xn的值进Xt,然后Xn向后移动8位
标签:
1 |
|
其中的my_labe就是标签,ldr加载my_label的值data为0xff,给了x0寄存器。为了美观一般也写作
1 |
|
其他指令:
指令 | 功能 |
---|---|
LDR | 加载数据指令 |
LDRSW | 加载有符号字大小的数据 |
LDRB | 加载字节大小的数据 |
LDRSB | 加载有符号字节的数据 |
LDRH | 加载半个字节大小的数据 |
LDRSH | 加载半个有符号字节大小的数据 |
STRB | 存储一个字节的数据 |
STRH | 存储半个字节的数据 |
移动指令:MOV
- MOV Xt, #偏移量 将xt的数据移动偏移量位
加法指令:ADD
- ADD Xd, Xn, #偏移量 意为Xn的值加上偏移量的值存入Xd内
- ADD Xd, Xn, Xt 数学含义为:Xd = Xn + Xt
- ADD Xd, Xn, Xt LSL 2 数学含义为: Xd = Xn + Xt << 2
减法指令:SUB
- SUB Xd, Xn, #偏移量 意为Xn的值减去偏移量的值存入Xd内
- SUB Xd, Xn, Xt 数学含义为:Xd = Xn - Xt
- SUB Xd, Xn, Xt LSL 2 数学含义为: Xd = Xn - Xt << 2
- SUBS Xd, Xn, Xt 数学含义为:Xd = Xn - Xt,如果出现了NZCV标志可以直接获取
比较指令:CMP
- CMP Xn, Xt 等效的算式为:Xn + NOT(Xt) + 1
通过读取LS寄存器的值就可以知道它是小于或等于,读取CS则是大于或等于
比较指令2:CMN
- CMN Xn, R 伪代码意为:Xn == -R?eq=1:eq=0
CMN是相反数比较,Xn与-R是否一样,一样则置EQ寄存器为1,反之为0.
移位指令:
- LSL向左移位
- LSR向右移位
- ASR算式右移
- ROR循环右移
与运算符:AND
- AND Xd, Xn, Xm 数学含义为:Xd = Xn & Xm
相对加载指令:ADR
- ADR Xd, label 加载label处的程序进入寄存器Xd内,对齐为4Kb
编译过程
一段C语言代码的编译经过如下过程:
- 预处理:将所有使用到的头文件内的方法导入进来,并组成中间文件
1 |
|
- 编译:优化中间文件的内容,优化代码并生成汇编代码
1 |
|
- 汇编:将汇编代码转化为二进制文件,并进行重定位
1 |
|
- 链接:将二进制文件转化为可执行文件并导入所有使用到的库
1 |
|
学习过C语言一定知道指针的概念,大家就会发现指针可以指向任何内容,包括函数,所谓函数也是一段在内存中保存的指令区域,一样可以获取到所在的内存地址。
链接器
任何一个可执行程序都不是独立存在并且不依赖其他文件的,所以我们需要进行添加所有依赖的文件,汇编内使用到的指令块为:
1 |
|
程序的第一条指令叫做入口点
ENTRY(symbol)
对于C语言,symbol就是main函数的内存地址。对于SECTION而言它可以写的格式如下:
1 |
|
之所以结合C语言是因为C语言可以内嵌汇编指令也就是:
1 |
|
我们甚至可以用汇编高效的完成交换算法:
1 |
|
其中的W为高位寄存器,可以跳到基本寄存器部分查看。
异常与中断
中断有两种,普通中断IRQ和快速中断FIQ,其中FIQ的优先级高于IRQ。异常有4个等级分别为:EL0、EL1、EL2、EL3.
- EL0:非特权模式,用于运行程序
- EL1:特权模式,用于运行系统内核
- EL2:用于运行虚拟化任务
- EL3:用于运行安全世界的管理程序
安全世界TrustZone:https://blog.csdn.net/pslyunhai3255/article/details/129229732
寄存器保存的地址就是异常返回的地址,ELR_ELx存放的是异常返回地址,也就是程序段地址。异常存放的位置叫异常向量表:
- NS:值为1表示低于EL3的异常级别处于非安全状态
- IRQ:值为1表示来自低于EL3的异常级别的IRQ会路由到EL3
- FIQ:值为1表示来自低于EL3的异常级别的FIQ会路由到EL3
- EA:值为1表示来自低于EL3的异常级别的外部中止和SError中断会路由到EL3
- RW:值为1表示低于EL3的异常级别都在AArch64执行状态下
- TGE:值为1表示如果系统实现了EL2
- AMO:值为1表示来自低于EL2的异常级别的SError中断会路由到EL2
- IMO:值为1表示来自低于EL2的异常级别的IRQ中断会路由到EL2
- FMO:值为1表示来自低于EL2的异常级别的FIQ会路由到EL2
总结
本期针对ARM的基础部分进行了描述,下一节将会讲解关于CPU的更多细节。