我试图了解内存管理如何处于低级别并且有几个问题。
1)Kip R. Irvine撰写的一本关于汇编语言的书说,在实模式中,前三个段寄存器在程序启动时加载了代码,数据和堆栈段的基址。这对我来说有点不合时宜。是手动指定这些值还是汇编程序生成将值写入寄存器的指令?如果它自动发生,它如何找出这些段的大小是什么?
2)我知道Linux使用扁平线性模型,即以非常有限的方式使用分段。此外,根据Daniel P. Bovet和Marco Cesati的“理解Linux内核”,有四个主要部分:用户数据,用户代码,内核数据和GDT中的内核代码。所有四个段都具有相同的大小和基址。我不明白为什么四个中只有它们的类型和访问权限不同(它们都产生相同的线性地址,对吧?)。为什么不只使用其中一个并将其描述符写入所有段寄存器?
3)不使用分段的操作系统如何将程序划分为逻辑段?例如,他们如何在没有段描述符的情况下将堆栈与代码区分开来。我读过分页可以用来处理这些事情,但是不明白怎么做。
答案 0 :(得分:4)
您必须阅读一些非常旧的书籍,因为没有人为实模式编程了;-)在实模式中,您可以获得实际地址对于phyical address = segment register * 0x10 + offset
的存储器访问,偏移量是一个通用寄存器内的值。因为这些寄存器是16位宽,所以一个段长64kb,没有什么可以做的,只是因为没有属性!使用* 0x10
乘法,可以使用1mb的内存,但根据放在段寄存器和地址寄存器中的内容,存在重叠组合。我没有为实模式编译任何代码,但我认为在二进制加载期间设置段寄存器是操作系统,就像加载器会分配一样加载ELF二进制文件时的一些页面。但是我确实编译了裸机内核代码,我必须自己设置这些寄存器。
由于架构限制,扁平模型中必须有四个段。在保护模式中,段寄存器不再包含段基地址,而是段选择器,它基本上是GDT的偏移量。根据段选择器的值,CPU将处于给定的权限级别,这是CPL(当前权限级别)。 段选择器指向具有DPL(描述符权限级别)的段描述符,如果段寄存器被填充,则最终为CPL使用此选择器(对于代码段选择器至少为true)。因此,您至少需要一对段选择器来区分内核和用户区。此外,段是代码段或数据段,因此您最终在GDT中最终得到四个段描述符。
我没有任何使用分段的严重操作系统的例子,只是因为对于后向合规性仍然存在分段。使用平面模型方法只不过是摆脱它的意思。无论如何,你是对的,分页是更有效和多功能的,并且几乎在所有架构上都可用(至少是概念)。我无法在这里解释分页内部,但你需要知道的所有信息都在优秀的英特尔人中:Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1
答案 1 :(得分:3)
扩展Benoit's answer to question 3 ...
将程序划分为逻辑部分,如代码,常量数据,可修改数据和堆栈,由不同的代理在不同的时间点完成。
首先,您的编译器(和链接器)创建指定此除法的可执行文件。如果你看一些可执行文件格式(PE,ELF等),你会发现它们支持某种类型的段或段或者你想要的任何类型。除了文件中的地址,大小和位置之外,这些部分还具有告诉操作系统这些部分的目的的属性,例如,这部分包含代码(这里是入口点),这是初始化的常量数据,即 - 未初始化的数据(通常不占用文件中的空间),这里是关于堆栈的东西,在那里有依赖项列表(例如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。它无法保护内存,因为实际地址模式下没有内存保护,因此16位DOS可执行格式非常简单。
答案 2 :(得分:-1)
在这种情况下,维基百科是你的朋友。 http://en.wikipedia.org/wiki/Memory_segmentation和http://en.wikipedia.org/wiki/X86_memory_segmentation应该是很好的起点。
我确信这里还有其他人可以亲自提供深入的解释。