Linux,GNU GCC,ld,版本脚本和ELF二进制格式 - 它们是如何工作的?

9
我试图了解Linux中的库版本控制以及如何将其全部应用到工作中。以下是相关内容:
- 我有两个动态库版本,它们公开相同的接口,称为`libsome1.so`和`libsome2.so`。 - 应用程序链接到`libsome1.so`。 - 此应用程序使用`libdl.so`动态加载另一个模块,称为`libmagic.so`。 - 现在,`libmagic.so`链接到`libsome2.so`。显然,在运行时,所有对`libsome2.so`接口的调用都将被解析为`libsome1.so`,除非使用链接器脚本来隐藏`libmagic.so`中的符号。可以通过检查`libVersion()`返回的值与宏`LIB_VERSION`的值进行确认。 - 因此,我尝试使用链接器脚本编译和链接`libmagic.so`,该脚本隐藏所有符号,仅公开其中定义的3个符号,并由其导出。这有效...或者至少`libVersion()`和`LIB_VERSION`的值匹配(并且报告版本2而不是1)。 - 但是,当某些数据结构序列化到磁盘时,我注意到一些损坏。如果在应用程序目录中删除`libsome1.so`并创建软链接以指向`libsome2.so`,则一切正常,不会发生相同的损坏。
我不禁认为这可能是由于运行时链接器解析符号时的某些冲突造成的。我尝试了许多方法,例如尝试链接`libsome2.so`,以便将所有符号别名为`symbol@@VER_2`(对此仍感到困惑,因为命令`nm -CD libsome2.so`仍会将符号列出为`symbol`而不是`symbol@@VER_2`)...没有任何方法可行!求助!!!!!
编辑:我应该早些提到,但所涉及的应用程序是Firefox,而`libsome1.so`是其中附带的`libsqlite3.so`。我不能重新编译它们。此外,使用版本脚本来隐藏符号似乎是目前唯一的解决方案。那么隐藏符号时真正发生了什么?它们是否变成SO的“本地”符号?rtld是否不知道它们的存在?当导出函数引用隐藏符号时会发生什么?

2
@joksnet:我以为 Stack Exchange 是给用户而不是开发人员用的……这个问题涉及到在 C++ Linux 中的开发……或者我只是自己欺骗了?:) 编辑:我错了!!由于某种原因,我以为 stackexchange = serverfault!!我不知道 unix.stackexchange.com!! - themoondothshine
@themoondothshine,请避免在每个技术社区的Stack Exchange上交叉发布您的问题。您第一次就做对了,但如果您没有这样做,社区会负责将其放到正确的位置。 - user113292
2
@joksnet,我不明白关于链接技术方面的问题为什么不适合在Stack Overflow上讨论。 - user113292
1
我同意Mark的看法。我已经添加了赏金,以期获得一个合理的解释。 - user257111
1
关于so数字的相关背景信息:http://unix.stackexchange.com/questions/475/how-do-so-shared-object-numbers-work 来自我的问题。 - user257111
显示剩余5条评论
1个回答

3
尝试编译两个库文件libsome1.solibsome2.so,分别使用其自己的版本添加符号版本控制(使用--version-script选项和ld)。然后使用新库文件链接应用程序和libmagic.so。这样,libsome1.solibsome2.so应该完全独立。
如果存在未加版本控制的符号引用,则仍可能出现问题。可以通过版本化定义来满足这些引用(这样就可以将符号版本控制添加到库中而不会破坏二进制兼容性)。如果存在多个同名符号,则有时很难预测将使用哪个符号。
关于工具,nm -D不显示有关符号版本控制的任何信息。请尝试使用objdump -Treadelf -s

谢谢提供这些信息。我学到了新东西!可能我早该提到,但是问题中的应用程序是Firefox,而libsome1.so是随它一起提供的libsqlite3.so。所以我没有重新编译它们的选项。不过,我在我创建的最小化示例上尝试了你的解决方案……它奏效了! - themoondothshine
我授予你赏金。我认为这是应得的,你的回答很好。再加些声望吧! - user257111

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接