Linux内存寻址之段描述符

       寻址的本质是CPU给出一个虚拟地址,经过寻址能够找到它的物理地址,我们称之为映射。上一节我们说到实模式寻址,在实模式下段寄存器中存放的是段首地址,加上PC程序寄存器中存放段内偏移值,两者相加即可得到物理地址。

       随着CPU位数增加到32位,大部分寄存器也增加到了32位,但段寄存器仍然保持了16位,且处理器提供了6个段寄存器:
CS (code segment) : 代码段寄存器,指向包含程序指令的段。
SS(stack segment) : 栈寄存器,指向包含当前程序栈的段。
DS(data segment) : 数据段寄存器,指向包含全局变量和静态变量的段。
       还有另外3个段为通用段,可以指向任意数据段。
       CS还有一个功能,它包含一个2位的字段,表示CPU当前的特权级(CPL),0代表最高优先级,3代表最低优先级,linux只有0和3两个级别,0代表内核级别,3代表用户态级别。

       在保护模式下,段寄存器不再保存段地址,而是段选择符。如下图所示:
Linux内存寻址之段描述符

       那么,段选择符是干什么的呢?我们能够想到的是,它是段地址的索引,也就是利用它去选择段地址。那段地址肯定也放在一段内存中。我们称之为段描述符。每一个段描述符占据8个字节,它代表一个段。段描述符放在一张表格中,我们称为全局描述符表GDT(global descriptpor table)或者局部描述符表(local decriptor table)。系统中通常只定义一个GDT,每个进程除了存放在GDT中的段之外,也可以有自己的LDT,用来存放自己用到的附加段。那GDT的首地址放在哪里呢?答案是gdtr控制寄存器,LDT的地址存放在ldtr控制寄存器中。

现在可以讲解,段选择符的三个字段了:
位0~1 : 当相应的段选择符装入到cs寄存器中时指示出CPU当前的特权级。
位2 : 指定段描述符是在GDT(TI=0)还是在LDT(TI=1)。
位3-15: 段选择符,指定该段描述符在描述符表中的位置。

       接着说段描述符每个字段的含义(图片来自百科):
Linux内存寻址之段描述符

Base 段首地址
Limit 段尾地址,即最后一个位置的地址,有了它就可以知道段的长度
G 表示段的粒度,如果G=0, 段的大小以字节为单位,如果置1,则以4096字节为单位
D/B 对于代码段和数据段来说含义是不一样的,但是相同的是,如果段的偏移量是32位长,就置1,如果偏移量是16位长,就清0
AVL Linux不用
P 为0时表示段当前不在主存中(在swap分区),为1时表示在主存中,linux总是把它置1
DPL 描述符特权级,用于限制对这个段的存取,表示访问这个段需要的最小级别,比如DPL=0表示只能当CPL是0是才能访问,即内核态,DPL=3则任何CPL都可以访问
S 系统标志,如果清0表示这是一个系统段,存储像GDT这种关键数据结构;置1表示普通的代码段或数据段
TYPE 描述了段的类型特征和它的存取权限

       说了这么多,问题来了,保护模式下到底如何寻址呢?下节见。