图片转载于网络,感谢原作者的分享:https://www.cnblogs.com/sewain/p/15187036.html
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位;
4. 描述符类型(S):1 位
- 位置:第 44 位。
- 作用:区分普通段(代码或数据段)和系统段(如调用门、任务状态段等)。
- 说明:
- S = 1:表示代码段或数据段。
- S = 0:表示系统段或门描述符。
- 使用场景:系统段通常包含特殊的信息(如任务状态、调用门等),在应用程序层级不可访问;代码段和数据段则是普通应用程序和内核的程序段。
5. 描述符特权级(DPL,Descriptor Privilege Level):2 位
- 位置:第 45-46 位。
- 作用:指定段的访问权限级别,控制不同权限级别之间的访问。
- 说明:DPL 值从 0 到 3,数值越小权限越高:
- DPL = 0:最高权限(通常为内核使用)。
- DPL = 3:最低权限(用户态程序使用)。
- 使用场景:用户态程序只能访问 DPL 为 3 的段,而内核态代码可以访问 DPL 为 0 的段,确保系统的安全性,防止用户态直接访问内核态代码。
6. 段存在位(P,Present):1 位
- 位置:第 47 位。
- 作用:表示该段是否在内存中。
- 说明:
- P = 1:段存在于内存中。
- P = 0:段不在内存中,访问该段会引发异常。
- 使用场景:段切换或段加载时,操作系统可以根据需要将段载入内存或释放,未加载的段设置为
P=0
。
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=0
。
11. 粒度位(G):1 位
- 位置:第 55 位。
- 作用:决定段界限的单位。
- 说明:
- G = 1:段界限以 4KB 为单位(适合大段)。
- G = 0:段界限以字节为单位(适合小段)。
- 使用场景:大段(如代码段或数据段)通常设置为 4KB 粒度,以覆盖更大的内存空间;小段或特定硬件映射区域可能设置为字节粒度。
12. 段基址高 8 位(Base 24:31):8 位
- 位置:第 56-63 位。
- 作用:段基址的高 8 位,与其他基址部分共同确定段的物理起始地址。
- 使用场景:用于完整指定段的基地址,在多段模型中实现数据隔离和内存保护。
附图
1. GDTR寄存器
2. 段选择子
GDT 描述符的每个位控制了段的不同属性,如权限级别、大小、类型、基址和粒度。通过这些位的组合,操作系统可以精确地配置内存段的访问权限、执行权限以及数据隔离,保证了内核和用户态程序的安全。