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

标签 linux gcc ld

我正在努力了解更多关于 Linux 中的库版本控制以及如何将其全部投入使用的信息。这是上下文:

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

-- 应用程序链接到 libsome1.so

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

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

-- 所以我接下来尝试使用链接描述文件编译和链接 libmagic.so通过它。这有效...或者至少 libVersion()LIB_VERSION 值匹配(并且它报告版本 2 而不是 1)。

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

我不禁想到这可能是由于运行时链接器对符号的解析存在一些冲突造成的。我已经尝试了很多事情,比如尝试链接 libsome2.so 以便所有符号都与 symbol@@VER_2 一致(我仍然对此感到困惑,因为命令 nm -CD libsome2.so 仍然将符号列为 symbol 而不是 symbol@@VER_2)...似乎没有任何效果!!!求助!!!!!!

编辑:我应该早点提到它,但有问题的应用程序是 Firefox,libsome1.solibsqlite3.so 附带的。我不太有重新编译它们的选择。此外,使用版本脚本来隐藏符号似乎是目前唯一的解决方案。那么当符号被隐藏时到底发生了什么?他们是否成为 SO 的“本地”? rtld 不知道它们的存在吗?当导出函数引用隐藏符号时会发生什么?

最佳答案

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

如果存在未版本化的符号引用,问题仍然会发生。此类引用可以通过版本化定义来满足(这样就可以在不破坏二进制兼容性的情况下将符号版本化添加到库中)。如果有多个同名符号,有时很难预测将使用哪一个。

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

关于Linux、GNU GCC、ld、版本脚本和 ELF 二进制格式——它是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4660388/

相关文章:

c - GCC 4.0 : How do you remove unnecessary -arch flags 的 R-Perl 安装问题

c - 为什么默认情况下不剥离用gcc编译的二进制文件

c - 针对没有源代码的 .so 文件的 GCC 链接

python - DYLD_LIBRARY_PATH 和 LD_LIBRARY_PATH 不能被 macOS Sierra 上的 python 的 os 和 subprocess 模块使用

linux - 如何从终端中的类似文件中选择一个文件(通过 tmux)

android - 从另一个共享库中检查丢失的共享库 (.so)

linux - JavaFX 应用程序包版本号

c - 使用 -std=c99 的隐式声明

c - 符号 etext、edata 和 end 在哪里定义?

linux - yum list installed|grep <rpm name> 未以 jboss 用户身份执行