GDT和LDT的关系

最近在阅读Linux内存管理时,突然对GDT(Glocal Descriptor Table)和LDT(Local Descriptor Table)产生了一些疑问。他们在内存是怎样存放的呢?程序在运行时又是如何对GDT和LDT产生了影响?

以下配图均来自《Linux内核完全注释(1.9.5版)》,所有的内容也都是基于Linux内核0.11版。其他Linux版本则需查看相应的代码进行分析

在Linux内核0.11中,对GDT和LDT的声明和配置如下:
Linux内核描述符表示意图

从上图可以看到LDTR指向的是GDT中的一部分,确切的说是指向了GDT的第五个描述符,而从这个描述符开始,包含了LDT。
从相应的内核代码中,我们看到在task_struct的声明中,有如下内容:

struct task_struct {
    ...
    struct desc_struct ldt[3];
    struct tss_struct tss;
};

这说明ldt是和每个task有关。每当需要创建新的process时,就需要在内存中把一块相应的区域划分给这个process的LDT:

int copy_process(int nr, ...)
{
    struct task_struct *p;
    p=(struct task_struct *)get_free_page();
    ...
    if (copy_mem(nr,p)) {
        //copy memory error will comes, here, free memory
        free_page((long) p);
        return -EAGAIN;
    }
    ...
    set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY, &(p->tss));
    set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY, &(p->ldt));
    p->state=TASK_RUNNING;
    return last_pid;
}

在上述程序中set_ldt_desc函数的作用就是把p->ldt的地址赋值给(gdt+(nr<<1)+FIRST_LDT_ENTRY)这个内存,也即让(gdt+(nr<<1)+FIRST_LDT_ENTRY)的内容指向p->ldt,这样就完成了GDT对LDT的索引。
nr是程序分配的新建任务的任务号,而return的是新建任务的进程号,这两个是不一样的。
变量gdt表示GDT在内存中的地址,在文件head.s中定义的。
FIRST_LDT_ENTRY是一个宏定义,表示数字5。从本文开头的图中可以看到,GDT的开始4项已经被占用。从第五项开始,保存着TSS(任务状态段)描述符和LDT(局部描述符表)描述符,所以任务nr的LDT描述符的地址相对于GDT地址是nr乘以2加上最初的偏移值,也即(nr<<1)+FIRST_LDT_ENTRY

阅读更多
换一批

没有更多推荐了,返回首页