【问题标题】:Why 64 bit mode ( Long mode ) doesn't use segment registers?为什么 64 位模式(长模式)不使用段寄存器?
【发布时间】:2014-02-05 14:09:26
【问题描述】:

我是初学者 :) 我正在研究英特尔架构, 我正在研究内存管理,例如分段和分页。 我正在阅读英特尔的手册,了解英特尔的架构非常好。

但是我仍然对一些基本的东西感到好奇。 为什么在 64 位长模式下,所有段寄存器都将变为位 0? 为什么系统不再使用段寄存器?

因为系统的 64 位大小(例如 GP 寄存器)足以一次包含这些逻辑地址? 保护在 64 位模式下是否正常工作?

我尝试查找 64 位寻址,但在 Google 中找不到。也许我的搜索能力很差,或者我可能需要一些特定的先前知识才能在 google 中搜索。

因此我想知道为什么 16 位段寄存器不会在 64 位模式下使用, 以及保护如何在 64 位模式下正常工作。

谢谢!

【问题讨论】:

  • 段寄存器是 16 位实模式的实现细节。这在 20 年前就不再重要了。 32 位和 64 位模式使用平坦的未分段虚拟内存地址空间。
  • @HansPassant:如果段寄存器与其他所有内容一起增长到 32 位,它们在面向对象的框架中可能非常相关和有用[让每个对象从某个段的偏移量零开始将允许框架使用偏移寄存器访问许多 gigs 的内存,这些偏移寄存器的大小是 x64 中的一半]。它们没有用的真正原因是段标识符保持 16 位,而其他所有内容都变大了。
  • going to bit 0。我不确定你的意思是什么,但它们既不一定为零,也不是 all 段寄存器的基数为零。 FSGS 仍然用于完整的 64 位基础,对于访问线程本地存储非常有用。

标签: memory-management x86-64 intel memory-segmentation


【解决方案1】:

从某种意义上说,当您使用通用寄存器执行数组(“索引”)类型寻址时,您所做的基本上与段寄存器相同。在 8 位和 16 位编程的糟糕的过去时代,许多应用程序需要比 16 位地址更多的数据(有时还需要更多代码)。

许多 CPU 通过拥有比 16 位地址所能达到的更大的可寻址内存空间来解决这个问题,并通过“段寄存器”或类似的方式使这些内存区域可访问。程序会将“段寄存器”中的地址设置为高于(65536 字节)16 位地址空间的地址。然后在执行某些指令时,会将指令指定地址添加到适当(或指定)的“段寄存器”中,以读取超出 16 位地址或 16 位偏移范围的数据(或代码)。

然而,今天的情况正好相反!

怎么会?今天,64 位 CPU 可以寻址超过(不少于)所有可寻址的内存空间。今天大多数 64 位 CPU 可以寻址 40 位到 48 位的物理内存。诚然,没有什么可以阻止他们寻址完整的 64 位内存空间,但他们知道没有人(除了 NSA)能负担得起这么多 RAM,此外,将这么多 RAM 挂在 CPU 总线上会因电容而加载它,并减慢 CPU 芯片外的所有内存访问。

因此,当前这一代的主流 CPU 可以寻址 40 位到 48 位的内存空间,这是超过 99.999% 的市场无法想象的。请注意,32 位是 4 GB(今天有些人确实超过了 2、4、8、16 倍),但即使是 40 位也可以寻址 256 * 4GB == 1024GB == 1TB。虽然今天 64GB 的 RAM 是合理的,在极端情况下甚至可能是 256GB,但 1024GB 并不是必需的,除非可能是 0.001% 的应用程序,而且启动起来负担不起。

如果您属于 0.001% 类别,则只需购买一个可寻址 48 位物理内存的 CPU,您所说的是 256TB……目前这是不切实际的,因为它会加载内存总线电容太大(甚至可能内存总线会完全停止工作)。

重点是这个。当您使用普通 64 位寄存器的普通寻址模式已经可以寻址比您的计算机所能容纳的更多的内存时,添加段寄存器的传统理由就消失了。

这并不意味着人们在 64 位 CPU 中找不到段寄存器的有用用途。他们可以。几种可能性是显而易见的。但是,对于 64 位通用寄存器和 64 位地址空间,没有什么是通用寄存器不能做的,而段寄存器可以。通用寄存器有很多用途,而段寄存器没有。因此,如果有人打算为现代 64 位 CPU 添加更多寄存器,他们会添加通用寄存器(可以做“任何事情”),而不是添加用途非常有限的“段寄存器”。

