微处理器及其结构¶
寄存器¶
段寄存器¶
通用寄存器¶
注:
- 
部分寄存器
- 写入 ah, al 时, ax / eax / rax 高位不变
 - 写入 ax 时, eax / rax 高位不变
 - 写入 eax 时 rax 高位自动清零
- 这样避免了 eax 与 rax 的相关性,方便寄存器重命名
 
 
 - 
寄存器编码: 顺序是 ax, cx, bx, dx, sp, bp, si, di
 - 
REX 前缀:
- ah, bh, ch, dh 变成了 spl, bpl, sil, dil
 - 详见 REX 前缀
 
 
状态寄存器¶
- 16 位: flags
 - 32 位: eflags
 - 64 位: rflags
 
状态标志位: CF, PF, AF, ZF, SF, TF, IF, DF, OF
系统运行模式与内存寻址¶
总览¶
- 
Legacy Mode:
- 实模式 (Real Mode): 16 位段寄存器作为选择值 (Selector), 有效地址 16 位, 经过运算得到 20 位物理地址,直接访问内存 (最大 1 MiB).
 - 虚拟 8086 模式 (Virtual 8086 Mode): 在 8086 寻址基础上,添加了可选的分页机制,扩大了可访问内存的范围.
 - 保护模式 (Protected Mode): 段寄存器只使用 16 位,作为选择值, 有效地址使用 32 位,通过段的描述符得到 Linear Address,再经过可选的分页机制得到物理地址.
 
 - 
Long Mode:
- 兼容模式 (Compatibility Mode): 类似保护模式,Virtual Address 为 32 位.
 - 64 位模式 (64-bit Mode): 64 位地址,只使用分页机制.
 
 
实模式¶
寻址方式¶
实模式下,没有虚拟内存的概念,所有内存地址均为物理地址。实模式采用 Fixed Segment,即定长分段的内存管理模式。
与操作系统课程中学习的分段有一点点不同,实模式的分段实际上就是一个硬件设计的技巧: 在 Intel 8086 处理器上,其地址总线为 20 位,可以寻址 1 MiB 的内存空间。然而 8086 的寄存器却只有 16 位,因此,8086 将内存地址分为段地址 (segment) 和偏移地址 (offset),并在计算地址时,将来自段寄存器的段地址左移四位,并与偏移地址相加,得到 20 位物理地址:
特点:
- 所有程序共享物理地址空间,便于共享,但也没有隔离。
 - Wrap Around 地址回绕: 当段地址 << 4 + 偏移地址超过 20 位地址总线时,会发生自然溢出,导致地址回绕。比如 
FFFF:FFFF的物理地址为0x10FFEF, 超出了 1 MiB 的范围,因此回绕为0x0FFEF. 又比如F800:8000指向0x100000, 实际访问的便是0x00000. 
中断向量表¶
保护模式¶
基本概念¶
保护模式采用 Variable Length Segment 即可变长度分段的内存管理方式。保护模式下,有一个非常重要的概念: 描述符 (descriptor),它是描述每个段属性的结构。这个描述符,实际上是 GDT (Global Descriptor Table) 或 LDT (Local Descriptor Table) 中的索引,通过它找到对应表项,就能获取到段的属性信息。
三个重要的描述符表:
- GDT: 全局描述符表,存放系统中所有进程的段描述符.
 - LDT: 局部描述符表,存放当前进程的段描述符.
 - IDT: 中断描述符表,存放中断处理程序的入口地址.
 
- 
L 位: 64 位模式使用分页机制,描述符新增了 L 位,需要开启 Long bit 来进入 64-bit 模式
 - 
Base: 基地址 (80286: 24 位, 80386 及以后: 32 位)
 - 
Limit: 段长度
 - 
G 位: 粒度位,设置为 1 时,Limit 的长度 1 bit 代表 4 KiB, 这样 4 KiB * 2^20 = 2^32 可以访问 32 位全部的内存
 - 
D / B 位: 代码段对应 D, 数据段对应 B, 表示默认操作数和有效地址长度
 - P 位: 描述符是否有效
 - 
DPL 位 (2 bit):
- 权限级别分为: Ring 0, Ring 1, Ring 2, Ring 3, 数字越小级别越高
 - 不得越权访问,提升权限需要通过门描述符 (Gate Descriptor)
 
 - 
S 位: 是否为系统描述符
 - Type 字段:
- 
对于非系统描述符,表示代码 / 堆栈 / 数据,以及读写权限:
- E 位: 扩展方向
- E = 0: 向上扩展,offset 范围 0 - limit
 - E = 1: 向下扩展,offset 范围 limit - 0xFFFFFFFF (用于堆栈段)
 
 - W 位: 数据段是否可写
 - C 位: 一致性代码段
- C = 0: 非一致性,只能被同特权级别代码段调用,或者通过门描述符调用
 - C = 1: 一致性,低特权级别程序可以使用,但权限保持原级别
 - 具体机制详见下面 DPL, RPL, CPL 的描述
 
 - A 位: 是否访问过
- 对于系统描述符,有如下几种:
 
 - 1100: Call Gate
 - 0101: Task Gate
 - D110: Interrupt Gate
 - D111: Trap Gate (D 指示门描述符大小 1 = 32 位, 0 = 16 位)
 
 - E 位: 扩展方向
 
 - 
 
