c++ - 如何检查为什么链接需要某些符号?

标签 c++ gcc linker clang++

这个问题很麻烦,让我们尝试一下简短的版本: 通常当你失败时 unresolved symbol reference这是相当困难的,在这里你调用链接器找不到的东西。您只需向链接器提供库,它就可以工作了。有时,在某些情况下,当你把头撞在墙上时,不明白为什么链接器在这里或那里想要这个符号,它没有被调用,至少没有直接调用。是否有一个工具/链接器开关可以解释为什么它认为“此处”需要该符号?

原问题: 这都是关于静态链接的。我有一个小实用程序,几行代码,几个包含内容。该实用程序与名为 lib1 的库静态链接。可以说lib1依赖于另一个库 lib2 ,自 lib1使用符号sym1来自lib2 。但是没有任何使用 sym1来自lib2是从实用程序中使用/调用的,也不是 lib1 中的任何内容。这可能取决于 lib2 。然而,上述的小实用程序失败了,并显示 sym1 的未解析符号。 。第一个问题是为什么?因为,在实用程序中 sym1任何地方都不需要,甚至不需要 lib1 中的符号使用 sym1在实用程序中使用时,为什么链接器首先要费心寻找这个符号?第二个问题,包含链有可能引入符号sym1到我的实用程序,然后它回答“为什么”,但不应该引入它(至少没有明显的原因),所以第二个问题是我如何找到为什么链接器认为实用程序需要 sym1来自lib2

什么/何时/为什么:Linux、C/C++、GCC-9/Clang-9

最佳答案

好吧,显然我在没有看到代码和错误消息的情况下设法回答了问题。是时候开设我的 psi 咨询公司了。

关于 Linux/ELF 目标上的链接,重要的是要记住链接器在尝试满足/解析符号时正在合并(并复制到最终可执行文件)部分(也称为段)。通常应用程序有.text(代码段)、.rodata(只读数据)段、.data(读/写初始化数据)段、.bss(未初始化数据)等。因此,如果需要符号,则可以在三个函数之间在一个编译文件中,将选择文件的整个 .text 部分。如果未使用但存在于部分函数中,则调用其他内容,链接器将开始搜索“其他内容”来满足,即使它与应用程序无关。

另外,还有一些 C++ 特有的东西:对于具有虚函数的类,编译器会生成 vtable,其中包含指向每个虚函数的指针,并将该表移动到 .rodata 部分。注意,那是什么 我们认为代码实际上最终位于(只读)DATA 部分。

如果您定义了除一个之外的所有虚拟函数,链接器很可能会发出错误消息,例如

/tmp/cc5YTcBb.o:(.rodata._ZTV3CL1[_ZTV3CL1]+0x18): undefined reference to `CL1::fnc2()

您可以看到问题出在 .rodata,而不是 .text。

这个故事的寓意:将代码和数据切成大量可能的最小部分/段,即链接原子。理想情况下,每个函数都有自己的部分,以及初始化或 r/o 数据。

最后一步是指示链接器(通过 -Wl 选项)丢弃(垃圾收集)所有未使用的部分。

一般来说,链接器会使用更多的 RAM,链接阶段可能会更慢,但应用程序会更小、更快。

命令行使用,看看GCC手册wrt选项含义。

g++ -fdata-sections -ffunction-sections -fipa-pta main.cpp -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed

关于c++ - 如何检查为什么链接需要某些符号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62450033/

相关文章:

c++ - openmp随机只使用一个核心

c - 加载使用另一个共享库的共享库

gcc - 向量按位且在GCC上具有恒定值

c++ - 有没有办法忽略未使用的 undefined reference ?

xamarin - 强制(或友好地询问)链接器链接掉特定程序集

c++ - 初始化指向常量数组的指针

c++ - Windows 句柄的 Getter

c++ - if/switch 中的声明

gcc - 如何强制 GCC 将 128 位/256 位结构作为 xmm/ymm 寄存器中的函数参数传递?

xcode - 构建错误重复符号 arclite.o