1.前言

本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理。

本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础、虚拟地址空间的管理、物理地址空间的管理.

本文将主要以X86架构为例来介绍Linux内存管理的段机制。

2.段机制

  • 段是虚拟地址空间的基本单位
  • 段机制必须把虚拟地址空间的一个地址转换为线性地址空间的一个线性地址
  • 段描述符

段的基地址(Base):在线性地址空间中段的起始地址;

段的界限(Limit):在虚拟地址空间中,段内可以使用的最大偏移量;

段的保护属性:表示段的特性。例如该段是否可以被读出或写入。或者该段是否可以作为一个程序来执行,以及段的特权等级

图 段描述符的一般格式

  • 段描述符表

图 段描述符表(段表)

索引描述虚拟地址空间段的编号;基地址是线性地址空间段的起始地址

补充:保护模式下段描述符表分为:

全局描述符表(GDT)

中断描述符表(IDT)

局部描述符表(LDT)

注:为加快对如上描述符表的访问,intel为之设计了专门的寄存器,存放描述符表的基地址及表的长度界限

  • 保护模式下的段寄存器

段寄存器存放段描述符表的索引(段号,也叫选择符),即从段描述符表中选择某个段.

其中:

索引(13位指明段号);

TI(Table Index)指明使用全局描述符表还是局部描述符表;

RPL(Requestor Previlege Level):2位指定4种特权级,用来决定内核态还是用户态

图 保护模式下的段寄存器

  • 保护模式下的特权级

保护模式提供了四个特权级,用0~3四个数字表示

一般操作系统只使用了其中最低和最高两个,即0表示最高特权级,内核态;3表示最低特权级,用户态

保护模式规定高特权级可随意访问低特权级,低特权级不能随便访问高特权级

  • 地址转换及保护

图 地址转换

程序中的虚拟地址可以表示为“选择符:偏移量”这样的形式,通过以下步骤可以把一个虚拟地址转换为线性地址:

  (1)在段寄存器(16位选择器)中装入段选择符,同时把32位地址偏移量装入某个寄存器(比如ESI、EDI等)中。

  (2)根据选择符中的索引值、TI及RPL值,再根据相应描述符表中的段基地址和段界限,进行一系列合法性检查(如特权级检查、界限检查),如果该段无问题,就取出相应的描述符放入段描述符高速缓冲寄存器中。

  (3)将描述符中的32位段基地址和放在ESI、EDI等中的32位有效地址(偏移量)相加,就形成了32位线性地址。

  注意,在上面的地址转换过程中,从两个方面对段进行了保护:

  (1) 在一个段内,如果偏移量大于段界限,虚拟地址将没有意义,系统将产生异常。

  (2) 如果要对一个段进行访问,系统会根据段的保护属性检查访问者是否具有访问权限,如果没有,则产生异常。例如,如果要在只读段中进行写入,系统将根据该段的属性检测到这是一种违规操作,则产生异常。

3.Linux如何处理段

Linux将整个虚拟地址空间划分为一个段,段的基地址为0,段的界限为4G。

由于很多体系结构并不要求段机制必选,因此这样处理即使用了段机制又巧妙的化解了段机制

  • IA32上设计操作系统时无法回避使用段机制

在IA32上任意给出的地址都是一个虚拟地址,即任意一个地址都是通过“选择符:偏移量”的方式给出的,这是段机制存访问模式的基本特点

所以在IA32上设计操作系统时无法回避使用段机制,IA32规定段机制是不可禁止的,因此不可能绕过它直接给出线性地址空间的地址

一个虚拟地址最终会通过“段基地址+偏移量”的方式转化为一个线性地址

  • 为何要绕过段机制

由于绝大多数硬件平台都不支持段机制,只支持分页机制,所以为了让Linux具有更好的可移植性,我们需要去掉段机制而只使用分页机制

  • Linux如何绕过段机制 

Linux的设计人员干脆让段的基地址为0,而段的界限为4GB,这时任意给出一个偏移量,则等式为“0+偏移量=线性地址”,也就是说“偏移量=线性地址”。

另外由于段机制规定“偏移量 <4GB”,所以偏移量的范围为0H~FFFFFFFFH,这恰好是线性地址空间范围,也就是说虚拟地址直接映射到了线性地址,

我们以后所提到的虚拟地址和线性地址指的也就是同一地址。

看来,Linux在没有回避段机制的情况下巧妙地把段机制给绕过去了。

  • Linux所必须创建哪些段  

由于IA32段机制还规定,必须为代码段和数据段创建不同的段,所以Linux必须为代码段和数据段分别创建一个基地址为0,段界限为4GB的段描述符。

不仅如此,由于Linux内核运行在特权级0,而用户程序运行在特权级别3,根据IA32的段保护机制规定,特权级3的程序是无法访问特权级为0的段的,所以Linux必须为内核和用户程序分别创建其代码段和数据段。

