局部描述符表LDT

9 篇文章 0 订阅
4 篇文章 0 订阅

上一篇为了简单我们只涉及到GDT,其实LDT跟它差不多,跳转的时候选择子的第3位也就是TI位为0我们就用GDT,如果TI=1我们就用LDT。

总结如下:

TI=0时:CS:IP=全局描述符表中第1(0x8>>3)项描述符给出的段基址+0的偏移地址
TI=1时:CS:IP=局部描述符表中第1(0x8>>3)项描述符给出的段基址+0的偏移地址
局部描述符表在哪里?这要问ldtr寄存器了,ldtr里面存了一个选择子对应的就是用来描述LDT的那个描述符。
原来局部描述符表的基地址存在全局描述符表的LDT描述符里,这个描述符的选择子放到了ldtr寄存器中。

使用步骤如下:

1.定义一个局部描述符表LDT

2.在GDT中定义一个描述符Descriptor_LDT其基地址用LDT的起始地址填充,描述符Descriptor_LDT的选择子为SelectorLDT。

3.用lldt命令加载lgtr

4.jmp时的选择子TI位置1就可以了

 

很简单看一下代码全明白了:

#define Descriptor(base,lim,type)\
.word lim&0xffff;\
.word base&0xffff;\
.byte (base>>16)&0xff;\
.word ((lim>>8)&0xf00)|(type&0x0f0ff);\
.byte ((base>>24)&0xff)

/*
*InitDescrptor(Descriptor,SegBase)初始化描述符函数
*Descriptor:要初始化的描述符
*SegBase:段基址
*/
#define InitDescrptor(Descriptor,SegBase)\
xor     %eax,%eax; \
mov     %cs,%ax  ; \                         
shl     $4,%eax  ; \       	            
addl    $(SegBase), %eax ;\     
movw    %ax, (Descriptor + 2);\
shr     $16, %eax;\
movb    %al, (Descriptor + 4);\
movb    %ah, (Descriptor + 7)

DA_C   = 0x98
DA_32  = 0x4000
DA_DRW = 0x92
SA_TIL = 0x4
DA_LDT = 0x82

.text
.globl start
.code16
start:
 jmpl $0x0, $code 
 
/**-----------------------------------------------------------------
 * 全局描述符表: GDT
 *-------------------------------*/		
GDT_START:	
Descriptor_DUMMY: Descriptor(0x0,0x0,0x0)
Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32)
Descriptor_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW)
Descriptor_LDT:   Descriptor(0x0,LDTLen - 1, DA_LDT)	# LDT
GDT_END:

GdtPtr:
	.word (GDT_END-GDT_START)-1	# so does gdt 
	.long GDT_START 	# This will be rewrite by code.
	
.set	SelectorLDT,0x18

msg:
 .string "Hello world!"
 
 
code:
	mov     %cs,%ax   
	mov     %ax,%ds 
	mov     %ax,%es    
	mov     %ax,%ss  
	mov  $0x8000,%sp  
	/*显示HelloWorld字符串*/
	mov $msg   ,%ax
	mov %ax    ,%bp
	mov $12    ,%cx
	mov $0x1301,%ax
	mov $0x000c,%bx
	mov $0     ,%dl
	
	int $0x10
	

/*初始全局描述符Descriptor_CODE32*/
InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32);

/*初始全局描述符Descriptor_CODE32*/
InitDescrptor(Descriptor_LDT,LDT_START);

/*初始LDT 中的描述符Descriptor_LDT_CODEA*/
InitDescrptor(Descriptor_LDT_CODEA,LABEL_CODE_A);

/*加载gdtr即将全局描述符表gdt的首地址和gdt的界限赋给gdtr寄存器*/       
	lgdt GdtPtr

/*关中断*/
	cli

/*打开地址线A20*/
	inb $0x92,%al
	or  $0x02,%al
	outb %al,$0x92

/*设置cr0寄存器,切换到保护模式*/
	movl %cr0,%eax
	or   $1,%eax
	movl %eax,%cr0


/*真正进入保护模式,执行此命令后CS=0x8,IP=0*/
	ljmp $0x8,$0


.align  32
.code32
/**-----------------------------------------------------------------
 * 局部描述符表: LDT
 *-------------------------------*/
