動態連接和靜態連接

做爲一名C/C++程序員,對於編譯連接的過程要了然於胸。首先大概介紹一下,編譯分爲3步,首先對源文件進行預處理,這個過程主要是處理一些#號定義的命令或語句(如宏、#include、預編譯指令#ifdef等),生成*.i文件;而後進行編譯,這個過程主要是進行詞法分析、語法分析和語義分析等,生成*.s的彙編文件;最後進行彙編,這個過程比較簡單,就是將對應的彙編指令翻譯成機器指令,生成可重定位的二進制目標文件。以上就是編譯的過程,下面主要介紹兩種連接方式--靜態連接和動態連接。程序員

        靜態連接和動態連接二者最大的區別就在於連接的時機不同,靜態連接是在造成可執行程序前,而動態連接的進行則是在程序執行時,下面來詳細介紹這兩種連接方式。函數

1、靜態連接
1.爲何要進行靜態連接
        在咱們的實際開發中,不可能將全部代碼放在一個源文件中,因此會出現多個源文件,並且多個源文件之間不是獨立的,而會存在多種依賴關係,如一個源文件可能要調用另外一個源文件中定義的函數,可是每一個源文件都是獨立編譯的,即每一個*.c文件會造成一個*.o文件,爲了知足前面說的依賴關係,則須要將這些源文件產生的目標文件進行連接,從而造成一個能夠執行的程序。這個連接的過程就是靜態連接性能

2.靜態連接的原理
         由不少目標文件進行連接造成的是靜態庫,反之靜態庫也能夠簡單地當作是一組目標文件的集合,即不少目標文件通過壓縮打包後造成的一個文件,以下圖,使用ar命令的-a參數查看靜態庫的組成:.net

 

        這裏的*.o目標文件在我前面的博客《從編寫源代碼到程序在內存中運行的全過程解析》中已經講的很清楚了,不清楚的能夠看一下。翻譯

        如下面這個圖來簡單說明一下從靜態連接到可執行文件的過程,根據在源文件中包含的頭文件和程序中使用到的庫函數,如stdio.h中定義的printf()函數,在libc.a中找到目標文件printf.o(這裏暫且不考慮printf()函數的依賴關係),而後將這個目標文件和咱們hello.o這個文件進行連接造成咱們的可執行文件。blog

 

        這裏有一個小問題,就是從上面的圖中能夠看到靜態運行庫裏面的一個目標文件只包含一個函數,如libc.a裏面的printf.o只有printf()函數,strlen.o裏面只有strlen()函數。內存

        咱們知道,連接器在連接靜態連接庫的時候是以目標文件爲單位的。好比咱們引用了靜態庫中的printf()函數,那麼連接器就會把庫中包含printf()函數的那個目標文件連接進來,若是不少函數都放在一個目標文件中,極可能不少沒用的函數都被一塊兒連接進了輸出結果中。因爲運行庫有成百上千個函數,數量很是龐大,每一個函數獨立地放在一個目標文件中能夠儘可能減小空間的浪費,那些沒有被用到的目標文件就不要連接到最終的輸出文件中。開發


3.靜態連接的優缺點
        靜態連接的缺點很明顯,一是浪費空間,由於每一個可執行程序中對全部須要的目標文件都要有一份副本,因此若是多個程序對同一個目標文件都有依賴,如多個程序中都調用了printf()函數,則這多個程序中都含有printf.o,因此同一個目標文件都在內存存在多個副本;另外一方面就是更新比較困難,由於每當庫函數的代碼修改了,這個時候就須要從新進行編譯連接造成可執行程序。可是靜態連接的優勢就是,在可執行程序中已經具有了全部執行程序所須要的任何東西,在執行的時候運行速度快。博客

問題:io

2、動態連接
1.爲何會出現動態連接
        動態連接出現的緣由就是爲了解決靜態連接中提到的兩個問題,一方面是空間浪費,另一方面是更新困難。下面介紹一下如何解決這兩個問題。

2.動態連接的原理
        動態連接的基本思想是把程序按照模塊拆分紅各個相對獨立部分,在程序運行時纔將它們連接在一塊兒造成一個完整的程序,而不是像靜態連接同樣把全部程序模塊都連接成一個單獨的可執行文件。下面簡單介紹動態連接的過程:

        假設如今有兩個程序program1.o和program2.o,這二者共用同一個庫lib.o,假設首先運行程序program1,系統首先加載program1.o,當系統發現program1.o中用到了lib.o,即program1.o依賴於lib.o,那麼系統接着加載lib.o,若是program1.o和lib.o還依賴於其餘目標文件,則依次所有加載到內存中。當program2運行時,一樣的加載program2.o,而後發現program2.o依賴於lib.o,可是此時lib.o已經存在於內存中,這個時候就再也不進行從新加載,而是將內存中已經存在的lib.o映射到program2的虛擬地址空間中,從而進行連接(這個連接過程和靜態連接相似)造成可執行程序。

3.動態連接的優缺點
        動態連接的優勢顯而易見,就是即便須要每一個程序都依賴同一個庫,可是該庫不會像靜態連接那樣在內存中存在多分,副本,而是這多個程序在執行時共享同一份副本;另外一個優勢是,更新也比較方便,更新時只須要替換原來的目標文件,而無需將全部的程序再從新連接一遍。當程序下一次運行時,新版本的目標文件會被自動加載到內存而且連接起來,程序就完成了升級的目標。可是動態連接也是有缺點的,由於把連接推遲到了程序運行時,因此每次執行程序都須要進行連接,因此性能會有必定損失。

        據估算,動態連接和靜態連接相比,性能損失大約在5%如下。通過實踐證實,這點性能損失用來換區程序在空間上的節省和程序構建和升級時的靈活性是值得的。

4.動態連接地址是如何重定位的呢?        前面咱們講過靜態連接時地址的重定位,那咱們如今就在想動態連接的地址又是如何重定位的呢?雖然動態連接把連接過程推遲到了程序運行時,可是在造成可執行文件時(注意造成可執行文件和執行程序是兩個概念),仍是須要用到動態連接庫。好比咱們在造成可執行程序時,發現引用了一個外部的函數,此時會檢查動態連接庫,發現這個函數名是一個動態連接符號,此時可執行程序就不對這個符號進行重定位,而把這個過程留到裝載時再進行。————————————————版權聲明:本文爲CSDN博主「kang___xi」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/kang___xi/article/details/80210717

相關文章
相關標籤/搜索