我正在从一本名为《操作系统》的书中阅读有关内存管理的内容。 之前,我已经研究过该主题,这很清楚,因为仅介绍了两种地址:物理和逻辑(物理和虚拟)。但是,这本书似乎介绍了三种类型,有时将它们中的两种视为相同,有时又视为不同。
这是一个引号(自己翻译,所以可能不是最好的):
在编写程序时,尚不知道在哪一点 程序将存储的内存,这就是为什么使用符号地址的原因 (变量名)。将符号地址转换为 物理地址称为地址绑定,可以在 不同的时间点。如果在编译过程中已知 程序将要进行地址绑定的是存储器的哪一部分 在这一点上完成。否则(最常见的情况)是编译器 生成相对地址(相对于 进程获取的内存)。执行程序时 loader 将相对地址映射到物理地址。
这一切似乎都很清楚。相对映射到物理。以下是之后的内容:
在执行过程中,与内存的交互是通过以下方式完成的: 读取和写入存储器位置的顺序。 CPU要么 从内存中读取指令或数据,或将数据写入内存 记忆。在这两个任务中,CPU不使用物理 而是CPU自身生成的逻辑地址。所有逻辑集 地址称为虚拟地址空间。
这已经很混乱了。逻辑地址和相对地址有什么区别?无论我在哪里查找,它们都永远不会分开。这是一个更加令人困惑的句子:
如果在编译时完成了地址绑定,并且 然后加载虚拟地址空间与物理地址匹配 空间。
更早之前说过,地址绑定是将符号地址转换为物理地址的过程。但是直到后来才引入相对地址的概念。据说加载是将相对转换为物理的过程。所以现在我在这里完全迷路了。
假设我们不知道流程将占用内存的哪一部分:时间轴如何?程序被编译,变量名(符号地址)被翻译成...我猜是相对的吗?然后,CPU需要执行一些读/写操作,并且使用...逻辑读/写操作?
此外,在本书的以下各节中,术语“相对”和“逻辑”似乎是随机使用的。好像它们是相同的,但仍然定义为不同。
有人可以帮我澄清一下吗?完美的答案可能是程序时间表的人为例子。什么时候引入了哪个地址,逻辑地址和相对地址之间有什么区别?
先谢谢了。
答案 0 :(得分:0)
相对地址表示两个位置或地址之间的距离(可以是逻辑的,线性的/虚拟的或物理的,在这一点上并不重要)。
例如,x86调用和跳转指令的格式指定了调用/跳转的距离(从调用/跳转指令结束后的字节数开始)。将该距离简单地添加到指令指针寄存器([R | E] IP)中,这就是下一条指令将来自的位置(再次,我现在忽略了逻辑,...,物理的)。
如果您的程序包含一个子例程并使用这样的指令调用它,则该程序在内存中的位置无关紧要,因为整个两个位置之间的距离保持不变(如果整个位置之间的关系将变得更加复杂该程序由几个活动部分组成,包括一个或多个库,但我们不要去那里了。
现在,假设您的程序有一个全局变量,需要读取它。如果存在类似于上述调用指令的存储器读取指令,则可以再次使用从指令指针到变量位置的距离。在64位x86 CPU之前,没有这样的指令/机制来访问数据,只有调用和跳转可能是IP相关的。
在没有这种与IP相关的数据寻址机制的情况下,您需要知道变量的实际地址,直到将程序加载到内存中以供执行之前,您才知道该变量的实际地址。在这种情况下,要做的是读取变量的指令最初接收的是相对于IP的变量地址(读取变量的指令的地址),或者仅仅是程序的启动。这就是程序存储在磁盘上的方式,指令内有一个相对地址。一旦加载,但在程序开始执行之前,将对读取该变量的指令中的变量地址进行调整,以使其成为实际地址,而不是相对于某个地址(IP或程序的开始)。程序的起始位置离地址0越远,则需要对该相对地址进行较大的调整。
有主意吗?
现在几乎完全不同且无关的东西……
在x86 CPU的上下文中,有以下几种地址:
如果我们一直回到8086/8088 ...实际上,如果我们再回到8080/8085,所有内存地址都是16位的,则它们不会被CPU进行任何转换并按原样显示在内存中,因此它们是物理的(在这里我们不是在谈论IP / PC相关的调用/跳转指令)。
16位允许64KB的内存。 8086/8088用另外16位扩展了这16位地址,以寻址超过64KB的存储器,但是它并不仅仅是将所有寄存器和地址从16位扩展到32位。相反,它引入了特殊的段寄存器,该寄存器将与8080/8085的那些旧16位地址成对使用。因此,一对寄存器,例如DS
(分段寄存器)和BX
(常规通用寄存器)可以对地址为DS * 16 + BX
的存储器进行寻址。对DS:BX
是逻辑地址,值DS * 16 + BX
是物理地址。通过这种方案,我们可以访问大约1MB的内存(只需为两个寄存器插入65535)。
80286通过引入所谓的保护模式稍微改变了上述内容,在该模式中,物理地址计算为segment_table[DS] + BX
(允许从1MB到16MB),但是这个想法还是一样。
接下来出现了80386,并将寄存器扩展到32位,并引入了另一层间接寻址。现在的物理地址简化了page_tables[segment_table[DS] + EBX]
。
一对DS:EBX
构成了逻辑地址,这就是程序所处理的内容(例如,在指令MOV EAX, DS:[EBX]
中),这是它可以观察到的。
segment_table[DS] + EBX
构成了线性/虚拟地址(程序可能无法始终知道该地址,因为它无法查看由操作系统管理的segment_table[]
)。如果未启用页面转换,则此线性/虚拟地址也等于最终的物理地址。
启用页面翻译后,物理地址为page_tables[segment_table[DS] + EBX]
。
要了解的更多信息:
DS:[EAX + EBX * 2 + 3]
操作系统通常将segment_table[]
设置为segment_table[any segment register]=0
,这样可以有效地将图片分割机制从图片中删除,并以例如物理地址= page_tables[EAX + EBX * 2 + 3]
。在这种设置中说逻辑和线性/虚拟地址是相同的(EAX + EBX * 2 + 3
)并不完全正确,但这无疑简化了思考。
现在,这些段表和页表与开始讨论的相对地址和重定位有什么关系?这些表仅使您可以将程序放置在物理内存中的任何位置,通常以对程序本身非常透明的方式进行。不需要知道它在物理上的位置,也不需要知道是否启用了页面翻译。
但是,使用页面翻译有一些好处,但这超出了本文的范围。