选择值的结构:
选择值 (CS / DS / SS 存的 16-bit):
- 第 15-3 位 (13-bit, 8 KiB 个描述符): Descriptor index
 - 第 2 位: TI, 表示描述符索引在 GDT (全局描述符) 还是 LDT (局部描述符)
 - 第 1-0 位: RPL 选择值自身的权限 Ring 0 - Ring 3
 
安全级别的设置:
- DPL: 描述符权限级别
 - RPL: 请求的权限级别,放在 DS 寄存器的低 2 位
 - CPL: CPU 自身的权限级别,放在 CS 寄存器的低 2 位
 
RPL 和 CPL,通过门描述符越级执行高权限的代码时,请求的内存地址还是原来的权限级别
- 数据需要 MAX(RPL, CPL) <= DPL
 - 堆栈需要 CPL = RPL = DPL
 
描述符表的基地址由专门的寄存器存储: GDTR 全局描述符寄存器, LDTR 局部描述符寄存器, IDTR 中断描述符寄存器
寻址方式¶
分段机制:
分页机制:
相关计算¶
- 
计算段界限
计算方法:
- 
G = 0 limit 1 bit = 1 B, 段大小 = (limit + 1) B
 - 
G = 1 limit 1 bit = 4 KiB, 段大小 = (limit + 1) x 4 KiB
 
例题
计算下面的段起始地址和结束地址: Base: 1000 0000, limit: 001FF
- 
G = 0, 1000 0000 - 1000 01FF
 - 
G = 1, 1000 0000 - 101F FFFF (结束位置 = 起始位置 + 段长度 - 1)
 
Tips: G = 1 时,左移 3 个十六进制位,补FFF
 - 
 - 
中断向量与入口地址计算
计算方法:
- 根据 IDTR 找到中断描述符表:
 
- 根据中断向量号找到对应的描述符:
 
该中断描述符会包含一个段选择值和偏移量,然后再走一遍分段机制,找到中断服务程序
 
保护模式的异常和中断:
| 中断向量号 | 助记符 | 介绍 | 类型 | 原因 | 
|---|---|---|---|---|
| 0 | #DE | Divide Error | Fault | DIV 和 IDIV 指令 | 
| 1 | #DB | Debug Exception | Fault/Trap | 指令、数据和 I/O 断点;单步执行等 | 
| 2 | — | NMI Interrupt | Interrupt | 不可屏蔽的外部中断 | 
| 3 | #BP | Breakpoint | Trap | INT3 指令 | 
| 4 | #OF | Overflow | Trap | INTO 指令 | 
| 5 | #BR | BOUND Range Exceeded | Fault | BOUND 指令 | 
| 6 | #UD | Invalid Opcode (Undefined Opcode) | Fault | 无效指令或保留指令 | 
| 7 | #NM | Device Not Available (No Math Coprocessor) | Fault | 浮点指令或 WAIT/FWAIT 指令 | 
| 8 | #DF | Double Fault | Abort | 任何会触发异常、NMI 或 INTR 的指令 | 
| 9 | — | Coprocessor Segment Overrun (reserved) | Fault | 浮点指令 | 
| 10 | #TS | Invalid TSS | Fault | 任务切换或访问 TSS | 
| 11 | #NP | Segment Not Present | Fault | 加载段寄存器或访问系统段 | 
| 12 | #SS | Stack-Segment Fault | Fault | 堆栈操作或加载 SS 寄存器 | 
| 13 | #GP | General Protection | Fault | 任何内存引用和其他保护检查 | 
| 14 | #PF | Page Fault | Fault | 任何内存引用 | 
| 15 | — | Intel reserved. Do not use. | — | — | 
| 16 | #MF | x87 FPU Floating-Point Error (Math Fault) | Fault | x87 FPU 浮点指令或 WAIT/FWAIT 指令 | 
| 17 | #AC | Alignment Check | Fault | 任何内存数据引用 | 
| 18 | #MC | Machine Check | Abort | 错误代码(如果有)及来源取决于具体型号 | 
| 19 | #XM | SIMD Floating-Point Exception | Fault | SSE/SSE2/SSE3 浮点指令 | 
| 20 | #VE | Virtualization Exception | Fault | EPT 违规 | 
| 21 | #CP | Control Protection Exception | Fault | RET、IRET、RSTORSSP 和 SETSSBSY 指令可能触发此异常,或由于缺少 ENDBRANCH 指令导致的异常跳转 | 
| 22-31 | — | Intel reserved. Do not use. | — | — | 
| 32-255 | — | User Defined (Non-reserved) Interrupts | Interrupt | 外部中断或 INT n 指令 | 
特权级别¶
门描述符: 门描述符是一种特殊的描述符,用于实现特权级别的转换。门描述符有两种: 任务门 (Task Gate) 和中断门 (Interrupt Gate)。
64 位模式¶
RIP 相对寻址¶
在 64 位模式下,当 ModR/M 位的 r/m 为 101 时,是根据下一条指令的 RIP + 相对偏移量来寻址 (兼容模式时时相对于 0 计算的). 此时 REX 前缀不影响 RIP 相对寻址.
地址规范形式¶
64 位模式下,地址为规范形式 (canonical form) 意味着从第 63 位到地址的 MSB 之前,必须是全 0 或全 1.
比如对于 48 位线性地址 addr,addr[63:48] 为全 0 或全 1:
- 规范形式: 0xFFFF 8010 BC00 1000, 0x0000 7C80 B810 2040
 - 非规范形式: 0x1122 3344 5566 7788
 













