Ste*_*eve 4 x86 operating-system x86-64 memory-segmentation
在 x86 中,当您想要访问内存地址时,您将指定一个地址,该地址将通过两个阶段转换为内存地址:分段和分页:
但是在 x64 中也使用分段吗?(我认为它没有被使用,但我不确定它是不是在所有情况下都使用,或者在某些情况下使用它)。
就您发布的图片而言,仅在寻址模式使用寄存器fsor时才使用分段gs(因为 Linux 和 Windows 使用非零基数主动配置了这些寄存器)。
分段在保护(32 位)和长(64 位)模式下的工作方式与实模式(16 位)截然不同。
特别是,一个段不仅仅是一个基数和一个限制,而是一组从填充了段描述符的两个表(GDT 或 LDT)加载的属性。
对于所有的段寄存器,但fs和gs所述CPU忽略计算有效地址(也称为偏移)中,具有如使用0为基础的效果相同的动作时的基础。
此外,对于所有段寄存器,它不执行限制检查(但是线性地址必须是规范的)。
值得一提的是,当加载段寄存器时,CPU仍然加载 GDT/LDT 中段描述符的所有信息(包括基数和限制)。
这是支持兼容模式(32 位语义)所必需的,实际上代码和数据的段描述符并没有扩展到具有 64 位的基数和限制(经过粒度位的影响)。
这就是为什么在两个 64 位 MSR 寄存器中分别指定fs和的基数的原因gs。
英特尔 SDM 声称fs和gs基础物理映射到这些 64 位 MSR,那么我不清楚是否加载fs和gs来自段描述符也将设置 MSR。应该是这种情况,但我还没有调查(EDIT prl 做了并确认是这种情况)。
虽然基数和限制都消失了,但对于一对寄存器,所有其他检查仍然存在。
特别是代码段的 DPL(在描述符中指定的特权)设置了 CPL(执行代码的特权)。
堆栈段必须具有与 CPL 相等的 DPL(对于另一个称为 RPL 的特权也是如此)。
cs仍然必须加载代码段,可读和可写属性仍然强制执行(可能除了 forfs和gs)。
所有系统描述符都保留下来(调用门、TSS 选择器等)。
所以分段的所有保护机制(除了限制)都保留了下来,所以我不会说它没有被使用。
实际上,分段机制在 CPU 进入新的执行模式(带保护)的方式中深度集成,不使用它是不可能的。
当然,线性地址转换不再使用它(但对于通常的两个fs和gs),正是由于这些寄存器,我认为最好仍然记住您的图片。
上面列出的保护有一些例外:
fs并且gs没有属性检查(根据英特尔 SDM),这可能意味着可以加载不可读的代码段并从中读取或不可写的数据段并写入其中。这将与 SDM 相矛盾,该 SDM 还声明“不可读取的代码段或系统段的段选择器不能加载到数据段寄存器(DS、ES、FS 和 GS)中”或更一般地说“没有指令可以写如果它不可写,则进入数据段。除非设置了可读标志,否则任何指令都不能读取可执行段。 ”。
代码段的可读位未正常运行。从字面上看 SDM:“其余字段正常运行(类型字段中的可读位除外) ”,但随后它并没有说明它究竟做了什么(大概什么都没有,它被忽略了)。
空选择器始终有效。这是在权限更改控制传输(随着新的 64 位模式更改)期间被利用的。