历史
早期,程序员自己管理主存,通过分解程序并覆盖主存的方式执行程序
- 取指令和存储操作数所有的地址都是物理地址;
- 执行速度快,无需进行地址转换;
- 未采用虚拟存储机制。
1961年有人提出自动执行overlay的方式,把程序员从大量繁琐的存储管理工作中解放出来,使得程序员编程时不用管主存容量的大小。
基本思想
- 把地址空间和主存容量的概念区分开来,程序员在地址空间里编写程序,程序则在真正的内存中运行;
- 由一个专门的机制实现地址空间和实际主存之间的映射;
- CPU 中的 MMU (Memory Management Unit) 负责将逻辑地址(即虚拟地址)转换为内存的物理地址。
逻辑地址(即虚拟地址)转换为内存的物理地址的方式:
分页式分段式段页式
分段
根据程序的模块化性质,按程序的逻辑结构划分成多个相对独立的部分,称为段;
一个程序可以有多个代码段;
一个程序可以有多个数据段;
段通常有段名、段起点、段长、段属性等信息
C语言程序中,变量的定义和指令写在一起,无分段的概念
机器语言层次上,是要分段的:在C程序编译时,将变量的空间分配和指令分开,分别放在不同段中。
主存分段管理
在分段内存模型中,每个分段通常加载不同的分段选择器,以便每个段寄存器指向线性地址空间内的不同段。
主存物理地址的形成
实方式
物理地址 = (段寄存器)左移4位 +偏移地址
- 32位CPU与8086一样,只能寻址1M物理存储空间
- 可以访问6个段:CS, DS, SS, ES, FS, GS,每个段至多64K
- 段开始单元的物理地址 /16➡段址
段中某一存储单元的地址用两部分表示——“段首地址:偏移地址”,称二维的逻辑地址。
8086中,只有4个段寄存器 CS, DS, ES, SS
- 在代码段中取指令时:指令物理地址 PA= (CS) 左移四位 + (IP) ,使用的是IP, 而不是EIP
- 在数据段中读/写数据时:数据的物理地址 PA = (DS或ES)左移四位 + 16位偏移地址 (偏移地址由寻址方式确定)
- 在堆栈操作时:栈顶的物理地址 PA = (SS) 左移四位 + (SP)
保护方式
在多任务环境下,系统中有多个程序在运行,程序之间要隔离。
分段是存储管理的一种方式,为保护提供基础,不同程序在不同段中,一个程序可以包含多个段,段用于封闭具有共同属性的存储区域;
描述符
存放为保护一个段需要的信息
- 段的起始位置(段基地址)
- 段的大小(段界限)
- 段的特权级
- 段的属性(是代码段、数据段还是堆栈段?数据段是否可写?代码段是否可读出?)
- 段的位置(在内存还是在磁盘?)
- 段的类型(在系统段还是用户段?)
- 段的使用(段被访问过,还是没有?)
描述符表
描述符的集合。
局部描述符表:一个LDT,是一个系统段,最大可为64KB,最多可存放8192个描述符。
对每一个程序,都建立一个局部描述符表(LDT)。
全局描述符表:只有一个。GDT最大可为64KB,存放8192个描述符。包括:
- 操作系统所使用的段的描述符;
- 各个LDT段的描述
保护方式下物理地址的形成
1——从虚拟地址到线性地址
xxxx指出找相应段描述符的方式,称段选择符。
1. TI 位为 0 (操作系统段)
• 从 GDTR 寄存器中获取 GDT 的基址;• 在 GDT 表中 , 以 XXXX 的高 13 位作为索引,取出一个描述符 A ;• 描述符 A 中的段基地址 + yyyyyyyy : 为要访问单元的 线性地址。
2. 若TI 位为 1 (用户程序段)
• 从 GDTR 寄存器中获取 GDT 的基址;• 在 GDT 表中 , 以 LDTR 的高 13 位作为索引,取出一个描述符 A ;• 描述符 A 描述的段为一个 LDT 段 (LDT_A ) ;• 用 XXXX 的高 13 位,作为索引,在 LDT_A 段中找到描述符 P_A 。• P_A 描述段的基址+ yyyyyyyy 为 线性地址。