分段机制

Posted davytitan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分段机制相关的知识,希望对你有一定的参考价值。

段的定义

 

段的介绍


分段机制就是把虚拟地址空间中的虚拟内存组织成一些长度可变的称为段的内存单元。 80386虚拟地址空间中的虚拟地址(逻辑地址)由一个段部分和一个偏移部分构成。段是虚拟地址到线性地址转化的基础。每个段有三个参数定义:

  1. 段基地址,指定段在线性地址空间中的开始地址。基地址是线性地址对应于段中偏移 0 处。
  2. 段限长,是虚拟地址空间中段内最大可用偏移地址。定义了段的长度。
  3. 段属性,指定段的特性。如该段是否可读、可写或可作为一个程序执行,段的特权级等。


多个段映射到线性地址中的范围可以部分重叠或覆盖,甚至完全重叠,如下图所示
技术图片

 

相关的数据结构
段的基地址、段限长以及段的保护属性存储在一个称为段描述符的结构项中。在逻辑地址到线性地址的转换映射过程中会使用这个段描述符。段描述符保存在内存中的段描述符表中。

段描述符表是包含段描述符项的一个简单数组。 使用段选择符来指定段描述符表中一个段描述符的位置来指定相应的段。

虚拟地址到线性地址转化
即使是使用段的最小功能,使用逻辑地址也能访问处理器地址空间中的每一个字节。逻辑地址由 16 位的段选择符合 32 位的偏移量组成。

当需要访问处理器地址空间中的某个字节时。段选择符指定了该字节所在的段,偏移量指定了该字节在段中相对于段基址的位置。处理器会吧每个逻辑地址转换成线性地址。线性地址是处理器线性地址空间中的 32 位地址。也是平坦的 4GB 地址空间,地址范围从 0 到 0xFFFFFFFF。线性地址空间中含有系统定义的所有段和系统表。

处理器把逻辑地址转化成一个线性地址的过程:

使用段选择符中的偏移值(段索引,我感觉这个偏移值应该是相对于段描述符表其实地址的偏移)在GDT(全局描述符表) 或 LDT(局部描述符表)中定位相应的段描述符。(仅当一个新的段选择符加载到段寄存器中时才需要 ??)

利用段描述符校验段的访问权限和范围,以确保该段是可以访问的并且偏移量位于段界限内。

利用段描述符中取得的段基地址加上偏移量,形成一个线性地址。
技术图片

 

 

段描述符表

段描述符表示存放段描述符的一个数组。 它的长度可变,最多可以包含 8192 个段描述符,每个段描述符长度为 8 个字节。段描述符表有两种:全局描述符表GDT和局部描述符表LDT。段描述符表结构如下图所示。技术图片

 

 

段描述符表存储在由操作系统维护着的特殊数据结构中,由处理器的内存管理硬件来引用。 这些特殊的数据结构保存在只有操作系统能够访问的受保护的内存区域,防止被应用程序修改。

虚拟地址空间被分割成大小相等的两半。一半由GDT来映射变换到线性地址,另一半由LDT来映射。整个虚拟地址空间共含有 2^14 个段: 一般空间(2^13)是由GDT映射的全局虚拟地址空间,另一半是由LDT映射的局部虚拟地址空间。 指定一个描述符表(GDT或LDT)和表中的描述符号,就可以定位到一个段描述符(通过段描述符就可以定位到段)。

当任务切换时,LDT会更换成新任务的LDT,GDT不会改变,因为GDT所映射的一半虚拟地址空间是系统中所有任务公有的,LDT所映射的另一半则在任务切换时被改变。系统中所有任务共享的段有GDT来映射。

系统中每个应用程序对应一个任务,并且每个任务都有自己的LDT,如下图所示,应用程序A在任务A中运行,拥有LDTa ,用来映射段Codea和Dataa。类似地,应用程序B在任务B中运行,使用LDTb来映射Codeb和Datab。操作系统内核的两个段Codeos和Dataos 使用GDT来映射,这样它可以被像个人物所共享。 LDTa和LDTb两个段也使用 GDT来映射。
技术图片

 

 

当任务A在运行时,可以访问 LDTa映射的Codea 和Dataa段,以及GDT映射的操作系统段COdeos和Dataos。当任务B在运行时,可以访问的段包括LDTb映射的Codeb和Datab段,以及GDT映射的操作系统段COdeos和Dataos。

通过让每个任务使用不同的LDT,演示了虚拟地址空间如何隔离每个任务。当任务A在运行时,任务B的段不是虚拟地址空间的部分。因此,任务A无法访问任务B的内存。同样的,当任务B运行时,任务A的段也不能被任务B访问。这种使用LDT来隔离每个应用程序任务的方法,正式关键保护的需求之一。

每个系统必须定义一个GDT,并可用于系统中所有程序或任务。可以选定义一个或多个LDT。可以为每个运行任务定义一个LDT,或者某些任务共享一个LDT。

GDT本身并不是一个段,而是线性地址空间的一个数据结构。GDT的基线性地址和长度必须加载进 GDTR 寄存器中。处理器并不使用 GDT中的第一个描述符。把这个"空描述符"加载到段寄存器中并不会产生一个异常。但是,如果使用这些加载了空描述符的段选择符来访问内存就会引发一般保护性异常。通过使用这个段选择符初始化段寄存器,就会引发异常。

LDT表存放在LDT类型的系统段中。此时GDT必须含有LDT的段描述符。如果系统支持多LDT,那么每个LDT都必须在GDT中有一个段描述和段选择符。一个LDT的段描述符可以存放在GDT表的任何地方。 访问LDT需使用其段选择符。为了在访问LDT是减少地址转换次数,LDT的段选择符、段基址、段限长以及访问权限需要存放在LDTR寄存器中。

段选择符

段选择符(或称段选择子)是段的一个十六位标志符,如下图所示。段选择符并不直接指向段,而是指向段描述符表中定义段的段描述符。 段选择符包括 3 个字段的内容:

  • 请求特权级RPL([0:1])
  • 表指引标志TI([2])TI = 0 ,表示描述符在GDT中,TI = 1,表示描述符在LDT中。
  • 索引值,给出了描述符在GDT或LDT表中的索引项号。


技术图片

 

 下面是一些段选择符的示例:

技术图片

 

 

段描述符

每个段描述符长度是 8 字节,含有三个主要字段:段基地址、段限长和段属性。段描述符通常由编译器。链接器、加载器或者操作系统来创建,绝不可能由应用程序来创建。

段描述符通用格式如下:

技术图片

 

以上是关于分段机制的主要内容,如果未能解决你的问题,请参考以下文章

深入理解计算机系统-之-内存寻址--linux中分段机制的实现方式

分段机制

通过分段机制和分页机制实现禁止数据写入

Linux分页机制之分页机制的演变--Linux内存管理

Linux内存寻址之分段机制

操作系统篇-分段机制与GDT|LDT