注:这是本人学习汤小丹等编写的计算机操作系统(西安电子科技大学出版社)的学习笔记,因此许多引用来源于此书,在正文中就不注明了!
程序在运行前需要经过以下步骤:编译程序对源程序进行编译生成目标程序.obj;链接程序将目标程序和需要的库文件链接在一起形成可执行程序.exe,即一个完整的装入模块;装入程序将装入模块装入内存,然后运行。依次称为程序的编译、链接、装入。
程序的装入方式有三种:绝对装入方式、可重定位装入方式和动态运行时的装入方式。
绝对装入方式。适用系统小且仅运行单道程序的情况,此时很容易知道程序装入后将留在内存的什么位置,因此程序经编译后将产生含有绝对地址(物理地址或内存地址)的目标代码,装入程序将按照该地址装入内存,因此装入内存后程序的实际地址(内存地址)与程序的逻辑地址完全相同,不需要进行地址变换。程序中所使用的绝对地址既可以在编译或汇编时指出(将程序中的符号地址转变为绝对地址),也可以由程序员直接赋予(用绝对地址编程),但要求程序员熟悉内存的使用情况。
可重定位装入方式。用户程序编译链接后形成的可执行程序的起始地址一般都是从0开始的,其它地址都是相对于起始地址计算的(逻辑地址),因此此时装入后的实际地址与程序中的逻辑地址不同,需要进行地址变换。对于多道程序采用基址寻址,有效地址EA=A+(BR),A为指令的地址码字段,BR为基址寄存器,其内容由OS和系统管理程序决定,值不变,系统根据BR的值为程序分配储存空间,因此装入后需要根据该值进行地址变换,即程序中的逻辑地址(或虚拟地址)加上基址即可,对于程序中的数据地址(语句中引用到的逻辑地址)和外部调用符号都要进行相应的修改,即需要对程序地址(指令地址)、数据地址和外部调用符号进行修改。把在装入时对目标程序中指令和数据地址的修改过程称为重定位,对于可重定位装入方式,该地址变换是一次完成的,以后不可以再修改,因此称为静态重定位。变址寻址,EA=A+(IX),IX为变址寄存器,此时IX的值可变,由用户设定,A的值不变,通常为数组的起始地址。变址寻址用于处理数组问题,编制循环程序;相对寻址,EA=(PC)+A,常用于转移类指令,无论该程序在主存的哪一个区域都可以正确运行,对于编写浮动程序非常有利。
动态运行时的装入方式。如果程序在内存中会发生移动,此时物理位置会发生变化,因此可重定位装入方式不再适用,移动后需要再次对地址进行修改,如在具有对换功能的系统中,一个进程可能会被多次换入和换出,其位置总是在发生变化,此时可采用动态运行时的装入方式。该方式,将装入模块装入内存后,并不立即把装入模块中的逻辑地址(虚拟地址)变换为物理地址,而是把这种地址变换过程推迟到真正执行时进行,即执行时通过:EA=A+(BR)来完成地址变换,因此装入模块的地址实际上一直都是逻辑地址(虚拟地址),程序执行时自动根据该地址进行变换,此时在CPU中需要设置一个基址寄存器BR,对于每一个进程,OS都会为其分配一个基址。
链接程序的功能是将一组目标程序和需要的库文件链接成一个完成的装入模块,根据进行链接的时间不同分为三种链接方式:静态链接方式、装入时动态链接、运行时动态链接。
静态链接方式。在装入之前就将所有的目标模块和需要的库文件链接成为一个完整的装入模块(可执行文件.exe),以后不再拆开。每个目标模块都采用的是逻辑地址,即起始地址均为0,因此链接过程中需要做以下修改:对相对地址(程序或指令地址、数据地址)进行修改;对外部调用符号进行修改,如CALLB,表示调用模块B(目标文件B),改为JSR“L”,L为B的首地址。如下:
装入时动态链接。对于各个目标模块和库文件采用边装入边链接的方式,即在装入一个目标模块时,若发生一个外部调用事件,将引起装入程序去找出相应的外部调用模块,并将其装入内存,然后进行链接,并按照上图所示的方式修改地址。该方式具有以下优点:1.便于对目标模块修改和更新。对于经过静态链接装配在一起的装入模块,如果要修改或更新某个目标模块,需要将其拆开,低效且麻烦,而且有时不可能。对于动态链接方式(装入时动态链接和运行时动态链接),模块是分开存放的,对于修改和更新很容易实现(注意即使装入了的模块,原模块依然存在,相当于拷贝一份装入)。2.便于实现目标模块的共享。对于静态链接方式,每个应用模块都必须含有其目标模块的拷贝,无法实现对目标模块的共享。而动态链接方式却可以容易将一个目标模块链接到几个应用模块上。
运行时动态链接。其是对装入时动态链接方式的一种改进。这种链接方式是,将对某些模块的链接推迟到程序执行时才进行。亦即,在执行过程中,当发现一个被调用模块尚未装入内存时,立即由OS去找到该模块,并将之装入内存,将其链接到调用者模块上。凡在执行过程中未被用到的目标模块(如处理错误用的模块,如果运行过程中不出现错误,则不会用到),都不会被调入内存和被链接到装入模块上,这样不仅能加快程序的装入过程,而且可节省大量的内存空间。
在运行时进行链接,通常被链接的共享代码称为动态链接库(DLL, Dynamic Link Library)或共享库(shared library)。