GDT、GDTR、LDT、LDTR的理解 [zz]

本文解析了GDT(全局描述符表)和LDT(局部描述符表)的工作原理,包括它们在任务切换过程中的作用,以及如何通过GDTR和LDTR寄存器将虚拟地址转换为线性地址。

GDT是全局描述附表,主要存放操作系统和各任务公用的描述符,如公用的数据和代码段描述符、各任务的TSS描述符和LDT描述符。(TSS是任务状态段,存放各个任务私有运行状态信息描述符)
LDT是局部描述符表,主要存放各个任务的私有描述符,如本任务的代码段描述符和数据段描述符等。
GDTR是一个长度为48bit的寄存器,内容为一个32位的基地址和一个16位的段限。其中32位的基址是指GDT在内存中的地址。
LDTR是局部描述符寄存器,由一个可见的16位寄存器(段选择子)和一个不可见的描述符寄存器组成(描述符寄存器实际上是一个不可见的高速缓冲区)。
这里加入我的理解:应为GDT中除了有段描述符之外还有LDT描述符,所以微处理器在GDT中寻址LDT时,也需要使用选择子,以保持与段描述符寻址的统一。
在这里还要引入一个段选择子的概念。段选择子是一个寄存器,高13位用来指示描述符在描述符表中的索引号,低两位是表示使用描述符的特权级别;另外一位(T1)是GDT和LDT的信号量,如果T1=0,则使用GDTR,如果T1=1,则使用LDTR。选择子将被装入段寄存器中。系统中的段寄存器共有六个:CS、SS、DS、ES、FS和GS。当选择子被装入段寄存器时,微处理器会自动将其对应的描述符装入描述符寄存器。
系统任务切换时,LDT切换,而GDT不切换(因为真个系统只有一个GDT),这时新任务的LDT描述符的选择子就被装入到LDTR中。

任务切换过程中,各个相关寄存器的变化?
当 任务切换时,如果使用的是LDT,首先变化的是LDTR。段选择子被装入LDTR,同时LDT描述符自动被装入描述符寄存器。系统利用LDTR中的段选择 子来定位LDT描述符在GDT中的位置。这里我不明白的是LDTR中的LDT描述符和GDT中的描述符是什么关系?为什么要这样做呢?自动装入到LDTR 中的描述符到底是什么?从哪来?请高手指点!

为什么要有一个GDTR,并且GDTR的结构和LDTR不一样呢?
这主要是因为系统只有一个GDT,而GDT的描述符有不能存放在GDT中(LDT的描述符都存放在GDT中),所以就需要一个GDTR来指示GDT在内存中的位置。因为GDTR是直接指示内存地址,而LDTR主要指示LDT描述符在GDT中的位置和属性,所以GDTR和LDTR的结构也不同。

 

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://xmurobin.blogbus.com/logs/11842842.html

------------------------- 以下来自他处-----------------------------------------------------------------------

GDTR和LDTR如何把虚拟地址转换线性地址



GDTR是一个48位寄存器,指向全局描述符表GDT,从16位到47位前32位表示GDT在内存中的地址,是线性地址,需要通过页表转换成物理地址
LDTR是一个16位寄存器,是在GDT中的索引,指向局部描述符表LDT,每个任务有一个LDT,不同的LDT占用不同的内存段,由不同的系统描述符描述,这些系统描述符放在GDT中.
LDTR里面保存的是索引值,指向LDT在GDT中的位置

如果手头上有虚拟地址xxxx:yyyyyyyy
首先从GDTR中取出GDT的基址BA找到GDT
xxxx一共16位,根据倒数第三位即T1位判断
如果T1=0,xxxx的前13位表示的是GDT的位置索引,根据索引得到一个描述符
该描述符含有段的基址与其他各种信息,段的起始地址+yyyyyyyyy就得到线程地址

如果T1=1,那么从LDTR得到LDT的位置索引,在GDT里面找到LDT描述符,LDT描述符里面包含LDT的线性地址
找到LDT,取出xxxx的前13位,在LDT中找到段描述符,该段描述符里面包含段的基址等信息.
而后段的基址加上yyyyyyyy得到线性地址
### GDT(全局描述符表) GDT 是保护模式下内存段(数据段、代码段等)的登记表,是线性地址空间的一个数据结构,每个系统必须定义一个 GDT,用于系统中的所有任务和程序。GDT 本身不是一个段,其线性基地址和长度必须加载进 GDTR 之中,且基地址最好进行 8 字节对齐,因为每个描述符长度是 8 字节 [^2]。 ### LDT(局部描述符表) LDT任务私有的结构,一个任务对应一个 LDT,用于实现保护模式下通过虚拟地址进行内存隔离,防止一个进程访问另一个进程的代码或数据段。LDT 同样存储在内存中的一段区域中,需要在 GDT 中注册,拥有自己的描述符来描述某任务LDT 的起始地址及偏移量大小,以便通过段选择子准确访问。不过,由于每加入一个任务都要在 GDT 中添加新的 LDT 描述表,且任务切换时要重新加载 LDTR,操作麻烦,现在很少使用 LDT 作为多任务的切换方式了。在 Linux 中,2.4 之前使用 LDT 辅助进程任务切换,2.4 之后所有任务共享一个 LDT,这个共享 LDT 条目放在 GDT 中,默认有 3 个条目:LDT[0] 为空;LDT[1] 为用户代码段;LDT[2] 为用户数据/堆栈段描述符,Linux 所生成的 LDT 的大小是 24 个字节 [^1][^3]。 ### TSS(任务状态段) TSS 用于进程任务切换。在 Linux 2.4 之前使用 TSS 进行进程任务切换,但 TSS 和 LDT 中的每一个条目都应该保存在 GDT 中,这限制了系统中的任务总数 [^1]。 ### 代码示例 以下是一个简单的伪代码示例,用于说明加载 GDTLDT 的概念: ```asm ; 定义 GDTgdt_start: ; 空描述符 dd 0x0 dd 0x0 ; 代码段描述符 dw 0xFFFF ; 段界限低 16 位 dw 0x0 ; 段基地址低 16 位 db 0x0 ; 段基地址中 8 位 db 10011010b ; 访问权限 db 11001111b ; 其他标志和段界限高 4 位 db 0x0 ; 段基地址高 8 位 ; 数据段描述符 dw 0xFFFF ; 段界限低 16 位 dw 0x0 ; 段基地址低 16 位 db 0x0 ; 段基地址中 8 位 db 10010010b ; 访问权限 db 11001111b ; 其他标志和段界限高 4 位 db 0x0 ; 段基地址高 8 位 gdt_end: ; GDT 描述符 gdt_descriptor: dw gdt_end - gdt_start - 1 ; GDT 长度 dd gdt_start ; GDT 基地址 ; 加载 GDT lgdt [gdt_descriptor] ; 假设 LDT 描述符已经在 GDT 中 ; 加载 LDT mov ax, 0x10 ; 假设 LDT 选择子为 0x10 lldt ax ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值