汇编教程:分段管理机制
2009-02-16 09:36:48 来源:WEB开发网本文介绍保护方式下的段定义以及由段选择子及段内偏移构成的二维虚拟地址如何被转换为一维线性地址。
<一>段定义和虚拟地址到线性地址的转换
段是实现虚拟地址到线性地址转换机制的基础。在保护方式下,每个段由如下三个参数进行定义:段基地址(Base Address)、段界限(Limit)和段属性(Attributes)。
段基地址规定线性地址空间中段的开始地址。在80386保护方式下,段基地址长32位。因为基地址长度与寻址地址的长度相同,所以任何一个段都可以从32位线性地址空间中的任何一个字节开始,而不象实方式下规定的边界必须被16整除。
段界限规定段的大小。在80386保护模式下,段界限用20位表示,而且段界限可以是以字节为单位或以4K字节为单位。段属性中有一位对此进行定义,把该位成为粒度位,用符号G标记。G=0表示段界限以字节位位单位,于是20位的界限可表示的范围是1字节至1M字节,增量为1字节;G=1表示段界限以4K字节为单位,于是20位的界限可表示的范围是4K字节至4G字节,增量为4K字节。当段界限以4K字节为单位时,实际的段界限LIMIT可通过下面的公式从20 位段界限Limit计算出来:
LIMIT=limit*4K+0FFFH=(Limit SHL 12)+0FFFH
所以当粒度为1时,段的界限实际上就扩展成32位。由此可见,在80386保护模式下,段的长度可大大超过64K字节。
基地址和界限定义了段所映射的线性地址的范围。基地址Base是线性地址对应于段内偏移为 0的虚拟地址,段内偏移为X的虚拟地址对应Base+X的线性地址。段内从偏移0到Limit范围内的虚拟地址对应于从Base到Base+Limit范围内的线性地址。
下图表示一个段如何从虚拟地址空间定位到线性地址空间。图中BaseA等代表段基地址, LimitA等代表段界限。另外,段C接在段A之后,也即BaseC=BaseA+LimitA。
例如:设段A的基地址等于00012345H,段界限等于5678H,并且段界限以字节为单位(G=0),那么段A对应线性地址空间中从00012345H-000179BDH的区域。如果段界限以4K字节为单位 (G=1),那么段A对应线性地址空间中从00012345H-0568B344H(=00012345H+5678000H+0FFFH) 的区域。
通过增加段界限,可以使段的容量得到扩展。这对于那些要在内存中扩展容量的普通数据段很有效,但对堆栈段情况就不是这样。因为堆栈底在高地址端,随着压栈操作的进行,堆栈向低地址方向扩展。为了适应普通数据段和堆栈数据段在两个相反方向上的扩展,数据段的段属性中安排了一个扩展方向位,标记为ED。ED=0表示向高端扩展,ED=1表示向低端扩展。一般只有堆栈数据段才使用向低端扩展的属性(堆栈段也可使用向上扩展的段),这是因为,向下扩展的段是为以下两个目的而设计的:
第一,堆栈段被定义为独特段,即DS和SS包含不同的选择器。
第二,一个堆栈段是靠将它复制到一个更大的段来扩充自己(而不是靠将现存的页增加到它的段上)。不打算用这种方法实现堆栈的设计者不需要定义向下扩展的段。
需要注意的是,只有数据段的段属性中才有扩展方向属性位ED,也就是说只有数据段(堆栈段作为特殊的数据段)才有向上扩展和向下扩展之分,其它段都是自然的向上扩展。
数据段的扩展方向和段界限一起决定了数据段内偏移的有效范围。当段最大为1M字节时,在向高端扩展的段内,从0到Limit的偏移是合法有效的偏移,而从Limit+1到1M-1的偏移是非法无效的偏移;在向低端扩展的段内,情形刚好相反,从0到Limit的偏移是非法无效的偏移,而从Limit+1到1M-1的偏移是合法有效的偏移,注意边界值Limit对应地址的有效性。段最大为4G时,情形类似。由此可见,如果一个段是向下扩展的,则所有的偏移必须大于限长,因为其限长是指下限,其基地址从高地址出开始。反之,若一个段是向上扩展的,则所有偏移必须小于等于限长,因为其限长是指上限,基地址从低地址处开始。通过使用段环绕,可以把向下扩展段定义到任何线性地址且可定义为任何大小。
在每次把虚拟地址转换为线性地址的过程中,要对偏移进行检查。如果偏移不在有效的范围内,那么就引起异常。
段属性规定段的主要特性。例如上面已经提到的段粒度G就是段属性的一部分。在对段进行各种访问时,将对访问是否合法进行检查,主要依据是段属性。例如:如果向一个只读段进行写入操作,那么不仅不能写入,而且会引起异常。在下面会详细说明各个段熟属性位的定义和作用。
<二>存储段描述符
用于表示上述定义段的三个参数的数据结构称为描述符。每个描述符长8个字节。在保护方式下,每一个段都有一个相应的描述符来描述。按描述符所描述的对象来划分,描述符可分为如下三类:存储段描述符、系统段描述符、门描述符(控制描述符)。下面先介绍存储段描述符。
1.存储段描述符的格式
存储段是存放可由程序直接进行访问的代码和数据的段。存储段描述符描述存储段,所以存储段描述符也被称为代码和数据段描述符。存储段描述符的格式如下表所示。表中上面一排是对描述符8个字节的使用的说明,最低地址字节(假设地址为m)在最右边,其余字节依次向左,直到最高字节(地址为m+7)。下一排是对属性域各位的说明。
存储段 描述符 |
m+7 | m+6 | m+5 | m+4 | m+3 | m+2 | m+1 | m+0 |
Base(31...24) | Attributes | Segment Base(23...0) | Segment Limite(15...0) |
存储段 描述符 属 性 |
Byte m+6 | Byte m+5 | ||||||||||||||
BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 | |
G | D | 0 | AVL | Limit(19...16) | P | DPL | DT1 | TYPE |
从上表可知,长32位的段基地址(段开始地址)被安排在描述符的两个域中,其位0—位23 安排在描述符内的第2—第4字节中,其位24—位31被安排在描述符内的第7字节中。长20 位的段界限也被安排在描述符的两个域中,其位0—位15被安排在描述符内的第0—第1字节中,其位16—位19被安排在描述符内的第6字节的低4位中。
使用两个域存放段基地址和段界限的原因与80286有关。在80286保护方式下,段基地址只有24位长,而段界限只有16位长。80286存储段描述符尽管也是8字节长,但实际只使用低 6字节,高2字节必须置为0。80386存储段描述符这样的安排,可使得80286的存储段描述符的格式在80386下继续有效。
80386描述符中的段属性也被安排在两个域中。下面对其定义及意义作说明。
(1)P位称为存在(Present)位。P=1表示描述符对地址转换是有效的,或者说该描述符所描述的段存在,即在内存中;P=0表示描述符对地址转换无效,即该段不存在。使用该描述符进行内存访问时会引起异常。
(2)DPL表示描述符特权级(Descriptor Privilege level),共2位。它规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。
(3)DT位说明描述符的类型。对于存储段描述符而言,DT=1,以区别与系统段描述符和门描述符(DT=0)。
(4)TYPE说明存储段描述符所描述的存储段的具体属性。
其中的位0指示描述符是否被访问过(Accessed),用符号A标记。A=0表示尚未被访问,A=1 表示段已被访问。当把描述符的相应选择子装入到段寄存器时,80386把该位置为1,表明描述符已被访问。操作系统可测试访问位,已确定描述符是否被访问过。
其中的位3指示所描述的段是代码段还是数据段,用符号E标记。E=0表示段为数据段,相应的描述符也就是数据段(包括堆栈段)描述符。数据段是不可执行的,但总是可读的。 E=1表示段是可执行段,即代码段,相应的描述符就是代码段描述符。代码段总是不可写的,若需要对代码段进行写入操作,则必须使用别名技术,即用一个可写的数据段描述符来描述该代码段,然后对此数据段进行写入。
在数据段描述符中(E=0的情况),TYPE中的位1指示所描述的数据段是否可写,用W标记。 W=0表示对应的数据段不可写。反之,W=1表示数据段是可写的。注意,数据段总是可读的。TYPE中的位2是ED位,指示所描述的数据段的扩展方向。ED=0表示数据段向高端扩展,也即段内偏移必须小于等于段界限。ED=1表示数据段向低扩展,段内偏移必须大于段界限。
在代码段描述符中(E=1的情况),TYPE中的位1指示所描述的代码段是否可读,用符号R标记。R=0表示对应的代码段不可读,只能执行。R=1表示对应的代码段可读可执行。注意代码段总是不可写的,若需要对代码段进行写入操作,则必须使用别名技术。在代码段中,TYPE中的位2指示所描述的代码段是否是一致代码段,用C标记。C=0表示对应的代码段不是一致代码段(普通代码段),C=1表示对应的代码段是一致代码段。关于一致代码段的说明,后面的文章将会详细介绍。
存储段描述符中的TYPE字段所说明的属性可归纳为下表:
|
|
(5)G为就是段界限粒度(Granularity)位。G=0表示界限粒度为字节;G=1表示界限粒度为4K 字节。注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。
(6)D位是一个很特殊的位,在描述可执行段、向下扩展数据段或由SS寄存器寻址的段(通常是堆栈段)的三种描述符中的意义各不相同。
在描述可执行段的描述符中,D位决定了指令使用的地址及操作数所默认的大小。D=1表示默认情况下指令使用32位地址及32位或8位操作数,这样的代码段也称为32位代码段;D=0 表示默认情况下,使用16位地址及16位或8位操作数,这样的代码段也称为16位代码段,它与80286兼容。可以使用地址大小前缀和操作数大小前缀分别改变默认的地址或操作数的大小。
在向下扩展数据段的描述符中,D位决定段的上部边界。D=1表示段的上部界限为4G;D=0表示段的上部界限为64K,这是为了与80286兼容。
在描述由SS寄存器寻址的段描述符中,D位决定隐式的堆栈访问指令(如PUSH和POP指令)使用何种堆栈指针寄存器。D=1表示使用32位堆栈指针寄存器ESP;D=0表示使用16位堆栈指针寄存器SP,这与80286兼容。
更多精彩
赞助商链接