注:這是本人學習湯小丹等編寫的計算機操作系統(西安電子科技大學出版社)的學習筆記,因此許多引用來源于此書,在正文中就不注明了!
程序在運行前需要經過以下步驟:編譯程序對源程序進行編譯生成目標程序.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)。