GLIBC中的Symbol Versioning

Posted ithiker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GLIBC中的Symbol Versioning相关的知识,希望对你有一定的参考价值。

文章目录


前言

由glibc编译得到的动态库是libc.so, glibc可以通过改变soname来发布新的版本,比如libc.so.6等等, 在实际中, 改变soname通常是大的发布, 如果需要一些小的改动,可以通过Symbol Versioning的方式实现.


一、Symbol Versioning的作用

Symbol Versioning主要有以下作用:

  • 允许同一个库中导出单个符号的多个实现,也就是说对于同一个函数声明,可以有多个实现版本
  • 不同的程序可以在链接时决定使用特定的版本
  • 可以不用改变soname, 来发布新的库(非兼容性的)

当然symbol versioning不仅仅可以使用在glibc中,也可以使用到其它c语言的代码中.

二、Symbol Versioning的使用

这里按照Reference 3中的例子,来说明如何使用symbol versioning:

  1. 首先定义一个函数以及它的version map 文件, 编译这个文件并生成动态库:
    bash$ cat sv_lib_v1.c
    #include <stdio.h>
    void xyz(void)  
        printf("v1 xyz\\n"); 
    
    
    bash$ cat sv_v1.map
    VER_1 
            global: xyz;
            local:  *;      # Hide all other symbols
    ;
    
    bash$ gcc -g -c -fPIC -Wall sv_lib_v1.c
    bash$ gcc -g -shared -o libsv.so sv_lib_v1.o -Wl,--version-script,sv_v1.map
    
  2. 运行程序, 该程序使用生成的动态库中VER_1的xyz的函数:
    bash$ cat sv_prog.c
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    
        void xyz(void);
    
        xyz();
        exit(EXIT_SUCCESS);
    
    bash$ gcc -g -o p1 sv_prog.c libsv.so
    
  3. 修改动态库的源文件增加一个新的xyz实现:
    $ cat sv_lib_v2.c 
    #include  <stdio.h>
    __asm__(".symver xyz_old,xyz@VER_1");
    __asm__(".symver xyz_new,xyz@@VER_2");
    
    void xyz_old(void)
    
       printf("v1 xyz\\n");
    
    
    void xyz_new(void)
    
       printf("v2 xyz\\n");
    
    
    void pqr(void)
    
       printf("v2 pqr()\\n");
    
    
    bash$ cat sv_v2.map
    VER_1 
           global: xyz;
           local:  *;      # Hide all other symbols
    ;
    
    VER_2 
           global: xyz; pqr;
           local:  *;      # Hide all other symbols
    ;
    bash$ gcc -g -c -fPIC -Wall sv_lib_v2.c
    bash$ gcc -g -shared -o libsv.so sv_lib_v2.o -Wl,--version-script,sv_v2.map
    
    上面源文件中的汇编指令分别说明了xyz_old是VER_1版本的xyz函数的实现, xyz_new是VER_2版本的xyz函数的实现; sv_v2.map是新的symbol versioning map. 重新生成新的binary:
    $ gcc -g -o p2 sv_prog.c libsv.so.1
    
    运行:
    $ LD_LIBRARY_PATH=. ./p2
    v2 xyz
    
    $ LD_LIBRARY_PATH=. ./p1
    v1 xyz
    
    这里, 我们如果删除最初的libsv.so, 然后运行p1, 会发现找不到库, 但是如果继续添加一个libsv.so软链接到lib.sv.so.1, 则可以运行成功:
    $ mv libsv.so libsv.so.bak
    
    $ LD_LIBRARY_PATH=. ./p1
    ./p1: error while loading shared libraries: libsv.so: cannot open shared object file: No such file or directory
    
    $ ln -sf libsv.so.1 libsv.so
    
    $ LD_LIBRARY_PATH=. ./p1
    v1 xyz
    
    
    这是因为libsv.so.1中含有VER_1的xyz和VER_2的xyz:
    $  readelf -W --dyn-syms libsv.so.1 | grep @
         3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (4)
         7: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (4)
         8: 0000000000000709    18 FUNC    GLOBAL DEFAULT   12 pqr@@VER_2
        11: 00000000000006f7    18 FUNC    GLOBAL DEFAULT   12 xyz@@VER_2
        12: 00000000000006e5    18 FUNC    GLOBAL DEFAULT   12 xyz@VER_1
    
    

Reference

  1. https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
  2. https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
  3. https://man7.org/conf/lca2006/shared_libraries/slide19a.html#:~:text=Allows%20a%20single%20library%20to,version%20number%20of%20the%20library.

以上是关于GLIBC中的Symbol Versioning的主要内容,如果未能解决你的问题,请参考以下文章

GLIBC中的Symbol Versioning

Qt sqlite3.o: undefined reference to symbol ‘dlclose@@GLIBC_2.2.5‘

全网首发:终极解决办法:/usr/bin/ld: libcc.so: no symbol version section for versioned symbol `memcpy@GLIBC_2.0‘

[C++]共享内存cmake报错undefined reference to symbol ‘shm_unlink@@GLIBC_2.2.5

安装mysql_sniffer报错undefined reference to symbol 'pthread_setspecific@@GLIBC_2.2.5'问题

linux下开发,解决cocos2d-x中编译出现的一个小问题, undefined reference to symbol &#39;pthread_create@@GLIBC_2.2.5&