• 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 
      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
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    2. 运行程序, 该程序使用生成的动态库中VER_1的xyz的函数:
      bash$ cat sv_prog.c
      #include 
      
      int main(int argc, char *argv[])
      {
          void xyz(void);
      
          xyz();
          exit(EXIT_SUCCESS);
      }
      bash$ gcc -g -o p1 sv_prog.c libsv.so
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    3. 修改动态库的源文件增加一个新的xyz实现:
      $ cat sv_lib_v2.c 
      #include  
      __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
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      上面源文件中的汇编指令分别说明了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
      
      • 1
      运行:
      $ LD_LIBRARY_PATH=. ./p2
      v2 xyz
      
      $ LD_LIBRARY_PATH=. ./p1
      v1 xyz
      
      • 1
      • 2
      • 3
      • 4
      • 5
      这里, 我们如果删除最初的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
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      这是因为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
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    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.
  • 相关阅读:
    【回归预测-LSTM预测】基于麻雀算法优化LSTM时间序列实现预测(含前后对比)附Matlab代码
    File类和IO流的相关面试(二)
    明星产品!种质资源数字化一站式解决方案!
    6、数据结构
    借我 1 小时,与 1000 人一起参与开源
    UART协议及串口回环
    Tauri 2.0.0 beta环境搭建
    WordPress 博客实现登录后台邮件提醒的教程
    Bankless:Maker DAO的生存危机
    异行星平台--CRM系统搭建
  • 原文地址:https://blog.csdn.net/gigglesun/article/details/126691687