三个重要的系统表GDT、LDT和IDT 首先说明的是,这三个表是在内存中由操作系统或系统程序员所建,并不是固化在哪里,所以从理论上是可以被读写的。
这三个表都是描述符表。描述符表是由若干个描述符组成,每个描述符占用8个字节的内存空间,每个描述符表内最多可以有(8K)8129个描述符。描述符是描述一个段的大小,地址及各种状态的。描述符表有三种,分别为全局描述符表GDT、局部描述符表LDT和中断描述符表IDT。
GDT表与IDT表
在整个系统中,全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何位置。系统用GDTR寄存器存放当前GDT表的基地址。用LDTR寄存器存放LDT表的地址。
寄存器 | 加载指令 | 保存指令 |
---|---|---|
GDTR寄存器 | LGDT | SGDT |
LDTR寄存器 | LLDT | SLDT |
IDTR寄存器 | LIDT | SIDT |
由于每个进程都有自己的一套程序段、数据段、堆栈段,有了局部描述符表则可以将每个进程的程序段、数据段、堆栈段封装在一起,只要改变LDTR就可以实现对不同进程的段进行访问。 随着任务的切换,系统当前的局部描述符表LDT也随之切换。通过LDT可以使各个任务私有的各个段与其它任务相隔离,从而达到受保护的目的。通过GDT可以使各任务都需要使用的段能够被共享。
我们可以这样理解GDT和LDT:GDT为一级描述符表,LDT为二级描述符表。
推荐两篇不错的文章:
GDT,LDT,GDTR,LDTR 详解,包你理解透彻
简单解释Windows如何使用FS段寄存器
该文中实操从FS的值查询GDT表和LDT表转换为虚拟地址,能加深对段寄存器的印象。
流程如下:
选择子Index确定描述符序号
查询描述符确定段基地址
段基地址与偏移之和就是线性地址
IDT表
整个系统IDT表也只有一张,GDT表也可以被放在内存的任何位置寄存器。IDTR寄存器存放IDT表的基地址。x86CPU最大可以支持256种中断ISR(中断处理程序),每个表项为8字节。Intel指定或保留了前32个中断号的作用,操作系统可以指定其余的中断号的作用。
中断的过程中可以产生新的中断。中断时有优先级的,高优先级的中断可以“中断”低优先级的中断。有的ISR不能被中断,可以使用STI (set interrupt-enable flag) and CLI(clear interrupt-enable flag)设置IF标志来启动和关闭中断。
!idt –a 命令可以看到所有中断处理函数的地址。
另外小贴士:实模式下IVT的每个表项是四字节。地址是从0x0h——0x3FFh也最多256项IVT。
Int 0x13h IVT偏移地址:0x4ch
Int 0x2Eh IDT偏移地址 :0x170h(KiSystemService)
typedef struct _IDTR //IDT基址
{
USHORT limit; //范围 占8位
ULONG base; //基地址 占32位 PIDT_ENTRY类型指针
}IDTR,*PIDTR;
IDT表的每个成员是一个8字节的数据结构_IDT_ENTRY。
typedef struct _IDT_ENTRY
{
USHORT offset_low; //中断处理函数地址低16位
USHORT selector;
UCHAR reserved;
UCHAR type:4;
UCHAR always0:1;
UCHAR dpl:2;
UCHAR present:1;
USHORT offset_high;//中断处理函数地址低16位
}IDT_ENTRY,*PIDT_ENTRY;//+3.offset_high<<16+offset_low //int 3 中断处理函数地址
参考文献
GDT,LDT,GDTR,LDTR 详解,包你理解透彻
http://www.techbulo.com/708.html
简单解释Windows如何使用FS段寄存器
https://bbs.pediy.com/thread-159935.htm