假如libgetthree.so libgetseven.so , 同时这两个so内部都用了internal_do_calculation()函数,并且各自定义了自己的internal_do_calculation()的实现,你会想当然的认为他们各自不影响,libgetthree和libgetseven会分别用自己的internal_do_calculation(),但事与愿违,你会发现都只会用其中一个so的符号

他经历的过程如下:

  1. 当exe执行的时候,他会去寻找PublicGetThree符号,于是dynamic loader就会在libgetthree.so种进行reslove
  2. 当exe执行的时候,他会去寻找PublicGetSeven符号,于是dynamic loader就会在libgetseven.so种进行reslove
  3. 接下来开始寻找internal_do_calculation符号,他发现在libgethree.so中有,于是就全部用他的了

于是你会发现,libgetseven.so用的是其他库的这个符号,错误就产生了。取决于你怎么链接顺序,经过测试,发现跟第一个库的顺序有关

但是如果我们一旦隐藏比如three.cpp的符号

我们再重新链接,发现就正常了

可以总结出如果你对某个so库中的符号做了hidden,他实际上有两个作用:

  1. 对于自己来说,他告诉这个动态库对于这个符号不能从其他库中去读取,只能读取自己的这个internal符号(-Bsymbolic / -Bsymbolic-functions仅仅起到这个第一个作用)
  2. 对于其他库来说,这个库中的这个符号被隐藏了,自然只能用自己的符号了

通过上面这两个效果,你可以发现,无论你是hidden libgetthree.so还是libgetseven.so都是work的。

除了以上的好处之外,如果你控制得体,比如全局使用-fvisibility=hidden,对对应的public API使用__attribute__((visibility("default")))来暴露,这样有以下额外的好处:

  1. 你的库的load time会减少
  2. 你的整体的运行speed会提高,因为编译器知道他可以对devirtualization / inline functions做额外的优化
  3. 你的shared library的size大小会减小,因为编译器会从exported symbols table中丢失hidden symbols

坏处:

他会让你做单元测试更加困难,因为你已经把你的内部实现符号都给隐藏了,因此当你做unit testing的时候,你需要用default visibility来重新build.你可以借此来重新配置你的debug / release build flags:

Debug:

  • -g - 加上debug info
  • -O0 - 不提供任何优化(可以提供在开发阶段的debug使用体验)

Release:

  • -fvisibility=hidden - 上面说的,可以提高效率
  • -O2 - 优化大小和提高速度

有一个需要注意的地方就是关于异常C++ Exceptions,当binary code捕获住了一个exception的时候,他需要typeinfo的查找,但是typeinfo的symbols会随着你本身symbols的hidden而hidden.

通过linker的-Bsymbolic / -Bsymbolic-functions同样可以解决上面的问题(gcc是要加上-Wl,-Bsymbolic),比如你可以用如下的命令来进行编译

他会带来正确的结果:

但是如果那他跟hidden visibility做比较的话还是有诸多缺点:

  1. -Bsymbolic的方式仍然会export他们的符号,因此可以认为他们只解决了我们上面提到的两个作用的第一个作用,因此仍然有可能其他库会去使用他,如果我们交换了libseven.so以及libthree.so的位置,可能就会出现问题
  1. hidden visibility比-B的方式优化了对应的空间以及提高了运行速度
  2. 也不是说-Bsymbolic没有任何好处,他相对hidden visibility的手法让你写单元测试的时候只需要进行一次库的编译

除了以上提供的方法之外,你还能利用-fvisibilty=protected来达到效果,他跟hidden类似,可以保护你当前shared library的库的符号不会被其他库方便,但是他不保证你的库会去污染其他库的符号表,比如我们来看例子:

这个情况下是OK的,因为我们保护了Seven本身,因此他的内部符号只会用自己的

我们来看另外一个例子

这就出问题了,因为我们虽然保护了three本身,但是他的符号也确实污染到了libseven.so,因此输出了3

你也可以通过匿名空间来达到效果

注意不要把你的public API也给包了,仅仅包你的实现,然后你通过nm查看发现他们默认变成小t了

但是如果你不用匿名空间,而是带名字的空间,他是大T的会做污染

因此可以看到匿名空间的一个作用就是自动帮你把符号隐藏. 同样,如果你的函数定义成static静态的,你的函数符号默认也是hidden的,也能起到同样的效果

Dynamic Linking解决相关问题:

试想一下如果你的library A和B都对C有依赖,其中A用的是新的C,B用的是老的C。这里面可能存在数据结构的不一致,就会出现问题,但是正是因为有了dynamic linking,如果A和B对于major version的C是兼容的,那么dynamic linking会帮你解决这个问题,因为他们所有遇到过的C的符号通过上面的解释,都会保持一致,因为有override的行为在里面。 但是并不是说dynamic linking就是万能解药,静态编译static linking的一个原因就是拥有尽可能小的分发依赖。 另外一个原因就是你要测试所有版本的依赖非常困难,通过静态编译到一个特定的版本允许让你拥有这个依赖的一致行为

