提问人:choiyhking 提问时间:9/20/2023 最后编辑:choiyhking 更新时间:9/20/2023 访问量:141
有关 x86 系统中段选择器的详细信息
Details about segment selectors in x86 system
问:
我正在研究x86系统的保护环。
在这张图片中,有段选择器。 我的问题是......
- 段选择器在 RAM 中?
- 谁创建区段选择器?自然而然?
- 一个区段可以有多个区段选择器吗?
- 顺便说一句,段选择器和段寄存器的关系?
- 这种结构(即分页分割、段选择器等)在现代系统上使用?
谢谢。
答:
我将尝试用尽可能简单的术语来解释这一点。
什么是细分?
分段是将内存划分为多个段的想法。这些区段具有基址和限制(或大小)。
传统上,在实模式(DOS时代)中,段定义如下:
base_address = segment_register * 16
limit = 64 KiB
但是,在保护模式下,段不再像这样定义。相反,有一个表格,其中包含有关每个细分的详细信息。作为奖励,它不仅描述了基址和限制,还描述了使用它所需的权限(这就是为什么它被称为保护模式)以及它是 16 位还是 32 位段。
全局描述符表 (GDT)
GDT 是由操作系统在内存中设置的表(即数组),其中包含描述符。它们有 2 种类型:段描述符(定义段及其所有属性)和系统描述符(定义内存中的各种操作系统结构,有些很重要,有些不那么重要)。
操作系统使用特权 lgdt
指令告知 CPU 此表的位置。但是,如果在用户模式代码中尝试它,它将出错。
区段描述符
区段描述符定义区段。请参阅下文,了解如何实际加载和使用一个。区段描述符具有此格式。
段选择器
段选择器只是 GDT 的索引。它们具有特定格式,其中最后 3 位用于其他目的(位 2 是表指示器,而位 1-0 是请求的权限级别)。只有第 15-3 位描述实际索引。例如,选择器指示 GDT 中的索引 4(从 0 开始)。0x20
段寄存器
段寄存器(、、、和)设计用于在使用时存储这些选择器。但是,当它们不使用时,它们可以存储在内存或任何其他地方。CS
DS
ES
FS
GS
SS
NULL 选择器充当 C 的 NULL 指针。您可以自由地将其加载到段寄存器中,但任何使用它的尝试都会出错。
例如:内存访问(例如将相对于 所描述的段基)(或者您可以显式指定段寄存器,例如 )。[ebx]
DS
[es:ebx]
在实模式下,这样的指令会访问内存地址。但是,在保护模式下,基址取自 GDT(在 表示的索引处),并将偏移量添加到其中。好的部分是,如果 指示的描述符是特权的,但进行内存访问的代码不是,它将出现常规保护故障。ds * 16 + ebx
DS
ebx
DS
区段描述符是如何创建的?
如前所述,段描述符是 GDT 的一部分,由操作系统创建。段选择器(通常)由操作系统提供给应用程序。如果需要,应用程序可以自由设置自己的选择器,前提是相应的描述符存在并且可以访问(在现代操作系统中几乎从未出现过这种情况)。
您可以有多个段选择器吗?
一个人可以而且总是有多个选择器。这是因为必须引用代码段描述符,而其他所有内容都引用数据段描述符。CS
每次访问内存访问 GDT 是不是很慢?
是的。如果是这种情况,则每次有人访问内存时,CPU 都必须访问正确的 GDT 条目,以便验证权限级别并获取段基数和计算限制。
幸运的是,每当您加载段寄存器时,CPU 都会缓存这些条目(到所谓的描述符缓存中)。这就是为什么加载段寄存器是一项相当昂贵的操作。然后,这些缓存将保证保持不变,直到您再次重新加载相应的段寄存器。这包括在不恢复描述符缓存的情况下切换出保护模式(这就是进入虚幻模式的方式)。
现代 32 位系统上的分段
无法在 x86 上禁用分段,但可以...井。。。绕过。通过将所有描述符设置为具有基本 0 和 4GiB 限制,您基本上绕过了分段的所有优点和缺点。
所有现代系统都使用分页来实现内存保护。但是,仍然需要分段,因为它强制执行权限级别。GDT 中的每个描述符都有一个 DPL(描述符权限级别)字段。这就是强制执行所谓的特权环的原因。如果用户模式应用程序有权访问环 0 选择器,则它可以执行特权指令并绕过所有保护机制,包括分页。
除此之外,还有一些系统结构(在GDT中使用系统描述符定义),例如任务状态段(TSS),它们对操作系统至关重要。例如,TSS 可确保当发生从环 3 到环 0 的任何转换时,堆栈 () 将切换到已知的内核堆栈,因为用户模式堆栈不可信。SS:ESP
分段仍用于 和 寄存器。在 Windows 中,引用指向线程信息块的描述符,而 NULL。FS
GS
FS
GS
64 位系统上的分段
在 64 位模式下,分段几乎被禁用。唯一真正重要的选择器是 ,它根据 DPL 字段设置权限级别。和 寄存器未使用。 并设置为 0(在 64 位模式下,NULL 选择器不执行任何操作,使用时不会出错),同时仍然指向描述符(加载 NULL 错误),尽管我不确定为什么它不能为 0。CS
DS
ES
SS
DS
ES
SS
但是,描述符不能设置基数或限制*。从本质上讲,CPU 创建的环境必须以 32 位模式手动创建。内存保护是通过分页实现的,这在 64 位模式下是必需的。
有一种方法可以设置 和 选择器的基础(请参阅 WRFSBASE 和 WRGSBASE
说明)。这完全不会影响 GDT 条目(它们仍然只有 32 位基数的空间),而是直接修改描述符缓存(寄存器本身通常设置为 0)。Windows 64 位使用而不是指向 TIB。
FS
GS
GS
FS
* 某些 CPU 支持在 256TiB 地址空间的最后 4GiB 中设置段限制。据我了解,这样做是为了在硬件虚拟化(VT-x 和 AMD-V)出现之前促进软件虚拟化。
评论
SS
SS
评论
mov cr3
CR0.PE
CR0.PG
CR4.PAE
EFER.LME