linux下so動態庫一些鮮爲人知的祕密(上)

  linux 下有動態庫和靜態庫,動態庫以.so爲擴展名,靜態庫以.a爲擴展名。兩者都使用普遍。本文主要講動態庫方面知識。linux

   

   基本上每個linux 程序都至少會有一個動態庫,查看某個程序使用了那些動態庫,使用ldd命令查看 ios

  1. # ldd /bin/ls
    c++

  2. linux-vdso.so.=> (0x00007fff597ff000)
    spa

  3. libselinux.so.=> /lib64/libselinux.so.(0x00000036c2e00000)
    線程

  4. librt.so.=> /lib64/librt.so.(0x00000036c2200000)
    code

  5. libcap.so.=> /lib64/libcap.so.(0x00000036c4a00000)
    對象

  6. libacl.so.=> /lib64/libacl.so.(0x00000036d0600000)
    進程

  7. libc.so.=> /lib64/libc.so.(0x00000036c1200000)
    ci

  8. libdl.so.=> /lib64/libdl.so.(0x00000036c1600000)
    資源

  9. /lib64/ld-linux-x86-64.so.(0x00000036c0e00000)

  10. libpthread.so.=> /lib64/libpthread.so.(0x00000036c1a00000)

  11. libattr.so.=> /lib64/libattr.so.(0x00000036cf600000)

   這麼多so,是的。使用ldd顯示的so,並非全部so都是須要使用的,下面舉個例子

main.cpp

  1. #include <stdio.h>
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main ()
    {
       cout << "test" << endl;
       return 0;
    }

   使用缺省參數編譯結果

  1. # g++ -o demo main.cpp

  2. # ldd demo

  3.     linux-vdso.so.=> (0x00007fffcd1ff000)

  4.         libstdc++.so.=> /usr/lib64/libstdc++.so.(0x00007f4d02f69000)

  5.         libm.so.=> /lib64/libm.so.(0x00000036c1e00000)

  6.         libgcc_s.so.=> /lib64/libgcc_s.so.(0x00000036c7e00000)

  7.         libc.so.=> /lib64/libc.so.(0x00000036c1200000)

  8.         /lib64/ld-linux-x86-64.so.(0x00000036c0e00000)

   若是我連接一些so,可是程序並不用到這些so,又是什麼狀況呢,下面我加入連接壓縮庫,數學庫,線程庫

  1. # g++ -o demo -lz -lm -lrt main.cpp

  2. # ldd demo

  3.         linux-vdso.so.=> (0x00007fff0f7fc000)

  4.         libz.so.1 => /lib64/libz.so.1 (0x00000036c2600000)

  5.         librt.so.1 => /lib64/librt.so.1 (0x00000036c2200000)

  6.         libstdc++.so.=> /usr/lib64/libstdc++.so.(0x00007ff6ab70d000)

  7.         libm.so.6 => /lib64/libm.so.6 (0x00000036c1e00000)

  8.         libgcc_s.so.=> /lib64/libgcc_s.so.(0x00000036c7e00000)

  9.         libc.so.=> /lib64/libc.so.(0x00000036c1200000)

  10.         libpthread.so.=> /lib64/libpthread.so.(0x00000036c1a00000)

  11.         /lib64/ld-linux-x86-64.so.(0x00000036c0e00000)

  看看,雖然沒有用到,可是同樣有連接進來,那看看程序啓動時候有沒有去加載它們呢

  1. # strace ./demo

  2.     execve("./demo", ["./demo"], [/* 30 vars */]) = 0

  3.     ... = 0

  4.     open("/lib64/libz.so.1", O_RDONLY) = 3

  5.     ...

  6.     close(3) = 0

  7.     open("/lib64/librt.so.1", O_RDONLY) = 3

  8.     ...

  9.     close(3) = 0

  10.     open("/usr/lib64/libstdc++.so.6", O_RDONLY) = 3

  11.     ...

  12.     close(3) = 0

  13.     open("/lib64/libm.so.6", O_RDONLY) = 3

  14.     ...

  15.     close(3) = 0

  16.     open("/lib64/libgcc_s.so.1", O_RDONLY) = 3

  17.     ...

  18.     close(3) = 0

  19.     open("/lib64/libc.so.6", O_RDONLY) = 3

  20.     ...

  21.     close(3) = 0

  22.     open("/lib64/libpthread.so.0", O_RDONLY) = 3

  23.     ...

  24.     close(3) = 0

  25.     ...

  看,有加載,因此一定會影響進程啓動速度,因此咱們最後不要把無用的so編譯進來,這裏會有什麼影響呢?

   你們知不知道linux從程序(program或對象)變成進程(process或進程),要通過哪些步驟呢,這裏若是詳細的說,估計要另開一篇文章。簡單的說分三步:

    一、fork進程,在內核建立進程相關內核項,加載進程可執行文件;

    二、查找依賴的so,一一加載映射虛擬地址

    三、初始化程序變量。

  能夠看到,第二步中dll依賴越多,進程啓動越慢,而且發佈程序的時候,這些連接但沒有使用的so,一樣要一塊兒跟着發佈,不然進程啓動時候,會失敗,找不到對應的so。因此咱們不能像上面那樣,把一些毫無心義的so連接進來,浪費資源。可是開發人員寫makefile 通常有沒有那麼細心,圖省事方便,那麼有什麼好的辦法呢。繼續看下去,下面會給你解決方法。

  先使用 ldd -u demo 查看不須要連接的so,看下面,一面瞭然,無用的so所有暴露出來了吧

  1. # ldd -u demo

  2. Unused direct dependencies:

  3.         /lib64/libz.so.1

  4.         /lib64/librt.so.1

  5.         /lib64/libm.so.6

  6.         /lib64/libgcc_s.so.1

  使用 -Wl,--as-needed 編譯選項

  1. # g++ -Wl,--as-needed -o demo -lz -lm -lrt main.cpp

  2. # ldd demo

  3.         linux-vdso.so.=> (0x00007fffebfff000)

  4.         libstdc++.so.=> /usr/lib64/libstdc++.so.(0x00007ff665c05000)

  5.         libc.so.=> /lib64/libc.so.(0x00000036c1200000)

  6.         libm.so.=> /lib64/libm.so.(0x00000036c1e00000)

  7.         /lib64/ld-linux-x86-64.so.(0x00000036c0e00000)

  8.         libgcc_s.so.=> /lib64/libgcc_s.so.(0x00000036c7e00000)

  9. # ldd -u demo

  10. Unused direct dependencies:


  呵呵,辦法很簡單省事吧,本文主要講so依賴的一些問題,下一篇將介紹so的路徑方面一些鮮爲人知的小祕密

相關文章
相關標籤/搜索