繁体   English   中英

共享库符号冲突和 static 链接(在 Linux 上)

[英]Shared library symbol conflicts and static linking (on Linux)

我遇到了一篇很好的文章Shared Library Symbol Conflicts (on Linux)中详细阐述的问题。 问题是,当执行和.so定义了同名函数时,如果.so调用这个function名称,它会在执行中调用那个,而不是这个in.so本身。

让我们来谈谈这篇文章中的案例。 我了解 layer.o 中的DoLayer() function 在编译layer.o时具有DoThing()的外部 function 依赖layer.o

但是在编译libconflict.so时,不应该就地解决外部 function 依赖项并仅用静态conflict.o/DoThing()的地址替换吗?

为什么layer.o/DoLayer()仍然使用动态链接来查找DoThing() 这是设计的行为吗?

这是设计的行为吗?

是的。

在 UNIX 上引入共享库时,目标是假装它们就像代码在常规(存档)库中一样工作。

假设您在libfoolibbar中都定义了foo() ,并且libbar中的bar()调用foo()

设计目标是cc main.c -lfoo -lbar无论libfoolibbar是存档库还是共享库,其工作方式都相同。 实现这一点的唯一方法是让libbar.so使用动态链接来解析从bar()foo()的调用,尽管有本地版本的foo()

这种设计使得创建自包含的libbar.so成为不可能——它的行为(最终调用哪些函数)取决于链接到进程中的其他函数。 这也与 Windows DLL 的工作方式相反。

当时没有考虑创建独立的 DSO,因为 UNIX 实际上是开源的。

您可以使用特殊的 linker 标志更改规则,例如-Bsymbolic 但是规则很快变得复杂,并且(因为这不是默认设置)您可能会在 linker 或运行时加载程序中遇到错误。

是的,这是一种设计行为。 当您将程序链接到二进制文件时,所有对命名外部(非静态)函数的引用都被解析为指向二进制文件的符号表。 链接的任何共享库都被指定为DT_NEEDED条目。

然后,当您运行二进制文件时,动态 linker 将每个所需的共享库加载到合适的地址,并将每个符号解析为一个地址。 有时这是懒惰地完成,有时是在第一次启动时完成一次。 如果有多个具有相同名称的符号,linker 将选择其中一个符号,并且您的程序可能会崩溃,因为您最终可能没有找到正确的符号。

请注意,这是 Linux 上的行为,它具有所有符号作为平面命名空间。 Windows 以不同的方式解析符号,使用树形拓扑,它既有优点(冲突较少)也有缺点(无法在一个库中分配 memory 并在另一个库中释放它)。

如果您希望LD_PRELOAD之类的东西正常工作,Linux 行为非常重要。 这允许您使用诸如 Electric Fence 之类的调试工具和诸如 Google 性能工具之类的 CPU 分析工具,或者在运行时替换 memory 分配器。 如果符号被优先解析为它们的二进制或共享库,那么这些都不会起作用。

然而,GNU 动态 linker 确实支持符号版本,因此可以将共享库的多个版本加载到同一个程序中。 通常,像 Debian 这样的发行版会使用他们希望经常更改的库来执行此操作,例如 OpenSSL。 If the program uses liba which uses OpenSSL 1.0 and libb which uses OpenSSL 1.1, then the program should still function in such a case since OpenSSL has versioned symbols, and each library will use the appropriate version of the relevant symbol.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM