图片转载于网络,感谢原作者的分享:https://www.cnblogs.com/sewain/p/15187036.html

GDT

GDT 描述符各个位的详细说明

在 x86 架构中,每个 GDT 描述符占用 8 字节(64 位),描述符字段从低到高依次为段界限、段基址、类型、权限和其他控制位。以下是各位的具体含义和用途:


1. 段界限(Limit):20 位

  • 位置:第 0-15 位(低 16 位)和第 48-51 位(高 4 位)。
  • 作用:指定段的大小,用来确定段的有效访问范围。
  • 说明:段界限是20位值,结合 G(粒度)位控制段的大小。
    • 如果 G = 1,段界限的单位是 4KB(最大 4GB)。
    • 如果 G = 0,段界限的单位是字节(最大 1MB)。
  • 使用场景:设置数据段或代码段的大小,避免对段外内存的非法访问。

2. 段基址(Base):32 位

  • 位置:第 16-31 位(低 16 位)、第 32-39 位(中间 8 位)和第 56-63 位(高 8 位)。
  • 作用:指定段的起始地址,用于确定段的物理地址。
  • 说明:段基址指定段的基地址,加上偏移量得到访问的实际内存地址。
  • 使用场景:分段内存模型中,通过不同段基址隔离各个段,实现内存保护和数据隔离。

3. 类型(Type):4 位

  • 位置:第 40-43 位。
  • 作用:定义段的属性和权限,控制代码段和数据段的访问权限。
  • 说明:根据段的类型不同,Type 位的含义有所不同:
    • 代码段
      • X 位(执行位):1 表示该段为可执行代码段。
      • C 位(依从位):1 表示代码段是依从的,高权限代码可以调用低权限的代码段。
      • R 位(可读位):1 表示代码段可读(通常可读,设置为 1)。
      • A 位(访问位):1 表示段已被访问,CPU 自动设置。
    • 数据段
      • E 位(扩展方向位):1 表示数据段向下扩展(常用于栈段)。
      • W 位(可写位):1 表示数据段可写,0 表示只读。
      • A 位(访问位):1 表示段已被访问,CPU 自动设置。
  • 使用场景:操作系统设置不同的代码和数据段,通过这些位控制代码的执行权限及数据的读写权限。例如,内核代码段设置为可执行不可读,数据段设置为可读写。

注意:对于代码段来说,这4位则分别是X、C、R、A位。而对于数据段来说,这4位分别是X、E、W、A位; GDT描述符字段含义详解 - 图2


4. 描述符类型(S):1 位

  • 位置:第 44 位。
  • 作用:区分普通段(代码或数据段)和系统段(如调用门、任务状态段等)。
  • 说明
    • S = 1:表示代码段或数据段。
    • S = 0:表示系统段或门描述符。
  • 使用场景:系统段通常包含特殊的信息(如任务状态、调用门等),在应用程序层级不可访问;代码段和数据段则是普通应用程序和内核的程序段。 GDT描述符字段含义详解 - 图3

5. 描述符特权级(DPL,Descriptor Privilege Level):2 位

  • 位置:第 45-46 位。
  • 作用:指定段的访问权限级别,控制不同权限级别之间的访问。
  • 说明:DPL 值从 0 到 3,数值越小权限越高:
    • DPL = 0:最高权限(通常为内核使用)。
    • DPL = 3:最低权限(用户态程序使用)。
  • 使用场景:用户态程序只能访问 DPL 为 3 的段,而内核态代码可以访问 DPL 为 0 的段,确保系统的安全性,防止用户态直接访问内核态代码。 GDT描述符字段含义详解 - 图4

6. 段存在位(P,Present):1 位

  • 位置:第 47 位。
  • 作用:表示该段是否在内存中。
  • 说明
    • P = 1:段存在于内存中。
    • P = 0:段不在内存中,访问该段会引发异常。
  • 使用场景:段切换或段加载时,操作系统可以根据需要将段载入内存或释放,未加载的段设置为 P=0GDT描述符字段含义详解 - 图5

7. 段界限高位(Limit 16:19):4 位

  • 位置:第 48-51 位。
  • 作用:与低16位共同构成段界限。
  • 使用场景:结合粒度位 G 控制段大小。大段或较大内存区通常设置为更高的段界限,以覆盖更大的内存区域。

8. 可用位(AVL):1 位

  • 位置:第 52 位。
  • 作用:保留给操作系统使用。
  • 说明:通常设置为 0,但可用于存储系统特定的控制信息。
  • 使用场景:操作系统或硬件扩展可以利用此位来标记特定用途或优化内存管理。

9. 64 位代码段(L):1 位

  • 位置:第 53 位。
  • 作用:在 IA-32e 模式下表示 64 位代码段。
  • 说明
    • L = 1:表示 64 位代码段。
    • L = 0:表示非 64 位代码段(如 32 位段)。
  • 使用场景:64 位模式下运行的代码段设置 L=1,仅在 64 位模式下有效;在 32 位模式下忽略此位。

10. 偏移寄存器操作数大小(D/B):1 位

  • 位置:第 54 位。
  • 作用:控制段的默认操作数和地址大小。
  • 说明
    • D/B = 1:默认操作数大小为 32 位,偏移寄存器使用 32 位。
    • D/B = 0:默认操作数大小为 16 位,偏移寄存器使用 16 位。
  • 使用场景:保护模式下的代码段、数据段和栈段通常设置 D/B=1,以支持 32 位操作;在16位程序中则设置为 D/B=0GDT描述符字段含义详解 - 图6

11. 粒度位(G):1 位

  • 位置:第 55 位。
  • 作用:决定段界限的单位。
  • 说明
    • G = 1:段界限以 4KB 为单位(适合大段)。
    • G = 0:段界限以字节为单位(适合小段)。
  • 使用场景:大段(如代码段或数据段)通常设置为 4KB 粒度,以覆盖更大的内存空间;小段或特定硬件映射区域可能设置为字节粒度。

12. 段基址高 8 位(Base 24:31):8 位

  • 位置:第 56-63 位。
  • 作用:段基址的高 8 位,与其他基址部分共同确定段的物理起始地址。
  • 使用场景:用于完整指定段的基地址,在多段模型中实现数据隔离和内存保护。

附图

1. GDTR寄存器

GDT描述符字段含义详解 - 图7

2. 段选择子

GDT描述符字段含义详解 - 图8

GDT 描述符的每个位控制了段的不同属性,如权限级别、大小、类型、基址和粒度。通过这些位的组合,操作系统可以精确地配置内存段的访问权限、执行权限以及数据隔离,保证了内核和用户态程序的安全。