【问题标题】:Assembly Segmented Model 32bit Memory Limit汇编段模型 32 位内存限制
【发布时间】:2011-05-01 15:49:25
【问题描述】:

如果使用分段内存模型运行的 32 位操作系统,它们仍然是 4GB 限制吗?

我正在阅读 英特尔奔腾处理器系列开发人员手册,其中指出,使用分段内存模型可以映射到 64TB 内存。

"在内存的分段模型中 组织,逻辑地址 空间由多达 16,383 每个最多 4 GB 的段,或 总大小为 2^46 字节(64 兆兆字节)。处理器映射这个 64 TB 逻辑地址空间 物理地址空间由 地址转换机制 在第 11 章中描述。应用 程序员可以忽略细节 这个映射。的优势 分段模型是在 每个地址空间都是分开的 检查并访问每个 段可以单独 控制。

这不是一个复杂的问题。我只是想确保我正确理解了文本。如果 Windows 或任何其他操作系统在分段模型而不是平面模型中工作,内存限制是否为 64TB?


更新:

英特尔的 3-2 3a 系统文档。


http://pdos.csail.mit.edu/6.828/2005/readings/i386/c05.htm


不应将段寄存器视为传统实模式意义上的。段寄存器充当全局描述符表的选择器。

在保护模式下,您使用 A:B 形式的逻辑地址来寻址内存。与实模式一样,A 是段部分,B 是该段内的偏移量。 > 保护模式中的寄存器限制为 32 位。 32 位可以表示 0 到 4Gb 之间的任何整数。 因为 B 可以是 0 到 4Gb 之间的任何值,所以我们的段现在的最大大小为 4Gb(与实模式中的推理相同)。 现在来看看区别。在保护模式下,A 不是段的绝对值。在保护模式下,A 是一个选择器。选择器表示在称为全局描述符表 (GDT) 的系统表中的偏移量。 GDT 包含一个描述符列表。这些描述符中的每一个都包含描述段特征的信息。

段选择器提供了分页无法实现的额外安全性。

[Segmentation and Paging]这两种方法各有优势,但分页要好得多。分段虽然仍然可用,但作为一种内存保护和虚拟内存的方法很快就会过时。事实上,x86-64 架构需要一个平面内存模型(一个基数为 0 且限制为 0xFFFFFFFF 的段)才能使其某些指令正常运行。

但是,分段完全内置于 x86 架构中。绕过它是不可能的。所以在这里我们将向您展示如何设置自己的全局描述符表 - 段描述符列表。

如前所述,我们将尝试建立一个平面内存模型。段的窗口应该从 0x00000000 开始并延伸到 0xFFFFFFFF(内存的末尾)。但是,分段可以做而分页不能做的一件事,那就是设置响铃级别。

-http://www.jamesmolloy.co.uk/tutorial_html/4.-The%20GDT%20and%20IDT.html

例如,GDT 列出了各种用户的访问级别和内存访问区域:

示例 GDT 表

GDT[0] = {.base=0, .limit=0, .type=0};             
// Selector 0x00 cannot be used
GDT[1] = {.base=0, .limit=0xffffffff, .type=0x9A}; 
// Selector 0x08 will be our code
GDT[2] = {.base=0, .limit=0xffffffff, .type=0x92}; 
// Selector 0x10 will be our data
GDT[3] = {.base=&myTss, .limit=sizeof(myTss), .type=0x89}; 
// You can use LTR(0x18)

http://wiki.osdev.org/GDT_Tutorial#What_should_i_put_in_my_GDT.3F

分页部分是映射到物理内存的部分。 (PAE) 可提供高达 64GB 的额外内存。

简而言之。答案是否定的,您不能拥有超过 4GB 的逻辑内存。我认为 英特尔奔腾处理器家族开发人员手册中关于 64TB 的声明是错误的。

【问题讨论】:

标签: assembly x86 operating-system paging memory-segmentation


【解决方案1】:

编辑:我的回答假设“4GB 限制”是指线性(虚拟)地址空间的最大大小,而不是物理地址空间。正如下面的 cmets 中所解释的,后者实际上根本不限于 4GB - 即使在使用平面内存模型时也是如此。


重复你的引用,强调:

逻辑地址空间由 多达 16,383 段 每个 4 GB

现在,引用“英特尔® 64 和 IA-32 架构软件开发人员手册第 1 卷:基本架构”(PDF 可用 here):

在内部,所有细分 为系统定义的映射到 处理器的线性地址空间。

正是这个线性地址空间(在 32 位处理器上)被限制为 4GB。因此,分段内存模型仍然会受到限制。

