概念
全局描述符表GDT是为了实现32位模式的分段,跟16位模式的分段是一个概念。只是实现方式不一样。
在32位中,描述一个段需要以下信息:
段的大小(至少1M,即20位)
段的起始地址(4G, 即32位)
段的属性(禁止写入,禁止执行, 系统专用等,12位)
我们用64位(8字节)来标识一个段的基地址,及其属性。可是CPU并没有一个这样的64位段寄存器,我们能是用的依然只有16位的段寄存器。而且由于CPU设计缺陷,段寄存器的低3位还不能用。
所以我们就需要做一个13位到64位的映射。段寄存器的13位最多能标识 8192 个段,那么就把 这8192个 8字节整齐的排列在内存里。并将起始地址保存在GDTR寄存器中。
如果想访问第1000个段,其段地址 = (GDTR + 1000 * 8) 中的 段起始地址的值
代码实现
set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);
set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);
load_gdtr(0xffff, 0x00270000);
//设置全局描述符表
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
if(limit > 0xfffff){ //如果段大小 > 1M,则G_bit 置 1。该段定义为4G空间
ar |= 0x8000;
limit /= 0x1000;
}
sd->limit_low = limit & 0xffff; // limit 低16位
sd->base_low = base& 0xffff; // base 低16位
sd->base_mid = (base >> 16) & 0xff; // base 中8位
sd->access_right = ar & 0xff; // 属性低8位
sd->limit_high = ((limit >> 16) & 0xf) | ((ar >> 8) & 0xf0); // limit高4位 | 属性高8位
sd-base_high = (base >> 24) & 0xff; // base 高8位
}
void load_gdtr(int limit, int addr) 函数无法用C语言实现,只能求助汇编了
_load_gdtr: ; void load_gdtr(int limit, int addr);
MOV AX,[ESP+4] ; limit
MOV [ESP+6],AX
LGDT [ESP+6]
RET
中断描述符
中断描述符 和 全局描述符 的实现方式相似
//设置全局描述符表
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
if(limit > 0xfffff){ //如果段大小 > 1M,?G_bit 置 1。?段定??4G空?
ar | 0x8000;
limit /= 0x1000;
}
sd->limit_low = limit & 0xffff; // limit 低16位
sd->base_low = base& 0xffff; // base 低16位
sd->base_mid = (base >> 16) & 0xff; // base 中8位
sd->access_right = ar & 0xff; // 属性低8位
sd->limit_high = ((limit >> 16) & 0xf) | ((ar >> 8) & 0xf0); // limit高4位 | 属性高8位
sd->base_high = (base >> 24) & 0xff; // base 高8位
return;
}
_load_idtr: ; void load_idtr(int limit, int addr);
MOV AX,[ESP+4] ; limit
MOV [ESP+6],AX
LIDT [ESP+6]
RET