前言
我们在编程的时候,多多少少都听过下面几个名词:逻辑地址、线性地址、物理地址和虚拟地址。先想几个问题:CPU直接使用的是什么地址?进程使用的是什么地址?在gdb调试时,打印的局部变量的地址,是哪种地址?
其实,逻辑地址可以认为是cpu执行程序过程中的一种中间地址,机器语言指令中出现的内存地址,都是逻辑地址;线性地址是进程使用的地址,是统一编址后的地址;物理地址就是和地址总线链接的RAM易失性存储单元。
为了更深入得了解逻辑地址和x86CPU寻址原理,下面从历史发展角度,依次来了解下x86上的段寄存器和分段机制。
x86段寄存器
【1】16位CPU
intel 处理器从4位机到最新的64位,历时发展数十年,从8086开始,Intel CPU正式进入x86时代,而段寄存器也是这个时候诞生。
8086处理器位数变成16位,但是地址总线又变成了20根。为了能够访问到整个地址空间,在CPU里添加了4个段寄存器,分别为CS(代码段寄存器)DS(数据段寄存器) SS(堆栈段寄存器)ES(扩展段寄存器)。所以段寄存器就是为了解决CPU位数和地址总线不同的问题而诞生的。
那么如何用16位CPU访问20根地址线呢?x86将物理内存划分很多段(所有的操作都是在真实的物理内存上,当时没有操作系统这么一说,这样就是所谓的实模式),段基地址采用两字节对齐(16的倍数),即16位的段寄存器只需要记录地址的高16位,ip寄存器记录段内偏移量。因此,进程要访问的线性地址 = (段寄存器 << 4) + (ip寄存器(偏移量)):图1 Intel 8086 CPU寻址
【2】32位CPU
到了我们处理器80386时候(保护模式),这时候cpu是32位,地址总线变成了32根,除了先前的4个段寄存器,还引入了两个新的段寄存器FS、GS(附加数据段寄存器)。但是它的寄存器大小为了兼容之前体系下的版本,寄存器依旧是16比特位宽,这么说寻址能力又不能满足了。这个时候增加了两个