GDT LDT GDTR LDTR

本文深入探讨了32位汇编语言中段描述符的概念及其作用,详细解释了段选择器、段描述符、段描述符表等关键概念,并介绍了如何通过这些机制来确定线性地址。


如果图片没有显示,请看原来的链接 http://www.360doc.com/content/12/1005/00/1317564_239524856.shtml

买了本罗老师的琢石成器,才看前3章就感觉晕晕忽忽,总体觉得要看懂这本书前提是必须会DOS汇编,了解32位汇编基础.DOS汇编本人只看了王爽老师的汇编语言前11章,中断这块还没有看,看来不看还是不行的。转回来说,罗老师这本书前3章写的很乱,尤其是描述符这块,看了似懂非懂,通而不透。只能自己抽丝剥茧,捋清头绪,慢慢体会:


段选择器:32位汇编中16位段寄存器(CS、DS、ES、SS、FS、GS)中不再存放段基址,而是段描述符在段描述符表中的索引值,D3-D15位是索引值,D0-D1位是优先级(RPL)用于特权检查,D2位是描述符表引用指示位TI,TI=0指示从全局描述表GDT中读取描述符,TI=1指示从局部描述符中LDT中读取描述符。这些信息总称段选择器(段选择子).

段描述符:8个字节64位,每一个段都有一个对应的描述符。根据描述符描述符所描述的对象不同,描述符可分为三类:储存段描述符,系统段描述符,门描述符(控制描述符)。在描述符中定义了段的基址,限长和访问内型等属性。其中基址给出该段的基础地址,用于形成线性地址;限长说明该段的长度,用于存储空间保护;段属性说明该段的访问权限、该段当前在内存中的存在性,以及该段所在的特权级。

段描述符表:IA-32处理器把所有段描述符按顺序组织成线性表放在内存中,称为段描述符表。分为三类:全局描述符表GDT,局部描述符表LDT和中断描述符表IDT。GDT和IDT在整个系统中只有一张,而每个任务都有自己私有的一张局部描述符表LDT,用于记录本任务中涉及的各个代码段、数据段和堆栈段以及本任务的使用的门描述符。GDT包含系统使用的代码段、数据段、堆栈段和特殊数据段描述符,以及所有任务局部描述符表LDT的描述符。

GDTR全局描述符寄存器:48位,高32位存放GDT基址,低16为存放GDT限长。
LDTR局部描述符寄存器:16位,高13为存放LDT在GET中的索引值。

IA-32处理器仍然使用xxxx:yyyyyyyy(段选择器:偏移量)逻辑方式表示一个线性地址,那么是怎么得到段的基址呢?在上面说明中我们知道,要得到段的基址首先通过段选择器xxxx中TI位指定的段描述符所在位置:

当TI=0时表示段描述符在GDT中,如下图所示:① 先从GDTR寄存器中获得GDT基址。② 然后再GDT中以段选择器高13位位置索引值得到段描述符。③ 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址yyyyyyyy才得到最后的线性地址。

 

 

当TI=1时表示段描述符在LDT中,如下图所示:① 还是先从GDTR寄存器中获得GDT基址。② 从LDTR寄存器中获取LDT所在段的位置索引(LDTR高13位)。③ 以这个位置索引在GDT中得到LDT段描述符从而得到LDT段基址。④ 用段选择器高13位位置索引值从LDT段中得到段描述符。⑤ 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址yyyyyyyy才得到最后的线性地址。



http://www.360doc.com/content/12/1005/00/1317564_239524856.shtml

### 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、付费专栏及课程。

余额充值