1、操作模式
IA-32架构支持三种基本操作模式:保护模式、实地址模式和系统管理模式。操作模式决定了哪些指令和体系结构功能是可访问的:
1)保护模式:该模式是处理器的自然状态。保护模式的功能之一是能够在受保护的多任务环境中直接执行“实地址模式”8086软件。这个特性被称为虚拟8086模式,尽管它实际上不是处理器模式。Virtual-8086模式实际上是一种受保护的模式属性,可以为任何任务启用。
2)实地址模式:该模式实现了带有扩展的英特尔8086处理器的编程环境(例如切换到保护模式或系统管理模式的能力)。处理器在上电或复位后被置于实地址模式。
3)系统管理模式(SMM):该模式为操作系统或执行程序提供了一种透明的机制,用于实现特定于平台的功能,如电源管理和系统安全。当外部SMM中断引脚(SMI#)被激活或从高级可编程中断控制器(APIC)接收到SMI时,处理器进入SMM。
英特尔64架构增加IA-32e模式。IA-32e模式有两个子模式:
兼容模式(IA-32e模式的子模式):兼容模式允许大多数传统16位和32位应用程序在64位操作系统下无需重新编译即可运行。为简洁起见,兼容子模式在IA-32架构中称为兼容模式。兼容模式还支持64位模式和受保护模式支持的所有权限级别。在虚拟8086模式下运行或使用硬件任务管理的传统应用程序将无法在此模式下工作。兼容模式由操作系统(OS)基于代码段启用。这意味着单个64位操作系统可以支持在64位模式下运行的64位应用程序,并支持在兼容模式下运行的传统32位应用程序(未针对64位进行重新编译)。兼容模式类似于32位保护模式。应用程序只能访问线性地址空间的前4gb。兼容模式使用16位和32位地址和操作数大小。与保护模式一样,该模式允许应用程序使用PAE(物理地址扩展)访问大于4gb的物理内存。
64位模式(IA-32e模式的子模式)—该模式使64位操作系统能够运行为访问64位线性地址空间而编写的应用程序。为简便起见,64位子模式在IA-32架构中称为64位模式。64位模式将通用寄存器和SIMD扩展寄存器的数量从8个扩展到16个,通用寄存器扩展到64位。该模式还引入了一个新的操作码前缀(REX)来访问寄存器扩展。操作系统基于代码段启用64位模式。它的默认地址大小是64位,默认操作数大小是32位。使用REX操作码前缀和操作数大小覆盖前缀,可以逐个指令地覆盖默认操作数大小。
2、基本执行环境概述
在 IA-32 处理器上运行的任何程序或任务都有一组资源,用于执行指令和存储代码、数据及状态信息。这些资源(如图 3-1 所示)构成了 IA-32 处理器的基本执行环境。英特尔 64 处理器支持 IA-32 处理器的基本执行环境,以及 IA-32e 模式下的类似环境,它可以执行 64 位程序(64 位子模式)和 32 位程序(兼容性子模式)。基本执行环境由处理器上运行的应用程序和操作系统或执行程序共同使用。
地址空间 :在 IA-32 处理器上运行的任何任务或程序都可以寻址最大 4 GB 字节(字节)的线性地址空间和最大 64 GB 字节( 字节)的物理地址空间。
基本程序执行寄存器 :8个通用寄存器、6个段寄存器、EFLAGS 寄存器和 EIP(指令指针)寄存器组成了一个基本的执行环境,在此环境中可以执行一系列通用指令。这些指令对字节、字和双字整数进行基本整数运算,处理程序流控制,对位和字节串进行操作,并对内存寻址。
x87 FPU 寄存器 : 8 个 x87 FPU 数据寄存器、x87 FPU 控制寄存器、状态寄存器、x87 FPU 指令指针寄存器、x87 FPU 操作数(数据)指针寄存器、x87 FPU 标记寄存器和 x87 FPU 操作码寄存器为操作单精度、双精度和双扩展精度浮点数值、字整数、双字整数、四字整数和二进制编码十进制 (BCD) 数值提供了执行环境。x87 浮点运算单元(FPU)具有高性能浮点处理能力,可用于图形处理、科学、工程和商业应用。它支持浮点、整数和打包 BCD 整数数据类型,以及 IEEE 浮点运算标准 754 中定义的浮点处理算法和异常处理架构。
MMX 寄存器:8个 MMX 寄存器支持对 64 位打包字节、字和双字整数执行单指令、多数据(SIMD)操作。
XMM 寄存器:8 个 XMM 数据寄存器和 MXCSR 寄存器支持对 128 位打包的单精度和双精度浮点数值以及 128 位打包的字节、字、双字和四字整数执行 SIMD 操作。
YMM 寄存器 :YMM 数据寄存器支持对 256 位打包的单精度和双精度浮点数值以及 256 位打包的字节、字、双字和四字整数执行 256 位 SIMD 操作。
边界寄存器:BND0-BND3 寄存器分别存储与内存缓冲区指针相关的下限和上限(各 64 位)。它们支持英特尔 MPX 指令的执行。
BNDCFGU 和 BNDSTATUS:BNDCFGU配置边界检查的用户模式MPX操作,BNDSTATUS提供了由MPX操作导致的#BR的附加信息。
堆栈:为了支持函数或子例程调用以及函数或子例程之间的参数传递,在执行环境中包括了堆栈和堆栈管理资源。堆栈位于内存中。
除了基本执行环境中提供的资源,IA-32体系结构还提供以下资源作为其系统级体系结构的一部分。它们为操作系统和系统开发软件提供广泛的支持。
I/O端口:IA-32架构支持输入/输出(I/O)端口之间的数据传输。
控制寄存器:5个控制寄存器(CR0至CR4)决定处理器的工作模式和当前执行任务的特征。
内存管理寄存器:GDTR、IDTR、任务寄存器和LDTR指定保护模式内存管理中使用的数据结构的位置。
调试寄存器:调试寄存器(DR0至DR7)控制并允许监控处理器的调试操作。
存储器类型范围寄存器(mtrr):mtrr用于为存储器区域分配存储器类型。
特定型号寄存器(MSR):处理器提供多种特定型号寄存器,用于控制和报告处理器性能。几乎所有MSR都处理与系统相关的功能,并且不能被应用程序访问。这个规则的一个例外是时间戳计数器。
机器检查寄存器:机器检查寄存器由一组控制、状态和错误报告MSR组成,用于检测和报告硬件(机器)错误。
性能监控计数器:性能监控计数器允许监控处理器性能事件。
3、64位模式执行环境
64位模式的执行环境类似于基本执行环境(本文第2节)。以下段落描述了二者之间的一些差异:
地址空间:在IA-32处理器上以64位模式运行的任务或程序可以寻址高达字节的线性地址空间和高达字节的物理地址空间。软件可以向CPUID查询处理器支持的物理地址大小。
基本程序执行寄存器 :可用的通用寄存器(GPR)数量为 16 个。通用寄存器宽 64 位,支持对字节、字、双字和四字整数的操作。对字节寄存器的访问统一到最低的 8 位。指令指针寄存器变为 64 位。EFLAGS 寄存器扩展到 64 位,称为 RFLAGS 寄存器。RFLAGS 的高 32 位被保留。RFLAGS 的低 32 位与 EFLAGS 相同。
XMM 寄存器 :共有 16 个 XMM 数据寄存器,用于 SIMD 操作。
YMM 寄存器 :共有 16 个用于 SIMD 操作的 YMM 数据寄存器。
堆栈: 堆栈指针大小为 64 位。堆栈大小不受 SS 描述符中的位控制(在非 64 位模式中),也不能由指令前缀覆盖指针大小。
控制寄存器 :控制寄存器扩展至 64 位。新增了一个控制寄存器(任务优先级寄存器:CR8 或 TPR)。
调试寄存器:调试寄存器扩展到 64 位。
描述符表寄存器 :全局描述符表寄存器(GDTR)和中断描述符表寄存器(IDTR)扩展为 10 字节,可容纳完整的 64 位基址。本地描述符表寄存器(LDTR)和任务寄存器(TR)也扩展到可保存完整的 64 位基址。
4、IA-32内存模型
当使用处理器的内存管理功能时,程序并不直接寻址物理内存。相反,它们使用三种内存模型之一访问内存:平面、分段或实地址模式: •
平面内存模型 :内存对于程序来说是一个单一的、连续的地址空间(图 3-3)。该空间称为线性地址空间。代码、数据和堆栈都包含在这个地址空间中。线性地址空间是可字节寻址的,地址从 0 到 连续运行(如果不是在 64 位模式下)。线性地址空间中任何字节的地址称为线性地址。
分段内存模型:内存对于程序来说是一组称为段的独立地址空间。代码、数据和堆栈通常包含在单独的段中。为了寻址段中的字节,程序发出逻辑地址。它由段选择器和偏移量组成(逻辑地址通常称为远指针)。段选择器标识要访问的段,偏移量标识该段地址空间中的字节。在 IA-32 处理器上运行的程序最多可以寻址 16,383 个不同大小和类型的段,每个段最大可达 字节。在内部,为系统定义的所有段都被映射到处理器的线性地址空间。为了访问内存位置,处理器将每个逻辑地址转换为线性地址。这种翻译对于应用程序来说是透明的。使用分段内存的主要原因是为了提高程序和系统的可靠性。例如,将程序的堆栈放置在单独的段中可以防止堆栈增长到代码或数据空间并分别覆盖指令或数据。
实地址模式内存模型:这是Intel 8086 处理器的内存模型。它支持提供与在 Intel 8086 处理器上运行的现有程序的兼容性。实地址模式使用分段内存的特定实现,其中程序和操作系统/执行程序的线性地址空间由每个大小高达 64 KB 的段数组组成。实地址模式下线性地址空间的最大大小为字节。
当使用 IA-32 架构的分页机制(启用分页)时,线性地址空间被划分为映射到虚拟内存的页面。然后,虚拟内存页根据需要映射到物理内存中。当操作系统或执行程序使用分页时,分页机制对于应用程序是透明的。应用程序看到的只是线性地址空间。
5、基本寄存器
IA-32 架构提供了 16 个基本程序执行寄存器,用于一般系统和应用程序编程(见图 3-4)。这些寄存器可以分组如下:
通用寄存器:这8个寄存器可用于存储操作数和指针。
段寄存器:这些寄存器最多可容纳6个段选择器。
EFLAGS(程序状态和控制)寄存器: EFLAGS 寄存器报告正在执行的程序的状态,并允许对处理器进行有限(应用程序级)控制。
EIP(指令指针)寄存器:EIP寄存器包含一个32位指针,指向下一条要执行的指令。
5.1、通用寄存器
32 位通用寄存器EAX、EBX、ECX、EDX、ESI、EDI、EBP 和ESP 用于以下用途:
• 逻辑和算术运算的操作数。
• 用于地址计算的操作数。
• 内存指针
尽管所有这些寄存器都可用于操作数、结果和指针的一般存储,但在引用 ESP 寄存器时应小心。 ESP 寄存器保存堆栈指针,一般情况下不应将其用于其他目的。
通用寄存器的特殊用途如下:
• EAX — 操作数和结果数据的累加器。
• EBX — 指向DS 段中数据的指针。
• ECX — 字符串和循环操作的计数器。
• EDX — I/O 指针。
• ESI — DS 寄存器所指向段中数据的指针;字符串操作的源指针。
• EDI — 指向 ES 寄存器所指向的段中的数据(或目标)的指针;字符串操作的目标指针。
• ESP — 堆栈栈顶指针(在SS 段中)。
• EBP — 指向堆栈栈底的指针(在SS 段中)。
在64位模式下,有16个通用寄存器,默认操作数大小为32位。然而,通用寄存器能够使用 32 位或 64 位操作数。如果指定 32 位操作数大小:EAX、EBX、ECX、EDX、EDI、ESI、EBP、ESP、R8D - R15D 可用。如果指定 64 位操作数大小:RAX、RBX、RCX、RDX、RDI、RSI、RBP、RSP、R8-R15 可用。 R8D-R15D/R8-R15 代表8个新的通用寄存器。
所有这些寄存器都可以按字节、字、双字和四字级别进行访问。 REX 前缀用于生成 64 位操作数大小或引用寄存器 R8-R15。
5.2、段寄存器
段寄存器(CS、DS、SS、ES、FS和GS)保存16位段选择器。段选择器是一个特殊的指针,用于标识内存中的段。要访问内存中的特定段,该段的段选择器必须存在于适当的段寄存器中。
如何使用段寄存器取决于操作系统或执行程序使用的内存管理模型的类型。当使用平面(未分段)内存模型时,段寄存器加载指向重叠段的段选择器,每个段从线性地址空间的地址0开始(见图3-6)。这些重叠的段构成了程序的线性地址空间。通常会定义两个重叠的段:一个用于代码,另一个用于数据和堆栈。CS段寄存器指向代码段,所有其他段寄存器指向数据和堆栈段。
当使用分段内存模型时,每个段寄存器通常加载不同的段选择器,以便每个段寄存器指向线性地址空间中的不同段(见图3-7)。因此,在任何时候,程序都可以在线性地址空间中访问多达六个段。要访问某个段寄存器未指向的段,程序必须首先将要访问的段的段选择器加载到段寄存器中。
每个段寄存器都与三种存储类型之一相关联:代码、数据或堆栈。例如,CS寄存器包含代码段的段选择器,其中存储了正在执行的指令。处理器使用由CS寄存器中的段选择器和EIP寄存器的内容组成的逻辑地址从代码段中获取指令。EIP寄存器包含下一条要执行的指令代码段内的偏移量。应用程序不能显式加载CS寄存器。相反,它是由改变程序控制的指令或内部处理器操作(如过程调用、中断处理或任务切换)隐式加载的。
DS、ES、FS和GS寄存器指向四个数据段。四个数据段的可用性允许高效和安全地访问不同类型的数据结构。例如,可能会创建四个单独的数据段:一个用于当前模块的数据结构,另一个用于从更高级别模块导出的数据,第三个用于动态创建的数据结构,第四个用于与另一个程序共享的数据。要访问额外的数据段,应用程序必须根据需要将这些数据段的段选择器加载到DS、ES、FS和GS寄存器中。
SS寄存器包含堆栈段的段选择器,其中存储了当前正在执行的程序、任务或处理程序的过程堆栈。所有堆栈操作都使用SS寄存器来查找堆栈段。与CS寄存器不同,SS寄存器可以显式加载,这允许应用程序设置多个堆栈并在它们之间切换。
64 位模式下,分段功能一般(但不完全)被禁用,从而创建一个扁平的 64 位线性地址空间。处理器将 CS、DS、ES、SS 的段基数视为零,创建的线性地址等于有效地址。FS 和 GS 段是例外,在某些线性地址计算中,它们的段寄存器(保存段基数)可用作额外的基寄存器。
5.3、EFLAFGS寄存器的标志位
32 位 EFLAGS 寄存器包含一组状态标志、一个控制标志和一组系统标志,如下图所示。
当挂起任务时(使用处理器的多任务处理功能),处理器会自动将 EFLAGS 寄存器的状态保存在挂起任务的任务状态段 (TSS) 中。当将自身绑定到新任务时,处理器会使用新任务 TSS 中的数据加载 EFLAGS 寄存器。当调用中断或异常处理程序时,处理器会自动将 EFLAGS 寄存器的状态保存在程序堆栈上。当通过任务切换处理中断或异常时,EFLAGS 寄存器的状态将保存在 TSS 中以供挂起的任务使用。
EFLAGS 寄存器的状态标志(位 0、2、4、6、7 和 11)指示算术指令(例如 ADD、SUB、MUL 和 DIV 指令)的结果。状态标志功能包括:
CF(位 0) 进位标志 — 如果算术运算在结果的最高有效位中生成进位或借位,则设置该标志;否则清除。该标志指示无符号整数算术的溢出情况。它也用于多精度算术。
PF(位 2)奇偶校验标志 — 如果结果的最低有效字节包含偶数个 1 位,则设置该标志;否则清除。
AF(位 4)辅助进位标志 — 如果算术运算从结果的第 3 位生成进位或借位,则设置该标志;否则清除。该标志用于二进制编码的十进制 (BCD) 算术。
ZF(位 6)零标志 — 如果结果为零则置位;否则清除。
SF(位 7)符号标志 — 设置为运算结果的最高有效位,即有符号整数的符号位。 (0 表示正值,1 表示负值。)
OF(位 11)溢出标志 — 如果整数结果太大正数或太小负数(不包括符号位)而无法容纳,则设置该标志。目标操作数;否则清除。该标志指示有符号整数(二进制补码)算术的溢出情况。
状态标志允许单个算术运算生成三种不同数据类型的结果:无符号整数、有符号整数和 BCD 整数。如果算术运算的结果被视为无符号整数,则 CF 标志指示超出范围的情况(进位或借位);如果被视为有符号整数(二进制补码数),则 OF 标志表示进位或借位;如果将 AF 标志视为 BCD 数字,则表示进位或借位。 SF 标志指示有符号整数的符号。 ZF 标志指示有符号或无符号整数零。
在64位模式下,EFLAGS被扩展到64位并称为RFLAGS。 RFLAGS 寄存器的高 32 位被保留。 RFLAGS的低32位与EFLAGS相同。
使用通用寄存器作为基址或索引组件受到以下方式的限制:
• ESP 寄存器不能用作索引寄存器。
• 当ESP 或EBP 寄存器用作基址寄存器时,SS 段是默认段。除此之外,DS 段是默认段