【讨论】:

  • 不……完全。对于爵士乐来说足够接近,但不足以保证 -1,但 Pentium 线上的后续处理器扩展(如 PAE 和 PSE-36 等)实际上为您提供了明显大于 4GB 的线性地址空间。事实上,大 16 倍。如果操作系统使用适当的段,那么单个进程就有可能访问所有这些空间(减去内核为自己保留的任何空间,自然而然)。
  • PAE 和 PSE-36 将 物理 地址空间增加到 4GB 以上 - 但线性(虚拟)地址仍限制为 32 位。跨度>
  • 不反对,只是从 Windows 的角度澄清:“如果使用适当的选项启动,Microsoft Windows 会实现 PAE,但当前的 32 位桌面版本强制物理地址空间在 4GB 以内,即使在PAE 模式。根据 Geoff Chappell 的说法,由于许可限制,微软将 32 位版本的 Windows 限制为 4GB,而微软技术研究员 Mark Russinovich 表示,发现某些驱动程序在遇到超过 4GB 的物理地址时会不稳定。” - PAE 上的维基
  • “由于多任务计算系统通常定义的线性地址空间比在物理内存中一次包含所有在经济上可行的要大得多,因此需要一些“虚拟化”线性地址空间的方法. 线性地址空间的这种虚拟化是通过处理器的分页机制处理的。” - Intel 3-2 Vol3A 第 94 页 这句话似乎与您关于 32 位进程上的线性地址空间有限的说法相反到 4GB。听起来线性地址空间大于内存是可行的。
  • 误区:PAE 将虚拟地址空间增加到 4GB 以上:blogs.msdn.com/b/oldnewthing/archive/2004/08/18/216492.aspx 我发誓英特尔文档可能具有误导性。
【解决方案2】:

你还记得过去吗? x86 上的 DOS 在实模式下使用 64kb 段? FAR 指针? HMA?短信服务?随着内存量的增长,他们找到了使用比处理器通常可以处理的更多内存的方法。但它很丑。

当然他们可以使用 32 位分段,但为什么呢?没有必要。当 32 位处理器出现时,4Gb 的限制已经绰绰有余,因此决定使用平面模型。

另外,一个 32 位操作系统可以使用超过 4Gb,它是被限制为 4Gb 地址空间的进程(在 Windows 上甚至是 2 或 3 个)。

【讨论】:

  • 进程是否仅因为是平面模型而受到限制?如果是分段模型呢?
  • @Shiftbit 不要将可直接寻址的地址范围与分段访问混淆。您可以使用 WME 访问更多内存,但您仍然无法执行 char* c = malloc(5*GB) 并在没有任何包装器的情况下直接从 if 读取任何值。
  • @Shiftbit 这里是一个更好的例子。您希望如何为具有 1M 的 64kb 段的处理器编程?它将有 64Gb 的地址空间。
【解决方案3】:

声明是 64TB 的逻辑地址空间。提出物理内存限制是无关紧要的,因为通过启用内存分页,可以绕过物理限制。

然而,这仍然是一个有点误导性的说法,因为段选择器的索引字段是 16 位,减去 1 位用于表指示符,2 位用于请求保护级别,总共留下 8,192(13 位)段选择器.对于 8,192 个 4GB 段,一个只能访问 GDT(全局描述符表)或 LDT(本地描述符表)中的 32TB 逻辑内存。为了能够访问 64TB 的逻辑内存,必须充分利用具有 16,384 个唯一段的 GDT 和 LDT。

不管怎样,第一个问题是“是否有 4GB 限制”,而答案是“否”。例如,在启用了分段和分页的 32 位系统上,可以将 512MB 分配给代码段(CS),1GB 分配给堆栈段(SS),4GB 分配给数据段(DS)。

如果操作系统使用分段内存模型,第二个问题是否会被限制在 64TB,这个问题的答案就不那么直接了。提供内存管理器是操作系统的工作。显然会有 32GB RAM 的物理限制。 32 位 Linux,因为它使用分页,可以为每个应用程序提供 4GB 的平面地址空间(忽略内核/用户拆分细节)。而且,每个进程都认为自己拥有 4GB 的物理地址空间。

简而言之,我认为您将分段的限制与分页的限制混淆了。分页使系统或应用程序能够使用比物理可用内存更多的 RAM。分段使进程能够映射到多个 32 位逻辑可寻址段。关键要注意,即使是平面模式也使用分段,但是所有的段寄存器都映射到同一个基地址。

