当前位置: 首页 > news >正文

操作系统 3.1-内存使用和分段

如何简单使用内存

这张幻灯片展示了计算机如何开始执行程序的基本过程,涉及到存储器、指令寄存器(IR)、运算器和控制器等计算机组件。

  1. 存储器:程序被加载到内存中。图中显示了一个指令 mov ax, [100],它的作用是将内存地址100处的值移动到寄存器ax中。内存地址100处的值是0。

  2. 指令寄存器(IR):指令从内存中取出后,被放入指令寄存器(IR)中,然后由运算器和控制器解析并执行。

  3. 运算器和控制器:这些组件负责解析指令并执行相应的操作。在这个例子中,指令被解析后,将内存地址100处的值(0)移动到寄存器ax中。

  4. 程序执行:幻灯片下方展示了一个C语言程序的例子,该程序定义了一个main函数,其中包含了一些变量和对atoi函数的调用。程序的输出显示了不同的输入(如sum 12345)和相应的结果(如76205685)。

  5. 内存使用内存的使用方式:将程序放到内存中,程序计数器(PC)指向开始地址。这意味着程序的执行是从内存中的某个特定地址开始的,这个地址由PC指示

内存使用

程序放入内存

这张幻灯片讨论了程序如何被加载到内存中,以及程序计数器(IP)如何指向程序的入口地址。幻灯片中展示了两种不同的内存布局方式,以及它们对程序执行的影响。

  1. 程序结构

    • 程序包含一个main函数,以及一些其他函数如call_xxcall_40

    • .text段包含了程序的代码和入口点_entry

  2. 内存布局

    • 第一种布局(左上角):

      • _entry是程序的入口地址。

      • call_maincall_exit是调用main函数和其他函数的指令。

      • _main函数的偏移量是40。

    • 第二种布局(右下角):

      • _entry仍然是程序的入口地址,但是_main函数的偏移量变成了1040。

  3. 程序计数器(IP)

    • IP指向程序的入口地址,即_entry

    • 在第一种布局中,IP正确地指向了_entry,程序可以正常执行。

    • 在第二种布局中,如果IP仍然指向_entry那么call 40指令将尝试调用一个不存在的地址,导致程序错误。

  4. 问题

    • 幻灯片右侧的问题指出,虽然内存可以使用了,但是存在一个问题,即在第二种布局中,调用指令没有正确地考虑_main函数的实际偏移量,导致程序可能无法正确执行。

重定位

重定位的概念

重定位是指修改程序中的地址,使其适应内存中的不同位置。这些地址通常是相对地址,即相对于程序在内存中的起始位置的偏移量。

编译时重定位

  • 定义:在编译时完成重定位,即在编译过程中就确定了程序在内存中的绝对地址。

  • 特点

    • 程序只能在内存的固定位置运行。

    • 优点是加载速度快,因为不需要在加载时进行地址调整。

    • 缺点是缺乏灵活性,因为程序不能被加载到任意内存位置。

载入时重定位

  • 定义:在程序加载到内存时完成重定位,即在加载过程中根据实际的内存地址调整程序中的相对地址。

  • 特点

    • 程序可以被加载到内存的任意位置。

    • 优点是灵活性高,因为程序可以适应不同的内存布局。

    • 缺点是加载速度可能较慢,因为需要在加载时进行地址调整。

图示解释
  • 左侧图示:显示了编译时重定位的错误示例,其中call 40指令指向了错误的地址(1000),导致程序无法正确执行。

  • 右侧图示:显示了载入时重定位的正确示例,其中call 1040指令正确地指向了新的地址(1040),确保程序可以正确执行。

运行时重定位

运行时重定位是在程序执行过程中,每执行一条指令时才完成地址的重定位。这种方法允许程序在内存中的加载位置更加灵活,因为程序中的逻辑地址可以在运行时被转换为物理地址。

图示解释

幻灯片中的图示展示了运行时重定位的过程:

  • 逻辑地址:程序中的地址是相对于某个基地址的偏移量(offset),例如 _sum: .int 0_main: mov [300], 0

  • 基地址(base):每个进程都有一个基地址,这是进程在内存中的起始地址。

  • 物理地址:通过将逻辑地址与基地址相加,得到实际的物理内存地址。

