保护模式编程之(一)——分段机制与GDT/LDT

2024-04-22 14:48

本文主要是介绍保护模式编程之(一)——分段机制与GDT/LDT,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述:若想理解操作系统程序中的启动相关的部分,必须要理解保护模式下的编程,而分段机制是保护模式编程下的基础。另外,由于实模式与保护模式的不同,对保护模式下的分段机制更需要注意。同时,这一部分的基本数据结构是以后理解代码跳转的基础,必须要熟练。


本文来源:保护模式编程之(一)——分段机制与GDT/LDT

1.段的定义


        段是虚拟地址到线性地址转换的基础,段的特征有以下三个:段基址,段限长,段属性。这三个特征存储在段描述符(segmentdescriptor)之中,用以实现从逻辑地址到线性地址的转换。段描述符存储在段描述符表(desriptortable)之中,通常,我们使用段选择符定位段描述符在这个表中的位置。每个逻辑地址由16位的段选择符+32位的偏移量组成。

        逻辑地址转换成线性地址的原理和过程如下:



2.段描述符表


         描述符表的长度可变,每个描述符的长度是8B,最多可以包含8K个这样的描述符(为什么呢?因为段选择子是16位的,其中的13bit用来作index)。有两种描述符表,GDTLDT。结构如下:(fd02





        段描述符表存放在由操作系统维护着的特殊数据结构之中,由处理器的内存管理硬件来引用。虚拟地址空间被分割成大小相等的两半,一半由GDT来映射,一半由LDT来映射。整个虚拟地址空间还有214次方个段,一半是由GDT映射的全局虚拟地址空间,一半是由LDT映射的局部虚拟地址空间。系统发生任务切换的时候,会更新任务的LDT

        每个系统必须定义一个GDT,用于系统中的所有任务和程序。可选择性定义若干个LDTGDT本身不是一个段,而是线性地址空间的一个数据结构;GDT的线性基地址和长度必须加载进GDTR之中。因为段描述符长度是8,所以GDT长度位8n-1.同时,因为每个描述符长度是8,所以GDT的基地址最好进行8字节对齐。

     LDT表存放在LDT类型的段之中,此时GDT必须含有LDT的段描述符。访问LDT需要使用段选择符,为了减少访问LDT时候的段转换次数,LDT的段选择符,段基址,段限长都要放在LDTR寄存器之中。注意:查找GDT在线性地址中的基地址,需要借助GDTR;而查找LDT相应基地址,需要的是GDT中的段描述符。LDT本身是一个段,而GDT不是。

     两外,使用SGDTSIDT指令的时候,需要存储6B的“伪描述符”(baseaddress+limit),此时为了避免对齐检查出错,需要将它放在地址位基数开始的地方。


3.段选择符


        段选择符也称为段选择子,16bit,它指向段描述符表中的段描述符。段选择符的结构如下:


        段选择符示例:其中ad分别表示内核代码段/内核数据段/任务代码段/任务数据段的值,分别是0x00080x00100x000f0x0017.

        

    段选择符通常是作为指针变量的一部分可见,但选择符的值通常是由链接或者加载器设置或者修改,而不是应用程序。(看图)


    从上图中,我们需要注意以下几点:

1)段寄存器只有六个,一个程序可以定义很多段,但只能同时访问六个

2)我们提供隐藏部分,也就是描述符缓冲,来减少对描述符表的引用次数。

3)有缓存,必然涉及到缓存一致性的维护,我们在描述符表中的描述符修改过后立即更新缓存。

4)有两类加载指令可以改变段寄存器的值:MOVpop/lds/les/lss/lgs/lfs)等显示指令和CALLJMP/RET/IRET/INTn/INTO/INT3)等隐式加载指令。


4.段描述符


    4.1段描述符的通用格式



    对这个图的简要解释:

1)段限长:两个字段,一个20b,和G以及E地段决定段限长的实际大小和方向。

2base32b,一般是16字节对齐

3type:指定段或者门的类型,访问种类和扩展方向,对它的解释需要依赖描述符类型标志S。具体解释结果如下:

4)描述符类型标志s

5)描述符特权级DPL

6)段存在标志P

7)默认操作大小/默认栈指针大小/上下界标志D/B

8)颗粒度标志G


4.2代码和数据段描述符类型

    S=1的时候,该描述符用于代码段和数据段,意义如下表所示。


        数据段的描述符,类型字段的低三位可以分别表示已访问(A),可写(W),拓展方向(E

       A位指名自从上次操作系统复位该位之后,一个段是否被访问过。当处理器将一个段选择符加载进入相关寄存器之后,就会置位该位,直到它被明确地清除。可用于虚拟内存管理和调试。

在保护模式下,代码段是不可写的。

       解说:关于一致性代码段和非一致性代码段?


4.3系统描述符类型

    如果段描述符的S标志是0的话,那么该描述符是一个系统段描述符。处理器能够识别以下类型的系统段描述符。

1)局部描述符表的段描述符

