程序的裝入和鏈接

注:這是本人學習湯小丹等編寫的計算機操作系統(西安電子科技大學出版社)的學習筆記,因此許多引用來源于此書,在正文中就不注明了!

程序在運行前需要經過以下步驟:編譯程序對源程序進行編譯生成目標程序.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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385441.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385441.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385441.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

內存對齊

1. 對齊原則: 數據成員對齊規則:結構(struct)(或聯合(union))的數據成員,第一個數據成員放在offset為0的地方,以后每個數據成員的對齊按照#pragma pack指定的數值和這個數據成員自身長度中,比較小的那個進行。結構(或…

1006. 換個格式輸出整數 (15)

讓我們用字母B來表示“百”、字母S表示“十”&#xff0c;用“12...n”來表示個位數字n&#xff08;<10&#xff09;&#xff0c;換個格式來輸出任一個不超過3位的正整數。例如234應該被輸出為BBSSS1234&#xff0c;因為它有2個“百”、3個“十”、以及個位的4。 輸入格式&a…

靜態庫的制作和使用

Linux下的靜態庫為lib*.a格式的二進制文件&#xff08;目標文件&#xff09;&#xff0c;對應于Windows下的.lib格式的文件。 &#xff08;1&#xff09;命名規則 lib庫名字 .a libMytest.a &#xff0c;則庫名字為mytest。下面以具體的代碼為例介紹如何制作靜態庫。 //mai…

IO多路復用之select

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); 分析&#xff1a; nfds: 監控的文件描述符集里最大文件描述符加1&#xff0c;因為此參數會告訴內核檢測前多少個文件描述符的狀態 readfds&#xff1a; …

1031. 查驗身份證(15)

一個合法的身份證號碼由17位地區、日期編號和順序編號加1位校驗碼組成。校驗碼的計算規則如下&#xff1a; 首先對前17位數字加權求和&#xff0c;權重分配為&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&#xff0c;8&#xff0c;4&#xff0c;2&#xff0c;1&…

虛擬地址空間

對于每一個進程都會對應一個虛擬地址空間&#xff0c;對于32位的操作系統&#xff08;其指令的位數最大為32位&#xff0c;因此地址碼最多32位&#xff09;&#xff0c;虛擬地址空間的大小為B即0~4GB的虛擬地址空間&#xff0c;其中內核空間為1GB&#xff0c;如下所示&#xff…

Leecode 69. x 的平方根

實現 int sqrt(int x) 函數。 計算并返回 x 的平方根&#xff0c;其中 x 是非負整數。 由于返回類型是整數&#xff0c;結果只保留整數的部分&#xff0c;小數部分將被舍去。 示例 1: 輸入: 4 輸出: 2 示例 2: 輸入: 8 輸出: 2 說明: 8 的平方根是 2.82842..., 由于返回類…

1002. 寫出這個數 (20)

讀入一個自然數n&#xff0c;計算其各位數字之和&#xff0c;用漢語拼音寫出和的每一位數字。 輸入格式&#xff1a;每個測試輸入包含1個測試用例&#xff0c;即給出自然數n的值。這里保證n小于10100。 輸出格式&#xff1a;在一行內輸出n的各位數字之和的每一位&#xff0c;拼…

C/C++中NULL指針

先談一下C/C的強制類型轉換Type cast。與強制類型轉換相對應的是自動類型轉換。或者強制類型轉換叫顯示類型轉換&#xff0c;自動類型轉換叫隱式類型轉換。自動類型轉換會在賦值運算、混合運算、參數傳遞、返回函數返回值、格式化輸出時且當類型出現不一致時發生&#xff0c;轉…

1009. 說反話 (20)

給定一句英語&#xff0c;要求你編寫程序&#xff0c;將句中所有單詞的順序顛倒輸出。 輸入格式&#xff1a;測試輸入包含一個測試用例&#xff0c;在一行內給出總長度不超過80的字符串。字符串由若干單詞和若干空格組成&#xff0c;其中單詞是由英文字母&#xff08;大小寫有區…

動態庫(共享庫)的制作和使用

Linux下的動態庫為lib*.so格式的二進制文件&#xff08;目標文件&#xff09;&#xff0c;對應于Windows下的.dll格式的文件。 &#xff08;1&#xff09;命名規則 lib庫名.so &#xff08;2&#xff09;動態庫的制作 1&#xff09;生成與位置無關的代碼&#xff08;.o&…

孤兒進程、僵尸進進程

一、兒進程與僵尸進程 1、基本概念 我們知道在unix/linux中&#xff0c;正常情況下&#xff0c;子進程是通過父進程創建的&#xff0c;子進程在創建新的進程。子進程的結束和父進程的運行是一個異步過程,即父進程永遠無法預測子進程 到底什么時候結束。 當一個 進程完成它的工…

管道 -pipe

gcc編譯器將源代碼編譯成可執行程序的過程中&#xff0c;需要經過許多中間步驟&#xff08;預處理、編譯、匯編、鏈接&#xff09;&#xff0c;這些過程實際上是由不同的程序來負責完成的&#xff08;/usr/bin/gcc、cpp、ccl、as和ld等&#xff09;。在這個過程的每一個階段中&…

gdb調試器(一)

在默認情況下&#xff0c;gcc在編譯時不會把調試符號插入到最終生成的二進制代碼&#xff08;機器代碼&#xff09;中&#xff0c;因為這樣會急劇增加可執行程序的大小。如果需要在編譯時生成調試符號的信息&#xff0c;則可以采用-g或-ggdb參數。 gcc在產生調試信息時&#x…

1048. 數字加密(20)

本題要求實現一種數字加密方法。首先固定一個加密用正整數A&#xff0c;對任一正整數B&#xff0c;將其每1位數字與A的對應位置上的數字進行以下運算&#xff1a;對奇數位&#xff0c;對應位的數字相加后對13取余——這里用J代表10、Q代表11、K代表12&#xff1b;對偶數位&…

網絡編程套接字API

uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);int inet_pton(int family, const char *strptr, void *addrptr); 分析&#xff1a; 第一個參數可以是AF_INET或AF_INET6&am…

gdb調試器(二)

Linux下的gdb&#xff08;GNU Debugger&#xff09;是一個用來調試C、C程序的調試器&#xff08;命令行方式的調試器&#xff09;&#xff0c;能夠在程序運行期間觀察程序的內部結構和內存的使用情況。程序員也可以使用gdb來跟蹤程序中的錯誤&#xff0c;從而減少程序員的工作量…

gdb調試器(三)

File/file 裝入想要調試的可執行文件 run(r) 執行當前被調試的程序 kill(k) 終止正在調試的程序 quit(q) 退出gdb shell 使用戶不離開gdb就可以執行Linux的shell命令 backtrace(bt) 回溯跟蹤&#xff08;當對代碼進行調試時&#xff0c;run后…

IO多路復用之poll

1. poll函數原型&#xff1a; int poll(struct pollfd *fds, nfds_t nfds, int timeout);參數&#xff1a; fds&#xff1a;指向一個結構體數組的第0個元素的指針&#xff0c;每個數組元素都是一個struct pollfd結構&#xff0c;用于指定測試某個給定的fd的條件 nfds&#x…

makefile文件的書寫規則(make和makefile)

對于makefile&#xff0c;掌握一個規則&#xff0c;兩個變量和三個函數。下面介紹一個規則。 makefile的作用&#xff1a;一個項目代碼的管理工具。當一個項目的代碼文件數&#xff08;如.c文件&#xff09;太多&#xff0c;用gcc編譯會太麻煩&#xff0c;如果全部文件一次性編…