LDT_START:
/*                       段基址    段界限      属性*/
Descriptor_LDT_CODEA: Descriptor(0, CodeALen - 1, DA_C + DA_32)# Code, 32 位

.set    LDTLen,(. - LDT_START)

#LDT 选择子
.set  SelectorLDTCodeA,(0x0 + SA_TIL)
LABEL_SEG_CODE32:
.align  32
.code32

	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*11+79)*2),%edi/*第11行,79列*/
	movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/
	movb $'P',%al/*显示的字符*/
	movw %ax,%gs:(%edi)
	
	movw $SelectorLDT,%ax
	lldt %ax

	ljmp	$SelectorLDTCodeA,$0	/* 跳入局部任务 LABEL_CODE_A*/
	
loop2:
	jmp loop2
	
LABEL_CODE_A:
	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*12+0)*2),%edi/*第10行,0列*/
	movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/
	movb $'A',%al/*要显示的字符*/
	movw %ax,%gs:(%edi)

loop3:
	jmp loop3
.set CodeALen,(. - LABEL_CODE_A)

.org 0x1fe, 0x90 
.word 0xaa55   

注意LABEL_SEG_CODE32中的

movw $SelectorLDT,%ax
lldt %ax/*加载lgtr*/

ljmp $SelectorLDTCodeA,$0 /* 跳入局部任务 LABEL_CODE_A*/

我们在LABEL_CODE_A中打印了一个字符‘A’

运行结果如下:

 

为了更直观一些我将代码改成了这样:

#define Descriptor(base,lim,type)\
.word lim&0xffff;\
.word base&0xffff;\
.byte (base>>16)&0xff;\
.word ((lim>>8)&0xf00)|(type&0x0f0ff);\
.byte ((base>>24)&0xff)

/*
*InitDescrptor(Descriptor,SegBase)初始化描述符函数
*Descriptor:要初始化的描述符
*SegBase:段基址
*/
#define InitDescrptor(Descriptor,SegBase)\
xor     %eax,%eax; \
mov     %cs,%ax  ; \                         
shl     $4,%eax  ; \       	            
addl    $(SegBase), %eax ;\     
movw    %ax, (Descriptor + 2);\
shr     $16, %eax;\
movb    %al, (Descriptor + 4);\
movb    %ah, (Descriptor + 7)

DA_C   = 0x98
DA_32  = 0x4000
DA_DRW = 0x92
SA_TIL = 0x4
DA_LDT = 0x82

.text
.globl start
.code16
start:
 jmpl $0x0, $code 
 
/**-----------------------------------------------------------------
 * 全局描述符表: GDT
 *-------------------------------*/		
GDT_START:	
Descriptor_DUMMY: Descriptor(0x0,0x0,0x0)
Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32)
Descriptor_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW)
Descriptor_LDT:   Descriptor(0x0,LDTLen - 1, DA_LDT)	# LDT
GDT_END:

GdtPtr:
	.word (GDT_END-GDT_START)-1	# so does gdt 
	.long GDT_START 	# This will be rewrite by code.
	
.set	SelectorLDT,0x18

msg:
 .string "Hello world!"
 
 
code:
	mov     %cs,%ax   
	mov     %ax,%ds 
	mov     %ax,%es    
	mov     %ax,%ss  
	mov  $0x8000,%sp  
	/*显示HelloWorld字符串*/
	mov $msg   ,%ax
	mov %ax    ,%bp
	mov $12    ,%cx
	mov $0x1301,%ax
	mov $0x000c,%bx
	mov $0     ,%dl
	
	int $0x10
	

/*初始全局描述符Descriptor_CODE32*/
InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32);

/*初始全局描述符Descriptor_CODE32*/
InitDescrptor(Descriptor_LDT,LDT_START);

/*初始LDT 中的描述符Descriptor_LDT_CODEA*/
InitDescrptor(Descriptor_LDT_CODEA,LABEL_CODE_A);
InitDescrptor(Descriptor_LDT_CODEB,LABEL_CODE_B);


/*加载gdtr即将全局描述符表gdt的首地址和gdt的界限赋给gdtr寄存器*/       
	lgdt GdtPtr

