静态库调用_静态链接和动态链接对比简析
0. 簡介
在Linux環境下進行開發工作,代碼要經過編譯鏈接生成二進制可執行文件,才能被CPU識別并執行;程序的編譯過程可以參考另外一篇文章《linux程序編譯過程簡析》;鏈接過程分為兩種,靜態鏈接和動態鏈接;
靜態鏈接和動態鏈接最明顯的區別是,兩者鏈接的時機不一樣;靜態鏈接在生成可執行文件時;動態鏈接在程序加載執行時;
1. 靜態鏈接
多個目標文件經過靜態鏈接生成靜態庫,靜態庫也可以看作是多個目標文件的集合;鏈接器在鏈接靜態庫時,是以目標文件為單位的,使用ar命令可以查看靜態庫中包含的目標文件;在引用靜態庫中的printf()函數時,鏈接器會把庫中包含printf()函數實現的目標文件鏈接進去,如果在這個目標文件中還有很多別的函數實現,這些沒有被實際使用到的函數也會被鏈接到結果文件中,所以應該盡量將函數實現按照功能模塊分成多個目標文件,以減少將沒有使用到的函數鏈接到可執行文件中;
靜態鏈接過程分兩步:
靜態鏈接的優缺點
缺點:
優點:
在可執行程序中已經包含了執行程序需要的所有函數,在執行的時候運行速度更快;
2. 動態鏈接
動態鏈接的基本思想是把程序按照模塊拆分成相對獨立的部分,在程序運行時將他們鏈接形成完整的程序,而不是像靜態鏈接一樣,把所有程序模塊鏈接到一起生成一個可執行文件;
動態鏈接在程序運行時才進行鏈接形成完整的程序;程序編譯的鏈接階段,鏈接器只是拷貝了一些重定位和符號信息;在程序加載時才解析so文件中代碼和數據的引用;
某個程序在運行中要調用某個動態鏈接庫中的函數時,系統會先檢查所有正在運行的程序,內存中是否已有該庫函數的副本,如果有,則將其共享給程序,如果沒有,則鏈接載入需要的動態鏈接庫文件;被調用的動態鏈接庫函數被加載在內存的某個位置,所有調用庫文件的程序都指向這個代碼段,因此庫文件的代碼必須使用相對地址,而不是絕對地址;在編譯時,這些庫文件用來做動態鏈接庫,要用地址無關代碼;
2.1 動態鏈接過程舉例
假設有兩個程序demo1.o和demo2.o,都依賴庫文件demolib.o,如果程序demo1.o先運行,系統先把demo1.o加載到內存中,系統檢測到demo1.o中用到了庫文件demolib.o中的函數,系統會加載demolib.o和其他的依賴庫文件到內存中;
在程序demo2.o運行時,同樣加載demo2.o到內存,之后系統檢測到demo2.o也用到了demolib.o中的函數,此時由于庫文件demolib.o已經加載到內存中了,此時就不需要重新加載demolib.o文件,而是將內存中已經存在的demolib.o映射到demo2.o的虛擬地址空間中進行鏈接,形成可執行程序;
2.2 動態鏈接的優缺點
優點:
1. 即使需要每個程序都依賴同一個庫,該庫文件不會像靜態鏈接在內存中存在多分副本,而是多個程序執行時共享同一個庫函數副本;
2. 更新方便,更新時只需替換庫文件中原來的目標文件,無需將所有的程序重新編譯鏈接;在程序運行時,新版本的目標文件會被加載到內存中并進行鏈接;
缺點:
由于把鏈接操作推遲到了程序運行時,每次程序運行都需要進行鏈接,性能會有一些損失;
2.3 動態鏈接地址重定位
動態鏈接把鏈接過程推遲到了程序運行時,在生成可執行文件時,需要用到動態鏈接庫;即在生成可執行程序時,發現少了一個外部實現的函數,此時會檢查動態鏈接庫,如果檢查到該函數名時一個動態鏈接符號名,可執行程序就不會對這個符號重定位,而把這個過程推遲到程序裝載時進行;
3. 生成庫文件
3.1 生成靜態鏈接庫
源代碼文件:demo.c
鏈接庫的源代碼文件:testlib.c
$ gcc -c testlib.c -o testlib.o // 把lib.c文件編譯不鏈接,生成.o文件$ ar testlib.o -rc libtest.a // 使用ar工具把.o文件打包生成.a庫文件3.2 靜態鏈接庫的使用
$ gcc demo.c -o demo -ltest -L. // testlib.a庫在鏈接時使用-ltest-L:表示要鏈接的庫所在的目錄
-l:指定鏈接的庫,編譯器查找鏈接庫時會在名稱前加上lib,后邊加上.a或.so來確定庫名稱;
3.3 生成動態鏈接庫
源代碼文件:demo.c
鏈接庫的源代碼文件:testlib.c
$ gcc -fPIC -c testlib.c -o testlib.o // 編譯不鏈接$ gcc -shared testlib.o -o libtest.so // 使用-shared生成動態鏈接庫-fPIC:用來創建與地址無關的編譯程序,為了在多個程序間共享
-shared:指定生成動態鏈接庫
也可以將以上兩步操作合并為一步
$ gcc -fPIC -shared testlib.c -o libtest.so3.4 動態鏈接庫的使用
$ gcc demo.c -o demo -ltest -L. ? ? // testlib.a庫在鏈接時使用-ltest由于動態鏈接庫是在程序加載執行時進行鏈接,所以在系統加載可執行程序時,需要庫文件的名字和絕對路徑,還需要系統提供的動態加載器;對于ELF格式的可執行文件,動態加載器是ld-linux.so*,它會先后搜索ELF文件中DT_RPATH段、環境變量LD_LIBRARY_PATH、/etc/ld.so.cache文件列表、/lib/,/usr/lib目錄,找到鏈接庫文件后將其加載到內存;
在程序執行時需要能夠找到鏈接庫文件:
1) 將庫文件安裝到/lib或/usr/lib目錄下;
2) 如果庫文件安裝在其他目錄,需要將路徑添加到/etc/ld.so.cache文件中,添加步驟如下:
a) 編輯/etc/ld.so.conf文件,加入庫文件所在目錄的路徑;
b) 運行ldconfig,重建/etc/ld.so.cache文件;
4. 總結
在網上看到有的文章中把程序和庫文件的靜態和動態鏈接方式,比作書本和筆記的關聯方式;
把書本上的內容比作程序,把參考書或者黑板上的筆記比作是要鏈接的目標;
靜態鏈接,就像是把筆記抄寫到書本上,或者抄寫到活頁上,粘貼到書本上,將筆記和書本合為一個整體;這樣即使忘了帶參考書,或者黑板上的筆記被擦掉,都不會影響,因為筆記和書本已經融合了;
優點是,效率更高了,看書方便多了;缺點是書本越來越厚;
動態鏈接,就像是在書本中標記筆記的位置注釋,如:該部分參考什么什么書,第幾頁等信息,把筆記和書本分離稱互相獨立的個體,將筆記單獨整理稱庫文件;在閱讀到注釋的地方,需要翻看筆記時才按照注釋索引,查找筆記中對應的內容;動態鏈接的方式,需要書本和筆記同時在手,才能正常閱讀;
優點是,不影響書本的空間;缺點是,查找筆記的效率比較低;
參考資料
《程序員的自我修養----鏈接、裝載與庫》
靜態鏈接與動態鏈接的區別和使用
深入淺出靜態鏈接和動態鏈接
回到目錄
總結
以上是生活随笔為你收集整理的静态库调用_静态链接和动态链接对比简析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对齐方式有那些_字节对齐不慎引发的挂死问
- 下一篇: 怎么把两个盒子显示在同一行_1个机顶盒2