6

在使用 C/C++ 编程时,迟早每个人都会面临“未定义的引用错误”。

这通常是由缺少库引起的,并且大多数错误通过链接缺少的库在几秒钟内得到修复。但是,例如,当使用具有单独文件的模板进行声明和实现时,可能会由于“意外”模板实例化而导致未定义的引用。不幸的是,我们现在得到的所有信息都是“未定义的引用错误”的一个实例,没有可能的原因提示,例如调用者的行号等。

我很好奇:有没有一种简单的方法来发现调用函数/模板导致未定义引用错误的实际源代码行?

4

1 回答 1

4

正如我在对这个问题的回答中提到的,获取导致链接错误的行号是否简单取决于编译器是否发出了所有必要的信息。

首先,这些是我遇到的导致您看到的行为的案例:

  • 编译器发出错误的调试信息(solaris studio 12.3 在某些情况下带有调试/优化)
  • 为超出范围的对象执行的析构函数
  • 编译器插入的代码:
    • 堆栈保护器
    • 消毒剂
    • 检测代码以进行调试或分析的其他工具

如果您有类似以下的链接错误,我建议的跟踪它可能会有所帮助:

asdf.o: In function `whatever':
asdf.o(.text+0x1238): undefined reference to `fdsa'

...因为至少你有一个地址可以使用。

首先,尝试addr2line

~ addr2line -e asdf.o 0x1238
# If it works, you'll get:
asdf.cc:N
# If it doesn't work, you'll get:
??:?

如果做不到这一点,请尝试objdump

~ objdump --dwarf=decodedline asdf.o

asdf.o:     file format elf64-x86-64

Decoded dump of debug contents of section .debug_line:

CU: asdf.cc:
File name                           Line number     Starting address
asdf.cc                                       1               0x1234
asdf.cc                                       3               0x1254
asdf.cc                                       5               0x1274

在我在这里给出的完全虚构的示例中,没有.debug_line对应于0x1238(链接器错误中的地址)的条目,因此它可能是编译器魔法(例如,由堆栈保护器或消毒剂之类的东西添加的额外代码),或者希望它与第 1/3 行发生的任何事情有关,因为地址位于这两行之间。

如果这还不足以让您继续:当我想继续进行时,我做了以下事情:

  1. 插入一个链接标志来阻止它去拆解以获得被破坏的符号
  2. 重新编译目标文件,但让它生成程序集
  3. 在程序集中搜索损坏的符号

假设程序集的注释足够好,将缺少的符号 + 来自 + 程序集的信息关联起来应该不难,objdump并且至少修复代码行以开始其余的搜索(假设你还有更多的兔子STL 经常出现的情况)。

于 2014-11-05T21:13:20.120 回答