2)任务段(TSS)描述符

3)调用门描述符

4)中断门描述符

5)陷阱门描述符

6)任务门描述符

    两大类:系统段描述符和门描述符。它们的具体描述符如下,使用方法见后续的blog


后记:存储管理模型比较繁杂,而且对应具体的硬件和相应的数据结构,需要反复理解和记忆才能弄通,总之在这个过程中,有一个问题一直需要思考:XX是什么?怎么得到它?得到它了以后什么东西会用到它?另外,此处总结操作系统的一条规律:哪里有速度差,哪里就有缓存;哪里有缓存,哪里就有一致性维护。


这篇关于保护模式编程之(一)——分段机制与GDT/LDT的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/926077

相关文章

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

16.Spring前世今生与Spring编程思想

1.1.课程目标 1、通过对本章内容的学习,可以掌握Spring的基本架构及各子模块之间的依赖关系。 2、 了解Spring的发展历史,启发思维。 3、 对 Spring形成一个整体的认识,为之后的深入学习做铺垫。 4、 通过对本章内容的学习,可以了解Spring版本升级的规律,从而应用到自己的系统升级版本命名。 5、Spring编程思想总结。 1.2.内容定位 Spring使用经验

Linux系统稳定性的奥秘:探究其背后的机制与哲学

在计算机操作系统的世界里,Linux以其卓越的稳定性和可靠性著称,成为服务器、嵌入式系统乃至个人电脑用户的首选。那么,是什么造就了Linux如此之高的稳定性呢?本文将深入解析Linux系统稳定性的几个关键因素,揭示其背后的技术哲学与实践。 1. 开源协作的力量Linux是一个开源项目,意味着任何人都可以查看、修改和贡献其源代码。这种开放性吸引了全球成千上万的开发者参与到内核的维护与优化中,形成了

Spring中事务的传播机制

一、前言 首先事务传播机制解决了什么问题 Spring 事务传播机制是包含多个事务的方法在相互调用时,事务是如何在这些方法间传播的。 事务的传播级别有 7 个,支持当前事务的:REQUIRED、SUPPORTS、MANDATORY; 不支持当前事务的:REQUIRES_NEW、NOT_SUPPORTED、NEVER,以及嵌套事务 NESTED,其中 REQUIRED 是默认的事务传播级别。

IPython小白教程:提升你的Python交互式编程技巧,通俗易懂!

IPython是一个增强的Python交互式shell,它提供了丰富的功能和便捷的交互方式,使得Python开发和数据分析工作更加高效。本文将详细介绍IPython的基本概念、使用方法、主要作用以及注意事项。 一、IPython简介 1. IPython的起源 IPython由Fernando Pérez于2001年创建,旨在提供一个更高效的Python交互式编程环境。 2. IPyt

从《深入设计模式》一书中学到的编程智慧

软件设计原则   优秀设计的特征   在开始学习实际的模式前,让我们来看看软件架构的设计过程,了解一下需要达成目标与需要尽量避免的陷阱。 代码复用 无论是开发何种软件产品,成本和时间都最重要的两个维度。较短的开发时间意味着可比竞争对手更早进入市场; 较低的开发成本意味着能够留出更多营销资金,因此能更广泛地覆盖潜在客户。 代码复用是减少开发成本时最常用的方式之一。其意图

Java并发编程—阻塞队列源码分析

在前面几篇文章中,我们讨论了同步容器(Hashtable、Vector),也讨论了并发容器(ConcurrentHashMap、CopyOnWriteArrayList),这些工具都为我们编写多线程程序提供了很大的方便。今天我们来讨论另外一类容器:阻塞队列。   在前面我们接触的队列都是非阻塞队列,比如PriorityQueue、LinkedList(LinkedList是双向链表,它实现了D

剑指offer—编程题7(用两个栈实现一个队列)

题目:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail 和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。 代码如下: [java]  view plain copy print ? public class Test07 {       /**       * 用两个栈模拟的队列       *

剑指Offer—编程题4 ( 替换空格)

一、题目:替换空格 题目:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输入“We are happy.”,则输出“We%20are%20happy.”。    在网络编程中,如果URL参数中含有特殊字符,如空格、'#'等,可能导致服务器端无法获得正确的参数值。我们需要将这些特殊符号转换成服务器可以识别的字符。转换的规则是在'%'后面跟上ASCII码的两位十六进制的表示。