首页
社区
课程
招聘
调试实战 | 解决另外一个链接错误
2023-10-22 20:06 7711

调试实战 | 解决另外一个链接错误

2023-10-22 20:06
7711

缘起

最近,在加班的过程中遇到一个链接错误 —— fatal error LNK1120: 1 unresolved externals。这种错误是老朋友了,对我这种常年写 bug 的老手来说,完全不是事儿,轻松+愉快。

根据以下的排查思路基本上能解决大多数链接错误:

既然报了链接错误,说明编译已经通过了,问题基本出现在库文件上。

有可能是找不到库文件(缺少库,或者库文件搜索路径不对),可以先确认工程配置是否正确或者使用 /verbose:lib 查看链接过程。

也可能是库文件不对(没包含对应的导出符号),可以通过 dumpbin /exports error.lib > error.txt 查看 lib 库中的导出符号。按照以上步骤排查基本上可以解决绝大多数链接错误。

好的,让我们一起来实战一下吧。

说明: 实际项目需要保密,本文的截图是我在本地用测试工程做的。

确保 lib 存在并且路径正确

通过查看工程设置可以得知,依赖的库文件是 TestLNK1120Dll.lib,附加库目录中也添加了这个 lib 所在的路径。肉眼看上去没问题。为了保险(之前遇到过更诡异的错误,配置看上去都对,但是实际的值不对),还是通过 /verbose:lib 选项看一下链接过程。

在对应工程上,右键 -> 属性 -> Configuration Property -> Linker -> Command Line,在 Additional Options 下面输入 /verbose:lib 即可。

link-option-verbose-lib
设置好后,重新编译。可以看到链接时整个库查找过程,如下图。

verbose-lib-link-process
至此,可以确定库文件路径配置没错,那大概率是库文件中的符号与程序中的符号不匹配导致的。

说明: 如果找不到 .lib 文件,报错应该类似下面这样:

fatal error LNK1104: cannot open file 'TestLNK1120Dll.lib'

查看 lib 文件中的导出符号

使用 dumpbin 可以查看 lib 库中的所有导出符号,命令如下:

dumpbin /exports d:\test\TestLNK1120.lib > d:\TestLNK1120.txt

注意: 以上命令需要在 dumpbin.exe 所在目录下执行,或者启动 Developer Command Prompt for VS xxx

然后根据 vs 编译错误提示中的符号在 TestLNK1120.txt 中搜索,应该是没有匹配项目。

搜索报错的符号

确实可以在 TestLNK1120.txt 中根据函数名 GetStaticData 搜到相关记录,但是根据完整的符号名称搜不到。

TestLNK1120.txt 文件中与 GetStaticData 相关的内容是:

?GetStaticData@@YAAAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ (class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > & __cdecl GetStaticData(void))

vs 报错提示是:

TestLNK1120.obj : error LNK2001: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl GetStaticData(void)" (?GetStaticData@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)

让我们对比一下这两个结果哪里不一样。

对比

别看上面的输出很多很乱,其实我们最需要关心的是经过名字改编的符号名。

vs 中经过名字改编后的符号名是

?GetStaticData@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ

lib 库中经过名字改编后的符号名是

?GetStaticData@@YAAAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ

如果仔细看,确实能发现这两个输出结果是不一样的,但是经过编译器处理的符号名非常不适合人类阅读。如果能看到函数原型就太好了。

其实,上面的输出结果既包含了函数原型,又包含了经过名字改编后的符号名。

vs 中的函数名:

class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl GetStaticData(void)

lib 库中的函数名:

class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > & __cdecl GetStaticData(void)

可以发现,lib 库中提供的函数的返回值是引用类型的,而 vs 中函数的返回值是不带引用的。

至此就破案了!

undname 工具

如果只有经过名字改编后的符号名,可以通过微软提供的 undname.exe 工具来翻译成人类友好的名称。

compare-undname

示例工程

可以到 gitee 上下载示例工程。

总结

dumpbin.exe 可以查看 lib 库中的符号信息

undname.exe 可以非常方便的查看未经过编译器处理的函数名


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2023-10-24 13:23 被编程难编辑 ,原因: 上传图片
收藏
点赞3
打赏
分享
最新回复 (8)
雪    币: 19299
活跃值: (28938)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-10-22 23:03
2
1
感谢分享
雪    币: 22979
活跃值: (3332)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
KevinsBobo 8 2023-10-23 09:49
3
0
最近三篇图都挂了
雪    币: 1431
活跃值: (1116)
能力值: ( LV3,RANK:23 )
在线值:
发帖
回帖
粉丝
Black貓①呺 2023-10-23 10:48
4
0
希望把之前发的图片都修复下,看着有点难受
雪    币: 19299
活跃值: (28938)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-10-23 13:48
5
1
图挂了
雪    币: 8511
活跃值: (9112)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
编程难 3 2023-10-24 13:24
6
0
KevinsBobo 最近三篇图都挂了
感谢版主提醒,已经补传了。好像看雪的自动传图功能有 bug,预览的时候能看到图,后面就丢了
雪    币: 8511
活跃值: (9112)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
编程难 3 2023-10-24 13:25
7
0
Black貓①呺 希望把之前发的图片都修复下,看着有点难受
感谢提醒,已经补传了
雪    币: 8511
活跃值: (9112)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
编程难 3 2023-10-24 13:25
8
0
秋狝 图挂了
感谢提醒,已经补传了
雪    币: 8511
活跃值: (9112)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
编程难 3 2023-10-24 13:25
9
0
秋狝 感谢分享
感谢阅读
游客
登录 | 注册 方可回帖
返回