首先看一下段选择符。段选择符为16位。为了方便查找段选择符,CPU提供了段寄存器来存放段选择符。段寄存器有cs, ss, ds, es, fs, gs(为16位),主要的有cs:代码段寄存器。包含程序指令的段;ss:栈段寄存器。指向当前程序栈的段。ds:数据段。指向静态数据或者全局数据段
段选择符的字段如下(相应的图):
其中,TI表示是存放在GDT还是存放在LDT,是0表示存放在GDT。否则存放在LDT。
INDEX表示的是选择索引号。就是用此索引号来在GDT中检索相应的段描述符。
RPL(requested privilege level)表示的是请求者的特权级。这里的特权指的是访问相应段的权限。在linux里面有用户态和内核态两种。这里的RPL(2位)是因为默认的是4级,linux里面使用的是0级来表示内核态,3级表示用户态。内核态能够访问用户态和内核态的地址空间和数据,用户态不可以访问内核态的数据空间(除了使用系统调用这个接口以外)。
接下来看看段描述符在内核中相应的表示(以下所有源码分析均是2.6.34):
linux/arch/x86/include/asm/desc_defs.h
14/*
15 * FIXME: Accessing the desc_struct through its fields is more elegant,
16 * and should be the one valid thing to do. However, a lot of open code
17 * still touches the a and b accessors, and doing this allow us to do it
18 * incrementally. We keep the signature as a struct, rather than an union,
19 * so we can get rid of it transparently in the future — glommer
20 */
21/* 8 byte segment descriptor */
22struct desc_struct {
23 union {
24 struct {
27 };
28 struct {
31 unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;
32 unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
33 };
34 };
35} __attribute__((packed));
这也就是传说中的8个字节的段描述符。每个段都会有一个段描述符。它描述了段的相应特征。具体的看相应字段。base0(占16位)和base1(占8位)和base2(占8位)组合形成了段的首字节的线性地址。
limit:存放段的最后一个内存单元的偏移量。这样就可以确定段的长度。但是这个还跟g位(占1位)有关。g:表示的是粒度。如果是0,则表示的是段的大小以字节为单位。否则,则表示的是以4k字节的倍数记。(通常一页为4k个字节)。
type字段(4位)表示的是最高位表示的是数据段还是代码段?为0则表示是数据段,为1表示是代码段。如果是数据段,则低三位表示: accessed (A)第8位, write-enable (W), and expansion-direction (E)。
如果是代码段,则低三位表示:accessed (A), read enable (R), and conforming (C)。 代码段可以被execute- only或者execute/read, 设置的是read enable位。其他的先不考虑
s位表示的是系统表示。清0了则代表是系统段,存储诸如LDT这种关键的数据结构。否则为代码段或者数据段。
dpl:表示的是descriptor privilege level.表示的是描述符特权级。与上面提到的请求特权级概念内涵一样。对于为0时(表明这个描述附所代表的信息是来自内核的),表示只有当CPL为0时才可以访问这个描述符。如果为3(表明这个描述符所代表的信息来自用户态的),则表明cpl为0俄3都可以访问这个描述符。
p表示是否存在内存中。为1表示在内存中。为0表示在磁盘中。通常都是为1。因为一般不把整个段全部放到磁盘。
结合具体的内核态数据段、代码段和用户态的数据段、代码段分析如下(图):
分析如下:
如用户数据段。
Base 0x00000000表示基址为0x00000000
G 1表示粒度为4K个字节
Limit Oxfffff结合G理解如下:限制大小为0xfffff也就是(0xfffff+1)*4k=4G也就是整个用户数据段的地址空间为4G大小。
S 1表示为普通的数据段,而不是系统段
Type 10对应的位为1010,表示此描述符是数据段,此段可写。
DPL 3表示是用户态的
D/B 3这个先不考虑。
P 1表示在内存中。