【发布时间】:2014-11-06 06:01:46
【问题描述】:
我了解对象排序在链接期间非常重要。在尝试让 ld 解析所有符号之前,我已经很头疼了。这次ld没有产生任何错误,但是输出错误!
项目很大(50K+ 行 C++),我无法生成简化版本,所以我将尝试描述我遇到的情况。希望高手能帮我解答一下。
g++ -o bad.out a.o b.o ... x.so y.so
g++ -o good.out a.o b.o ... y.so x.so
虽然 good.out 可以正确运行,但 bad.out 不能。 x.so 和 y.so 均由独立供应商提供,因此它们的顺序无关紧要。这里有更多线索:
- a.o 使用 x.so
- b.o 使用 y.so
- a.o 和 b.o 是独立的,但它们都使用一些公共类
不正确的行为表现为从未回调的函数 OnRspLogin()。这是一个在 y.so 中定义并在 b.o 中实现的纯虚函数。 "grep OnRspLogin *.o *.so" 仅在 y.so 和 b.o 中找到匹配项。
显然 ld 没有将 OnRspLogin() 解析为 b.o 中的那个,但它解析到了哪一个?这让我很担心,因为链接器没有产生任何错误或警告。
我在 CentOS 6.5 上使用 gcc 4.4.7-4。
编辑: 我发现 x.so 和 y.so 都包含一些常见的符号(例如 T TcpClient),所以我猜链接器在解析 b.o:TcpClient 时选择了 x.so:TcpClient(而不是 y.so:TcpClient)。虽然更改 .so 顺序可能会解决这个问题,但恐怕链接器可能会错误地解析 a.o 中的一些其他符号。那么有没有办法告诉链接器只使用 y.so 来解析 b.o?请注意,这些 .so 文件由第 3 方提供,我无法更改它们。
【问题讨论】:
-
为什么觉得函数没有解析?这是不可能的。如果它没有被调用,原因是没有代码路径调用它。 that 的原因可能是 x.so 和 y.so 定义了相同的符号,而 thsat 采用的执行路径取决于使用该符号的哪个版本。顺便说一句,使用
nm在目标文件中查找符号,直接 grepping 对象是没有信息的。 -
我不是说函数没有解析;我说它没有解决正确的问题。实际上 x.so 和 y.so 包含共同的符号。有没有办法告诉 ld 使用哪个 .so?
-
你说过只有一个功能,意思是它是正确的。在多个 .so 中有重复的定义是麻烦的迹象。您可能无法同时使用这两个 .so。
-
加载的第一个符号将在整个程序中使用。这在您的情况下可能有效,也可能无效。除了尝试之外别无他法(答案当然永远不会确定)。