Linux内核——段描述符详解
在 x86 架构的保护模式下,段描述符(Segment Descriptor) 是分段机制的核心数据结构,定义了内存段的属性(如基地址、界限、权限等)。Linux 通过全局描述符表(GDT)和局部描述符表(LDT)管理这些段描述符。每个段描述符占用 8 字节(64 位),其二进制布局如下:
用户段描述符,以字节形式表示如下:
关键字段详解
-
基地址(Base Address)
- 32 位字段(由 Base[31:24]、Base[23:16]、Base[15:0] 组成),表示段的起始物理地址。
- Linux 中基地址通常设为 0(平坦模型),因此逻辑地址偏移量直接等于线性地址。
-
段界限(Limit)
- 20 位字段(由 Limit[19:16] 和 Limit[15:0] 组成),表示段的最大偏移量,即段长。
- 单位由 G 标志位(第55位)决定:
- G=0:界限(段长)单位为字节,这时一个段最大空间为 1MB=220字节 。
- G=1:界限(段长)单位为 4KB 页,这时一个段最大空间 为4GB 。
- Linux 中段界限设为 0xFFFFFFFF(即 4GB),覆盖整个 32 位地址空间。
-
A位(第5字节第0位):
用于请求分段不分页的系统中,每当该段被访问时,将 A 置 1。对于分页系统,则 A 被忽略未用。
-
类型(Type,第5字节第1、2、3位)
- 定义段的类型和访问权限:
- 代码段(Type[3]=1):可执行,可读(Type[1]=1)。
- 数据段(Type[3]=0):可读/写(Type[1]=1`)。
- 类型占 3 位,第 3 位为 E 位,表示段是否可执行。当 E=0 时,为数据段描述符,这时的第 2 位 ED 表示扩展方向。当 ED=0 时,为向地址增大的方向扩展,这时存取数据段中的数据的偏移量必须小于或等于段界限,当 ED=1 时,表示向地址减少的方向扩展,这时偏移量必须大于界限。当表示数据段时,第 1 位(W)是可写位,当 W=0 时,数据段不能写,W=1 时,数据段可写入。在 80386 中,堆栈段也被看成数据段,因为它本质上就是特殊的数据段。当描述堆栈段时,ED=0,W=1,即堆栈段朝地址增大的方向扩展。
- 定义段的类型和访问权限:
Type[3] | Type[2] | Type[1] | 说明 |
0(数据段) | ED=0(向地址增大的方向扩展) | W=0,不能写 W=1,可写入 | 数据段 |
ED=1(向地址减少的方向扩展) | |||
1(代码段) | C=1 | R=0,不能读 R=1,可读 | 代码段 |
3. 当段为代码段时,第 3 位 E=1,这时第 2 位为一致位(C)。当 C=1 时,如果当前特权级低于描述符特权级,并且当前特权级保持不变,那么代码段只能执行。所谓当前特权级(Current Privilege Level),就是当前正在执行的任务的特权级。第 1 位为可读位 R,当R=0 时,代码段不能读,当 R=1 时可读。
-
权限(DPL,第5字节,第6、7位)
- DPL字段(Descriptor Privilege Level),定义访问该段所需的最低特权级:
- 0:内核态(Ring 0)。
- 3:用户态(Ring 3)。
- DPL字段(Descriptor Privilege Level),定义访问该段所需的最低特权级:
-
段存在标志(P,第5字节,第8位)
- P=1:段存在于内存中;P=0:段无效(访问会触发异常)。
-
其他标志
- S(System,第5字节第5位):S=1 表示代码/数据段;S=0 表示系统段(如 TSS、LDT)。
- D/B(Default Operation Size,第6字节,第7位):D 位表示缺省操作数的大小,如果 D=0,操作数为 16 位,如果 D=1,操作数为 32 位。具体在代码段和数据段中含义如下
- 代码段:D=1 表示 32 位指令,D=0 表示 16 位指令。
- 数据段:B=1 表示 32 位栈,B=0 表示 16 位栈。
- L(Long Mode,第6字节,第6位):L=1 表示 64 位代码段(仅 x86-64 有效)。对于长模式下的任务状态段(Task State Segment)或局部描述符表(Local Descriptor Table),段描述符(Segment Descriptor)的格式会有所不同,以确保基地址(Base)字段能够容纳一个 64 位的线性地址(Linear Address)。此类段描述符在表中占据两个常规表项的空间,并以小端字节序(Little Endian)排列,即该条目的低半部分在表中位于高半部分之前。
长模式下,一个表项占两个段描述符(128 bit),以扩充基址(Base)部分长度到64位。
-
AVL(Available,第6字节,第5位):
保留给操作系统自由使用。
Linux 采用平坦内存模型,所有段的基地址为 0,段界限为 0xFFFFFFFF,主要通过段描述符实现权限隔离,而非实际分段。
系统段特殊说明
以上介绍了用户段的段描述符基本结构,对一系统段,结构和用户段类似
区别在于:
-
- S(System,第5字节第5位):S=0 表示系统段(如 TSS、LDT)。
- G位固定位0(第55位),单位:字节。所以,系统段最长1M
- 存取字节(第5字节)的类型占4个bit(用户段占3个)。Linux定义了16种系统段