【发布时间】:2023-03-05 03:57:01
【问题描述】:
段选择器何时出现。英特尔指南中的行说:
"每个段描述符都有一个关联的段选择器。一个段 选择器为使用它的软件提供 GDT 的索引 或 LDT(其关联的段描述符的偏移量), 全局/本地标志(确定选择器是否指向 GDT 或 LDT),以及访问权限信息。”
我不太明白。
是否有单独的段选择器寄存器? 它是如何计算的? 为什么我们需要它?
【问题讨论】:
标签: assembly operating-system x86
段选择器何时出现。英特尔指南中的行说:
"每个段描述符都有一个关联的段选择器。一个段 选择器为使用它的软件提供 GDT 的索引 或 LDT(其关联的段描述符的偏移量), 全局/本地标志(确定选择器是否指向 GDT 或 LDT),以及访问权限信息。”
我不太明白。
是否有单独的段选择器寄存器? 它是如何计算的? 为什么我们需要它?
【问题讨论】:
标签: assembly operating-system x86
GDT 代表 全局描述符表。
这里重要的是 table 这个词,Intel 所说的 table 是指数组。
作为一个表一个数组,它有元素,每个元素被称为Descriptor。当然每个元素都可以被索引,即它有一个唯一的索引
段选择器寄存器保存描述符的索引。进入段选择器寄存器的值称为 selector。
但是事情要复杂一些。
索引 不是 选择器。
除了index之外,一个段选择器寄存器,还有两个东西:
程序员想要用于访问描述符的权限。对于每个寄存器,这称为 RPL(请求特权级别),但 CS 称为 CPL(当前特权级别)。 RPL 和 CPL 在使用段选择器寄存器中所起的作用在 Intel 手册中有定义,这里就不多解释了。
用于查看的表。一个表是GDT,另一个是LDT。英特尔手册中再次说明了差异和用途。
所以非正式的规则是:
选择器 = 索引 + table_to_use + 权限
table_to_use + 索引 = 描述符 = 关于要使用的内存段的所有信息
当然,+ 根本不意味着算术加法。段选择器寄存器的实际位域是
15 3 2 0
+--------------------------------------------------+----+--------+
| Index | TI | RPL |
+--------------------------------------------------+----+--------+
TI = Table Indicator: 0 = GDT, 1 = LDT
因此,例如值 05h 选择索引为 0 的描述符(在 LDT 中使用 RPL=1),这是无效的,因为英特尔明确要求不这样做使用描述符 0。
第一个可用的 descriptor 可通过 selector 08h 访问,它选择 GDT 作为表,RPL=0 . 08h-0bh的值都选择GDT中索引为1的descriptor,只是RPL不同。
这是术语的完整 ASCII 艺术
<---- Selector ----> +----- Segment Selector Register
+-------+----+-----+ v
| Index | TI | RPL | = DS
+-------+----+-----+ GDT LDT
| | +---------------------+ +---------------------+
| +------------>| Null Descriptor | | Null Descriptor |
| +---------------------+ +---------------------+
| | Descriptor 1 | | Descriptor 1 |
| +---------------------+ +---------------------+
| | | | |
| ... ... ... ... ... ... ... ...
| | |
| +---------------------+
+------------------->| Descriptor K |
+---------------------+
| |
... ... ... ...
关于它的计算方式以及我们为什么需要它
简答:阅读英特尔手册,因为它是完整的参考。
长答案:我们,用户模式程序员,不计算它。由于所有这些与段有关的事情归结为限制程序的权限,并且因为它是操作系统而不是我们发出命令,所以我们只需使用操作系统给我们的值(基本上通过加载我们的程序)作为 GDT 和 LDT 是由 OS 建立的,现在它愿意在任何方面与我们合作。
我们需要分段,因为在 真实模式 中有分段(Google 了解更多信息),因为它们可以避免在没有分页的情况下重新定位和聚集隔离(Google 了解更多信息)并且因为分段现在包含比简单的基本偏移和限制更多的信息。其中之一是:Descriptor Privilege Level,它限制了用户模式程序的权限。
【讨论】:
那么会发生什么:
每当加载程序时,链接加载程序都会使用适当的选择器加载“段寄存器”。
段寄存器(例如 CS、DS、SS 等)分为两部分:可见和隐藏。
它是加载器以适当的值加载的可见部分。
此值是 GDT 或 LDT 中的索引,具体取决于选择器的 TI 标志。
处理器自己加载隐藏部分。隐藏部分的信息是线性地址空间中的段基地址、段限制、访问信息。
【讨论】:
在实模式下,对内存的访问是分段的,即通过指定段位置和段偏移来访问。然后通过将偏移量添加到左移段位置来计算物理地址。段位置段和段偏移都是16位。
由于 Intel 的设计选择显然非常注重向后兼容性,因此他们选择保留 16 位大小的段寄存器。当保护模式出现时,这会导致问题。在保护模式下,GDT(全局描述符表)和 LDT(本地描述符表)保存在内存中的某个位置。这些描述符包含有关处理器使用的段的所有必要数据。为了访问这些描述符,您需要一个段选择器,它本质上是段描述符数组(即 LDT 或 GDT)的索引。
本质上,将 5 指定为段选择器的值会导致 CPU 使用本地/全局描述符表中的第 5 个(索引从零开始)描述符。
【讨论】:
LGDT/LLDT/LIDT 指令来加载描述符表。然后,您分配给选择器的任何值都将成为描述符表的索引。例如,将 3 分配给 ES 意味着您之前加载的描述符表中的第 3 个条目的值。并且任何使用 ES: 前缀的访问都将导致使用该条目的内容访问内存。