LINUX動態庫檔案 soname realname linkname 詳解

gaopengtttt發表於2016-06-14
先明白動態庫檔案的3個名字
soname  :透過gcc/g++ -soname,libtest2.so.1 設定他是程式中連線檔案的時候找的檔案,本身為一個連線,他包含大版本,如果任何小版本的變化,直接替換到
          realname,然後ln -s 建立同樣的soname 到新的realname檔案即可,不需要重新編譯程式。
realname:是動態庫檔案的真實的名字及-o libtest2.so.1.1 生成的,sonanme 軟連線指向它,雖然程式連線的時候找到的soname但是透過連線找到實際的
          realname,他包含大版本和小版本。
linkname:這個可有可無,但是如果要,他不包含版本資訊,在g++的時候應該使用這個名字,避免版本改動重新編譯makefile,如果哪天大版本也發生了變化
          使用linkname是版本無關的任然能夠編譯透過。我們只需要重新建立linkname的指向到新版本即可
比如:
libtest2.so.1.1 為realname
libtest2.so.1   為soname
libtest2.so     為linkname
編譯或者使用makefile的時候應該儘量使用linkname,而不是使用realname

g++ main.cpp libtest2.so 

1、生成目標檔案,二進位制機器碼未連線,使用-c,-g為可以除錯
 g++ -fPIC -c -g t2.cpp {可以多個}   
 生成.o的機器碼檔案沒有連線 -fPIC程式碼位置無關
2、生成動態庫檔案
 g++ -shared -Wl,-soname,libtest2.so.1 -o libtest2.so.1.1 t2.o {可以多個}
 生成soname為libtest2.so.1真實名字為libtest2.so.1.1的動態庫檔案檔名字為relname
 1.1為主版本和發行版
 readelf -d libtest2.so.1.1
 可以檢視soname和relname
3、生成soname軟連線
 /etc/ld.so.conf 加入一行 /home/gaopeng/CPLUSPLUS/part9
 執行ldconfig自動生成soname
 同時搜尋庫檔案檔案也會搜尋/etc/ld.so.conf的新配置的目錄下的soname
 
 或者指定目錄生成soname
 ldconfig -n /home/gaopeng/CPLUSPLUS/part9
 生成連線連線實際上就是soname指向realname
 或者
 也可以使用ln -s 來建立soname
 ln -s /home/gaopeng/CPLUSPLUS/part9/libfu.so.1.1 /home/gaopeng/CPLUSPLUS/part9/libfu.so.1
 後兩種方式需要修改
 LD_LIBRARY_PATH環境變數指向這個目錄/home/gaopeng/CPLUSPLUS/part9/
 因為預設不會再自定義的目錄下面早除非指定了
 /etc/ld.so.conf並且ldconfig生效了
4、
 g++ main.cpp libtest2.so.1.1 不推薦這種方式應該使用linkname見下面
5、
ldd a.out
檢視程式需要的庫檔案,這裡表示出來的是soname位置,而不是rename或者linkname
程式動態連線實際上如果有soname就會找到soname

建立linkname
如 lns -s  libtest2.so.1.1 libtest2.so
這裡的libtest2.so 就是一個link name
那麼我們編譯的時候
就是
g++ main.cpp libtest2.so 代替掉第四步

使用者的soname和realname檔案及linkname檔案全部放到 /usr/lib下,這種情況下只要有soname正確的指向了,就
不需要修改,當然也可以隨意
這裡使用soname放到/usr/lib下其他放到當前目錄
當前realname檔案在目錄/home/gaopeng/CPLUSPLUS/part9/
生成soname,使用ln -s方法
sudo ln -s /home/gaopeng/CPLUSPLUS/part9/libfu.so.1.1 /usr/lib/libfu.so.1
sudo ln -s /home/gaopeng/CPLUSPLUS/part9/libfu2.so.1.10 /usr/lib/libfu2.so.1
生成linkname,使用ln -s
gaopeng@bogon:~/CPLUSPLUS/part9$ ln -s libfu.so.1.1 libfu.so
gaopeng@bogon:~/CPLUSPLUS/part9$ ln -s  libfu2.so.1.10 libfu2.so
gaopeng@bogon:~/CPLUSPLUS/part9$ g++ main.cpp libfu.so libfu2.so 
gaopeng@bogon:~/CPLUSPLUS/part9$ ldd a.out 
        linux-vdso.so.1 =>  (0x00007ffccb799000)
        libfu.so.1 => /usr/lib/libfu.so.1 (0x00007f1be882e000)
        libfu2.so.1 => /usr/lib/libfu2.so.1 (0x00007f1be862c000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f1be8328000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1be7f63000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1be7c5d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1be8a31000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1be7a47000)

如果mv任何一個realname檔案出錯
gaopeng@bogon:~/CPLUSPLUS/part9$ mv libfu.so.1.1 libfu.so.1.1bak
gaopeng@bogon:~/CPLUSPLUS/part9$ ./a.out 
./a.out: error while loading shared libraries: libfu.so.1: cannot open shared object file: No such file or directory
gaopeng@bogon:~/CPLUSPLUS/part9$ ldd a.out 
        linux-vdso.so.1 =>  (0x00007ffcedde5000)
        libfu.so.1 => not found                   ---這裡soname就找不到了
        libfu2.so.1 => /usr/lib/libfu2.so.1 (0x00007fd86e4f1000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd86e1ed000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd86de28000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd86db22000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd86e6f3000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd86d90c000)
        
當然soname也可以放到任何目錄,如我隨意放了一個目錄為
/home/gaopeng/CPLUSPLUS/part9/lib

realname檔案在
/home/gaopeng/CPLUSPLUS/part9
那麼顯然在/usr/lib下找不到這個soname,那麼我們需要做的就是
export LD_LIBRARY_PATH=/home/gaopeng/CPLUSPLUS/part9/lib
讓g++程式能夠找到這個soname,或者修改/etc/ld.so.conf並且ldconfig生效了


但是一般情況下linkname soname realname都在同一個目錄下,這裡只是想說明
程式執行的時候要找的只是soname的位置,而soname指向了realname
        
最後 
 g++ t2.cpp -fPIC -shared -o libtest2.so.1.10 不生成soname 的方式,不推薦這種方式,這種方式

readelf -d libmysqlclient.so.20.3.0  readelf可以檢視soname及依賴庫檔案

Dynamic section at offset 0x39ead8 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libmysqlclient.so.20]
 0x000000000000000c (INIT)               0x25d90
 0x000000000000000d (FINI)               0xb81e8
 0x000000006ffffef5 (GNU_HASH)           0x1b8
 0x0000000000000005 (STRTAB)             0x1eb0
 0x0000000000000006 (SYMTAB)             0x5a8
 0x000000000000000a (STRSZ)              3872 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x59f9f0
 0x0000000000000002 (PLTRELSZ)           3960 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x24e18
 0x0000000000000007 (RELA)               0x3128
 0x0000000000000008 (RELASZ)             138480 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffc (VERDEF)             0x2fe8
 0x000000006ffffffd (VERDEFNUM)          3
 0x000000006ffffffe (VERNEED)            0x3048
 0x000000006fffffff (VERNEEDNUM)         6
 0x000000006ffffff0 (VERSYM)             0x2dd0
 0x000000006ffffff9 (RELACOUNT)          5506
 0x0000000000000000 (NULL)               0x0

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2120139/,如需轉載,請註明出處,否則將追究法律責任。

相關文章