6

我试图了解内存管理是如何在低级别进行的,并且有几个问题。

1) Kip R. Irvine 的一本关于汇编语言的书说,在实模式下,程序启动时,前三个段寄存器加载了代码、数据和堆栈段的基地址。这对我来说有点模棱两可。这些值是手动指定的,还是汇编器生成指令将值写入寄存器?如果它自动发生,它如何找出这些段的大小?

2)我知道Linux使用扁平线性模型,即以非常有限的方式使用分段。此外,根据 Daniel P. Bovet 和 Marco Cesati 的“Understanding the Linux Kernel”,GDT 中有四个主要部分:用户数据、用户代码、内核数据和内核代码。所有四个段都具有相同的大小和基地址。如果它们仅在类型和访问权限上有所不同(它们都产生相同的线性地址,对吗?),我不明白为什么需要其中四个。为什么不只使用其中一个并将其描述符写入所有段寄存器?

3)不使用分段的操作系统如何将程序划分为逻辑段?例如,它们如何区分堆栈和没有段描述符的代码。我读到分页可用于处理此类事情,但不明白如何。

4

3 回答 3

4
  1. 您一定读过一些很老的书,因为没有人再为实模式编程了;-) 在实模式中,您可以使用 获取内存访问的物理地址phyical address = segment register * 0x10 + offset,偏移量是一个通用寄存器中的值。因为这些寄存器是 16 位宽的,一个段将是 64kb 长,而且你对它的大小无能为力,只是因为没有属性!通过* 0x10乘法,可以使用 1mb 的内存,但是根据您在段寄存器地址寄存器中放入的内容,会有重叠的组合。我还没有为real-mode编译任何代码,但我认为由操作系统来设置段寄存器在二进制文件加载期间,就像加载程序在加载 ELF 二进制文件时分配一些页面一样。但是我确实编译了裸机内核代码,我必须自己设置这些寄存器。

  2. 由于架构限制,平面模型中必须有四个段。在保护模式下段寄存器不再包含段基地址,而是一个段选择器,它基本上是 GDT 的偏移量。根据段选择器的值,CPU 将处于给定的特权级别,这就是 CPL(当前特权级别)。段选择器指向一个段描述符,它有一个 DPL(描述符特权级别),如果段寄存器被这个选择器填充(至少对于代码段选择器是正确的),它最终是 CPL 。因此,您至少需要一对段选择器将内核与用户区区分开来。此外,段要么是代码段,要么是数据段,所以你最终会在 GDT 中得到四个段描述符。

  3. 我没有任何使用分段的严重操作系统的例子,只是因为分段仍然存在以实现向后兼容。使用平面模型方法只不过是摆脱它的一种手段。无论如何,你是对的,分页更加高效和通用,并且几乎适用于所有架构(至少是概念)。我无法在此处解释分页内部原理,但您需要了解的所有信息都在优秀的英特尔人员内部:英特尔® 64 和 IA-32 架构软件开发人员手册第 3A 卷:系统编程指南,第 1 部分

于 2012-06-07T21:15:40.243 回答
3

扩展Benoit 对问题 3 的回答......

将程序划分为代码、常量数据、可修改数据和堆栈等逻辑部分是由不同的代理在不同的时间点完成的。

首先,您的编译器(和链接器)创建指定此划分的可执行文件。如果您查看许多可执行文件格式(PE、ELF 等),您会发现它们支持某种节或段或任何您想要调用的格式。除了文件中的地址、大小和位置之外,这些部分还具有告诉操作系统这些部分的用途的属性,例如,此部分包含代码(这里是入口点),this - 已初始化的常量数据,that - 未初始化的数据(通常不占用文件中的空间),这里有一些关于堆栈的内容,还有依赖项列表(例如 DLL)等。

接下来,当操作系统开始执行程序时,它会解析文件以查看程序需要多少内存,每个部分需要在哪里以及需要什么内存保护。后者通常通过页表完成。代码页被标记为可执行和只读,常量数据页被标记为不可执行和只读,其他数据页(包括堆栈的数据页)被标记为不可执行和读写。正常情况下应该是这样。

通常,程序需要读写,同时需要动态生成代码的可执行区域,或者只是为了能够修改现有代码。组合的 RWX 访问可以在可执行文件中指定,也可以在运行时请求。

可以有其他特殊页面,例如用于动态堆栈扩展的保护页面,它们被放置在堆栈页面旁边。例如,您的程序从为 64KB 堆栈分配的足够页面开始,然后当程序尝试访问超出该点时,操作系统会拦截对这些保护页面的访问,为堆栈分配更多页面(直到支持的最大大小)和进一步移动保护页。这些页面不需要在可执行文件中指定,操作系统可以自己处理它们。该文件应仅指定堆栈大小以及可能的位置。

如果操作系统中没有硬件或代码来区分代码内存和数据内存或强制执行内存访问权限,则划分非常正式。16 位实模式 DOS 程序(COM 和 EXE)没有以某种特殊方式标记代码、数据和堆栈段。COM 程序将所有内容放在一个共同的 64KB 段中,它们以 IP=0x100 和 SP=0xFFxx 开头,内部代码和数据的顺序可以是任意的,它们几乎可以自由地交织在一起。DOS EXE 文件只指定了起始 CS:IP 和 SS:SP 位置,除此之外,代码、数据和堆栈段与 DOS 无法区分。它所需要做的就是加载文件,执行重定位(仅适用于 EXE),设置 PSP(程序段前缀,包含命令行参数和一些其他控制信息),加载 SS:SP 和 CS:IP。

于 2012-06-15T08:22:59.040 回答
-1

在这种情况下,维基百科是你的朋友。http://en.wikipedia.org/wiki/Memory_segmentationhttp://en.wikipedia.org/wiki/X86_memory_segmentation应该是很好的起点。

不过,我相信这里还有其他人可以亲自提供深入的解释。

于 2012-06-05T20:32:54.350 回答