Linker g++;链接器解析.so文件之间的符号

Linker g++;链接器解析.so文件之间的符号,linker,g++,Linker,G++,我理解对象顺序在链接过程中非常重要。在试图让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均由独立供应商提供,因此它们的订购应该无关紧要

我理解对象顺序在链接过程中非常重要。在试图让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都包含一些常见的符号(例如TcpClient),所以我猜链接器在解析b.o:TcpClient时选择了x.so:TcpClient(而不是y.so:TcpClient)。在更改时。因此顺序可能会解决此问题,我担心链接器可能会错误地解析a.o中的其他符号。那么是否仍有必要告诉链接器仅使用y.so解析b.o?请注意,这些.so文件是由第三方提供的,我无法更改它们

我发现x.so和y.so都包含一些常用符号(例如T TcpClient)

这是个问题。如果这些符号应该是不同的,那么就不能将这两个库链接在一起——它们是不兼容的

供应商解决此类问题的通常方法是,他们在所有导出的符号(例如,
vendorA\u TcpClient
)上使用不同的、供应商特定的前缀,并隐藏所有其他符号

请注意,这些.so文件是由第三方提供的,我无法更改它们


您可以告诉供应商,您不能使用他们的库,除非他们避免定义不带唯一标识符前缀的符号,并且除非他们解决此问题,否则您不会向他们付款。供应商在这样做时通常会变得非常敏感。

您认为为什么功能没有得到解决?这是不可能的。如果没有调用它,原因是没有代码路径调用它。原因可能是x.so和y.so定义了相同的符号,而thsat的执行路径取决于使用该符号的哪个版本。顺便说一下,使用
nm
在对象文件中查找符号,直接对对象进行grepping是没有信息的;我说它不是正确的。确实,x.so和y.so包含公共符号。到底有没有办法告诉ld使用哪一个呢?你说过只有一个函数,这意味着它是正确的。有几个重复的def。这也是麻烦的征兆。您可能无法同时使用这两个符号。因此,加载的第一个符号将在整个程序中使用。在您的情况下,这可能有效,也可能无效。除了尝试(答案当然永远不会确定)之外,没有其他方法可以判断。不幸的是,供应商不愿意更改他们的.so文件,因为这些文件已发布给许多客户,而且QA速度慢且风险大。他们只是互相指责。。。他们的bintool是否可以更改符号名称?对于这两个供应商也是如此,尽管TcpClient出现在他们的.so文件中,但它完全是内部的,从未在供应商API中公开过。我想知道这是否有关系,因为linker不需要解决它。所以他们发布了内部符号暴露的库,然后拒绝更改它们,因为他们的客户开始依赖于这些他们本来不应该看到的符号?美好的