码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • GLIBC中的Symbol Versioning


    文章目录

    • 前言
    • 一、Symbol Versioning的作用
    • 二、Symbol Versioning的使用
    • Reference


    前言

    由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.
  • 相关阅读:
    在Windows环境与Linux环境下搭建Zookeeper单机环境与集群环境
    springboot配置加密的正确姿势
    【Spring IOC/DI】bean 的 5 种注册 与 5 种注入
    从零编写linux0.11 - 第八章 软盘操作
    第二次线上面试总结(2022.9.14)
    dalle:zero-shot text-to-image generation
    数据挖掘:用ID3算法或者朴素贝叶斯分析一个数据集
    云原生Java架构实战Kubernetes(k8s)安装介绍及简单使用(一篇就够了)
    Django系列:Django开发环境配置与第一个Django项目
    abp(net core)+easyui+efcore实现仓储管理系统——供应商管理升级之下(六十四)
  • 原文地址:https://blog.csdn.net/gigglesun/article/details/126691687
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号