软件工程实践 Blog5

2021SC@SDUSC


学习模块:计算机系统 —— 笔记 05
主要内容:储备系统原理的知识,自底向上的学习路线


006 程序内存地址的转换

实际场景:
设想一下,如果一台计算机的内存中只运行一个程序 A,这种方式正好用前面 CPU 的实模式来运行,因为程序 A 的地址在链接时就可以确定,例如从内存地址 0x8000 开始,每次运行程序 A 都装入内存 0x8000 地址处开始运行,没有其它程序干扰。
现在改变一下,内存中又放一道程序 B,程序 A 和程序 B 各自运行一秒钟,如此循环,直到其中之一结束。这个新场景下就会产生一些问题,当然这里我们只关心内存相关的这几个核心问题:

  1. 谁来保证程序 A 跟程序 B 没有内存地址的冲突?换句话说,就是程序 A、B 各自放在什么内存地址,这个问题是由 A、B 程序协商,还是由操作系统决定。
  2. 怎样保证程序 A 跟程序 B 不会互相读写各自的内存空间?
    这个问题相对简单,用保护模式就能解决。
  3. 如何解决内存容量问题?程序 A 和程序 B,在不断开发迭代中程序代码占用的空间会越来越大,导致内存装不下。
  4. 还要考虑一个扩展后的复杂情况,如果不只程序 A、B,还可能有程序 C、D、E、F、G……它们分别由不同的公司开发,而每台计算机的内存容量不同。这时候,又对我们的内存方案有怎样的影响呢?

要想完美地解决以上最核心的 4 个问题,一个较好的方案是:让所有的程序都各自享有一个从 0 开始到最大地址的空间,这个地址空间是独立的,是该程序私有的,其它程序既看不到,也不能访问该地址空间,这个地址空间和其它程序无关,和具体的计算机也无关。
这个方案就是虚拟地址


虚拟地址
正如其名,这个地址是虚拟的,自然而然地和具体环境进行了解耦,这个环境包括系统软件环境和硬件环境

虚拟地址是逻辑上存在的一个数据值,比如 0~100 就有 101 个整数值,这个 0~100 的区间就可以说是一个虚拟地址空间,该虚拟地址空间有 101 个地址。

以最开始 Hello World 作为例子,使用 objdump 工具反汇编一下 Hello World 二进制文件,就会得到如下的代码片段:

00000000000004e8 <_init>:4e8:  48 83 ec 08            sub    $0x8,%rsp4ec:  48 8b 05 f5 0a 20 00   mov    0x200af5(%rip),%rax        # 200fe8 <__gmon_start__>4f3:  48 85 c0               test   %rax,%rax4f6:  74 02                  je     4fa <_init+0x12>4f8:  ff d0                  callq  *%rax4fa:  48 83 c4 08            add    $0x8,%rsp4fe:  c3                     retq

上述代码中,左边第一列数据就是虚拟地址,第三列中是程序指令,如:“mov 0x200af5(%rip),%rax,je 4fa,callq *%rax”指令中的数据都是虚拟地址。

事实上,所有的应用程序开始的部分都是这样的。
这正是因为每个应用程序的虚拟地址空间都是相同且独立的。

那么这个地址是由谁产生的呢?

答案是链接器
其实我们开发软件经过编译步骤后,就需要链接成可执行文件才可以运行,而链接器的主要工作就是把多个代码模块组装在一起,并解决模块之间的引用,即处理程序代码间的地址引用,形成程序运行的静态内存空间视图。只不过这个地址是虚拟而统一的,而根据操作系统的不同,这个虚拟地址空间的定义也许不同,应用软件开发人员无需关心,由开发工具链给自动处理了。由于这虚拟地址是独立且统一的,所以各个公司开发的各个应用完全不用担心自己的内存空间被占用和改写。

物理地址
虽然虚拟地址解决了很多问题,但是虚拟地址只是逻辑上存在的地址,无法作用于硬件电路的,程序装进内存中想要执行,就需要和内存打交道,从内存中取得指令和数据。
而内存只认一种地址,那就是物理地址。
什么是物理地址呢?物理地址在逻辑上也是一个数据,只不过这个数据会被地址译码器等电子器件变成电子信号,放在地址总线上,地址总线电子信号的各种组合就可以选择到内存的储存单元了。但是地址总线上的信号(即物理地址),也可以选择到别的设备中的储存单元,如显卡中的显存、I/O 设备中的寄存器、网卡上的网络帧缓存器。不过如果不做特别说明,我们说的物理地址就是指选择内存单元的地址。

虚拟地址到物理地址的转换

虚拟地址必须转换成物理地址,这样程序才能正常执行。
要转换就必须要转换机构,它相当于一个函数:p=f(v),输入虚拟地址 v,输出物理地址 p。
那么要怎么实现这个函数呢?
用软件方式实现太低效,用硬件实现没有灵活性,最终就用了软硬件结合的方式实现,它就是 MMU(内存管理单元)。MMU 可以接受软件给出的地址对应关系数据,进行地址转换。我们先来看看逻辑上的 MMU 工作原理框架图。如下图所示:


