![Linux不使用分段而只使用分页吗?](https://linux22.com/image/10851/Linux%E4%B8%8D%E4%BD%BF%E7%94%A8%E5%88%86%E6%AE%B5%E8%80%8C%E5%8F%AA%E4%BD%BF%E7%94%A8%E5%88%86%E9%A1%B5%E5%90%97%EF%BC%9F.png)
Linux 编程接口显示进程的虚拟地址空间的布局。图中的每个区域都是一个线段吗?
从了解 Linux 内核,
MMU 中的分段单元将段和段内的偏移量映射到虚拟内存地址,然后分页单元将虚拟内存地址映射到物理内存地址,这是否正确?
内存管理单元(MMU)通过称为分段单元的硬件电路将逻辑地址转换为线性地址;随后,称为分页单元的第二个硬件电路将线性地址转换为物理地址(见图 2-1)。
那为什么说Linux不使用分段而只使用分页呢?
80x86 微处理器中已包含分段功能,以鼓励程序员将其应用程序拆分为逻辑相关的实体,例如子例程或全局和本地数据区域。然而, Linux 以非常有限的方式使用分段。其实分段和分页都有些多余,因为两者都可以用来分隔进程的物理地址空间:分段可以为每个进程分配不同的线性地址空间,而分页可以将相同的线性地址空间映射到不同的物理地址空间。 Linux 更喜欢分页而不是分段,原因如下:
• 当所有进程使用相同的段寄存器值时(即,当它们共享同一组线性地址时),内存管理会更简单。
• Linux 的设计目标之一是可移植到多种体系结构;特别是 RISC 架构对分段的支持有限。
Linux 2.6 版本仅在 80x86 架构需要时才使用分段。
答案1
x86-64 架构在长模式(64 位模式)下不使用分段。
其中四个段寄存器:CS、SS、DS 和 ES 被强制为 0,并且限制为 2^64。
https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments
操作系统不再可能限制可用的“线性地址”范围。因此不能使用分段来进行内存保护;它必须完全依赖于分页。
不必担心 x86 CPU 的细节,这些细节仅适用于在传统 32 位模式下运行时。 Linux 的 32 位模式使用得不多。它甚至可能被认为“多年来一直处于被善意忽视的状态”。看Fedora 中的 32 位 x86 支持[LWN.net,2017]。
(碰巧 32 位 Linux 也不使用分段。但是你不需要相信我,你可以忽略它:-)。
答案2
图中的每个区域都是一个线段吗?
不。
虽然分段系统(x86 上的 32 位保护模式)旨在支持单独的代码、数据和堆栈段,但实际上所有段都设置为同一内存区域。也就是说,它们从 0 开始,到内存末尾(*)结束。这使得逻辑地址和线性地址相等。
这称为“平面”内存模型,比具有不同段和其中的指针的模型要简单一些。特别是,分段模型需要更长的指针,因为除了偏移指针之外还必须包括段选择器。 (16 位段选择器 + 32 位偏移量,总共 48 位指针;而只有 32 位平面指针。)
除了平面内存模型之外,64 位长模式实际上甚至不支持分段。
如果要在 286 上以 16 位保护模式进行编程,则需要更多段,因为地址空间是 24 位,但指针只有 16 位。
(* 请注意,我不记得 32 位 Linux 如何处理内核/用户空间分离。分段将允许通过设置用户空间段限制来实现这一点,以便它们不包括内核空间。分页允许它,因为它提供了每页保护级别。)
那为什么说Linux不使用分段而只使用分页呢?
x86 仍然有这些段,您无法禁用它们。它们只是尽可能少地使用。在 32 位保护模式下,需要为平面模型设置段,即使在 64 位模式下它们仍然存在。
答案3
由于 x86 有段,所以不可能不使用它们。但cs
(代码段)和ds
(数据段)基地址都设置为零,因此分段并没有真正使用。线程本地数据是一个例外,通常不使用的段寄存器之一指向线程本地数据。但这主要是为了避免为此任务保留通用寄存器之一。
它并没有说 Linux 不在 x86 上使用分段,因为这是不可能的。您已经突出显示了一部分,Linux 以非常有限的方式使用分段。第二部分是Linux 仅在 80x86 架构需要时才使用分段
您已经引用了原因,分页更容易且更便携。
答案4
Linux x86/32 不使用分段,因为它将所有段初始化为相同的线性地址和限制。 x86架构要求程序有段:代码只能从代码段开始执行,堆栈只能位于堆栈段,数据只能在其中一个数据段中操作。 Linux 通过以相同的方式设置所有段(除了您的书中没有提及的例外情况)来绕过此机制,以便相同的逻辑地址在任何段中都有效。这实际上相当于根本没有段。