程序如何運(yùn)行,編譯、鏈接、裝入?
一、地址概念和程序如何運(yùn)行
在多道程序環(huán)境下,要使程序運(yùn)行,必須先為之創(chuàng)建進(jìn)程。而創(chuàng)建進(jìn)程的第一件事,便是將程序和數(shù)據(jù)裝入內(nèi)存。如何將一個(gè)用戶源程序變?yōu)橐粋€(gè)可在內(nèi)存中執(zhí)行的程序,通常都要經(jīng)過以下幾個(gè)步驟:
首先是要編譯
由編譯程序(Compiler)將用戶源代碼編譯成cpu可執(zhí)行的目標(biāo)代碼,產(chǎn)生了若干個(gè)目標(biāo)模塊(Object Module)(即若干程序段)。形成的目標(biāo)代碼,每個(gè)目標(biāo)代碼都是以0為基址順序進(jìn)行編址,原來用符號名訪問的單元用具體的數(shù)據(jù)——單元號取代。這樣生成的目標(biāo)程序占據(jù)一定的地址空間,稱為作業(yè)的邏輯地址空間,簡稱邏輯空間。
其次是鏈接
由鏈接程序(Linker)將編譯后形成的一組目標(biāo)模塊(程序段),以及它們所需要的庫函數(shù)鏈接在一起,形成一個(gè)完整的裝入模塊(Load Module);
最后是裝入(地址重定位)
由裝入程序(Loader)將裝入模塊裝入物理內(nèi)存。物理內(nèi)存是真實(shí)存在的插在主板內(nèi)存槽上的內(nèi)存條的容量的大小。
二. 程序的鏈接
源程序經(jīng)過編譯后,可得到一組目標(biāo)模塊,再利用鏈接程序?qū)⑦@組目標(biāo)模塊鏈接,形成裝入模塊。根據(jù)鏈接時(shí)間的不同,可把鏈接分成如下三種:
1.靜態(tài)鏈接方式(Static Linking)
我們通過一個(gè)例子來說明在實(shí)現(xiàn)靜態(tài)鏈接時(shí)應(yīng)解決的一些問題。在圖 4-4(a)中示出了經(jīng)過編譯后所得到的三個(gè)目標(biāo)模塊A、B、C,它們的長度分別為 L、M和N。在模塊A中有一條語句CALL B,用于調(diào)用模塊B。在模塊B中有一條語句CALL C,用于調(diào)用模塊C。B和C都屬于外部調(diào)用符號,在將這幾個(gè)目標(biāo)模塊裝配成一個(gè)裝入模塊時(shí),須解決以下兩個(gè)問題:
2.裝入時(shí)動(dòng)態(tài)鏈接(Load-time Dynamic Linking)
用戶源程序經(jīng)編譯后所得的目標(biāo)模塊,是在裝入內(nèi)存時(shí)邊裝入邊鏈接的,即在裝入一個(gè)目標(biāo)模塊時(shí),若發(fā)生一個(gè)外部模塊調(diào)用事件,將引起裝入程序去找出相應(yīng)的外部目標(biāo)模塊,并將它裝入內(nèi)存,還要按照圖4-4所示的方式來修改目標(biāo)模塊中的相對地址。裝入時(shí)動(dòng)態(tài)鏈接方式有以下優(yōu)點(diǎn):
3.運(yùn)行時(shí)動(dòng)態(tài)鏈接(Run-time Dynamic Linking)
在許多情況下,應(yīng)用程序在運(yùn)行時(shí),每次要運(yùn)行的模塊可能是不相同的。但由于事先無法知道本次要運(yùn)行哪些模塊,故只能是將所有可能要運(yùn)行到的模塊都全部裝入內(nèi)存,并在裝入時(shí)全部鏈接在一起。顯然這是低效的,因?yàn)橥鶗行┠繕?biāo)模塊根本就不運(yùn)行。
三. 程序的裝入(地址的變換)
為了闡述上的方便,我們先介紹一個(gè)無需進(jìn)行鏈接的單個(gè)目標(biāo)模塊的裝入過程。該目標(biāo)模塊也就是裝入模塊。在將一個(gè)裝入模塊裝入內(nèi)存時(shí),可以有絕對裝入方式、可重定位裝入方式和動(dòng)態(tài)運(yùn)行時(shí)裝入方式,下面分別簡述之。
1.絕對裝入方式(Absolute Loading Mode)
在編譯時(shí),如果知道程序?qū)Ⅰv留在內(nèi)存的什么位置,那么,編譯程序?qū)a(chǎn)生絕對地址的目標(biāo)代碼。即按照物理內(nèi)存的位置賦予實(shí)際的物理地址。例如,事先已知用戶程序(進(jìn)程)駐留在從R處開始的位置,則編譯程序所產(chǎn)生的目標(biāo)模塊(即裝入模塊)便從R處開始向上擴(kuò)展。
因此,通常是寧可在程序中采用符號地址,然后在編譯或匯編時(shí),再將這些符號地址轉(zhuǎn)換為絕對地址。
2.靜態(tài)地址重定位(可重定位裝入方式 Relocation Loading Mode)
絕對裝入方式只能將目標(biāo)模塊裝入到內(nèi)存中事先指定的位置。在多道程序環(huán)境下,編譯程序不可能預(yù)知所編譯的目標(biāo)模塊應(yīng)放在內(nèi)存的何處,因此,絕對裝入方式只適用于單道程序環(huán)境。
3.動(dòng)態(tài)地址重定位(動(dòng)態(tài)運(yùn)行時(shí)裝入方式Dynamic Run-time Loading)
可重定位裝入方式可將裝入模塊裝入到內(nèi)存中任何允許的位置,故可用于多道程序環(huán)境;但這種方式并不允許程序運(yùn)行時(shí)在內(nèi)存中移動(dòng)位置。因?yàn)?,程序在?nèi)存中的移動(dòng),意味著它的物理位置發(fā)生了變化, 這時(shí)必須對程序和數(shù)據(jù)的地址(是絕對地址)進(jìn)行修改后方能運(yùn)行。
四. Windows NT動(dòng)態(tài)鏈接庫
5.1. 構(gòu)造動(dòng)態(tài)鏈接庫
DLL是包含函數(shù)和數(shù)據(jù)的模塊,它的調(diào)用模塊可為EXE或DLL,它由調(diào)用模塊在運(yùn)行時(shí)加載;加載時(shí),它被映射到調(diào)用進(jìn)程的地址空間。在VC中有一類工程用于創(chuàng)建DLL。
- 庫程序文件 .C:相當(dāng)于給出一組函數(shù)定義的源代碼;
- 模塊定義文件 .DEF:相當(dāng)于定義鏈接選項(xiàng),也可在源代碼中定義;如:DLL中函數(shù)的引入和引出(dllimport和dllexport)。
- 編譯程序利用 .C文件生成目標(biāo)模塊 .OBJ
- 庫管理程序利用 .DEF文件生成DLL輸入庫 .LIB和輸出文件 .EXP
- 鏈接程序利用 .OBJ和 .EXP文件生成動(dòng)態(tài)鏈接庫 .DLL。
5.2. DLL的裝入方法
1)裝入時(shí)動(dòng)態(tài)鏈接(load-time):
- 在編程時(shí)顯式調(diào)用某個(gè)DLL函數(shù),該DLL函數(shù)在可執(zhí)行文件中稱為引入(import)函數(shù)。
- 鏈接時(shí)需利用 .LIB文件。在可執(zhí)行文件中為引入的每個(gè)DLL建立一個(gè)IMAGE_IMPORT_DESCRIPTOR結(jié)構(gòu)。
- 在裝入時(shí)由系統(tǒng)根據(jù)該DLL映射在進(jìn)程中的地址改寫Import Address Table中的各項(xiàng)函數(shù)指針。Hint是DLL函數(shù)在DLL文件中的序號,當(dāng)DLL文件修改后,就未必指向原先的DLL函數(shù)。在裝入時(shí),系統(tǒng)會查找相應(yīng)DLL,并把它映射到進(jìn)程地址空間,獲得DLL中各函數(shù)的入口地址,定位本進(jìn)程中對這些函數(shù)的引用
2)運(yùn)行時(shí)動(dòng)態(tài)鏈接(run-time):
在編程時(shí)通過LoadLibrary(給出DLL名稱,返回裝入和鏈接之后該DLL的句柄), FreeLibrary, GetProcAddress(其參數(shù)包括函數(shù)的符號名稱,返回該函數(shù)的入口指針)等API來使用DLL函數(shù)。這時(shí)不再需要引入庫(import library)。
- LoadLibrary或LoadLibraryEx把可執(zhí)行模塊映射到調(diào)用進(jìn)程的地址空間,返回模塊句柄;
- GetProcAddress獲得DLL中特定函數(shù)的指針,返回函數(shù)指針;
- FreeLibrary把DLL模塊的引用計(jì)數(shù)減1;當(dāng)引用計(jì)數(shù)為0時(shí),拆除DLL模塊到進(jìn)程地址空間的映射;
HINSTANCE hInstLibrary;//模塊句柄定義
DWORD (WINAPI *InstallStatusMIF)(char*, char*, char*, char*, char*, char*, char*, BOOL);//函數(shù)指針定義
if (hInstLibrary = LoadLibrary("ismif32.dll"))//映射
{
InstallStatusMIF = (DWORD (WINAPI *)(char*,char*,char*, char*, char*, char*, char*, BOOL)) GetProcAddress(hInstLibrary, "InstallStatusMIF");//獲得函數(shù)指針
if (InstallStatusMIF)
{
if (InstallStatusMIF(“office97”, “Microsoft”, “Office 97”, “999.999”, “ENU”, “1234”, ”Completed successfully”, TRUE) !=0)//調(diào)用DLL模塊中的函數(shù)
{
}
}
FreeLibrary(hInstLibrary);//拆除映射
}
作者:hguisu原文地址:https://blog.csdn.net/hguisu/article/details/5713099版權(quán)歸原作者所有,如有侵權(quán),請聯(lián)系刪除。???????????????? END ????????????????
關(guān)注我的微信公眾號,回復(fù)“加群”按規(guī)則加入技術(shù)交流群。
歡迎關(guān)注我的視頻號: