我正在研究x86系统的保护环。
在这张图中,有段选择器。 我的问题是...
谢谢。
我将尝试用尽可能简单的术语来解释这一点。
GDT 是操作系统在内存中建立的一个表,其中包含描述符。它们有两种类型:段描述符和系统描述符(定义内存中各种操作系统的重要结构)。
段描述符简单地定义了段。本质上,段设置了内存的基础。例如,诸如
[ebx]
之类的内存访问将与 DS
描述的段基数相关(或者您可以显式指定段寄存器,例如 [es:ebx]
)。段描述符具有 this 格式。
段选择器只是 GDT 中的 索引。它们具有特定的格式,其中最后 3 位用于其他目的(第 2 位是表指示符,而第 1-0 位是请求的特权级别)。只有位 15-3 描述了实际索引。例如,如果将
DS
设置为 0x20
,这意味着 GDT 中的索引 4(从 0 开始)。
段寄存器(
CS
、DS
、ES
、FS
、GS
和SS
)旨在在使用时存储这些选择器。但是,当它们不使用时,可以将它们存储在内存中或任何其他地方。
如前所述,段描述符是GDT的一部分,由操作系统创建。段选择器(通常)由操作系统提供给应用程序。如果需要,应用程序可以自由设置自己的选择器,只要相应的描述符存在并且可以访问(在现代操作系统中几乎从来不会出现这种情况)。
一个人可以而且总是有多个选择器。这是因为
CS
必须引用代码段描述符,而其他所有内容都是数据段描述符。
在 x86 上无法禁用分段,但它可以……嗯……绕过。通过将所有描述符设置为基数 0 和 4GiB 限制,您基本上可以绕过分段的所有优点和缺点。
所有现代系统都使用分页来实现内存保护。然而,分段仍然是必需的,因为它强制执行特权级别。 GDT中的每个描述符都有一个DPL(描述符特权级别)字段。这就是强制实施所谓的特权环的原因。如果用户模式应用程序有权访问 Ring 0 选择器,它就可以执行特权指令并绕过所有保护机制,包括分页。
除此之外,还有一些对操作系统至关重要的系统结构(使用系统描述符在 GDT 中定义),例如任务状态段 (TSS)。例如,TSS 可确保当发生从 Ring 3 到 Ring 0 的任何转换时,堆栈 (
SS:ESP
) 会切换到众所周知的内核堆栈,因为用户模式堆栈不可信。