段描述符与段选择子

GDTR 寄存器

存放的是GDT(全局描述符表)表的位置和大小,大小为48位
在windeg中 r gdtr 查看GDT表的位置
r gdtl 查看表的大小
GDT表里面存放的元素称为段描述符 大小为8字节

dd +地址 查看地址里面的内容 查看4字节
dq +地址 查看8字节
eq +地址 +8字节数据 往指定地址写入数据
段描述符与段选择子_第1张图片

3环读取gdtr寄存器值
char buff[]={0};

_asm{
	sgdt buff
}

buff里面存的就是gdtr寄存器的值, 低两字节是gdt表的大小,高四字节是gdt表的地址,一共6字节。

段描述符

段描述符与段选择子_第2张图片

P位 当P位位1时 段描述符有效 为0时无效
Limit 长度为20位,高四字节的16至19位 低四字节的0至15位。 当G位为0时,Limit的单位是字节。为1时,Limit的单位是4KB(FFF)。加起来就是32位。

S位 当s位为1时,当前段描述符为代码段或者数据段描述符。为0时,是系统段描述符。

段寄存器

段寄存器结构

WORD Selectot  //段选择子
WORD Attribute  //属性   段描述符高四字节的第8位开始 到第23位结束
DWORD Base   //基地址
DWORD Limit //界限

段选择子

段描述符与段选择子_第3张图片
段选择子是一个16位的段描述符

串起来: 给一个段寄存器赋值的时候 类似 mov ds,ax 实际上ds会被赋值96位 过程是这样的
1:把ax看成段选择子 经过段权限检查(段选择子的RPL<=DPL)
2:看TI 位,如果为0,查GDT表。如果为1,查LDT表(windows只用GDT表所以这里的值一定为0);
3:把第3至15位看成一个索引,在GDT表中查出段描述符(8字节),查出来的值给段寄存器赋值。

段描述符与段选择子_第4张图片

TYPE域

段描述符与段选择子_第5张图片
s位为1时
type域位于段描述符高4四字节的第8至11位。
当第11位为0时:当前段为数据段
E 扩展方向 为0 向上扩展 为1 向下扩展 windows只用了向上扩展,向下扩展会出错。已测试
W 可写 为1表示可写,0表示不可写
A 是否访问 为1表示被访问过,为0表示没有被访问过

当第11位位1时,当前段为代码段。
A 是否访问 为1表示被访问过,为0表示没有被访问过
R 可读 为1表示可读,0表示不可读
C 一致性 为1时 是一致代码段,为0 非一致代码段

一致代码段与非一致代码段区别

非一致代码段: 用户权限只能访问用户数据
一致代码段: 用户权限可以访问内核数据
s位为0时
段描述符与段选择子_第6张图片
解析段描述符代码:

#include "stdafx.h"
#include 
#include "stdio.h"
typedef struct  {
    unsigned short limit_low;  //limit的低16位
    unsigned short base_low;   //base的低16位
    unsigned char base_middle;  //base的中间8位
    unsigned char type:4; 		//数据段或者代码段的详细描述
    unsigned char s:1; 			//0 代表当前段位代码段,1代表数据段
    unsigned char dpl:2; 		//当前等级描述符		 
    unsigned char p:1; 			// 当P位位1时 段描述符有效  为0时无效    
    unsigned char limit_high: 4;  //limit的16-19位
    unsigned char :1;		//系统没有使用这一位
    unsigned char :1;			//没有使用	
    unsigned char d_b:1;			// D/B位,CPU在读取指令时解析硬编码不同,不用关心。
    unsigned char g:1;			//0 代表limit的单位是1字节,1 代表limit的单位是4kb	
    unsigned char base_high;    //base的高8位
		}GDT,*PGDT;