【讨论】:

  • 分段在分页之前“解决”。启用分页后,段基址 + 偏移量会生成 32 位“线性”虚拟地址。即段基础是虚拟的,并且不会扩展您在任何给定时间可以映射的内存量。要访问超过 4GiB 的物理 RAM,您需要多个具有单独虚拟地址空间的“线程”/进程,或者您需要将物理 RAM 的不同部分重新映射到 32 位虚拟地址空间。当然,或者使用 x86-64 长模式。
  • 我不确定是否禁用分页。如果没有分页,您将无法使用 PAE,但是如果您设置分段限制 = 4G / 基本 = 3G(或略低于 4G)会发生什么情况。然后,您可能可以访问低 4G 之外的物理内存的某些部分,从该高基地址偏移 32 位。如果线性地址仍然是 32 位,也可能不是。
【解决方案4】:

AFAIK,由于操作系统的其他限制,答案是“不一定”。他们可能希望将内存的最大大小保持在远低于理论限制的水平,因为这可能会使某些内部内存结构更小且性能更高。但我真的不知道...我不是Mark Russinovich...

看看PAE。我认为这就是你所说的,但是自从我毕业到 64 位指针后,我决定用肯塔基纯波本威士忌杀死处理窗口记忆模型的脑细胞.

【讨论】:

  • 我特别喜欢 Wiki 中的这句话 “x86 处理器硬件架构增加了用于选择额外内存的额外地址线,因此物理地址大小从 32 位增加到 36 位。理论上,这会将最大物理内存大小从 4 GB 增加到 64 GB。虚拟地址的 32 位大小没有改变,因此常规应用软件继续使用 32 位地址的指令,并且(在平面内存模型中)限制为 4 GB 的虚拟地址空间。”
【解决方案5】:

英特尔的分段模型限制为 16,384 个分段。这个数字太小了,无法真正使事情变得方便。如果系统可以在 2 到 40 亿段之间快速切换,那会更好。这就是我希望看到的,而不是 64 位线性空间。一种可以有效地将每个分配的对象放入不同段的设计将允许对每个分配的对象进行无额外开销的范围检查,对象重定位对运行代码的影响最小(假设 CPU 可以注意到当前选择的段何时无效)等,而只要求对象引用在缓存中占用的空间是 64 位指针的一半。

【讨论】:

  • 听起来你想要一个 32 位指针来 be 一个段选择器。 (并且寻址模式必须定义哪个组件是段,哪些是偏移量?)如果 CPU 硬件必须从段描述符表中查找段基数/限制,那么您只是重新发明了虚拟内存页表,但可能没有固定的页面大小。所以桌子会很大。您肯定需要某种类似 TLB 的结构来缓存最近使用的段基数/限制,因为在实际 x86 中,如果没有第一个 mov fs, eax 或其他任何内容,您将无法 使用 段选择器,这很慢。
  • 无论如何,我不明白这怎么可能没有额外开销,即使您重新设计 x86 分段甚至超过 386,所以您不限于几个活跃的分段一次,而是可以使用通用寄存器中的段选择器值作为指针。这将花费硬件复杂性来实现任何类型的良好性能,并且大概 386 有足够的时间将晶体管花在 TLB 上进行分页。 (或者这可以完全取代分页,但这会使 x86 成为一种怪异的 ISA 方式,与普通的分页方式不同。)
  • @PeterCordes:作为一种真正简单的方法,像 8086 一样将 32 位值向左缩放 4 位,并且您的地址空间是 64GiB 而不是 4。请注意,一些 Java 实现使用 32 位将引用放大 8 倍以产生 35 位地址,所以这几乎是一回事。作为一种更好的方法,使用前 4 位选择 16 个可配置段组中的一个,并将剩余的 28 个按可按组配置的值缩放。
  • @PeterCordes:这种方法不会提供边界检查,但允许使用 32 位引用而不是 64 位。使用段描述符方法需要硬件缓存段描述符,但如果要让每个段的前几个字节与描述符共享一个缓存行,那么需要在访问对象之前访问对象头的代码它最近没有访问过(在 .NET 等 VM 中很常见)会在获取缓存描述符的同时获取所需的信息,从而最大限度地减少开销。
  • 好的,这可以工作,但绝对不是零开销。要在段内获得字节可寻址性,您需要使用像[ebx + eax] 这样的 2 寄存器寻址模式,其中基数被视为段,索引被视为字节偏移量。对于静态对象,[disp32 + idx] 可以是静态段内的字节偏移量,但[disp32 + base] 可以将 disp32 视为字节偏移量(在 disp8 范围之外),以 base 作为段。 IDK 如何扩展 8086 的 lea 指令。似乎它会使 386 成为一个困难的编译器目标,尤其是。对于当时的编译器。
猜你喜欢
  • 2017-01-27
  • 1970-01-01
  • 2011-02-28
  • 2011-04-09
  • 2011-01-31
  • 1970-01-01
  • 2011-03-08
  • 2013-08-19
相关资源
最近更新 更多