这篇是x86_64内存寻址的第二篇,现代的Intel处理器提供了两种方式来运行Intel 8086(比较老的处理器)程序,Intel在兼用方面做得的确好。 - 实地址模式 - 虚拟8086模式
在处理器启动的时候,处理器初始处于实地址模式。这个模式除了增加了一些增强功能,几乎完全复制了老式8086的执行环境。也就是说在8086编译运行的程序完全可以在新的处理器上运行。
在处理器运行在保护模式中,处理器可以切换为虚拟8086模式运行8086程序,在虚拟8086模式,8086程序作为单独的保护模式运行,也就说传统的8086程序可以在保护模式下运行,而且还能使用处理器提供的保护机制。另外,保护模式还允许多个虚拟8086程序在同一个处理器中运行。
在本章我们将学习实地址模式和虚拟8086模式的寻址,也就是实地址模式寻址。关于更加详细的这个两个模式的信息参考Intel开发手册
实地址模式
在实地址模式中,处理器的内存寻址空间为2^20-1,也就说地址线大小为20位。在此模式下处理器不会将段寄存器解释成段选择子,它会直接将线性地址解析成物理地址。
处理器为了获得20位的地址,需要将逻辑地址映射成20位的物理地址,逻辑地址由段寄存器和偏移量组成,处理器通过将段寄存器的值左移4位然后加上16位的偏移量组成20位的线性地址,由于在此模式下,没有分页和分段,这20位的线性地址就是最终的物理地址。计算公式如下:
PhysicalAddress = Segment Base * 16 + Offset
例如,CS:IP`为`0x2000:0x0010,那么经过上面的公式计算为:
>>> hex((0x2000 << 4) + 0x0010) '0x20010'
但是,需要注意特殊的一些情况,我们知道8086的地址线大小为20位,可寻址空间0-2^20-1(1MByte),但在有些情况下一些寻址空间可能大于1MByte。举个例子,我们假设寻址`0xffff:0xffff`的地址,经过计算
>>> hex((0xffff << 4) + 0xffff) '0x10ffef'
虽然段计算器和偏移量都是在合法范围内,但却超过了处理器可以寻址的空间。为了解决这种情况,处理器提供了一个叫做A20地址线的功能,如果这个功能是关闭的,那么最终选择的地址将超过的范围截断,为`0x00ffef`。但有些处理支持大于20的地址线,所以在A20地址线功能打开的时候,这个地址将被处理器直接寻址。