查看so库中是否有某个定义_论Linux ELF中动态库符号重定义利用 属性/Linker 做隐藏的手法...相关推荐

  1. linux查看动态库导出的符号,Linux下控制动态库导出

    在Linux中动态库的确给程序带来了良好的扩充性,并减少了内存的使用量,但这是有代价的.例如: #include Int main(int argc, char *argv[]) { Printf(& ...

  2. linux 下的动态库制作 以及在python 中如何调用 c 函数库

    linux 下的动态库制作 以及在python 中如何调用 c 函数库 动态库: 动态库又称动态链接库英文为DLL,是Dynamic Link Library 的缩写形式,DLL是一个包含可由多个程序 ...

  3. 解决Linux多个动态库间的符号冲突问题

    c和c++开发人员或多或少都使用过Linux动态库,但是很多时候我们都不会去深入了解其中的一些细节和原理,直到自己的程序出现莫名其妙的问题后才会去着手解决,我也是在遇到一些动态库的问题后才去深入寻找解 ...

  4. 【Linux学习】动态库和静态库

    目录 一.动静态库的概念和原理 1. 认识动静态库 2. 动静态库的概念 3. 动静态库的原理 二.动静态库的生成与打包 1. 静态库的生成与打包 2. 动态库的生成与打包 三.动静态库的使用 1. ...

  5. Linux下的动态库和静态库

    什么是库? 在 Linux 开发时,我们经常会看到一些形如 xxx.so 的名称出现,其中 so 是 Shared Object 的缩写,即可以共享的目标文件,也就是我们所称为的动态链接库,和在 Wi ...

  6. C++:重定义:符号重定义:变量重定义(二):解决变量重定义(const static)

    C++:重定义:符号重定义:变量重定义_hongwen_yul的博客-CSDN博客 上一篇文章中,我们知道解决变量重复定义其中一个办法是:尽量不要头文件中定义变量,头文件只做变量的声明.但是如果我们一 ...

  7. linux加载动态库问题

    当我们在linux系统引用动态库时,经常会遇到一个问题,加入我们需要的动态库没有在系统的默认目录下,我们编译时使用-L指定了动态库的路径,编译时没有问题,但是执行调用该动态库的可执行文件时,却提示找不 ...

  8. sql server定义_在SQL Server中查看定义权限

    sql server定义 We have various database objects such as view, stored procedures, triggers, functions a ...

  9. linux中查询动态库版本的命令,linux 程序、动态库、静态库内部添加版本号和编译时间详解...

    给程序和库添加版本号和库,有利于维护和升级. 当然你可以在文件名上体现,比如有个程序叫 yun,文件名写为 yun_1.0.2,但这个需要每次手动维护,而且不能100%确保当前程序就是那个版本.所以, ...

最新文章

  1. 【linux】SELinux工具:semanage的安装和使用
  2. Python到底有多强大?只需 15 行代码即可进行人脸检测
  3. BZOJ 2143 飞飞侠(线段树优化建边 / 并查集优化最短路)【BZOJ修复工程】
  4. 基于 Kubernetes 的边缘云原生
  5. 线性代数的问题:是否存在这样的矩阵,它满足正交对角化的条件,但它不是实对称矩阵呢?
  6. SSM实现导出报表为Excel
  7. SAP CRM Fiori应用里取top20的service url的determine逻辑
  8. visual studio 判断dropdownlist选的是什么_心理测试:五个小蓝人,你选哪个?测你是不是一个容易追求的人...
  9. 【Elasticsearch】Elasticsearch 缓存深度剖析:一次提高一种缓存的查询速度
  10. Jsp+Ssh+Mysql实现的Java Web学生考勤管理
  11. 【嵌入式软件工程师常用工具分享】串口监控工具
  12. C语言实现strcmp函数
  13. 虚拟主机和服务器之间的区别
  14. git bisect_Git Bisect如何使调试更容易
  15. 一个人竟然撸了一个网易云音乐云村
  16. 最近两周出去面试遇到的面试题(前端初级、长更)
  17. 求是潮android最新版,是谁在暗中观察
  18. 05.局域网_NAT
  19. [转载]芋道 Soul 极简入门(国产微服务网关)
  20. 鲍尔默飙泪谈离职原因:董事会嫌我速度慢

热门文章

  1. python commands_Windows环境下使用python的commands.getstatusoutput
  2. system函数_自学C++基础教程【函数】
  3. 成为项目经理需要具备什么条件?
  4. mybatis3 添加ehcache支持
  5. oracle 如何终止存储过程的运行
  6. mysql查询_MYSQL查询
  7. linux环境OpenRASP使用教程,集成openRASP与攻击测试
  8. [转载] java-继承和多态
  9. c语言 nan 常量_NaN32常量(Julia)
  10. 编辑距离 dp_使用动态编程(DP)编辑距离