zoukankan      html  css  js  c++  java
  • 动态库的soname实验

    soname的实验演示:

    1、制作一个动态库,源文件b.c,程序如下:
    #include <stdio.h>

    int funb(int a, int b)
    {
            printf("hello funb ");
            return a + b;
    }


    2、编译成动态库
    gcc  -fPIC -shared  -Wl,-soname,libfuncb.so  -o libfuncb.so.1 b.c
    注意生成的文件的真实名字是libfuncb.so.1, 而这个动态库的soname是libfuncb.so。

    root@vm:/home/zhangmeng/sonametest# gcc  -fPIC -shared  -Wl,-soname,libfuncb.so  -o libfuncb.so.1 b.c
    root@vm:/home/zhangmeng/sonametest# ll
    total 24
    drwxr-xr-x  2 root      root      4096 Feb 23 11:54 ./
    drwxrwxrwx 56 zhangmeng zhangmeng 4096 Feb 23 11:44 ../
    -rw-r--r--  1 root      root        87 Feb 23 11:45 b.c
    -rwxr-xr-x  1 root      root      8112 Feb 23 11:54 libfuncb.so.1*
    -rw-r--r--  1 root      root       116 Feb 23 11:51 main.c

    用readelf -d看一下:
    root@vm:/home/zhangmeng/sonametest# readelf -d libfuncb.so.1

    Dynamic section at offset 0xe08 contains 25 entries:
      Tag        Type                         Name/Value
     0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
     0x000000000000000e (SONAME)             Library soname: [libfuncb.so]
     0x000000000000000c (INIT)               0x550
     0x000000000000000d (FINI)               0x6c4
     0x0000000000000019 (INIT_ARRAY)         0x200df0
     0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
     0x000000000000001a (FINI_ARRAY)         0x200df8
     0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
     0x000000006ffffef5 (GNU_HASH)           0x1f0
     0x0000000000000005 (STRTAB)             0x380
     0x0000000000000006 (SYMTAB)             0x230
     0x000000000000000a (STRSZ)              185 (bytes)
     0x000000000000000b (SYMENT)             24 (bytes)
     0x0000000000000003 (PLTGOT)             0x201000
     0x0000000000000002 (PLTRELSZ)           24 (bytes)
     0x0000000000000014 (PLTREL)             RELA
     0x0000000000000017 (JMPREL)             0x538
     0x0000000000000007 (RELA)               0x478
     0x0000000000000008 (RELASZ)             192 (bytes)
     0x0000000000000009 (RELAENT)            24 (bytes)
     0x000000006ffffffe (VERNEED)            0x458
     0x000000006fffffff (VERNEEDNUM)         1
     0x000000006ffffff0 (VERSYM)             0x43a
     0x000000006ffffff9 (RELACOUNT)          3
     0x0000000000000000 (NULL)               0x0

    可以看到libfuncb.so.1 的soname是libfuncb.so,也就是说我们编译时使用的soname生效了。

    3、写一个主函数,文件名字main.c,程序如下:
    #include <stdio.h>
    int funb(int, int);
    int main()
    {
            int ret = funb(3, 4);
            printf("ret = %d ", ret);
            return 0;
    }


    4、执行编译
    root@vm:/home/zhangmeng/sonametest# gcc main.c -o main libfuncb.so.1
    root@vm:/home/zhangmeng/sonametest# ll
    total 36
    drwxr-xr-x  2 root      root      4096 Feb 23 11:57 ./
    drwxrwxrwx 56 zhangmeng zhangmeng 4096 Feb 23 11:44 ../
    -rw-r--r--  1 root      root        87 Feb 23 11:45 b.c
    -rwxr-xr-x  1 root      root      8112 Feb 23 11:54 libfuncb.so.1*
    -rwxr-xr-x  1 root      root      8640 Feb 23 11:57 main*
    -rw-r--r--  1 root      root       116 Feb 23 11:51 main.c


    5、执行一下main
    root@vm:/home/zhangmeng/sonametest# ./main
    ./main: error while loading shared libraries: libfuncb.so: cannot open shared object file: No such file or directory

    报错了, 可以看到main找不到libfuncb.so, 虽然我们编译main时使用的是libfuncb.so.1,但是链接器会将libfuncb.so.1的soname写到可执行程序main中,
    这样main在执行时,依赖的其实是libfuncb.so,而当前文件夹下并没有libfuncb.so

    6、用readeif -d验证一下main的依赖
    root@vm:/home/zhangmeng/sonametest# readelf -d main

    Dynamic section at offset 0xe18 contains 25 entries:
      Tag        Type                         Name/Value
     0x0000000000000001 (NEEDED)             Shared library: [libfuncb.so]
     0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
     0x000000000000000c (INIT)               0x400560
     0x000000000000000d (FINI)               0x400774
     0x0000000000000019 (INIT_ARRAY)         0x600e00
     0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
     0x000000000000001a (FINI_ARRAY)         0x600e08
     0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
     0x000000006ffffef5 (GNU_HASH)           0x400298
     0x0000000000000005 (STRTAB)             0x400408
     0x0000000000000006 (SYMTAB)             0x4002d0
     0x000000000000000a (STRSZ)              190 (bytes)
     0x000000000000000b (SYMENT)             24 (bytes)
     0x0000000000000015 (DEBUG)              0x0
     0x0000000000000003 (PLTGOT)             0x601000
     0x0000000000000002 (PLTRELSZ)           72 (bytes)
     0x0000000000000014 (PLTREL)             RELA
     0x0000000000000017 (JMPREL)             0x400518
     0x0000000000000007 (RELA)               0x400500
     0x0000000000000008 (RELASZ)             24 (bytes)
     0x0000000000000009 (RELAENT)            24 (bytes)
     0x000000006ffffffe (VERNEED)            0x4004e0
     0x000000006fffffff (VERNEEDNUM)         1
     0x000000006ffffff0 (VERSYM)             0x4004c6
     0x0000000000000000 (NULL)               0x0

    可以看到依赖的shared library确实是libfuncb.so而不是libfuncb.so.1,这时候怎么办呢?

    7、建立软链接
    因为main在启动时实际上是去找一个叫做libfuncb.so的文件(库), 所以我们建立libfuncb.so到libfuncb.so.1的软链接

    执行如下:
    root@vm:/home/zhangmeng/sonametest# ln -s libfuncb.so.1 libfuncb.so
    root@vm:/home/zhangmeng/sonametest# ll
    total 36
    drwxr-xr-x  2 root      root      4096 Feb 23 12:04 ./
    drwxrwxrwx 56 zhangmeng zhangmeng 4096 Feb 23 11:44 ../
    -rw-r--r--  1 root      root        87 Feb 23 11:45 b.c
    lrwxrwxrwx  1 root      root        13 Feb 23 12:04 libfuncb.so -> libfuncb.so.1*
    -rwxr-xr-x  1 root      root      8112 Feb 23 11:54 libfuncb.so.1*
    -rwxr-xr-x  1 root      root      8640 Feb 23 11:57 main*
    -rw-r--r--  1 root      root       116 Feb 23 11:51 main.c

    root@vm:/home/zhangmeng/sonametest# LD_LIBRARY_PATH=. ./main
    hello funb
    ret = 7
    root@vm:/home/zhangmeng/sonametest#


    可以看到现在执行成功了,至于为什么要加LD_LIBRARY_PATH,这是因为现在libfuncb.so是有了,但是你得告诉动态链接器去哪里才能找到他,而没有建立软链接之前,它根本不存在。

    8、更新libfuncb.so.1
    现在我们要更新动态库,而且动态库也是要带版本号的,名字为libfuncb.so.2,不能对已经有的可执行程序产生影响。
    这时我们在编译libfuncb.so.2时也要将soname指定为libfuncb.so,编出来之后删除原来的软链接,重新建立libfuncb.so到libfuncb.so.2的软链接

    这时候可执行程序就可以直接运行了。

    9、生成软链接的另一种方法
    将libfuncb.so.1或者libfuncb.so.2所在的路径加入到/etc/ld.so.conf中
    include /etc/ld.so.conf.d/*.conf
    /usr/lib/local
    /usr/local/lib
    /home/zhangmeng/sonametest

    保存后,执行ldconfig,这时会在/home/zhangmeng/sonametest目录下自动生成soname名字到libfuncb.so.1或者libfuncb.so.2的软链接,如果多个文件有相同的soname,会报错


    soname作用:
    引入soname就是引入了一层间接层,就是我们真正的库的版本在变化的时候,不用更改已经运行的可执行程序。这里有一点很重要,就是我们有对动态库加版本号这个需求,
    比如libfuncb.so.1或者libfuncb.so.2,如果没有在库名字上加版本号的需求,那么也没有必要引入soname这个间接层了,直接把库的名字叫libfuncb.so就可以了,
    这样更新libfuncb.so之后也不会对可执行程序造成影响,这种方式下我们可以把版本号以其它方式写到动态库里,而不是体现在文件名字上。

  • 相关阅读:
    [工具-002]把png图片转换成ico图标
    软件攻城狮究级装B指南
    [翔哥高手无敌之路]0-002.如何提取apk中的信息?
    [Python基础]003.语法(2)
    [COCOS2DX-LUA]0-001.利用ClippingNode实现放大镜功能
    [书籍分享]0-005.淘宝技术这十年
    [翔哥高手无敌之路]0-001.项目有多余资源?那就删除吧!
    [Python基础]002.语法(1)
    [Objective-C] 001_Hello Objective-C
    DB2 pureXML 动态编程组合拳:iBatis+BeanUtils+JiBX
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/12349187.html
Copyright © 2011-2022 走看看