查找导致未定义引用错误的源代码行

7

在使用C/C++编程时,迟早会遇到"未定义的引用错误"。这通常是由于缺少库文件导致的,大多数情况下只需要链接上缺失的库文件即可在几秒钟内解决这些错误。

然而,当我们使用模板并将声明和实现分别放在不同的文件中时,可能会出现由于"意外"的模板实例化而导致的未定义引用错误。不幸的是,我们现在得到的所有信息都只是一个"未定义的引用错误"实例,没有任何可能提示错误原因的线索,例如调用者的行号等。

我想知道的是:是否有一种简单的方法来找出调用函数/模板并导致未定义引用错误的实际源代码行?


2
通常会给出函数的名称,只要它被称为相对独特的东西,你就可以使用 grep -n 来获取行号... 但是如果你有400个名为 size() 的函数,那可能帮助不大... - Mats Petersson
1
这不仅仅是解缠符号名称的问题吗?但是我想这取决于你所说的神秘的“C/C++”是什么意思。 - Kerrek SB
只需在文件中使用 grep 命令查找未定义的标识符。 - Captain Obvlious
3
仅仅说用grep查找函数并不能解决问题。可能会存在遗漏作用域解析运算符导致成员函数未定义,makefile或项目中未正确包含文件,缺少编译器特定的导出声明,忘记使用extern等因素。使用grep能找到其中一些问题,但并不是全部问题,而且并非所有安装了GCC的系统都有grep命令。真正的问题在于如何排除这些棘手的情况。 - Sqeaky
1
这不仅仅是一个解缠问题,例如实例化模板可能是原始源代码中难以发现的符号。可以使用诸如grep或一般的“在文件中查找[XYZ]”之类的工具来查找错误。我只是好奇是否有办法让编译器/链接器工具链提示我正确的方向,而不是自己做所有事情。也许由于编译器和链接器工具和步骤的分离,这是不可能的,但从理论上讲,工具链应该能够提供更多信息性的消息。 - Arvid Terzibaschian
发现有一个类似的问题,有匹配的答案: https://dev59.com/jHDYa4cB1Zd3GeqPDLBg?rq=1 - Arvid Terzibaschian
1个回答

5

如我在回答这个问题时所提到的,能否直接获取导致链接错误的行数取决于编译器是否发出了所有必要的信息。

首先,以下是我遇到过的导致您看到的行为的情况:

  • 编译器发出有误的调试信息(在某些情况下进行优化的 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 的情况)。

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