分段寄存器使用
我试图理解内存管理如何在低级别上出现,并且有几个问题。
1)由Kip R. Irvine撰写的一本关于汇编语言的书说,在实模式下,当程序启动时,首先在三个段寄存器中加载代码,数据和堆栈段的基址。 这对我来说有点模糊。 这些值是手动指定还是汇编器生成指令以将值写入寄存器? 如果它自动发生,它如何发现这些细分市场的规模?
2)我知道Linux使用扁平线性模型,即以非常有限的方式使用分割。 另外,根据Daniel P. Bovet和Marco Cesati的“了解Linux内核”,GDT中有四个主要部分:用户数据,用户代码,内核数据和内核代码。 所有四个段都具有相同的大小和基地址。 我不明白为什么他们中的四个需要它们,如果它们只有类型和访问权限(它们都产生相同的线性地址,对吧?)。 为什么不使用其中的一个,并将其描述符写入所有段寄存器?
3)不使用分段的操作系统如何将程序划分为逻辑段? 例如,他们如何区分堆栈和没有段描述符的代码。 我读过分页可以用来处理这样的事情,但不知道如何。
扩展Benoit对问题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可执行格式非常简单。
你必须阅读一些真正的旧书,因为没有人再为真实模式编程;-)在实模式中,你可以通过物理phyical address = segment register * 0x10 + offset
获得存储器访问的物理地址,偏移量是一个值在一个通用寄存器内。 因为这些寄存器是16位宽的,所以一个段的长度将是64kb,并且对于它的大小没有任何可以做的事情,只是因为没有属性! 在* 0x10
乘法的情况下,1mb的内存变得可用,但根据你在段寄存器和地址寄存器中放置的内容,有重叠的组合。 我没有为实模式编译任何代码,但我认为在二进制加载过程中设置段寄存器的操作系统是由操作系统决定的,就像加载器在加载ELF二进制文件时分配一些页面一样。 但是我编译裸机内核代码,我必须自己设置这些寄存器。
由于架构限制,平面模型中有四个部分是强制性的。 在保护模式下,段寄存器不再包含段基地址,而是基本上是GDT偏移量的段选择器。 根据段选择器的值,CPU将处于特定级别的权限,这是CPL(当前权限级别)。 段选择器指向一个具有DPL(描述符权限级)的段描述符,如果段寄存器用这个选择符填充(对于代码段选择符至少为真),该描述符最终是CPL。 因此,您至少需要一对段选择器来区分内核和用户区。 此外,段是代码段或数据段,因此您最终会在GDT中使用四个段描述符。
我没有任何使用分割的严肃操作系统的例子,只是因为分割依然存在以实现向后兼容。 使用平面模型方法不过是摆脱它的一种手段。 无论如何,你说得对,分页的方式更加高效和多功能,几乎可以在所有架构(至少是概念)上使用。 我无法在这里解释分页内部信息,但是您需要知道的所有信息都在英特尔的优秀人员之内:英特尔®64和IA-32架构软件开发人员手册卷3A:系统编程指南,第1部分
在这种情况下维基百科是你的朋友。 http://en.wikipedia.org/wiki/Memory_segmentation和http://en.wikipedia.org/wiki/X86_memory_segmentation应该是很好的起点。
不过,我确信这里有其他人可以亲自提供深入的解释。
链接地址: http://www.djcxy.com/p/82375.html