动态加载库中,链接器如何解决重复符号?

6
我有两个动态加载库lib_smtp.so和libpop.so等。 两者都有一个名为protocol的全局变量,分别初始化为"SMTP"和"POP"。 我还有另一个静态库libhttp.a,其中protocol初始化为“HTTP”。
现在由于某种原因,我需要将所有动态链接和可加载库编译成静态库并包含在可执行文件中。 这样做时,在链接静态库期间会出现“符号重复定义”错误。
我很好奇在动态链接期间连接了所有三个库的情况下,链接器如何解决重复的符号?
如果不能,是否有一种方法可以像链接器在动态链接中那样静态地完成相同符号的所有静态库添加到可执行文件中,而没有任何冲突? 如果不行,为什么静态链接库的过程不同呢?
2个回答

7
现代Linux和其他几个操作系统中的动态链接是基于ELF二进制格式的。可执行文件或其他共享库所依赖的(ELF)动态库具有优先级。为了解析给定的符号,动态链接器按优先顺序检查每个库,直到找到定义该符号的库为止。当多个动态对象定义相同的符号并且还有多个动态对象使用该符号时,情况可能会变得棘手。那么在不同的动态对象中解析符号可能会有所不同。完整的细节超出了SO的范围,但我不知道比Ulrich Drepper的论文“如何编写共享库”更好的技术解释。

谢谢,我的情况是多个动态对象定义并使用相同的符号“protocol”,但没有任何问题。因此,在运行时,一个例程process_http()将读取符号值为“HTTP”,而在libsmtp.so中定义的process_smtp()将读取符号值为“SMTP”。为了实现这一点,符号必须已经被清晰地解析并具有单独的地址?如果我错了,请纠正我。 - raj_gt1
1
同一程序中的不同模块是否看到全局变量的不同值被描述为“没有任何问题”是有争议的,但我想这就是您想要的。是的,当然,在不同的模块中必须将符号解析为不同的地址,因为程序的所有组件都在同一地址空间中运行。动态符号查找中优先级最高的对象通常是正在解析的引用所在的对象;这可能解释了您观察到的行为。 - John Bollinger

2
在动态链接中,有一种名为“符号可见性”的功能被启用。基本上,这允许仅在对象(在共享对象的意义上)边界之间公开某些符号。以默认隐藏符号的方式编译和链接共享对象,并仅显式地暴露那些被调用者所需的符号是一个好的风格。
符号可见性应用于链接过程中,到目前为止只在动态链接器中实现。在静态链接中也可以实现它,苹果的GCC变体实现了所谓的“Mach-O可重定位对象文件”,可以静态链接并应用可见性。但我不知道原始的GCC、binutils ld或gold链接器是否可以对普通的ELF执行此操作。

如何为Cocoa应用程序静态链接可见性限制? - uchuugaka

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