x86 始于 Intel 的 16 位 8086。80286 引入保护模式,IA-32 建立了 32 位编程模型和分页,AMD64 将架构扩展到 64 位执行。Intel 将组合架构称为 Intel 64 和 IA-32;AMD 文档使用 AMD64。供应商名称不决定每项功能,因此软件必须显式发现扩展。
字节序和操作数大小 #
x86 按字节寻址内存,并以小端顺序存储多字节整数:最低有效字节占据最低地址。对于从地址 p 开始的 32 位值 0x12345678,内存内容如下:
address p p+1 p+2 p+3
byte 78 56 34 12架构术语将 16 位值称为字,32 位值称为双字,64 位值称为四字,128 位值称为双四字。这些名称独立于 C 实现的类型大小。
指令操作数大小取决于执行模式、前缀、操作码以及 REX、VEX 或 EVEX 字段。在 64 位模式下,许多整数指令仍默认使用 32 位操作数;在支持的情况下,REX.W 编码选择 64 位。地址大小是独立属性,用于控制有效地址计算。
普通整数加载和存储允许未对齐地址,但跨越缓存行或页面边界可能增加延迟或改变故障行为。原子性保证取决于对齐、宽度、内存类型和指令,因此共享数据应满足架构的明确要求。
执行模式 #
复位后,x86 处理器以实地址模式启动。固件建立后续模式所需的表和控制寄存器。
- 实地址模式使用 8086 风格的分段模型,不进行保护模式的权限强制。
- 保护模式支持 16 位或 32 位代码和数据段、描述符检查、四个权限级别以及可选分页。
- 虚拟 8086 模式在操作系统控制下,作为保护模式任务运行实模式风格的 8086 软件。
- 长模式包含 64 位模式和兼容模式。兼容模式在 64 位操作系统下执行受保护的 16 位或 32 位代码。
- 系统管理模式是单独的固件环境,由系统管理中断进入,而不是应用程序执行模式。
在 64 位模式下,普通地址生成将 CS、DS、ES 和 SS 基址视为零,并且不强制执行其传统限制。FS 和 GS 保留可用基址,通常用于线程本地状态和每 CPU 状态。即使平坦寻址移除了大部分分段算术,描述符类型和权限检查仍然相关。
逻辑、线性、虚拟和物理地址 #
Intel 术语将段选择子加偏移称为逻辑地址。分段验证访问并添加段基址,生成线性地址。禁用分页时,线性地址会根据架构宽度和平台行为直接映射到物理地址。启用分页时,页表会将线性地址转换为物理地址。
操作系统文档通常将进程可见的线性地址称为虚拟地址。因此,在分页边界处,“线性”和“虚拟”可以指同一个数值地址,但它们强调不同模型。虚拟化下的客户机还可以增加从客户物理内存到主机物理内存的另一层转换。
指令从基址和索引寄存器、比例因子以及位移形成有效偏移。在 64 位模式下,线性地址必须对启用的地址宽度具有规范形式。非规范地址会在普通分页转换前触发故障。页表随后应用存在、可写、用户/监管者、禁止执行和其他权限。
异常、中断和控制转移 #
中断描述符表将向量映射到门。处理器检测到的异常、软件中断指令和外部中断使用这些向量,但中断控制器路由取决于平台。
异常通常分为:
- 故障在架构完成前报告,修正后通常可以重新启动指令,例如页不存在故障。
- 陷阱在触发指令之后报告,例如断点。
- 中止报告通常无法可靠重新启动的条件。
向量决定处理器是否压入错误代码以及可用的保存状态。改变权限的门还会根据任务状态段切换栈。软件验证目标状态后,使用 IRET 或系统调用专用返回指令返回。
近分支在当前代码段内改变指令指针。远转移和门可以加载新的代码段并执行额外检查。SYSCALL/SYSRET 和 SYSENTER/SYSEXIT 提供更快的已配置路径,但其寄存器约定属于操作系统 ABI。
扩展和操作系统发现 #
CPUID 通过编号叶和子叶报告供应商标识、拓扑信息、地址宽度、缓存参数和功能位。软件必须先确定支持的最大叶,然后测试打算使用的每项功能。在通过功能位建立正确性后,族或型号编号可以选择优化方案。
某些功能除了处理器支持外,还需要操作系统管理。对于 AVX 系列状态,软件通过 CPUID 检查 XSAVE 和 OSXSAVE,然后使用 XGETBV 确认操作系统启用了所需的 XCR0 组件。AVX-512 和更新的状态可能需要额外位。类似原则适用于监管者功能,用户可见的 CPUID 位并不授予权限。
使用功能还必须考虑 ABI 和部署策略。编译器基线目标可能不同于运行构建的机器,因此可移植二进制文件会使用保守基线、函数多版本化或运行时分派。
相关文章涵盖指令编码、指令族、寄存器、内存组织和保护模式权限。
评论
在 GitHub 上阅读或评论(发表评论需要登录)