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

时间:2011-01-11 17:14:26

标签: linux gcc ld

我正在尝试更多地了解Linux中的库版本控制以及如何将其全部用于工作。这是上下文:

- 我有两个版本的动态库,它们公开了同一组接口,比如libsome1.solibsome2.so

- 应用程序与libsome1.so链接。

- 此应用程序使用libdl.so动态加载另一个模块,例如libmagic.so

- 现在libmagic.solibsome2.so相关联。显然,如果不使用链接描述文件隐藏libmagic.so中的符号,则在运行时,libsome2.so中对接口的所有调用都将解析为libsome1.so。这可以通过检查libVersion()返回的值与宏LIB_VERSION的值来确认。

- 所以我接下来尝试编译并链接libmagic.so一个链接器脚本,该脚本隐藏除libmagic.so中定义的3之外的所有符号并由其导出。这可行...或者至少libVersion()LIB_VERSION值匹配(并且它报告的版本2不是1)。

- 但是,当某些数据结构被序列化到磁盘时,我注意到了一些损坏。在应用程序的目录中,如果我删除libsome1.so并在其位置创建指向libsome2.so的软链接,则一切都按预期工作,并且不会发生相同的损坏。

我不禁认为这可能是由于运行时链接器的符号解析中的某些冲突引起的。我尝试了很多东西,比如尝试链接libsome2.so,以便所有符号都被赋予symbol@@VER_2(我仍然感到困惑,因为命令nm -CD libsome2.so仍然将符号列为{{1}而不是symbol)......似乎什么都行不通!帮助!!!!!!

编辑:我之前应该提到它,但有问题的应用是Firefox,而symbol@@VER_2libsome1.so随附的。我不太可能重新编译它们。此外,使用版本脚本隐藏符号似乎是目前唯一的解决方案。那么当隐藏符号时会发生什么?他们成为SO的“本地”吗? rtld不知道它们的存在吗?当导出的函数引用隐藏符号时会发生什么?

1 个答案:

答案 0 :(得分:4)

尝试同时编译libsome1.solibsome2.so以添加符号版本控制,每个版本都有自己的版本(使用--version-script选项ld)。然后使用新库链接应用程序和libmagic.so。然后,libsome1.solibsome2.so应完全分开。

如果存在对符号的无版本引用,则仍会出现问题。版本化定义可以满足此类引用(因此可以在不破坏二进制兼容性的情况下将符号版本控制添加到库中)。如果有多个同名符号,有时很难预测将使用哪个符号。

关于工具,nm -D不显示有关符号版本控制的任何信息。请改为objdump -Treadelf -s