这就意味着Linux必须创建4个段描述符——特权级0的代码段和数据段,特权级3的代码段和数据段。

  • Linux通过分页机制来保护内存  

如果如上这样定义段,则上一节所说的段保护的第一个作用就失去了,因为这些段使用完全相同的线性地址空间(0~4GB),它们互相覆盖。

可以设想,如果不使用分页的话,线性地址空间直接被映射到物理空间,则你修改任何一个段的数据,都会同时修改其它段的数据

段机制所提供的通过“基地址:界限”方式本来将线性地址空间分割,以让段与段之间完全隔离,这种实现段保护的方式根本就不起作用了。

那么,这是不是意味着用户可以随意修改内核数据?显然不是的,这是因为,一方面用户段和内核段具有不同的特权级别,另一方面,Linux之所以这么定义段,正是为了实现一个纯的分页,而分页机制会提供给我们所需要的保护。

4.参考文献

[1] Linux内存管理讲座PPT-陈莉君

Linux内存管理2---段机制的更多相关文章

  1. Linux内存管理3---分页机制

    1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...

  2. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

  3. 浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...

  4. 了解linux内存管理机制(转)

    今天了解了下linux内存管理机制,在这里记录下,原文在这里http://ixdba.blog.51cto.com/2895551/541355 根据自己的理解画了张图: 下面是转载的内容: 一 物理 ...

  5. [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

    Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...

  6. 【转载】Linux 内存管理机制

    在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,主要特点是,无论物理内存有多大,Linux 都将其充份利用,将 ...

  7. Linux内存管理Swap和Buffer Cache机制

    Linux内存管理Swap和Buffer Cache机制 一个完整的Linux系统主要有存储管理,内存管理,文件系统和进程管理等几方面组成,贴出一些以前学习过的一个很好的文章.与大家共享!以下主要说明 ...

  8. Linux内存管理机制简析

    Linux内存管理机制简析 本文对Linux内存管理机制做一个简单的分析,试图让你快速理解Linux一些内存管理的概念并有效的利用一些管理方法. NUMA Linux 2.6开始支持NUMA( Non ...

  9. 【转载】浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多? 在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在 ...

随机推荐

  1. 洛谷 P3297 [SDOI2013]逃考 解题报告

    P3297 [SDOI2013]逃考 题意 给一个平面矩形,里面有一些有标号点,有一个是人物点,人物点会被最近的其他点控制,人物点要走出矩形,求人物点最少被几个点控制过. 保证一开始只被一个点控制,没 ...

  2. 洛谷 P2467 地精部落 解题报告

    P2467 [SDOI2010]地精部落 题目描述 传说很久以前,大地上居住着一种神秘的生物:地精. 地精喜欢住在连绵不绝的山脉中.具体地说,一座长度为\(N\)的山脉\(H\)可分为从左到右的\(N ...

  3. luogu4197 Peaks (kruskal重构树+主席树)

    按照边权排序建出kruskal重构树,每次就变成了先找一个权值<=x的最远的祖先,然后看这个子树的第k小.离散化一下,在dfs序上做主席树即可 而且只需要建叶节点的主席树 注意输出的是第k小点的 ...

  4. 安装 scrapy 报错 error: Microsoft Visual C++ 14.0 is required

    问题描述 使用 pip install scrapy 安装 scrapy 时出现以下错误: error: Microsoft Visual C++ 14.0 is required 错误提示中给出了一 ...

  5. 求矩形面积(问题来自PythonTip)

    描述: 已知矩形长a,宽b,输出其面积和周长,面积和周长以一个空格隔开. 例如:a = 3, b = 8 则输出:24 22 方法一: a=int(input('')) //input返回的是字符串类 ...

  6. Docker:搭建RabbitMQ集群

    RabbitMQ原理介绍(一) RabbitMQ安装使用(二) RabbitMQ添加新用户并支持远程访问(三) RabbitMQ管理命令rabbitmqctl详解(四) RabbitMQ两种集群模式配 ...

  7. 20190311 Windows上ZooKeeper伪集群的实现

    1. 复制并修改conf/zoo.cfg文件 以zoo1.cfg为例: dataDir=E:\\Develop\\zookeeper\\3.4.6\\zookeeper-3.4.6\\data1 da ...

  8. php脚本#!/usr/bin/env php 写法

    脚本语言的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它. 比如php脚本的第一行可以写成如下几种格式 #!/usr/bin/php #!/usr/bin/env php # ...

  9. Springmvc和poi3.9导出excel并弹出下载框

    Springmvc 和 poi3.9 用java程序从数据库导出数据到excel(在博客园的第一篇原创博客) @RequestMapping(value = "/importexcel.ht ...

  10. 11、JPA-JPQL

    /** * JPQL,Java Persistence Query Language 的简称.是一种和 SQL 类似的中间性和对象化查询语言,它最终会被编译成针对不同底层数据库的 SQL 查询,从而屏 ...