/*关中断*/
	cli

/*打开地址线A20*/
	inb $0x92,%al
	or  $0x02,%al
	outb %al,$0x92

/*设置cr0寄存器,切换到保护模式*/
	movl %cr0,%eax
	or   $1,%eax
	movl %eax,%cr0

	movw $SelectorLDT,%ax
	lldt %ax/*加载lgtr*/
	
/*真正进入保护模式,执行此命令后CS=0x8,IP=0*/
	#ljmp $0x8,$0     /*选择子的TI位为0          跳入LABEL_SEG_CODE32      打印字符'P'*/
  ljmp	$(0x8+0x4),$0	/* 0x4将选择子的TI位置1    跳入局部任务 LABEL_CODE_B  打印字符'B'*/
/*
*TI=0时:CS:IP=全局描述符表中第1(0x8>>3)项描述符给出的段基址+0的偏移地址
*TI=1时:CS:IP=局部描述符表中第1(0x8>>3)项描述符给出的段基址+0的偏移地址
*局部描述符表在哪里?这要问ldtr寄存器了,ldtr里面存了一个选择子对应的就是用来描述LDT的那个描述符。
*原来局部描述符表的基地址存在全局描述符表的LDT描述符里,这个描述符的选择子放到了ldtr寄存器中。
*/


/**-----------------------------------------------------------------
 * 局部描述符表: LDT
 *-------------------------------*/
LDT_START:
/*                       段基址    段界限      属性*/
Descriptor_LDT_CODEA: Descriptor(0, CodeALen - 1, DA_C + DA_32)# Code, 32 位
Descriptor_LDT_CODEB: Descriptor(0, CodeBLen - 1, DA_C + DA_32)# Code, 32 位
.set    LDTLen,(. - LDT_START)

/**-----------------------------------------------------------------
 * #LDT 选择子
 *----------------*/
.set  SelectorLDTCodeA,(0x0 + SA_TIL)
.set  SelectorLDTCodeB,(0x8 + SA_TIL)

/**-----------------------------------------------------------------
 * 32位代码,显示字符P
 *----------------*/	
LABEL_SEG_CODE32:
.align  32
.code32

	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*11+79)*2),%edi/*第11行,79列*/
	movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/
	movb $'P',%al/*显示的字符*/
	movw %ax,%gs:(%edi)

	jmp .

/**-----------------------------------------------------------------
 * 32位代码,显示字符A
 *----------------*/		
LABEL_CODE_A:
	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*12+0)*2),%edi/*第10行,0列*/
	movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/
	movb $'A',%al/*要显示的字符*/
	movw %ax,%gs:(%edi)
	
	jmp .
.set CodeALen,(. - LABEL_CODE_A)

/**-----------------------------------------------------------------
 * 32位代码,显示字符B
 *----------------*/	
LABEL_CODE_B:
	movw $0x10,%ax
	movw %ax,%gs/* 视频段选择子(目的)*/
	movl $((80*12+3)*2),%edi/*第10行,0列*/
	movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/
	movb $'B',%al/*要显示的字符*/
	movw %ax,%gs:(%edi)
	
	jmp .
.set CodeBLen,(. - LABEL_CODE_B)

.org 0x1fe, 0x90 
.word 0xaa55   


注意99到104行代码

当我们用ljmp $0x8,$0            时选择子的TI位为0 , 跳入LABEL_SEG_CODE32, 打印字符'P'

当我们用ljmp $(0x8+0x4),$0 时选择子的TI位为0, 跳入LABEL_CODE_B          , 打印字符'B'

LDT和GDT的关系:

LDT和GDT从本质上说是相同的,只是LDT嵌套在GDT之中。LDTR记录局部描述符表的起始位置,与GDTR不同LDTR的内容是一个段选择子。由于LDT本身同样是一段内存,也是一个段,所以它也有个描述符描述它,这个描述符就存储在GDT中,对应这个表述符也会有一个选择子,LDTR装载的就是这样一个选择子。LDTR可以在程序中随时改变,通过使用lldt指令。如图,如果装载的是Selector 2则LDTR指向的是表LDT2。我们可以这样理解GDT和LDT:GDT为一级描述符表,LDT为二级描述符表。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值