歡迎您光臨本站 註冊首頁

Linux下的動態共享鏈接庫的分析與使用

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

  動態共享庫的工作方式與靜態鏈接庫不同.對於每個使用靜態鏈接庫的應用程序而言,在應用程序中都存在著靜態鏈接庫拷貝.但是動態共享庫卻不是這樣的,動態共享庫是被所有使用它的應用程序共享的,無論調用一個動態共享庫的進程有多少,系統中始終只運行著一個動態共享庫,這裡動態共享庫中「共享」的含義.至於「動態」,則主要強調的是鏈接發生在什麼階段.對於靜態鏈接庫而言,鏈接過程發生在編譯階段,操作系統在載入程序時不再對程序做任何改變,因此「靜態」鏈接;然而對於使用動態共享庫的程序而言,編譯器在編譯程序時只知道程序

  將要使用到某個動態共享庫中的某個符號.至於這個符號所對應的具體實體,在編譯時則是未知的.從符號轉換為實體的工作留給了操作系統在載入程序時支完成.這樣一個轉換過程實質上就是把程序的鏈接過程推遲到了程序執行時來完成.這與在編譯期間完成鏈接雷管顯然是不一樣的.這也是動態共享庫被冠以「動態」的原因.

  動態共享庫有以下的優點,使它在Linux開發中比靜態鏈接庫更加的流行.

  (1) 節省內存

  動態共享庫無論被多少應用程序使用,在內存中都只存在一個動態共享庫的副本,而不像靜態鏈接庫那樣,一個應用程序在運行中用到靜態鏈

  接庫,就會有多個靜態鏈接庫的副本 .

  (2) 節省磁碟

  這和節省內存有點相似,同樣這也是由於靜態鏈接庫存在多個靜態鏈接庫的副本造成的.同樣的應用程序,使用動態共享庫編譯出的版本通常比使用靜態鏈接庫編譯出來的版本要小.因此,在嵌入式系統開發中使用動態共享庫也不節省空間,提供了一種很好的選擇.

  (3) 便於軟體修復與升級

  由於動態共享是獨立於應用程序存在的,因此,用新版本的動態共享庫替舊版本的工作將變得非常容易.如果使用靜態鏈接庫的話,假設在一個靜態庫中發現了一個bug,那麼要修正這個bug的話,就要重新編譯所有使用這個靜態庫的應用程序,使用這個靜態庫的應用程序有很多的話,可以想像工作量是有多大.

  (4) 提高性能

  與採用靜態鏈接庫臃腫的應用程序相比,採用動態共享庫的應用程序明顯「苗條」得多,這樣當操作系統載入應用程序時,是需要把應用程序

  複製到內存中的,這樣的「苗條」的動態鏈接庫也就有了很大的優勢,同時提高了程序的性能.

  當然,動態鏈接庫在有上述這些優勢的同時,也有以下的幾個劣勢.複雜性,兼容性,調試困難.但是它在Linux上使用頻率上仍然比靜態鏈接庫要高的多.應用的更加廣泛.

  動態共享庫的重要概念-----soname

  動態共享庫有一個重要的概念---soname.動態共享庫在Linux系統上是以文件的形式存在的,這樣,每個動態共享庫也就有一個文件名,假設把動態共享庫的文件名定義為filename.那麼必須牢記一件事性就是soname和filename不是一個概念的.在Linux下,每個動態共享庫都必須被賦予一個按特定的名稱,Linux的文檔將其稱之為soname.soname通常包含共享庫的名字和版本號,通過soname,系統或鏈接器可以唯一地確定一個動態共享庫.比如Linux的C函數庫的soname是libc.so.6,這裡,c是函數庫的名字,6是該動態共享庫的版本號.

  然而,應用程序並不是直接和名字為soname的文件相鏈接的.比如,對於Linux C庫而言,儘管通常在系統中能夠找到名為libc.so.6的文件,但這個文件實際上卻只是一個軟連接也就是符號鏈接.這裡清楚地顯示出libc.so.6是一個到libc-2.3.2.so的軟連接.那麼,這個軟連接是由ldconfig建立的.ldconfig做的事情就是配置動態鏈接器的運行時綁定.對於一個編譯好的動態鏈接庫,如何知道它的soname是什麼呢?可以使用readelf.readelf有一個選項-d,這個選項可以列印出ELF文件中dynameic段的內容.在ELF中的dynamic段中就包含著動態共享庫的soname.在Linux系統中存在著一個文件 /etc/ld.so.conf.這個文件中的每一行指定了ldconfig應當搜索的目錄,在這些目錄下面存放著系統運行中所需要的動態共享庫文件,以.so.x.x結尾的文件;ldconfig依次搜索這些目錄,為找到的每個動態共享庫文件建立一個到共soname的軟鏈接.

  動態共享庫的構建和安裝

  在為動態共享庫編譯目標文件時,GCC編譯器的下面這些選項是需要的:

  -share:這個選項告訴GCC生成共享目標文件.生成的共享目標文件可以與其他目標文件鏈接在一起構成一個可自執行文件,此選項必須和-fPIC等選項聯合使用.

  -fPIC:這個選項告訴GCC生成位置無關代碼(Position-Independent Code,PIC)在共享庫中應當使用位置無關代碼.

  -Wl,-soname,xxx:這是一個特殊的GCC選項.通過該選項,GCC會把-soname,xxx作為一個命令行選項傳遞給鏈接器ld,ld拿這個選項來做什麼呢?在每個動態共享庫的dynamic段都有一個soname項.-soname,xxx選項的作用就是告訴鏈接器ld,將要鏈接產生的文件是一個動態共享庫,它的soname是xxx.比如,如果編譯版本號為6的Linux C庫,就應當在生成libc-2.3.2.so時給GCC指定鏈接選項-Wl,-soname,libc.so.6.

  構建動態共享庫的一個步驟通常是下面的一個命令行:

  gcc -share -Wl,soname,xxx -o libname filelist liblist

  在這個命令行中,libname表示最終產生的動態共享庫文件名.比如libc-2.3.2.so.filelist是一組目標文件列表,它表明了哪些編譯好的目標文件將放到最終產生的動態共享庫裡面去.由於動態共享庫可以依賴於其他共享庫,因此這一項指定了最終產生的動態共享庫將依賴的那些共享庫的列表.

  動態共享庫在構建完成之後,如果需要安裝到特定和系統目錄下(如最常見的/usr/local/lib目錄),只需要將動態共享庫文件複製到相應的目錄下即可.然後運行ldconfig建立以soname命名的軟連接,前提是共享庫所在的目錄包含在/etc/ld.so.conf文件中,此外 ,為了讓鏈接器能夠以標準的方式與動態共享庫鏈接,還需要創建一個不帶版本號的軟連接.我們可以看到在Linxu系統下的lib目錄下有很多的的.so.XX 的文件,這就是系統中使用到的動態共享庫

  其中我們可以看到libc.so.6.這個是linux下的C函數庫文件.我們可以看到這是一個符號鏈接,真正的文件是libc-2.10.2.so.

  #lib$ ls -l libc.so.6

  lrwxrwxrwx 1 root root 14 2009-12-09 20:59 libc.so.6 -> libc-2.10.1.so

  #lib$ readelf -d libc-2.10.1.so

  Dynamic section at offset 0x168b40 contains 26 entries:

  Tag Type Name/Value

  0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]

  0x000000000000000e (SONAME) Library soname: [libc.so.6]

  0x000000000000000c (INIT) 0x1e7b0

  0x000000000000001a (FINI_ARRAY) 0x365740

  0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)

  0x0000000000000004 (HASH) 0x1620d8

  0x000000006ffffef5 (GNU_HASH) 0x2b8

  0x0000000000000005 (STRTAB) 0x10560

  0x0000000000000006 (SYMTAB) 0x3c00

  0x000000000000000a (STRSZ) 21963 (bytes)

  0x000000000000000b (SYMENT) 24 (bytes)

  0x0000000000000003 (PLTGOT) 0x368fe8

  0x0000000000000002 (PLTRELSZ) 192 (bytes)

  0x0000000000000014 (PLTREL) RELA

  0x0000000000000017 (JMPREL) 0x1e5d8

  0x0000000000000007 (RELA) 0x16e38

  0x0000000000000008 (RELASZ) 30624 (bytes)

  0x0000000000000009 (RELAENT) 24 (bytes)

  0x000000006ffffffc (VERDEF) 0x16bf8

  0x000000006ffffffd (VERDEFNUM) 15

  0x000000000000001e (FLAGS) STATIC_TLS

  0x000000006ffffffe (VERNEED) 0x16e08

  0x000000006fffffff (VERNEEDNUM) 1

  0x000000006ffffff0 (VERSYM) 0x15b2c

  0x000000006ffffff9 (RELACOUNT) 1190

  0x0000000000000000 (NULL) 0x0

  下面以foo.c和bar.c 文件為例:如何構建動態共享庫

  #:~/program$ gcc -fPIC -g -c -o foo.o foo.c

  #~/program$ gcc -fPIC -g -c -o bar.o bar.c

  #:~/program$ gcc -shared -g -Wl,-soname,libfoobar.so.0 -o libfoobar.so.0.0 foo.o bar.o -lc

  #:~/program$ sudo cp libfoobar.so.0.0 /usr/local/lib

  #:~/program$ sudo ldconfig

  #:~/program$ cd /usr/local/lib

  #:/usr/local/lib$ ls

  libfoobar.so.0 libfoobar.so.0.0 python2.6

  #:/usr/local/lib$ ln -sf libfoobar.so.0 libfoobar.so

  ln: creating symbolic link `libfoobar.so': Permission denied

  #:/usr/local/lib$ sudo ln -sf libfoobar.so.0 libfoobar.so

  #:/usr/local/lib$

  #:~/program$ gcc -g -o foobar main.c -lfoobar

  #:~/program$ ./foobar

  This is foo!library2 is

  foo()=foo

  This is library1 is called

  bar()=bar

  這裡的共享庫的soname指定為libfoobar.so.0,最終生成的動態共享庫文件為libfoobar.so.0.0,foo.o和bar.o是要放到libfoobar.so.0-.0中的目標文件列表,-lc則是libfoobar.so.0.0所依賴的共享庫列表,這裡只有一個Linux C庫被依賴.接著把libfoobar.so.0.0安裝到/usr/local/lib目錄上去,然後運行ldconfig,同時為了讓鏈接器能夠鏈接上libfoobar.so.0.0,還要創建一個指向libfoorbar.so.0和符號連接.

  這裡簡要的分析了一下Linux動態共享庫的使用,為以後自己的使用做個記錄.


[火星人 ] Linux下的動態共享鏈接庫的分析與使用已經有553次圍觀

http://coctec.com/docs/linux/show-post-51133.html