上图中展示了 MMU 通过地址关系转换表,将 0x80000~0x84000 的虚拟地址空间转换成 0x10000~0x14000 的物理地址空间,而地址关系转换表本身则是放物理内存中的。

如果在地址关系转换表中,这样来存放:一个虚拟地址对应一个物理地址。那么问题来了,32 位地址空间下,4GB 虚拟地址的地址关系转换表就会把整个 32 位物理地址空间用完,这显然不行。
要是结合前面的保护模式下分段方式呢,地址关系转换表中存放:一个虚拟段基址对应一个物理段基址,这样看似可以,但是因为段长度各不相同,所以依然不可取。
综合刚才的分析,系统设计者最后采用一个折中的方案,即把虚拟地址空间和物理地址空间都分成同等大小的块,也称为页,按照虚拟页和物理页进行转换。根据软件配置不同,这个页的大小可以设置为 4KB、2MB、4MB、1GB,这样就进入了现代内存管理模式——分页模型


一个虚拟页可以对应到一个物理页,由于页大小一经配置就是固定的,所以在地址关系转换表中,只要存放虚拟页地址对应的物理页地址就行了。

MMU
MMU 即内存管理单元,是用硬件电路逻辑实现的一个地址转换器件,它负责接受虚拟地址和地址关系转换表,以及输出物理地址。

根据实现方式的不同,MMU 可以是独立的芯片,也可以是集成在其它芯片内部的,比如集成在 CPU 内部,x86、ARM 系列的 CPU 就是将 MMU 集成在 CPU 核心中的。SUN 公司的 CPU 是将独立的 MMU 芯片卡在总线上的,有一夫当关的架势。

下面我们只研究 x86 CPU 中的 MMU。x86 CPU 要想开启 MMU,就必须先开启保护模式或者长模式,实模式下是不能开启 MMU 的。由于保护模式的内存模型是分段模型,它并不适合于 MMU 的分页模型,所以我们要使用保护模式的平坦模式,这样就绕过了分段模型。这个平坦模型和长模式下忽略段基址和段长度是异曲同工的。地址产生的过程如下所示:

上图中,程序代码中的虚拟地址,经过 CPU 的分段机制产生了线性地址,平坦模式和长模式下线性地址和虚拟地址是相等的。如果不开启 MMU,在保护模式下可以关闭 MMU,这个线性地址就是物理地址。因为长模式下的分段弱化了地址空间的隔离,所以开启 MMU 是必须要做的,开启 MMU 才能访问内存地址空间。

MMU 页表
页表描述了虚拟地址到物理地址的转换关系,也可以说是虚拟页到物理页的映射关系,所以称为页表。
为了增加灵活性和节约物理内存空间(因为页表是放在物理内存中的),所以页表中并不存放虚拟地址和物理地址的对应关系,只存放物理页面的地址,MMU 以虚拟地址为索引去查表返回物理页面地址,而且页表是分级的,总体分为三个部分:一个顶级页目录,多个中级页目录,最后才是页表,逻辑结构图如下:

从上面可以看出,一个虚拟地址被分成从左至右四个位段。第一个位段索引顶级页目录中一个项,该项指向一个中级页目录,然后用第二个位段去索引中级页目录中的一个项,该项指向一个页目录,再用第三个位段去索引页目录中的项,该项指向一个物理页地址,最后用第四个位段作该物理页内的偏移去访问物理内存。这就是 MMU 的工作流程。

保护模式下的分页

此处笔记掠过部分详细的地址解析。

开启 MMU

要使用分页模式就必先开启 MMU,但是开启 MMU 的前提是 CPU 进入保护模式或者长模式,开启 CPU 这两种模式的方法,我们在Blog 4,下面我们就来开启 MMU,步骤如下:

  1. 使 CPU 进入保护模式或者长模式。
  2. 准备好页表数据,这包含顶级页目录,中间层页目录,页表,假定我们已经编写了代码,在物理内存中生成了这些数据。
  3. 把顶级页目录的物理内存地址赋值给 CR3 寄存器。
mov eax, PAGE_TLB_BADR ;页表物理地址
mov cr3, eax
  1. 设置 CPU 的 CR0 的 PE 位为 1,这样就开启了 MMU。
;开启 保护模式和分页模式
mov eax, cr0
bts eax, 0    ;CR0.PE =1
bts eax, 31   ;CR0.P = 1
mov cr0, eax

MMU 地址转换失败

MMU 的主要功能是根据页表数据把虚拟地址转换成物理地址,但有没有可能转换失败?绝对有可能,例如,页表项中的数据为空,用户程序访问了超级管理者的页面,向只读页面中写入数据。这些都会导致 MMU 地址转换失败。MMU 地址转换失败了怎么办呢?失败了既不能放行,也不是 reset,MMU 执行的操作如下:
1.MMU 停止转换地址。
2.MMU 把转换失败的虚拟地址写入 CPU 的 CR2 寄存器。
3.MMU 触发 CPU 的 14 号中断,使 CPU 停止执行当前指令。
4.CPU 开始执行 14 号中断的处理代码,代码会检查原因,处理好页表数据返回。
5.CPU 中断返回继续执行 MMU 地址转换失败时的指令。

