💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃個人主頁 :阿然成長日記 👈點擊可跳轉
📆 個人專欄: 🔹數據結構與算法🔹C語言進階🔹C++🔹Liunx
🚩 不能則學,不知則問,恥于問人,決無長進
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目錄
- 動態庫的鏈接理解:
- 鏈接的三種方式
- 問題一:誰來決定哪些庫加載,哪些沒加載?
- 問題二:談談裝入的三種方式
- 談談程序的加載的地址問題
- 動態庫是如何被進程動態鏈接的
動態庫的鏈接理解:
首先:你應該知道一個前提知識,每一個程序都有自己對應的進程空間,這個地址空間被劃分為很多區域,例如:棧、堆、共享區~。
系統中有很多程序,這些程序會用到一些公共方法,將這些公共方法打包成動態庫、共享庫。首次使用到庫時需要加載到內存中,之后其他程序在使用公共方法時,直接從內存中映射一份下來。不需要拷貝到自己的地址空間中,節省了內存。這種鏈接方式又叫動態鏈接
如下圖,進程1和進程2都是用了同一個庫中的方法,直接從內存中映射一份下來
鏈接的三種方式
- 靜態鏈接:在程序運行之前,先將各個目標模塊以及他們所需要的庫函數連接成一個完整的可執行文件(裝入模塊),之后不再拆開。
- 裝入時動態鏈接:將各目標模塊裝入內存時,邊裝入邊鏈接
- 運行時動態鏈接:在程序執行中需要該目標模塊時才對他進行鏈接,優點是便于修改和更新,便于實現對目標模塊的共享。
問題一:誰來決定哪些庫加載,哪些沒加載?
os操作系統,記住一句話操作系統中的管理都是先描述后組織,加載進來的一個個庫,操作系統會為它們生成一個結構體類似于PCB存儲它的描述信息,然后對其進行一個雙向指針連接,由操作系統來進行管理。
問題二:談談裝入的三種方式
裝入的三種方式
- 絕對裝入:在編譯時知道程序放在內存中的哪個位置,編譯程序將產生絕對地址的目標代碼。靈活性很低,只適用于單道程序環境,只有單道程序環境可以在程序運行之前就能確定程序將要放入哪個位置
- 靜態重定位:又稱為可重定位裝入。裝入模塊全部使用邏輯地址,在裝入的時候將邏輯地址全部轉換為物理地址。
特點是必須分配其要求的全部內存空間,如果沒有足夠的內存,就不能裝入作業。作業一旦進入內存后,在運行期間就不能再移動,也不能再申請內存空間。 - 動態重定位:又稱為動態運行時裝入。裝入模塊使用相對地址。相對地址到物理地址的轉變要等到實際運行的時候才能確定。因此裝入內存后所有的地址仍然是邏輯地址。這種方式需要一個重定位寄存器的支持。
重定位寄存器:存放裝入模塊存放的起始位置。當實際運行的時候實時地將邏輯地址轉換為物理地址。采用動態重定位允許程序在內存中發生移動。可以將程序分配到不連續的存儲區:在程序運行前只需要裝入他的部分代碼即可投入運算,然后在程序運行期間根據需要動態申請分配內存,便于程序段的共享,可以向用戶提供一個比存儲空間大得多的地址空間。
每個程序加載到內存中,都會有一個進程地址空間結構體,有棧區、堆區、共享區等等。它實際上就是一個個的有起始地址的空間組合在一起的一塊空間。并不是連續的
首先,你的代碼一定是保存在了磁盤上的,并且它會以絕對地址進行編址----又叫平坦模式。只需要拿到首地址,然后加上偏移量,
相對編址:就是每個區內的代碼都是從0地址處開始編址
談談程序的加載的地址問題
你有沒有想過一個問題,就是你寫好的代碼,cpu是如何找到你的代碼所在位置的呢
1.你寫的代碼經過編譯形成一個可執行程序。通常它會以絕對地址進行編址----又叫平坦模式
。
例如下圖。一個可執行文件經過編譯鏈接
后形成了一個可執行程序。
-
它包含
一個表頭
和一堆二進制代碼
。
為了方便我們看,使用反匯編
將 二進制代碼裝換成我們看的懂的匯編指令
-
觀察上圖,可以看到每一條匯編指令都有一個八進制的地址,fun1和fun2是兩個函數,還有一個main函數去調用。 這些地址,又叫邏輯地址。
2 .根據可執行程序文件的表頭(表頭中包含了入口地址,每個分區的起始地址等
)填充進程的地址空間。,
3.從磁盤加載到內存,加載到內存后,又得到了一個物理地址,本身自帶的就有邏輯地址。所有邏輯地址到物理地址的映射關系就有了。頁表的左側是邏輯地址,右側是物理地址。
4.cup中的程序計數器pc指針用來保存正在執行指令的下一條指令
- 執行的過程如下圖,藍色線所示,從cup的pc指針找到要執行的指令,放入到指令寄存器中,然后cpu執行這個指令。
動態庫是如何被進程動態鏈接的
首先,第一次用到庫的時候肯定是 先需要加載到內存中的,加載到內存后,它也會有一個頁表(邏輯-物理地址)映射關系。而且庫的名稱對應的有加載到內存的起始地址。
邏輯(虛擬)地址就能找到庫
所在內存位置,加上偏移量
就能找到庫中函數
的起始地址,所以,當一個進程用到庫中函數時,它會將函數代碼映射到程序地址空間的共享區中。其他程序在使用時也是一個道理,不需要拷貝到自己的代碼區中,只需在共享區做個映射即可。