段定义:
段是实现线性地址到虚拟地址转换机制的基础,在保护模式下每个段由三个参数定义:段基址,段界限(长度),段属性;
段基址:段的开始地址,在80386的保护模式下长度为32位。因为基地址长度为32位,所以任何一个段都可以在32位的线性地址空间的任何一个字节处开始。而不像实 模式下规定段的边界必须被16整除;
段界限:规定段的大小,在80386的保护模式下由20位来表示。段界限的单位分为1字节和4K字节两种(由段属性位中的G位决定采用哪种单位)。 20位段界限由高32位的D16 - D19和低32位中的D0 - D15组成;
段属性:规定段的各种特性,例如段的粒度G位和扩展属性位E等。都是段属性的一部分。在对段进行各种访问时,将对访问是否合法进行检查,其主要依据就是段的属性。
① 段属性中颗粒度 G == 0 时表示段界限单位是1字节,20位的段界限值可 表示的范围是1B -- 1MB(2的20次方),增量为1字节;
② 段属性颗粒度 G == 1 时表示段界限以4K字节为单位,20位的段界限值可表示的范围是4KB -- 4GB(2的20次方乘以2的12次方),增量为4KB即2的12次方 == 1000H;当段界限以4KB为单位时,段界限计算公式:Limit * 4KB + 0FFFH == (Limit << 12) + 0FFFH;(因为4KB == 1000H 所以 + 0FFFH是保持页对齐);所以当颗粒度G == 1时,段的界限实际就扩展为 20 + 12 ==32位;
例如:假设段的基址为 00012345H,段的界限是5678H
A:G == 0时,段界限的单位是1字节,该段对应的线性地址空间,就是从00012345H -- 000179BDH的区域;(00012345H + 5678H == 000179BDH)
B:G == 1时,段界限的单位是4KB字节.该段的对应线性地址空间是从00012345H -- 0568B344H的区域;(00012345H + 5678H * 4KB + 0FFFH == 00012345H + 56780000H + 0FFFH)
增加段的界限:数据段(包括堆栈段,默认情况下数据段和堆栈段构成段组)扩容有两种情况;
①段属性扩展方向位 E(数据段才有)== 0 。表示由低地址向高地址扩展;
②段属性扩展方向位 E == 1。表示高地址向低地址扩展;
说明:对于堆栈段(特殊的数据段)堆栈底部在高地址一端,随着压栈操作的进行堆栈向低地址扩展。为了适应普通的数据段和堆栈段向两个不同方向的扩展数据段的段属性中设置了扩展方向位 E;
只有数据段(数据段和代码段是不一样的,看下面的图)才有E属性位堆栈段被定义为独特的段其中DS和SS包含不同的选择子。一个堆栈段是将它复制到一个更大的段空间来扩充自己,而不是将显存的页加到它的段上;
数据段在向低位扩展时,其域在Limit + 1 --- 1M - 1之间为合法。在向高位扩展时其域在 0 --- Limit 之间为合法。每一次虚拟地址转化都要对偏移地址进行检查,不合法则会引发异常;
段寄存器的结构:
段描述符有64位。而段寄存器是由96位组成的。其中16位是可见的,其余80位不可见。在80位不可见的数据中只有64位是有效的。
下面是段寄存器的数据结构:
在执行指令 MOV DS,AX 的过程中(DS是段寄存器我们平时说的16位是因为只有16位是可见的,实际上它是96位)是怎样把数据写入到96位的段寄存器中;
①段寄存器中存储AX的值作为Selector的值;并用该值当做索引去GDT表中去查询对应下标的64位的值;(段选择子的介绍在我前面发布的保护模式文章里有详细介绍)GDT是Protected Mode(保护模式)所必须的数据结构,也是唯一的,全局可见的(对任何任务)。
②将读取到的64位的值写入到DS寄存器的80位不可见部分(Attributes,Base,Limit.80位只有64位是有效的);