当 CPU 执行一条访问内存的指令比如mov eax, [0x1234]时背后发生的事情大致如下------------------- ------------------- ------------------- | 1. 段寄存器 CS/DS | --- | 2. 段选择子(16位) | --- | 3. 从 GDT 中索引 | | 中存有段选择子 | | 包含索引、TI、RPL | | 对应的段描述符 | ------------------- ------------------- ------------------- | v ------------------- ------------------- ------------------- | 6. 检查权限/界限 | --- | 5. 段描述符 | --- | 4. GDTR 基地址 | | 并计算物理地址 | | 包含基地址、界限、 | | 索引×8 地址 | | | | 权限位等 | | | ------------------- ------------------- -------------------关键点段选择子16位存放在 CS、DS、ES、SS、FS、GS 等段寄存器中。GDTR存放 GDT 的基地址线性地址和界限大小。段描述符8字节存放在 GDT 表中每个描述符定义一个内存段基地址、段界限、访问权限、类型等。CPU 通过GDTR.基地址 段选择子.索引 × 8找到对应的段描述符从而知道访问哪个内存段。一图看懂数据结构关系GDTR (48/80位) ------------------------------------ | 界限 (16位) | 基地址 (32/64位) | ------------------------------------ | v ------------------------------------------------------ | GDT (全局描述符表) | ------------------------------------------------------ | 空描述符(8B) | 代码段描述符(8B) | 数据段描述符(8B) | ...| ------------------------------------------------------ 索引 0 索引 1 索引 2 ^ | 段选择子 (16位) ------------------- | 索引 | TI | RPL | | (13位)| (1位)| (2位) | -------------------索引13位在 GDT 或 LDT 中定位描述符最多 8192 个。TITable Indicator0 表示 GDT1 表示 LDT局部描述符表。RPLRequested Privilege Level请求特权级用于权限检查。一个完整的代码流程示例从实模式到保护模式; 1. 定义 GDT gdt_start: dq 0x0000000000000000 ; 空描述符必须 gdt_code: dw 0xFFFF ; 段界限低16位 dw 0x0000 ; 基地址低16位 db 0x00 ; 基地址中8位 db 10011010b ; 访问权限P1, DPL0, S1, Code1, Read1 db 11001111b ; 标志G1, D/B1, L0 段界限高4位 db 0x00 ; 基地址高8位 gdt_data: ; 类似只是访问权限改为 10010010b数据段可读写 gdt_end: ; 2. 构造 GDTR 所需数据 gdt_descriptor: dw gdt_end - gdt_start - 1 ; 段界限 表大小 - 1 dd gdt_start ; 基地址32位保护模式 ; 3. 加载 GDTR lgdt [gdt_descriptor] ; 4. 切换到保护模式设置 CR0.PE 1 mov eax, cr0 or eax, 0x1 mov cr0, eax ; 5. 远跳转刷新 CS加载代码段选择子 0x08 jmp 0x08:flush_cs flush_cs: ; 6. 加载数据段选择子假设数据段索引为 0x10 mov ax, 0x10 mov ds, ax mov es, ax mov ss, ax关键点总结概念作用存在位置GDTR存储 GDT 的基地址和界限CPU 内部寄存器GDT存储所有段描述符的数组内存由操作系统维护段描述符定义单个段的基地址、界限、权限等GDT 中的一项8字节段选择子指向 GDT/LDT 中某个描述符的索引段寄存器CS/DS等lgdt将内存中的描述符加载到 GDTR特权指令Ring 0sgdt将 GDTR 内容存储到内存任何特权级调试用LDT局部描述符表每个任务可以有自己的段表通过 LDTR 寄存器指向。分页机制x86 在分段基础上还有分页通过 CR3 指向页目录分段分页构成完整的内存管理。长模式64位在 x86-64 下分段机制被大幅弱化基地址通常为 0段界限被忽略但 GDT 仍然存在用于权限和模式切换。