软件工程实践 Blog5相关推荐

  1. 【软件工程实践】Hive研究-Blog5

    [软件工程实践]Hive研究-Blog5 2021SC@SDUSC 研究内容介绍 本人负责的是负责的是将查询块QB转换成逻辑查询计划(OP Tree) 如下的代码出自apaceh-hive-3.1.2 ...

  2. 【软件工程实践】Hive研究-Blog6

    [软件工程实践]Hive研究-Blog6 2021SC@SDUSC 研究内容介绍 本人负责的是负责的是将查询块QB转换成逻辑查询计划(OP Tree) 如下的代码出自apaceh-hive-3.1.2 ...

  3. 软件工程python就业方向-软件工程实践总结

    软工ByeBye~ 请回望暑假时的第一次作业,你对于软件工程课程的想象 对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强计算机专业的能力和就业竞争力",对比目前的所学所练所 ...

  4. 软件工程实践2017第二次作业

    软件工程实践2017第二次作业 1)Github地址 https://github.com/Maple27/sudoku 2)解题思路 个人从小就对数独就很喜欢,对解数独有一定程度的了解,这次自己开发 ...

  5. 个人作业——软件工程实践总结

    一.请回望暑假时的第一次作业,你对于软件工程课程的想象 对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强计算机专业的能力和就业竞争力",对比目前的所学所练所得,在哪些方面达 ...

  6. 个人作业收官——软件工程实践总结

    个人作业收官--软件工程实践总结 一.回望开学初对于软件工程课程的想象,回望博客开篇时对于这门课和这学期的期望, 1)对比现在的你和开学初博客开篇的课程目标和期待. 能力的预期 1.对于java的一些 ...

  7. 软件工程专业(互联网应用开发与优化方向)软件工程实践二环节教学大纲

    软件工程专业(互联网应用开发与优化方向)软件工程实践二环节教学大纲 培训课程 Phthon Web开发 实训公司 XXX 总周数 3周

  8. 2017软件工程实践总结

    一.请回望暑假时的第一次作业,你对于软件工程课程的想象 1)对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强计算机专业的能力和就业竞争力",对比目前的所学所练所得,在哪些方 ...

  9. 『软件工程12』软件工程实践方法——软件测试

    软件工程实践方法-- 软件测试 一.软件测试概述 1.软件测试的目的 (1)从用户和开发者角度 (2)Myers软件测试目的 2.软件测试的原则 3.软件测试的对象 4.测试信息流 5.测试与软件开发 ...

  10. 三周的 软件工程实践课 课程安排建议

    不少学校想在暑期安排软件工程实践课, 在这么短的时间内要做到软件生命周期的完整体验是有很多挑战的,下面是一个建议: 软件工程课程设计 - 三周计划,10 次授课,10 次学生报告. 第一周,准备: 在 ...

最新文章

  1. 【Netty】Netty组件介绍
  2. angular例子笔记
  3. MyEclipse10安装SVN插件
  4. codevs 2924 数独挑战
  5. 你发这些什么目的_吸引女生冷知识:朋友圈发照片的“潜规则”,男生要懂
  6. codeforces 1287A -Angry Students(模拟)
  7. Apache RocketMQ:简单消息示例
  8. C++中operator的两种用法
  9. Linux Process VS Thread VS LWP
  10. python-利用生成器函数生成斐波那契数列
  11. 《伟大的小细节:互联网产品设计中的微创新思维》——3.2 时间/日期因素
  12. 有关Oracle cvu和cvuqdisk
  13. 深度学习之四大经典CNN技术浅析
  14. 基于Matlab矩形孔径的菲涅耳衍射
  15. STM32用串口(USB串口)下载程序的方法
  16. 河北关于加快新型建筑工业化发展的实施意见发布
  17. 关于我使用校园网电脑被限速成10M宽带的悲惨教训
  18. spring源码bean生命周期篇 一 如何实例化对象
  19. 会计基础-会计账簿+对账+结账+财产清查+财务会计报告+会计核算程序
  20. 【C语言】探究整型数据在内存中的存储

热门文章

  1. ESP8266WiFi模块的使用以及arduino调试
  2. golang对接paypal支付
  3. 基于LabVIEW 2018开发的自动化测试系统源码,该系统模仿TestStand编写
  4. 微信小程序轮播图高度自适应
  5. HashMap如何解决hash冲突?
  6. iconv 判断字符编码_iconv函数文字编码格式转换
  7. 浙大PAT甲级题目1081-1100详细代码解答|标准答案|C++语言|浙软机考
  8. 好好编程-物流项目02【tomcat插件启动web项目】
  9. Tomcat日志配置,可结合log4j
  10. Matlab之数据归一化函数——mapminmax()