他们确实有。您可能已经注意到,AMD 和 Intel 不断向 SIMD 寄存器文件添加更多 [sorta] 通用寄存器,并且 AMD 在设计 64 位 x86_64 CPU(Intel复制)。

【讨论】:

  • 8086 段寄存器是一个很好的硬件设计,实际上,只是因为它们的数量不够,并且指令集中有一些令人讨厌的遗漏[例如mov segReg,immed]。然而,缺乏语言支持。如果分配被四舍五入到 16 字节的倍数,那么指向已分配对象的指针应该只占用两个字节而不是四个字节,但通用语言没有段落对齐指针的概念。然而,许多面向对象的框架可以很好地处理类似于实模式分割的东西(但使用 32 位 regs)。
  • 您错过了 FSGS 仍然有用,实际上它们在 Windows 和 Linux 上都被积极用于访问 TLS。
  • 我认为您完全错过了如何在 32 位保护模式下使用段寄存器。它们甚至不能用于访问更多内存,它们被用作全局描述符表中的选择器来设置偏移量和一些内存保护。此功能在长模式下几乎完全禁用。我认为这是实际的问题(是什么把我带到了这里)。您还错过了分布式共享内存模型,该模型允许访问物理分布在网络上的大量内存。
  • @Celelibi:我认为您可以制作一个在 32 位保护模式下使用非平坦内存空间的操作系统,具有多个 4GiB 段。没有人做过/做过,并且 CPU 针对这种情况进行了优化。 (非零段偏移会减慢所有内存访问,IIRC)。
  • 为了扩展@Celelibi 关于分布式共享内存的观点,即使是多插槽单系统也将内存连接到每个插槽中的单独内存控制器。每个插槽中的多通道内存控制器也意味着大量记忆棒的总线负载更少。 (桌面 CPU 有双通道控制器,但服务器 CPU 可以有更多。) 64 位 虚拟 地址空间还允许内存映射巨大的文件。只有物理地址空间才能反映在单个缓存一致的 SMP 系统中可能连接到多少实际 RAM。
【解决方案2】:

大多数关于 32/64 位世界中段寄存器无关性问题的答案总是围绕内存寻址展开。我们都同意段寄存器的主要目的是绕过 16 位 DOS 世界中的地址空间限制。但是,从安全能力的角度来看,段寄存器提供了 4 个地址空间隔离环,如果我们使用 64 位长模式,例如 64 位操作系统,则不可用。对于当前流行的操作系统(例如 Windows 和 Linux)来说,这不是问题,它们仅使用具有两个隔离级别的 ring 0 和 ring 3。环 1 和 2 有时是内核的一部分,有时是用户空间的一部分,具体取决于代码的编写方式。从隔离的角度来看,随着硬件虚拟化(相对于操作系统虚拟化)的出现,虚拟机管理程序在 ring 0 或 ring 1/2/3 中都不太适合。 Intel 和 AMD 为 VM 的 root 和非 root 操作添加了额外的指令(例如,INTEL VMX)。

那么重点是什么?如果一个人正在设计一个具有 4 个隔离环的新安全操作系统,那么如果禁用分段,我们就会遇到问题。例如,我们为硬件多路复用代码、管理程序代码/容器/VM、操作系统内核和用户空间各使用一个环。因此,我们可以根据上述要求提出利用分段提供的额外安全性的案例。但是,Intel/AMD 仍然允许 F 和 G 段寄存器具有非零值(即不禁用分段)。据我所知,没有任何操作系统能够利用这一希望为硬件虚拟化编写更安全的操作系统/Hypervisor。

【讨论】:

  • x86-64 仍然使用与 32 位保护模式相同的 2 位(4 级)特权级机制。 CS 选择器的低 2 位是 CPL(当前权限级别),基于 GDT 条目允许的权限级别检查机制仍然相同。对于 CS/DS/ES/SS,段基数/限制固定为 0 / -1,但 CS 仍需要索引 GDT 中的有效代码段。这也是 x86-64 CPU 知道是将机器代码解码为 16、32 还是 64 位模式的方式,以及是否允许像 invlpg 这样的特权指令(环 0)。
  • 内存保护由分页提供,但其他特权级的东西仍然存在。我不确定特权级别是否会影响数据段加载/存储,例如有环 1 可以读取但环 3 不能读取的内存。因此,即使所有 4 个特权级别仍然存在,它也可能无法完全使用。
猜你喜欢
  • 2015-06-24
  • 2017-01-03
  • 2014-11-17
  • 2021-07-20
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
  • 2013-11-22
相关资源
最近更新 更多