进程控制块(PCB)
  • 基地址存储PCB中存储了进程的基地址,这是运行时重定位的关键信息。

  • 地址翻译在执行指令时,操作系统首先从PCB中取出进程的基地址,然后根据指令中的逻辑地址计算出物理地址。

运行时重定位的步骤
  1. 取出基地址:从PCB中取出进程的基地址。

  2. 地址翻译:将逻辑地址与基地址相加,得到物理地址。

  3. 执行指令:使用物理地址访问内存,执行指令。

交换

交换(Swap)的概念

交换是操作系统用来管理内存的一种技术,它涉及将暂时不活跃的进程从内存移动到磁盘上,以便为其他进程腾出内存空间。当需要再次运行被交换出去的进程时,操作系统会将其从磁盘重新加载到内存中。

可重定位性的重要性

幻灯片中提到“程序1仍应该是可重定位的”,这意味着程序在被加载到内存中时,其地址可以被动态调整以适应内存中的不同位置。这对于交换过程至关重要,因为:

  • 当进程被从磁盘重新加载到内存时,它可能被放置在与之前不同的内存位置。

  • 当一个进程被重新换入内存时,由于之前占据的内存空间可能已不再可用,因此需要进行运行时重定位,确保进程的地址在内存中被正确更新,以便能够根据当前内存地址找到相应的数据或指令,从而保证进程的正常执行。

总结-内存使用的详细过程

  1. 创建进程和PCB

    • 为了执行程序,操作系统需要创建一个进程,并为该进程创建一个进程控制块(PCB)。

    • PCB中存储了进程的状态信息,包括程序的基地址

  2. 在内存中找到空闲区域

    • 操作系统在内存中寻找一个足够大的空闲区域来加载程序。

    • 找到的空闲区域的起始地址被设置为程序的基地址

  3. 加载程序

    • 程序被加载到内存中找到的空闲区域。

    • 程序中的逻辑地址需要根据基地址进行调整,以确保程序可以正确执行。

  4. 执行程序

    • 程序开始执行,每次执行指令时,都需要进行地址翻译,将逻辑地址转换为物理地址。

    • 地址翻译涉及到基地址和偏移量的计算。

  5. 进程切换和内存管理

    • 在多任务操作系统中,进程可能会被切换出去,释放内存,或者被换入,重新加载到内存中。

    • 运行时重定位允许进程在内存中移动,而不影响其执行。

分段

程序员眼中的程序

  1. 程序的组成

    • 程序由若干个部分(段)组成,每个段具有不同的特点和用途。

    • 例如,代码段是只读的,而数据段可能会动态增长。

  2. 程序的分段案例

    • 主程序(main):程序的入口点,通常包含程序的主要逻辑。

    • 变量集(data):存储程序中使用的变量。

    • 函数库(如sin):程序可能调用的函数集合,例如数学函数库。

    • 动态数组(array):程序中动态分配的数组,其大小可能在运行时改变。

    • 栈(stack):用于存储函数调用时的局部变量和返回地址,通常具有后进先出(LIFO)的特性。

  3. 分段的优点

    • 符合用户观点:用户可以独立考虑每个段,这有助于分治和模块化编程。

    • 独立管理:每个段可以独立地加载、卸载和保护,提高了程序的安全性和稳定性。

  4. 地址定位

    • 程序中的指令和数据可以通过段号和段内偏移来定位。

    • 例如,mov [es:bx], ax 指令中,es 表示段寄存器,bx 表示段内偏移。

程序的分段存储

  1. 内存布局

    • 程序在内存中被分为多个段,每个段从0开始,以便于管理和访问。

    • 这种布局方式简化了内存管理,因为每个段可以独立地加载到内存中的任何位置。

  2. 段表

    • 操作系统维护一个段表,记录每个段的基地址和其他属性。

    • 在进程切换时,操作系统会更新段表,以反映当前进程的内存布局。

  3. 地址翻译

    • 当程序访问内存时,操作系统使用段表将逻辑地址转换为物理地址。

程序分段如何放入内存

