熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Oracle >> 正文

Linux 動態函式庫解析(二)

2013-11-13 15:29:12  來源: Oracle 

  動態連結 VS 靜態聯結
  
    在 Linux 中執行檔我們可以編程成靜態聯結以及動態連結以下我們舉一個簡短的程序作為例子:
  
  #include
  int main()
  {
  printf( test);
  }
  
    若我們執行 :
  
  [root@hlchou /root]# gcc testc o test
  
    所產生出來的執行檔 test預設為使用動態函式庫所以我們可以用以下的指令 :
  
  [root@hlchou /root]# ldd test
  libcso => /lib/libcso (x)
  /lib/ldlinuxso => /lib/ldlinuxso (x)
  
    來得知目前該執行檔共用了哪些動態函式庫以我們所舉的 test 執行檔來說共用了兩個動態函式庫分別為 libcso 與 ldlinuxso我們還可以透過下面的 file 指令來得知該執行檔的相關屬性如下
  
  [root@hlchou /root]# file test
  test: ELF bit LSB executable Intel version dynamically
  linked (use s shared libs) not stripped
  
    not stripped 表示這個執行檔還沒有透過 strip 指令來把執行時用不到的符號以及相關除錯的資訊刪除舉個例子來說目前這個test 執行檔大小約為 bytes
  
  [root@hlchou /root]# ls l test
  rwxrxrx root root Oct : test
  
    經過strip後則變為 bytes
  
  [root@hlchou /root]# strip test
  [root@hlchou /root]# ls l test
  rwxrxrx root root Oct : test
  
    不過讀者必須注意到一點經過 strip 過的執行檔就無法透過其它的除錯軟件從裡面取得函式在編程時所附的相關資訊這些資訊對我們在除錯軟件時可以提供不少的幫助各位在應用上請自行注意
  
    相對於編程出來使用動態函式庫的執行檔 test我們也可以做出靜態聯結的執行檔 test
  
  [root@hlchou /root]# gcc static testc o test
  
    透過指令 ldd我們可以確定執行檔 test 並沒有使用到動態函式庫
  
  [root@hlchou /root]# ldd test
  not a dynamic executable
  
    再透過指令 file可以注意到 test 目前為 statically linked且亦尚未經過 strip
  
  [root@hlchou /root]# file test
  test: ELF bit LSB executable Intel version statically
  linked not stripped
  
    相信大夥都會好奇使用靜態聯結且又沒有經過 strip 刪去不必要的符號的執行檔的大小會是多少透過 ls l來看我們發現大小變成 bytes 比起靜態聯結的執行檔大了相當多
  
  [root@hlchou /root]# ls l test
  rwxrxrx root root Oct : test
  
    若再經過 strip則檔案大小變為 bytes
  
  [root@hlchou /root]# strip test
  [root@hlchou /root]# ls l test
  rwxrxrx root root Oct : test
  
    與使用動態函式庫的執行檔 test 比較起來大了約 倍 (/)因此整體來說在使用的環境中使用動態函式庫並且經過 strip 處理的話可以讓整體的空間較為精簡許多執行檔都會用到同一組的函式庫像 libc 中的函式是每個執行檔都會使用到的若是使用動態函式庫則可以盡量減少同樣的函式庫內容重復存在系統中進而達到節省空間的目的
  
    筆者一年前曾寫過一個可以用來刪去動態函式庫中不必要函式的工具針對這個只用到了 printf 的程序來產生新的 libcso 的話我們可以得到一個精簡過的 libcso 大小約為 bytes
  
  [root@hlchoua lib]# ls l libcso*
  rwxrxrx root root Nov : libcso
  lrwxrwxrwx root root Nov : libcso > libcso
  
    與靜態聯結的執行檔大小 bytes 比較起來若是在這個環境中使用了動態函式庫的話成本約為 + = bytes不過這是只有一個執行檔的情況下使用動態函式庫的環境會小輸給使用靜態聯結的環境在一個基本的 Linux 環境中如果大量的使用動態函式庫的話像是有 個以上的執行檔的話那用動態函式庫的成本就大大的降低了像如果兩個執行檔都只用到了 printf那靜態聯結的成本為 * = bytes而使用動態函式庫的成本為 * + = bytes兩者相差約一倍
  
    很明顯的我們可以看到動態函式庫在 Linux 環境中所發揮的妙用它大幅的降低了整體環境的持有成本提高了環境空間的利用率
  
    ldlinuxso 在 RedHat 我們可以在 /lib 或是 /usr/lib 目錄底下找到許多系統上所安裝的動態函式庫在文章的這個部分筆者將把整個函式庫大略的架構作一個說明
  
    其實 Linux 跟 Windows 一樣提供了一組很基本的動態函式庫在 Windows 上面我們知道 kerneldll 提供了其它動態函式庫基本的函式呼叫而在 Linux 上面則透過 ldlinuxso 提供了其它動態函式庫基本的函式在筆者電腦的 RedHatldlinuxso 是透過 link 到 ldso(這部分需視各人所使用的 glibc 版本不同而定)
  
  rwxrxrx root root Jan : ldso
  lrwxrwxrwx root root Jan : ldlinuxso > ldso
  
    ldlinuxso 是屬於 Glibc (GNU C Library) 套件的一部分只要是使用 Glibc 動態函式庫的環境就可以見到 ldlinuxso 的蹤影
  
    接下來我們透過指令 ldd 來驗證出各個函式庫間的階層關系首先如下圖我們執行了 ldd lsldd pwdldd vi可以看出各個執行檔呼叫了哪些動態函式庫像執行檔 ls 呼叫了 /lib/libcso (x)與 /lib/ldlinuxso (x)而括號內的數字為該函式庫載入記憶體的位置在本文的稍後會介紹到函式庫載入時的細節到時讀者會有更深入的了解
  
    其實我們不難發現在 Linux 上使用動態函式庫的執行檔幾乎都會去呼叫 libcso 與 ldlinuxso 這兩個動態函式庫筆者過去修改 Glibc 的套件時也了解到在 Linux 中函式庫的關系ldlinuxso 算是最底層的動態函式庫它本身為靜態聯結主要的工作是提供基本的函式給其他的函式庫而我們最常會呼叫的 libcso 則是以 ldlinuxso 為基礎的一個架構完成的動態函式庫它幾乎負責了所有我們常用的標准 C 函式庫像是我們在 Linux 下寫的 Socket 程序其中的connect()bind()send() 之類的函式都是由 libcso 所提供的
  
    也因此libcso 的大小也是相當可觀的在 RedHat 中經過 strip 後大小約為 bytes
  
  [root@hlchoua /root]# ldd /bin/ls
  libcso => /lib/libcso (x)
  /lib/ldlinuxso => /lib/ldlinuxso (x)
  [root@hlchoua /root]# ldd /bin/pwd
  libcso => /lib/libcso (x)
  /lib/ldlinuxso => /lib/ldlinuxso (x)
  [root@hlchoua /root]# ldd /bin/vi
  libtermcapso => /lib/libtermcapso (x)
  libcso => /lib/libcso (xb)
  /lib/ldlinuxso => /lib/ldlinuxso (x)
  
    如下我們透過 ldd 驗證 vi 所用到的動態函式庫 /lib/libtermcapso它本身是呼叫了 libcso 的函式所組成的
  
  [root@hlchoua /root]# ldd /lib/libtermcapso
  libcso => /lib/libcso (x)
  /lib/ldlinuxso => /lib/ldlinuxso (x)
  
    接下來我們依序測試了 /lib/libcso 與 /lib/ldlinuxso
  
  [root@hlchoua /root]# ldd /lib/libcso
  /lib/ldlinuxso => /lib/ldlinuxso (x)
  [root@hlchoua /root]# ldd /lib/ldlinuxso
  statically linked
  
    我們可以整理以上的結論畫成如下的一個架構圖
  
      
    在這個圖中我們可以清楚的明白 ldlinuxso 負責了最基礎的函式而 libcso 再根據這些基本的函式架構了完整的 C 函式庫供其它的動態函式庫或是應用程序來呼叫
  
    透過筆者所寫的一個 ELF 工具程序(注二)我們也可以清楚的看到 libcso呼叫了 ldlinuxso 哪些函式
  
  [root@hlchoua /root]# /Ielf /lib/libcso|more
  ========================================================
  open_target_file:/lib/libcso
  ==>ldlinuxso
  __register_frame_table
  cfsetispeed
  xdr_int_t
  utmpname
  _dl_global_scope_alloc
  __strcasestr
  hdestroy_r
  rename
  __iswctype_l
  __sigaddset
  xdr_callmsg
  pthread_setcancelstate
  xdr_union
  __wcstoul_internal
  setttyent
  strrchr
  __sysv_signal ┅(more)
  

From:http://tw.wingwit.com/Article/program/Oracle/201311/16795.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.