8086架构
8个16位通用寄存器(CPU 内部的数据单元)
其中的4个AX、BX、CX、DX 为可以分成两个 8 位的寄存器来使用,分别是 AH、AL、BH、BL、CH、CL、DH、DL。
其中 H 就是 High(高位),L 就是 Low(低位)的意思。
IP 寄存器
指令指针寄存器(Instruction Pointer Register),指向代码段中下一条指令的位置。
CPU 会根据它来不断地将指令从内存的代码段中,加载到 CPU 的指令队列中,然后交给运算单元去执行。
段寄存器
CS -代码段寄存器(Code Segment Register)
通过它可以找到代码在内存中的位置
DS -数据段寄存器(Data Segment Register)
通过它可以找到数据在内存中的位置。
SS -栈寄存器(Stack Register)
栈是程序运行中一个特殊的数据结构,数据的存取只能从一端进行,秉承后进先出的原则,push 就是入栈,pop 就是出栈。
段数据-寻址过程
对于一个段,有一个起始的地址,而段内的具体位置,我们称为偏移量(Offset)。
例如 8 号会议室的第三排,8 号会议室就是起始地址,第三排就是偏移量。
背景
在 CS 和 DS 中都存放着一个段的起始地址(16位)
代码段的偏移量在 IP 寄存器中,数据段的偏移量会放在通用寄存器中。
偏移量也是 16 位的,但 8086 的地址总线地址是 20 位
解决方案
起始地址 *16+ 偏移量
通过这个操作相当于将起始地址左移了4位,再加上偏移量,就能得到一个20位的数据地址了
局限
对于只有 20 位地址总线的 8086 来讲,能够区分出的地址也就 2^20=1M,超过这个空间就访问不到了。
如果想访问 1M+X 的地方,这个位置已经超过 20 位了,由于地址总线只有 20 位,在总线上超过 20 位的部分根本是发不出去的,所以发出去的还是 X,最后还是会访问 1M 内的 X 的位置。
在 32 位处理器中,有 32 根地址总线,可以访问 2^32=4G 的内存。
进化架构(32bit)
通用寄存器
扩展为8个32位的,但为了兼容性,仍然保持了8位和16位的使用方式
指向下一条指令的指令指针寄存器 IP,就会扩展成 32 位的,同样也兼容 16 位的。
段寄存器
扩展性的局限
因为原来的模式其实有点不伦不类,因为它没有把 16 位当成一个段的起始地址,也没有按 8 位或者 16 位扩展的形式,而是根据当时的硬件,弄了一个不上不下的 20 位的地址。
这样每次都要左移四位,也就意味着段的起始地址不能是任何一个地方,只是能整除 16 的地方。
新的定义
CS、SS、DS、ES 仍然是 16 位的,但是不再是段的起始地址。段的起始地址放在内存的某个地方。
这个地方是一个表格,表格中的一项一项是段描述符(Segment Descriptor)。这里面才是真正的段的起始地址。而段寄存器里面保存的是在这个表格中的哪一项,称为选择子(Selector)。
这样,将一个从段寄存器直接拿到的段起始地址,就变成了先间接地从段寄存器找到表格中的一项,再从表格中的一项中拿到段起始地址。这样段起始地址就会很灵活了。
当然为了快速拿到段起始地址,段寄存器会从内存中拿到 CPU 的描述符高速缓存器中。
兼容性
32 位的系统架构下,前一种模式称为实模式(Real Pattern),后一种模式称为保护模式(Protected Pattern)。
当系统刚刚启动的时候,CPU 是处于实模式的,这个时候和原来的模式是兼容的。
当需要更多内存的时候,进行一系列的操作,切换到保护模式,就能够用到 32 位 CPU 的特性。
所以事实上是不能无缝兼容的,需要通过切换模式兼容。