程序分段放入内存

  1. 分段存储

    • 程序不是作为一个整体被加载到内存中,而是将其分为多个段,每个段独立加载到内存的不同位置。

    • 图中显示了四个段(0, 1, 2, 3),它们被加载到内存中的不同区域。

  2. 内存布局

    • 内存被划分为多个区域,每个区域存储程序的一个段。

    • 比如图中案例,段0被加载到内存的180K位置,段1被加载到360K位置,段2被加载到70K位置,段3被加载到460K位置。

运行时重定位

  1. 指令示例

    • mov [DS:100], %eax:这条指令表示将寄存器eax的值移动到数据段(DS)偏移100的位置。

    • jmp 100, CS:这条指令表示跳转到代码段(CS)偏移100的位置。

  2. 段表

    • 段表列出了每个段的基址、长度和保护属性。

    • 例如,段0的基址是180K,长度是150K,保护属性是只读(R)。

  3. 地址计算

    • 运行时重定位涉及将逻辑地址转换为物理地址。

    • 逻辑地址由段号和段内偏移组成。物理地址通过将段基址与偏移相加得到。

示例计算

  1. 假设DS=1,CS=0

    • 对于mov [DS:100], %eax,如果DS=1,则物理地址为段1的基址(360K)加上偏移100,即360K+100=360100。

    • 对于jmp 100, CS,如果CS=0,则物理地址为段0的基址(180K)加上偏移100,即180K+100=180100。

  2. jmp 500K的重定位

    • 如果直接跳转到物理地址500K,需要确定500K属于哪个段,然后使用该段的基址和偏移进行跳转。

GDT和LDT的在内存使用的作用

在x86架构的操作系统中,GDT(全局描述符表)和LDT(局部描述符表)是用于内存管理和段式内存保护的关键数据结构。它们在内存使用和地址转换中扮演着重要角色。以下是对GDT和LDT作用的分析:

GDT(全局描述符表)

  1. 全局性:GDT是全局的,意味着它对系统中的所有进程都是可见的。它包含了操作系统内核和所有用户进程共享的段描述符。

  2. 内核空间:GDT通常包含了内核代码段和数据段的描述符,这些段描述符定义了内核的内存布局。

LDT(局部描述符表)

  1. 用户空间:LDT通常包含了用户进程的代码段、数据段、堆栈段等描述符,这些描述符定义了用户空间的内存布局。

地址转换过程

  1. 段选择子:在x86体系结构中,段选择子(如CS、DS、SS等)包含了段号,用于在GDT或LDT中索引对应的段描述符。

  2. GDT和LDT的查找:当一个进程执行时,其段选择子中的段号首先在GDT中查找。如果该段号对应的描述符的局部描述符表(LDT)有效位被设置,则在该进程的LDT中查找对应的段描述符。

  3. 基地址计算:一旦找到段描述符,CPU会使用该描述符中的基地址和段内偏移来计算物理地址。

  4. 内存访问控制:段描述符中的段限长和访问权限位用于控制内存访问,确保进程不能访问不属于它的内存区域。

    相关文章:

  • BeeWorks:高效协作的局域网聊天工具
  • 《Vue Router实战教程》21.扩展 RouterLink
  • 设计模式 四、行为设计模式(2)
  • 苍穹外卖2
  • 算法训练之动态规划(四)——简单多状态问题
  • AutoEval:现实世界中通才机器人操作策略的自主评估
  • 电机控制储备知识 四:电机的分类
  • 示波器测量纹波噪声的一些建议
  • JavaScript 实现 WiFi 信号强度模拟类
  • C++顺序栈的实现
  • 蓝桥杯比赛 python程序设计——神奇闹钟
  • 图像颜色空间对比(Opencv)
  • 【Nginx】Nginx代理Tomcat配置及404问题解决
  • JavaScript逆向工程:如何判断对称加密与非对称加密
  • LLM应用开发(七)--记忆
  • 聊一聊接口测试时遇到第三方服务时怎么办
  • map映射到二维数组
  • Windows下安装depot_tools
  • 云曦月末断网考核复现
  • 力扣HOT100之链表: 148. 排序链表
  • 网页设计的目的/网站seo方案撰写
  • 个人网站建设课程介绍/青岛 google seo
  • 手机网站 ui/珠海网站建设制作
  • 外贸海外网站推广/肇庆seo
  • 怎么弄网站/王通seo赚钱培训
  • 网站制作做网站/专业seo网络营销公司