Linux動態(tài)庫soname的使用

通過一個簡單的例子,體驗一下Linux動態(tài)庫soname的使用。

假設(shè)有一個動態(tài)庫:libbar.so.1.1.0,其對應(yīng)的三個名稱如下。

  1. realname:libbar.so.1.1.0
  2. soname:libbar.so.1
  3. linkname:libbar.so

先生成一個libbar.so,通過-Wl,-soname指定soname為libbar.so.1。

$ g++ -fPIC -shared -Wl,-soname,libbar.so.1 -o libbar.so.1.1.0

$ readelf -d libbar.so.1.1.0

Dynamic section at offset 0x520 contains 24 entries:
  Tag        Type                         Name/Value
 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: [libbar.so.1]
 0x000000000000000c (INIT)               0x398
 0x000000000000000d (FINI)               0x4d8
 0x000000006ffffef5 (GNU_HASH)           0x120
 0x0000000000000005 (STRTAB)             0x248
 0x0000000000000006 (SYMTAB)             0x158
 0x000000000000000a (STRSZ)              160 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x2006f8
 0x0000000000000002 (PLTRELSZ)           24 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x380
 0x0000000000000007 (RELA)               0x320
 0x0000000000000008 (RELASZ)             96 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x300
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x2e8
 0x000000006ffffff9 (RELACOUNT)          1
 0x0000000000000000 (NULL)               0x0

使用ldconfig生成soname對應(yīng)的符號鏈接文件。

$ ldconfig -n /tmp/

$ ll libbar.so.1
lrwxrwxrwx 1 henshao users 15 Nov 28 01:00 libbar.so.1 -> libbar.so.1.1.0

接著寫一個程序使用libbar.so。

#鏈接需要linkname,否則會提示找不到動態(tài)庫。
$ gcc foo.c -o foo -L. -lbar
/usr/bin/ld: cannot find -lbar
collect2: ld returned 1 exit status

#生成linkname的服務(wù)鏈接文件
$ ln -s libbar.so.1 libbar.so

#這次編譯能成功
$ gcc foo.c -o foo -L. -lbar

#可見foo依賴的是soname,而不是linkname。
$ ldd foo
    linux-vdso.so.1 =>  (0x00007fffa27ff000)
    /opt/alisentry/$LIB/alisentry_exec.so => /opt/alisentry/lib64/alisentry_exec.so (0x00007fabfda17000)
    /opt/alisentry/$LIB/alisentry_kill.so => /opt/alisentry/lib64/alisentry_kill.so (0x00007fabfd814000)
    libbar.so.1 => not found
    libc.so.6 => /lib64/libc.so.6 (0x00007fabfd4b0000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fabfd2ac000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fabfdc1d000)

為什么主程序會依賴soname,而不是linkname和realname?這是因為Linux的動態(tài)庫的命名格式是libbar.so.x.y.z,最后一個z版本的變動一定是兼容的。y版本升級一般向前兼容。所以這個y和z不能寫死。x版本變動一般是不兼容升級。所以使用soname是最為合理的。

再做一個有意思的測試。將libbar.so.1重命名為aaa,然后同樣創(chuàng)建aaa的符號鏈接為libbar.so

$ ll libbar.so* aaa
lrwxrwxrwx 1 henshao users    3 Nov 28 01:28 libbar.so -> aaa
lrwxrwxrwx 1 henshao users   15 Nov 28 01:27 aaa -> libbar.so.1.1.0
-rwxr-xr-x 1 henshao users 5301 Nov 28 01:27 libbar.so.1.1.0

有趣的是,foo依然知道依賴libbar.so.1,而不是aaa。

$ gcc foo.c -o foo -L. -lbar

$ ldd foo
    linux-vdso.so.1 =>  (0x00007fff19ce7000)
    /opt/alisentry/$LIB/alisentry_exec.so => /opt/alisentry/lib64/alisentry_exec.so (0x00007fb07c389000)
    /opt/alisentry/$LIB/alisentry_kill.so => /opt/alisentry/lib64/alisentry_kill.so (0x00007fb07c186000)
    libbar.so.1 => not found
    libc.so.6 => /lib64/libc.so.6 (0x00007fb07be22000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fb07bc1e000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fb07c58f000)

在Linux系統(tǒng)里面找個實際的例子看看。wget依賴libz.so.1。

$ ldd /usr/bin/wget
    linux-vdso.so.1 =>  (0x00007fff631ff000)
    /opt/alisentry/$LIB/alisentry_exec.so => /opt/alisentry/lib64/alisentry_exec.so (0x00007fe75c93e000)
    /opt/alisentry/$LIB/alisentry_kill.so => /opt/alisentry/lib64/alisentry_kill.so (0x00007fe75c73b000)
    libssl.so.6 => /lib64/libssl.so.6 (0x00007fe75c4e1000)
    libcrypto.so.6 => /lib64/libcrypto.so.6 (0x00007fe75c190000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fe75bf8c000)
    libz.so.1 => /usr/lib64/libz.so.1 (0x00007fe75bd78000)
    librt.so.1 => /lib64/librt.so.1 (0x00007fe75bb6f000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fe75b816000)
    libgssapi_krb5.so.2 => /usr/lib64/libgssapi_krb5.so.2 (0x00007fe75b5e8000)
    libkrb5.so.3 => /usr/lib64/libkrb5.so.3 (0x00007fe75b353000)
    libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007fe75b150000)
    libk5crypto.so.3 => /usr/lib64/libk5crypto.so.3 (0x00007fe75af2b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe75cb44000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe75ad10000)
    libkrb5support.so.0 => /usr/lib64/libkrb5support.so.0 (0x00007fe75ab07000)
    libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007fe75a905000)
    libresolv.so.2 => /lib64/libresolv.so.2 (0x00007fe75a6f0000)
    libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fe75a4d7000)
    libsepol.so.1 => /lib64/libsepol.so.1 (0x00007fe75a291000)

$ll /usr/lib64/libz.so*
lrwxrwxrwx 1 root root 19 Dec  3  2015 /usr/lib64/libz.so -> ../../lib64/libz.so
lrwxrwxrwx 1 root root 21 Dec  3  2015 /usr/lib64/libz.so.1 -> ../../lib64/libz.so.1
lrwxrwxrwx 1 root root 25 Dec  3  2015 /usr/lib64/libz.so.1.2.3 -> ../../lib64/libz.so.1.2.3

$ ll /lib64/libz*
lrwxrwxrwx 1 root root    13 Dec  3  2015 /lib64/libz.so -> libz.so.1.2.3
lrwxrwxrwx 1 root root    13 Dec  3  2015 /lib64/libz.so.1 -> libz.so.1.2.3
-rwxr-xr-x 1 root root 83280 May 28  2014 /lib64/libz.so.1.2.3

$ readelf -d /usr/lib64/libz.so.1.2.3

Dynamic section at offset 0x139f8 contains 21 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libz.so.1]
 0x000000000000000c (INIT)               0x1b48
 0x000000000000000d (FINI)               0xc958
 0x000000006ffffef5 (GNU_HASH)           0x158
 0x0000000000000005 (STRTAB)             0xdd8
 0x0000000000000006 (SYMTAB)             0x3e8
 0x000000000000000a (STRSZ)              1148 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x213bc8
 0x0000000000000002 (PLTRELSZ)           1200 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x1698
 0x0000000000000007 (RELA)               0x1368
 0x0000000000000008 (RELASZ)             816 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x1328
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x1254
 0x000000006ffffff9 (RELACOUNT)          26
 0x0000000000000000 (NULL)               0x0
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容