天天看點

Linux靜态庫和動态庫的分析及實作

1.什麼是庫

  在windows平台和linux平台下都大量存在着庫。

  由于windows和linux的本質不同,是以二者庫的二進制是不相容的。

  本文僅限于介紹linux下的庫。

  2.庫的種類

  linux下的庫有兩種:靜态庫和共享庫(動态庫)。

  二者的不同點在于代碼被載入的時刻不同。

  靜态庫的代碼在編譯過程中已經被載入可執行程式,是以體積較大。

  共享庫的代碼是在可執行程式運作時才載入記憶體的,在編譯過程中僅簡單的引用,是以代碼體積較小。

  3.庫存在的意義

  庫是别人寫好的現有的,成熟的,可以複用的代碼,你可以使用但要記得遵守許可協定。

  現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,是以庫的存在意義非同尋常。

  共享庫的好處是,不同的應用程式如果調用相同的庫,那麼在記憶體裡隻需要有一份該共享庫的執行個體。

  4.庫檔案是如何産生的

  在linux下,靜态庫的字尾是.a,它的産生分兩步:

  step 1.由源檔案編譯生成一堆.o,每個.o裡都包含這個編譯單元的符号表。

  step 2.ar指令将很多.o轉換成.a,成為靜态庫。

  動态庫的字尾是.so,它由gcc加特定參數編譯産生。

  例如:

  $ gcc -fpic -c *.c

  $ gcc -shared -wl,-soname, libfoo.so.1 -o libfoo.so.1.0 *.

  5.庫檔案是如何命名的,有沒有什麼規範

  在linux下,庫檔案一般放在/usr/lib 下,

  靜态庫的名字一般為libxxxx.a,其中xxxx是該lib的名稱

  動态庫的名字一般為libxxxx.so.major.minor,xxxx是該lib的名稱,major是主版本号,minor是副版本号。

  6.如何知道一個可執行程式依賴哪些庫

  ldd指令可以檢視一個可執行程式依賴的共享庫,

  例如# ldd /bin/lnlibc.so.6

  => /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2

  => /lib/ld- linux.so.2 (0×40000000)

  可以看到ln指令依賴于libc庫和ld-linux庫

  7.可執行程式在執行的時候如何定位共享庫檔案

  當系統加載可執行代碼時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑

  此時就需要系統動态載入器(dynamic linker/loader)。

  對于elf格式的可執行程式,是由ld-linux.so*來完成的,它先後搜尋elf檔案的 dt_rpath段—環境變量ld_library_path—/etc/ld.so.cache檔案清單—/lib/,/usr/lib目錄找到庫檔案後将其載入記憶體。第5步:由.o檔案建立動态庫檔案

  動态庫檔案名命名規範和靜态庫檔案名命名規範類似,也是在動态庫名增加字首lib,但其檔案擴充名為.so。例如:我們将建立的動态庫名為myhello,則動态庫檔案名就是libmyhello.so。用gcc來建立動态庫。

  在系統提示符下鍵入以下指令得到動态庫檔案libmyhello.so。

  # gcc -shared -fpci -o libmyhello.so hello.o

  #

  我們照樣使用ls指令看看動态庫檔案是否生成。

  # ls

  hello.c hello.h hello.o libmyhello.so main.c

  第6步:在程式中使用動态庫

  在程式中使用動态庫和使用靜态庫完全一樣,也是在使用到這些公用函數的源程式中包含這些公用函數的原型聲明,然後在用gcc指令生成目标檔案時指明動态庫名進行編譯。我們先運作gcc指令生成目标檔案,再運作它看看結果。

  # gcc -o hello main.c -l. -l myhello

  # ./hello

  ./hello: error while loading shared libraries: libmyhello.so: cannot open shared object

  file: no such file or directory

  哦!出錯了。快看看錯誤提示,原來是找不到動态庫檔案libmyhello.so。程式在運作時,會在/usr/lib和/lib等目錄中查找需要的動态庫檔案。若找到,則載入動态庫,否則将提示類似上述錯誤而終止程式運作。我們将檔案libmyhello.so複制到目錄/usr/lib中,再試試。

  # mv libmyhello.so /usr/lib

  ./hello: error while loading shared libraries: /usr/lib/libhello.so: cannot restore segment

  prot after reloc: permission denied

  由于selinux引起,

  # chcon -t texrel_shlib_t /usr/lib/libhello.so

  hello everyone!

  成功了。這也進一步說明了動态庫在程式運作時是需要的。

  我們回過頭看看,發現使用靜态庫和使用動态庫編譯成目标程式使用的gcc指令完全一樣,那當靜态庫和動态庫同名時,gcc指令會使用哪個庫檔案呢?抱着對問題必究到底的心情,來試試看。

  先删除 除.c和.h外的 所有檔案,恢複成我們剛剛編輯完舉例程式狀态。

  # rm -f hello hello.o /usr/lib/libmyhello.so

  hello.c hello.h main.c

  在來建立靜态庫檔案libmyhello.a和動态庫檔案libmyhello.so。

  # gcc -c hello.c

  # ar cr libmyhello.a hello.o

  hello.c hello.h hello.o libmyhello.a libmyhello.so main.c

  通過上述最後一條ls指令,可以發現靜态庫檔案libmyhello.a和動态庫檔案libmyhello.so都已經生成,并都在目前目錄中。然後,我們運作gcc指令來使用函數庫myhello生成目标檔案hello,并運作程式hello。

  # gcc -o hello main.c -l. -lmyhello

  從程式hello運作的結果中很容易知道,當靜态庫和動态庫同名時, gcc指令将優先使用動态庫。

最新内容請見作者的github頁:http://qaseven.github.io/

繼續閱讀