在8086基础的拓展,例如将16位的AX拓展为32位。为了向后兼容,AX依旧是16位寄存器,EAX是拓展32位寄存器。AX是EAX的低16位,就像AL是AX的低8位一样。
段寄存器依旧是16位,并且增加了两个新的段寄存器:FS和GS。它们和ES一样,就是额外的寄存器(备胎)。
在实模式下,内存只有1M大小,也就是2^20字节。对应的有效地址就是从00000到FFFFF。但是这么多的地址需要20位的数才能表示。但是对于8086的16位寄存器无法表示完整。Intel便通过两个16位的数才得到实模式下的地址。那么具体怎么得到呢,前16位的值叫做selector,selector值必须储存在段寄存器中。后16位的值叫做offset。这样物理地址就可以用一个32-bit的selector:offset来表示出来。通过一下的公式:
16*selector+offset
在16进制中乘以一个16很简单,就像在10进制中乘一个10一样,仅需要在selector后面加一个0,然后再将offset的值加上即可得到物理地址,例如
047C:0048
等于
047C0+0048
,即04808
。
selector是16字节的数(也就是它有 24个地址,而每个地址有1字节内存)。当然,实段地址有一些不好的地方:
一个单一的select寄存器只能检索到64K大小,上界便是16-bit的offset。那如果有一个程序,其要运行的程序有大于64K的大小,那么这和问题如何解决?
在内存中的每个字节并不一定只有唯一的段地址。物理地址04808有可能是047C:0048, 047D:0038, 047E:0028或者047B:0058。这样段地址的比较就非常复杂。
在80286的16位保护模式下,selector值与实模式下的值的解释是完全不一样的。 在实模式下,selector值为paragraph memory(16字节)。 在保护模式下,selector是到描述表(descriptor table)的一个索引值(index)。 两种模式下,程序都分为段: 在实模式下,这些段在物理内存的固定地址上,selector就是段开头的paragraph数, 在保护模式下,段不再在物理内存段固定地址,事实上,它们不一定要在内存中了。
在保护模式下,运用了一个叫做虚拟内存的技术一个虚拟内存的基本想法是,只要保证程序此时在用的数据和代码在内存中。其他的数据和代码可以暂时储存在磁盘上知道它们需要再次被使用。 在16-bit保护模式下,段在内存和磁盘之间移动: 当段从磁盘回到内存时,很有可能该段会被放在和它移动到磁盘之前的一个不同的地方。而这就时操作系统所做的。
保护模式下,每个段在描述表中分配了一个入口。这个入口上有系统想要知道该段段所有信息:它是否还在内存;如果在,那么在哪里;允许获取(例如只读)。那么,该段入口的索引值就是存储在段寄存器里的selector值。
不好的地方就是,offset依旧时16位的。因此段大小依旧限制在64K。
386的32-bit与286的16-bit保护模式比较,有两个主要的不同:
Offsets拓展到32-bits。这就允许一个offset达到4 billion,段的大小升级到4G。 段可以被分为更小的4K大小的页(pages)。虚拟内存就不再与段合作而是与页合作。
注意
关于内存,有一些计量单位,如下表:
名称 | 含义 |
---|---|
word | 2 bytes |
double word | 4 bytes |
quad word | 8 bytes |
paragraph | 16 bytes |
参考资料: