美文网首页
Linux动态库soname的使用

Linux动态库soname的使用

作者: 阿呆少爷 | 来源:发表于2019-01-17 14:23 被阅读63次

    通过一个简单的例子,体验一下Linux动态库soname的使用。

    假设有一个动态库:libbar.so.1.1.0,其对应的三个名称如下。

    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对应的符号链接文件。

    $ 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,否则会提示找不到动态库。
    $ gcc foo.c -o foo -L. -lbar
    /usr/bin/ld: cannot find -lbar
    collect2: ld returned 1 exit status
    
    #生成linkname的服务链接文件
    $ 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的动态库的命名格式是libbar.so.x.y.z,最后一个z版本的变动一定是兼容的。y版本升级一般向前兼容。所以这个y和z不能写死。x版本变动一般是不兼容升级。所以使用soname是最为合理的。

    再做一个有意思的测试。将libbar.so.1重命名为aaa,然后同样创建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系统里面找个实际的例子看看。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
    

    相关文章

      网友评论

          本文标题:Linux动态库soname的使用

          本文链接:https://www.haomeiwen.com/subject/mruoqqtx.html