一、ARM64体系结构概览:AArch64执行状态、寄存器组与异常等级
各位同学,咱们今天正式进入ARM64的世界。说实话,我第一次接触ARM64的时候,脑子里全是x86的那套东西,结果踩了不少坑。后来才明白,ARM64的设计哲学跟x86完全不一样——它更简洁、更规整,但也更讲究规矩。
这一章,咱们把地基打牢。我会从三个核心维度带你过一遍:AArch64执行状态、寄存器组、以及异常等级与安全模型。这些东西你搞懂了,后面写汇编、调性能、做系统移植,心里才有底。
1.1 AArch64执行状态:64位的真正起点
ARMv8-A架构引入了两种执行状态:AArch64和AArch32。咱们这门课只关注AArch64,也就是纯64位模式。
为什么叫“纯64位”?因为AArch64不是AArch32的简单扩展,而是重新设计的指令集。它使用64位虚拟地址、31个64位通用寄存器,并且抛弃了ARMv7时代那些历史包袱——比如PC可以直接读写、CPSR那种复杂的状态寄存器。
核心特征:
- 地址宽度:64位虚拟地址,但当前实现通常只用48位或52位
- 指令长度:固定32位,不再有Thumb/Thumb-2混合指令
- 寄存器:31个通用寄存器(X0-X30),每个64位宽
- 异常模型:4个异常等级(EL0-EL3),清晰分层
我个人习惯把AArch64比作一张白纸。ARM公司把过去20年的经验教训全倒进去,重新画了一张干净的图纸。你想想看,一个指令集能固定32位长度,这对流水线和分支预测有多友好?我在做性能调优时,经常因为指令对齐问题在x86上折腾半天,但在ARM64上几乎不用操心。
1.2 寄存器组:你的31个“工作台”
寄存器是CPU最宝贵的资源。AArch64提供了三类寄存器:通用寄存器、SIMD&FP寄存器、以及特殊寄存器。咱们一个一个说。
1.2.1 通用寄存器(X0-X30)
一共31个64位通用寄存器,编号X0到X30。每个寄存器都可以当作64位(X形式)或32位(W形式)使用。比如X0是64位,W0就是它的低32位。
| 寄存器 | 别名/用途 | 调用约定 |
|---|---|---|
| X0-X7 | 参数寄存器 | 传递参数,X0也用于返回值 |
| X8 | 间接结果寄存器 | 返回大结构体时使用 |
| X9-X15 | 临时寄存器 | 调用者保存(caller-saved) |
| X16-X17 | IP0/IP1 | 过程内调用临时寄存器 |
| X18 | 平台寄存器 | 平台保留,通常不用 |
| X19-X28 | 被调用者保存 | callee-saved,函数内必须恢复 |
| X29 | 帧指针(FP) | 指向当前栈帧基址 |
| X30 | 链接寄存器(LR) | 保存函数返回地址 |
这里有个坑,我当年就栽过。X18在Windows和Linux上的用法不一样——Windows把它当作TEB(线程环境块)指针,Linux则保留给平台使用。如果你写跨平台代码,千万别碰X18。
避坑指南:我曾经在移植一个RTOS时,顺手把X18当通用寄存器用了,结果在某个硬件平台上直接崩溃。查了两天才发现,那个平台的固件把X18映射到了特殊功能寄存器。所以,除非你100%确定,否则别碰X18。
1.2.2 SIMD&FP寄存器(V0-V31)
ARM64的SIMD(单指令多数据)和浮点运算共用一组寄存器:V0到V31,每个128位宽。它们可以当作多种视图使用:
- B/H/S/D/Q:8位/16位/32位/64位/128位标量
- V.8B/V.16B:8个或16个字节
- V.4H/V.8H:4个或8个半字
- V.2S/V.4S:2个或4个单精度浮点
- V.2D:2个双精度浮点
说白了,这32个寄存器就是你的“向量工作台”。做图像处理、音频编解码、或者矩阵运算时,它们能同时处理多个数据,效率极高。我记得有一次优化一个视频解码器,把关键循环改成NEON指令后,性能直接翻了3倍。
1.2.3 特殊寄存器
特殊寄存器不直接参与数据运算,但控制着CPU的行为。常用的有:
- SP(栈指针):每个异常等级有自己的SP,EL0和EL1可以共享
- PC(程序计数器):AArch64中不能直接写PC,只能通过分支指令修改
- PSTATE:处理器状态,包含NZCV标志位、异常掩码等
- TPIDR_EL0/TPIDR_EL1:线程/进程ID寄存器,常用于存储线程局部存储指针
嗯,这里要注意:PSTATE不是寄存器,而是一组状态位的抽象。你没法直接读写它,只能通过MSR/MRS指令操作它的别名寄存器,比如NZCV、DAIF等。
1.3 异常等级(EL0-EL3)与安全模型
ARM64的异常模型是它最优雅的设计之一。4个异常等级,从低到高:
- EL0:用户态,运行应用程序
- EL1:操作系统内核
- EL2:虚拟机监视器(Hypervisor)
- EL3:安全监视器(Secure Monitor)
每个等级都有独立的虚拟内存配置、异常向量表、以及系统寄存器。等级越高,权限越大。EL3可以访问所有资源,EL0只能碰自己的用户空间。
重要:异常等级不是简单的“优先级”,而是隔离域。EL0的崩溃不会影响EL1,EL1的崩溃不会影响EL2。这种分层设计让系统更健壮,也更容易做虚拟化和安全隔离。
1.3.1 安全模型:TrustZone
ARM64还有一个“安全世界”和“非安全世界”的概念,这就是TrustZone。它把物理硬件分成两个隔离的环境:
- 非安全世界(Normal World):运行普通操作系统和应用程序
- 安全世界(Secure World):运行安全操作系统,处理密钥、指纹、支付等敏感操作
切换两个世界需要通过EL3的安全监视器调用(SMC)。我在做手机安全方案时,经常需要写SMC处理程序——那玩意儿调试起来特别痛苦,因为安全世界里的断点会触发安全异常,普通调试器根本抓不到。
1.4 知识体系总览
下面这张图,把咱们这一章的核心内容串起来了。你可以把它当作ARM64体系结构的“地图”。
1.5 小结
这一章咱们把ARM64的骨架搭起来了。你记住三件事:
- AArch64是纯64位世界,跟32位模式完全割裂,别混着用
- 寄存器是性能的命根子,31个通用寄存器+32个SIMD寄存器,怎么分配、怎么保存,直接影响函数调用开销
- 异常等级是安全的基础,EL0到EL3层层隔离,写驱动、做虚拟化、搞安全方案,都得跟它们打交道