程序的链接与装入
我们的代码会经过下面这4个环节,从而形成最终文件 。(C语言为例)
预处理, 展开头文件/宏替换/去掉注释/条件编译 (test.i main .i)
编译, 检查语法,生成汇编 ( test.s main .s)
汇编, 汇编代码转换机器码 (test.o main.o)
链接 链接到一起生成可执行程序 a.out
-
布局如下:
给定地址 DS:SI = 0x0200:0x0230
实模式下地址转换
0x0200 << 4 + 0x0230 = 0x02230
保护模式下地址转换
由0x0200 = (0000 0010 0000 0000)2
查找全局描述符表第64项描述符给出的分段基址,加上0x0230才是线性地址(若为分页,则是物理地址
程序的编译
由编译程序将用户源代码编译成cpu可执行的目标代码(.o文件),产生了若干个目标模块(即若干程序段)。
程序的装入
由装入程序将装入模块装入内存,构造PCB,形成进程,开始运行(使用物理地址)。
1.绝对装入方式
在编译时,如果知道程序将驻留在内存的什么位置,那么,编译程序将产生绝对地址的目标代码。 绝对装入程序按照装入模块中的地址,将程序和数据装入内存。 装入模块被装入内存后,由于程序中的逻辑地址与实际内存地址完全相同,故不须对程序和数据的地址进行修改。程序中所使用的绝对地址,既可在编译或汇编时给出,也可由程序员直接赋予。
注:
由于内存划分为系统区和用户区,程序实际在用户区执行,故实际上程序的实际内存地址也有一定的增加,不可能像逻辑地址一样从0开始。
-
优点:使CPU执行目标代码快
-
缺点:(1)由于内存大小限制,能装入内存并发执行的进程数大大减少
(2)编译程序必须知道内存的当前空闲地址部分和其地址,并且把进程的不同程序段连续地存放起来,编译非常复杂。
2.静态地址重定位
绝对装入方式只能将目标模块装入到内存中事先指定的位置。在多道程序环境下,编译程序不可能预知所编译的目标模块应放在内存的何处,因此,绝对装入方式只适用于单道程序环境。
在多道程序环境下,所得到的目标模块的起始地址通常是从 0 开始的,程序中的其它地址也都是相对于起始地址计算的。此时应采用可重定位装入方式,根据内存的当前情况,将装入模块装入到内存的适当位置。
静态地址重定位:即在程序装入对目标代码装入内存的过程中完成,是指在程序开始运行前,程序中指令和数据的各个地址均已完成重定位,即完成虚拟地址到内存地址映射。地址变换通常是在装入时一次完成的,以后不再改变。
-
优点:无需硬件支持
-
缺点:(1)程序重定位之后就不能在内存中搬动了;
(2)要求程序的存储空间是连续的,不能把程序放在若干个不连续的区域中。
3.动态地址重定位
可重定位装入方式可将装入模块装入到内存中任何允许的位置,故可用于多道程序环境;但这种方式并不允许程序运行时在内存中移动位置。因为,程序在内存中的移动,意味着它的物理位置发生了变化, 这时必须对程序和数据的地址(是绝对地址)进行修改后方能运行。然而,实际情况是,在运行过程中它在内存中的位置可能经常要改变,此时就应采用动态运行时装入的方式。
动态地址重定位:不是在程序执行之前而是在程序执行过程中进行地址变换。更确切的说,是把这种地址转换推迟到程序真正要执行时才进行,即在每次访问内存单元前才将要访问的程序或数据地址变换成内存地址。动态重定位可使装入模块不加任何修改而装入内存。为使地址转换不影响指令的执行速度,这种方式需要一个重定位寄存器的支持。
优点:(1)目标模块装入内存时无需任何修改,因而装入之后再搬迁也不会影响其正确执行,这对于存储器紧缩、解决碎片问题是极其有利的;
(2)一个程序由若干个相对独立的目标模块组成时,每个目标模块各装入一个存储区域,这些存储区域可以不是顺序相邻的,只要各个模块有自己对应的定位寄存器就行。
缺点:需要硬件支持。
程序的链接
根据外部访问符号名表(如变量名、函数名等),将经过编译或汇编 得到的一组目标模块以及它们所需要的库函数,装配成一个完整的装入模块 。
1.静态链接方式
下图B和C都属于外部调用符号,在将这几个目标模块装配成一个装入模块时,须解决以下两个问题:
(1) 对相对地址进行修改。
(2) 变换外部调用符号。
这种先进行链接所形成的一个完整的装入模块,又称为可执行文件。通常都不再拆开它,要运行时可直接将它装入内存。这种事先进行链接,以后不再拆开的链接方式,称为静态链接方式。
2.装入时动态链接(所有的模块都装入内存 )
用户源程序经编译后所得的目标模块,是在装入内存时边装入边链接的, 然后再按照上图所示的方式来修改目标模块中的相对地址。
优点:
(1) 、 便于修改和更新。对于经静态链接装配在一起的装入模块,如果要修改或更新其中的某个目标模块,则要求重新打开装入模块。这不仅是低效的,而且有时是不可能的。若采用动态链接方式,由于各目标模块是分开存放的,所以要修改或更新各目标模块是件非常容易的事。
(2)、 便于实现对目标模块的共享。在采用静态链接方式时,每个应用模块都必须含有其目标模块的拷贝,无法实现对目标模块的共享。但采用装入时动态链接方式,OS则很容易将一个目标模块链接到几个应用模块上,实现多个应用程序对该模块的共享。
3.运行时动态链接(需要某个模块时才装入内存)
在许多情况下,应用程序在运行时,每次要运行的模块可能是不相同的。但由于事先无法知道本次要运行哪些模块,故只能是将所有可能要运行到的模块都全部装入内存,并在装入时全部链接在一起。显然这是低效的,因为往往会有些目标模块根本就不运行。比较典型的例子是作为错误处理用的目标模块,如果程序在整个运行过程中都不出现错误,则显然就不会用到该模块。
在执行过程中,当发现一个被调用模块尚未装入内存时,立即由OS去找到该模块并将之装入内存,把它链接到调用者模块上。凡在执行过程中未被用到的目标模块,都不会被调入内存和被链接到装入模块上,这样不仅可加快程序的装入过程,而且可节省大量的内存空间。