1. 地址的种类
首先明确一下逻辑地址和线性地址这两个概念:
1. 逻辑地址
2. 线性地址
3. 物理地址
1.1 逻辑地址:
逻辑地址是编译器生成的,我们使用在linux环境下,使用C语言指针时,指针的值就是逻辑地址。对于每个进程而言,他们都有一样的进程地址空间,类似的逻辑地址,甚至很可能相同。
1.2 线性地址:
线性地址是由分段机制将逻辑地址转化而来的,如果没有分段机制作用,那么程序的逻辑地址就是线性地址了。
1.3 物理地址
物理地址是CPU在地址总线上发出的电平信号,要得到物理地址,必须要将逻辑地址经过分段,分页等机制转化而来。
2. 三种寻址模型
x86体系结构下,使用的较多的内存寻址模型主要有三种:
1. 实模式扁平模型 real mode flat model
2. 实模式分段模型 real mode segment model
3. 保护模式扁平模型 protected mode flat model
下面是对这三种模型的描述
实模式和保护模式相对,实模式运行于20位地址总线,保护模式则启用了32位地址总线,地址使用的是虚拟地址,引入了描述符表;虽然二者都引入了段这样一个概念,但是实模式的段是64KB固定大小,只有16KB个不同的段,CS,DS等存储的是段的序号(想想为什么?)。保护模式则引入了GDT和LDT段描述符表的数据结构来定义每个段。
扁平模型和分段模型相对,区别在于程序的线性地址是共享一个地址空间还是需要分成多个段,即为多个程序同时运行在同一个CS,DS的范围内还是每个程序都拥有自己的CS,DS:前者(flat)指令的逻辑地址要形成线性地址,不需要切换CS,DS;后者的逻辑地址,必须要经过段选择子去查找段描述符,切换CS,DS,才能形成线性地址。
3. 实模式扁平模型
该模式只有在386及更高的处理器中才能出现!
80386的实模式,就是指CPU可用的地址线只有20位,能寻址0~1MB的地址空间。注意:80386的实模式并不等同于8086/8088的实模式,后者的实模式其实就是实模式分段模型!
扁平模型,意味着我们这里不使用任何的分段寄存器。(其实还是使用了CS,DS,只是不用程序员去显示地为该寄存器赋值,jmp指令时就已经将CS, DS设置好了)
Linux启动代码 arch/i386/boot/bootsect.S就工作在该模式下。
逻辑地址 ----> 物理地址
4. 实模式分段模型
对于 8086/8088 运行在实模式的程序,其实就是运行在实模式分段模型中。对于不同的程序,有不同的CS,DS值,每个程序的段起始地址都不同。对于这样的程序而言,偏移地址16位的特性决定了每个段只有64KB大小。
详细过程可以用下图来描述:该图来自 http://duartes.org/gustavo/blog/
5. 保护模式扁平模型
我们的Linux, Window XP/7采用的内存寻址模型,Linux中,段主要分为4种,即为内核代码段,内核数据段,用户代码段,用户数据段。
对于内核代码段和数据段而言,CS,DS的值是0xC00000000,而用户代码和数据段的CS,DS的值是0x00000000
当CPU运行于32位模式时,不管怎样,寄存器和指令都可以寻址整个线性地址空间,所以根本就不需要再去使用基地址。基址可以设为一个统一的值。
下面是一个示例,该图来自 http://duartes.org/gustavo/blog/
扁平模型在这里得到了很好的体现,这个用户空间的程序基地址是0,。事实上,所有的用户空间的程序,其GDT指向的基地址都是0。