23-段描述符与段选择子

目录

1. GDT表

2. 段描述符

3. 段选择子

4. 段描述符属性

4.1 段描述符属性P位和G位

4.2 段描述符属性G位

5. 段描述符填充到段寄存器


1. GDT表

现在思考一个问题,当你写一个段寄存器的时候,只给了一个16位的数,但段寄存器有96位,那剩下的80位是怎么来的?这个16位的数是随便写的吗?

事实上是,通常在执行MOV DS,AX这些指令时,CPU会查表,并根据AX的值来决定查找GDT(全局描述符表)还是LDT(局部描述符表),查找表的什么位置,查出多少数据。

有同学可能会好奇GDT表在哪里,表的大小有多大呢?这就要说到gdtr寄存器了,gdtr是一个48位的寄存器,其中32位存储了GDT表的开始位置,剩下的16位存储了GDT表的大小,打开winDbg以命令方式查看,如下图所示:

r gdtr命令是用于查看GDT表的开始位置,r gdtl是用于查看GDT表大小,dd 8003f000可以查看GDT表里面的数据。

 

2. 段描述符

BASE: 段基址,由上图中的两部分(BASE 31-24 和 BASE 23-16)组成

G:LIMIT的单位,该位 0表示单位是字节,1表示单位是 4KB

D/B: 该位为 0 表示这是一个 16 位的段,1 表示这是一个 32 位段

AVL: 该位是用户位,可以被用户自由使用

LIMIT: 段的界限,单位由 G 位决定。数值上(经过单位换算后的值)等于段的长度(字节)- 1

P: 段存在位,该位为 0 表示该段不存在,为 1 表示存在

DPL:段权限

S: 该位为 1 表示这是一个数据段或者代码段。为 0 表示这是一个系统段(比如调用门,中断门等)

TYPE: 根据 S 位的结果,再次对段类型进行细分

 

简单来说,段描述符就是GDT表中存储的一个元素,GDT表存储了很多这样的元素,段描述符的大小为8字节。

还是回到原先的问题,当执行MOV DS,AX这些指令时就会去查GDT表中的段描述符,AX寄存器指定了查找GDT表的哪一个段描述符,然后把查找到的数据存放到DS段寄存器中,为此我们还需要了解段选择子。

 

3. 段选择子

段选择子是一个16位的整数(段寄存器的16位可见部分),段选择子的形式如下图所示:

段选择子(16位的整数)记录了GDT表的段描述符的具体位置,总的来说,段选择子总共分为以下三部分:

0-1位是RPL位,2位是TI位,3-15位是Index位

RPL:请求特权级,以什么样的权限去访问段

TI:Table Indicator,当TI=0表示查找GDT表,TI=1则查找LDT表

INDEX:在GDT表或LDT表中的索引号,查找哪个段描述符

 

4. 段描述符属性

除了MOV指令,我们还可以使用LES、LSS、LDS、LFS、LGS指令修改寄存器。需要注意的是:CS不能通过上述的指令进行修改,因为CS是代码段,CS的改变会导致EIP的改变,要改CS,必须要保证CS与EIP一起改。

int main(){
    char buffer[6];					
    __asm							
    {	
        //这条指令的意思是将高2个字节给es寄存器,低四个字节给ecx寄存器
        //注意,这条指令不一定能执行成功,这取决于buffer的值
        les ecx,fword ptr ds:[buffer] 	
    }
    return 0;
}

段寄存器的值是通过查找GDT表中的段描述符进行填充的,但是段描述符是64位的,段寄存器是96位的,那么要如何将段描述符填充到段寄存器呢?还要用到段描述符的属性。

 

4.1 段描述符属性P位和G位

段描述符的属性如上所示,其中P位在15位,G位在23位,CPU在执行汇编指令时会首先检测P位,当P = 1时,说明段描述符有效,P=0则说明段描述符无效,如果P=0则后面的检测就不再继续。

 

4.2 段描述符属性G位

段寄存器的结构如下:

struct SegMent {
    WORD selector;	    //16位
    WORD attribute;	    //16位
    DWORD base;		    //32位
    DWORD limit;           //32位
}

段描述符结构如下:

首先我们明白一个事实,段寄存器有96位,段描述符只有64位,段描述符填充到段寄存器还差32位,那么段描述符和段寄存器之间的对应关系是如何的呢?

段寄存器的selector很好理解,其实就是16位的段选择子。

attribute对应的就是段描述符高4字节的8-23位。

base对应的有高4字节的24-31位和0-7位,还有低4字节的16-31位,这三部分构成了一个32位的地址。

limit对应的有高4字节的16-19位,低4字节的0-15位,也就是说limit总共也就20位,转成16进制最大为0xFFFFF,剩下的12位是从哪里来呢?没错,就是段描述符的G位。如果G=0,在limit前面补000,最大可以表示0x000FFFFF;如果G=1,在limit后面补FFF,最大可以表示0xFFFFFFFF

 

5. 段描述符填充到段寄存器

现在有0x1B和0x23两个段选择子,我们要将其对应的段描述符填充到段寄存器中,GDT表的数据如下所示:

 

分析段选择子0x1B:

0x1B = ‭0000 0000 0001 1011
RPL = 3
TI = 0		查找GDT表
INDEX = 3 ,	查找GDT表的段描述符 = 00cffb00`0000ffff
Selector = 0x1B
Attribute = 0xcffb
Base = 0x00000000
Limit = 0xFFFFFFFF

 

分析段选择子0x23:

0x23 = 0000 0000 0010 0011
RPL = 3
TI = 0
INDEX = 4  , 查找GDT表的段描述符 = 00cff300`0000ffff
Selector = 0x23
Attribute = 0xcff3
Base = 0x00000000
Limit = 0xFFFFFFFF

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值