操作系统 程序如何运行:编译、链接、装入

前言

本文梳理程序是如何运行的。

内存的基础知识

内存的概念和作用

内存是用于存储数据的硬件。程序执行前需要先放到内存中才能被CPU处理。

  • 存储单元
    内存地址从0开始,每个地址对应一个存储单元。
    如果计算机是按字节编址的,则每个存储单元的大小为1字节,即8位;
    如果是按字编址的,那么每个存储单元的大小为一个字;字长是按CPU指令长度来的,32位/64位等。

进程运行的基本原理

  • 指令的工作原理
    代码会被编译成机器码被操纵系统执行,包含相应指令、操作码、和若干参数等。
    在生成机器指令时并不知道该进程的数据会被放到什么位置,所以编译时生成的指令中一般是使用逻辑地址。

  • 逻辑地址 vs 物理地址
    逻辑地址,就是相对地址;
    物理地址,绝地地址;
    程序编程时产生的指令只用关心相对地址,实际放入内存中时再根据进程起始位置得到绝对地址就能找到相应的数据了。
    从逻辑地址到物理的地址的转换将有装入程序完成。

  • 代码编译到运行流程:编译->链接->装入
    编译:由编译程序Compiler将源代码编译成若干个目标模块,翻译成机器语言
    链接:由链接程序Linker将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块(可执行文件);
    装入:可执行文件只有被装载到内存以后才能被CPU执行,由装入程序Loader将装入模块装入内存运行;

三种链接方式

源程序经过编译后,可得到一组目标模块,再利用链接程序将这组目标模块链接,形成装入模块。根据链接时间的不同,可把链接分成如下三种:

  • 静态链接:
    在程序运行前,先将各个目标模块以及他们所需的库函数连接成一个完成的可执行文件,之后不再拆开;

  • 装入时动态链接:
    将各目标模块装入内存时,边装入边链接。

  • 运行时动态链接:
    在程序执行中需要该目标模块时,才对它进行链接。
    优点是便于修改和更新,便于实现对目标的共享。

三种装入方式

可执行文件只有被装载到内存以后才能被CPU执行,由装入程序Loader将装入模块装入内存运行;
装入模块有三种方式完成逻辑地址到物理地址的装换:有绝对装入、可重定位装入、动态运行装入三种方式,此处以连续分配方式为例,后续讲解非连续分配方式的地址转换;
现在一般都采用动态运行装入;

  • 绝对装入:
    在编译时,如果知道程序将放到内存中的哪个位置,编译程序将产生绝对地址的目标代码。即编译、链接后得到的装入模块的指令直接就使用了绝对地址;
    装入程序按照装入模块中的地址,将程序和数据装入内存;
    绝对装入只适用于单道程序环境。

  • 静态重定位(可重定位装入):
    编译、链接后的装入模块的地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址,装入程序根据内存的当前情况,将装入模块装入到内存的适当位置,并在装入时对地址进行重定位,将逻辑地址变换为物理地址。
    地址变换是在装入时一次性完成的。

    • 特点:
      静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,则装入失败。作业一旦进入内存后,运行期间不能再移动,也不能再申请新的内存空间。
  • 动态重定位(动态运行时装入):
    编译、链接后的装入模块的地址都是从0开始的,装入程序把装入模块装入内存后,在程序真正执行时候进行地址转换。因此装入内后后所有地址依然是逻辑地址。
    这种方式需要一个重定位寄存器(存放装入模块存放的起始位置)的支持。
    采用动态重定位时允许程序在内存中发生移动。

    • 特点:
      并且可将程序分配到不连续的内存空间中;
      还可以只用装入部分程序代码即可运行,在程序运行时进行动态内存分配即可;
      便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间;

参考:
程序如何运行:编译、链接、装入
Linux下编译、链接和装载

你可能感兴趣的:(计算机网络,操作系统等,操作系统)