void segmentDesctiprotInfoParse(PGDT pGdt)
{
	if (!pGdt->p)
	{
		printf("当前段描述符无效\n");
		return;
	}
	
	printf("当前段描述符的 DPL =%x\n",pGdt->dpl);
	
	if (pGdt->s==0)
	{
		
		switch (pGdt->type)
		{
			case 1:
				printf("该段描述符为系统段描述符,类型为 16位TSS(Avallable)");
				break;
			case 2:
				printf("该段描述符为系统段描述符,类型为 LDT");
				break;
			case 3:
				printf("该段描述符为系统段描述符,类型为 16位TSS(Busy)");
				break;
			case 4:
				printf("该段描述符为系统段描述符,类型为 16位调用门");
				break;
			case 5:
				printf("该段描述符为系统段描述符,类型为 (Task)任务门");
				break;
			case 6:
				printf("该段描述符为系统段描述符,类型为 16位(Intertupt)中断门");
				break;
			case 7:
				printf("该段描述符为系统段描述符,类型为 16位(Trap)陷阱门");
				break;
			case 9:
				printf("该段描述符为系统段描述符,类型为 32位TSS(Avallable)");
				break;
			
			case 11:
				printf("该段描述符为系统段描述符,类型为 32位TSS(Busy)");
				break;
			
			case 12:
				printf("该段描述符为系统段描述符,类型为 32位调用门");
				break;
			case 14:
				printf("该段描述符为系统段描述符,类型为 32位(Intertupt)中断门");
				break;
			case 15:
				printf("该段描述符为系统段描述符,类型为 32位(Trap)陷阱门");
				break;
			default:
				printf("该段描述符为系统段描述符,被系统保留,未使用");
		
		}
		return;
	}
	else
	{
		switch (pGdt->type)
		{
		case 0:
			printf("当前段描述符为数据段 权限为:只读 向上扩展 未被访问\n");
			break;
		case 1:
			printf("当前段描述符为 数据段 权限为:只读 向上扩展 已被访问\n");
			break;
		case 2:
			printf("当前段描述符为 数据段 权限为:可读 可写 向上扩展  未被访问\n");
			break;
		case 3:
			printf("当前段描述符为 数据段 权限为:可读 可写 向上扩展  已被访问\n");
			break;
		case 4:
			printf("当前段描述符为 数据段 权限为:只读 向下扩展 未被访问\n");
			break;
		case 5:
			printf("当前段描述符为 数据段 权限为:只读 向下扩展 以被访问\n");
			break;
		case 6:
			printf("当前段描述符为 数据段 权限为:可读 可写 向下扩展 未被访问\n");
			break;
		case 7:
			printf("当前段描述符为 数据段 权限为:可读 可写 向下扩展 已被访问\n");
			break;

		case 8:
			printf("当前段描述符为 非一致代码段 权限为:可执行 未被访问\n");
			break;
		case 9:
			printf("当前段描述符为 非一致代码段 权限为:可执行 已被访问\n");
			break;
		case 10:
			printf("当前段描述符为 非一致代码段 权限为:只读 可执行 未被访问\n");
			break;
		case 11:
			printf("当前段描述符为 非一致为代码段 权限为:只读 可执行 已被访问\n");
			break;
		case 12:
			printf("当前段描述符为 一致代码段 权限为:可执行 未被访问\n");
			break;
		case 13:
			printf("当前段描述符为 一致代码段 权限为:可执行 已被访问\n");
			break;
		case 14:
			printf("当前段描述符为 一致代码段 权限为:只读 可执行 未被访问\n");
			break;
		case 15:
			printf("当前段描述符为 一致代码段 权限为:只读 可执行 已被访问\n");
			break;

		}
		//计算base值
		int base=pGdt->base_low+(pGdt->base_middle<<16)+(pGdt->base_high<<24);
		printf("当前段描述符的base=%X\n",base);
		//计算limit值
		int limit_high=pGdt->limit_high;
		int limit=(limit_high<<16)+pGdt->limit_low;
		if (pGdt->g==1)
		{
			limit=(limit<<12)+0xfff;
		}
		printf("当前段描述符的limit=%X\n",limit);
		
	}

	

}

int main(int argc, char* argv[])
{
	printf("非一致代码段: 用户权限只能访问用户数据\n");
	printf("一致代码段: 用户权限可以访问内核数据\n\n");

	//测试数据,数组第一个元素是低32位,第二个元素是高32位
	unsigned int a[]={0x0000f200,0x0400ffff };
	GDT gdt;
	memcpy(&gdt,&a,sizeof(GDT));
	segmentDesctiprotInfoParse(&gdt);
	return 0;
}







你可能感兴趣的:(#,保护模式-段)