MS VC 链接器 (link.exe):为什么没有针对 32/64 位 CPU 架构不匹配的警告?

发布于 2024-12-12 18:22:30 字数 3086 浏览 1 评论 0原文

(更新:根据汉斯的建议,这里有一个 改进 link.exe 行为的建议,以及如果你在那里有帐户,你可以投票。)


好吧,我是个傻瓜。一月份,我在我的计算机 Win7 Pro 64 位上安装了 Oracle。我安装的是64位版本。昨天,我尝试使用 MSVC Express 编译并链接一个小型测试程序 oci1.coci.hoci.lib

cl /nologo /c /I%ORACLE_HOME%\oci\include oci1.c
link /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib

我的尝试一直失败 LNK2019,这意味着 函数“function”中引用的外部符号“symbol”无法解析。当然,有问题的符号 (_OCIEnvCreate) 是由 oci.lib 提供的,因此链接器应该能够解析它。

我终于意识到它无法工作,因为我的编译器只是 32 位,而导入库是 64 位。如果您是个傻瓜并且不知道或不记得,那么您可以使用 dumpbin 实用程序查看它:

$ dumpbin /headers %ORACLE_HOME%\oci\lib\msvc\oci.lib | head
File Type: LIBRARY
FILE HEADER VALUES
        8664 machine (x64)

$ dumpbin /headers oci1.obj | head
File Type: COFF OBJECT
FILE HEADER VALUES
         14C machine (x86)

到目前为止,一切都很好。但我浪费了一些时间,并希望避免重复这种经历。

虽然 LNK2019 错误消息并非不正确,但它并不会引导您走向正确的方向。没有任何警告表明您正在尝试链接不同 CPU 架构的二进制文件。

请注意,当您指定 X64 架构时,系统会提醒您指定了 X86 二进制文件:

$ link /machine:x64 /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib
oci1.obj : fatal error LNK1112:
Modul-Computertyp "X86" steht in Konflikt mit dem Zielcomputertyp "x64".

但是当您显式或隐式指定 X86 架构时,没有如此精确的警告:

$ link /machine:x86 /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib
oci1.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol
  "_OCIEnvCreate" in Funktion "_main".
oci1.exe : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.

我刚刚找到了 /VERBOSE 切换到 link.exe,使用时提示没有符号可以在我的 64 位 oci.lib 中找到。

您是否可以打开其他选项来使链接过程更加,呃,万无一失?


更新:根据 Hans 的回答,我在 32 位导入库上运行了 dumpbin,名称显示如下:

$ dumpbin /exports D:\Opt\MySQL5.5\lib\libmysql.lib
_load_defaults
_myodbc_remove_escape@8
_mysql_affected_rows@4
_mysql_autocommit@8
_mysql_change_user@16
_mysql_character_set_name@4

而 64 位 OCI 导入库中的名称我正在处理这里出现未修饰的:

OCIXmlDbFreeXmlCtx
OCIXmlDbInitXmlCtx
ORLRconNativeInt
ORLRvalNativeInt
OraCoreIsPhysicalRawFile
OraMemAlloc

关于 X86 调用约定的维基百科

在 Windows 上下文中编译 x64 架构时(无论是 使用 Microsoft 或非 Microsoft 工具),只有一个调用 约定 - 此处描述的约定,因此 stdcall、thiscall、cdecl、 fastcall 等现在都是一样的。

还与有关名称修改的文章相关。

现在对我来说很有意义。一种且唯一的调用约定,因此不需要名称修改,因此在针对 X86 进行编译时,根据 cdecl 没有前导下划线。

(Update: As per Hans' suggestion, here's a suggestion to improve link.exe's behaviour, and you can vote for it if you have an account over there.)


Okay, I'm a fool. In January I installed Oracle on my computer, Win7 Pro 64 Bit. I installed the 64 Bit version. Yesterday, using MSVC Express, I tried to compile and link a small test programm oci1.c against oci.h and oci.lib.

cl /nologo /c /I%ORACLE_HOME%\oci\include oci1.c
link /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib

My attempts kept failing with LNK2019, which means unresolved external symbol 'symbol' referenced in function 'function'. The symbol in question (_OCIEnvCreate) is, of course, provided by oci.lib, so the linker should be able to resolve it.

It finally dawned on me that it couldn't work because my compiler is 32 bit only, and the import library is 64 bit. If you're a fool and you don't know or remember, then you can see it using the dumpbin utility:

$ dumpbin /headers %ORACLE_HOME%\oci\lib\msvc\oci.lib | head
File Type: LIBRARY
FILE HEADER VALUES
        8664 machine (x64)

$ dumpbin /headers oci1.obj | head
File Type: COFF OBJECT
FILE HEADER VALUES
         14C machine (x86)

So far, so good. But I wasted some time and would like to avoid repeating that experience.

While not incorrect, the LNK2019 error message doesn't lead you straight in the right direction. There's no warning that you're attempting to link binaries for different CPU architectures.

Note that when you specify the X64 architecture, you are alerted to the fact that you specified X86 binaries:

$ link /machine:x64 /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib
oci1.obj : fatal error LNK1112:
Modul-Computertyp "X86" steht in Konflikt mit dem Zielcomputertyp "x64".

But there is no such precise warning when you specify the X86 architecture, explicitly or implicitly:

$ link /machine:x86 /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib
oci1.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol
  "_OCIEnvCreate" in Funktion "_main".
oci1.exe : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.

I just found the /VERBOSE switch to link.exe, which when used hints that no symbols are found in my 64 bit oci.lib.

Are there other options you can turn on to make the linking process more, eh, fool-proof?


Update: As per Hans' answer, I ran dumpbin on a 32 bit import library, and the names appear as follows:

$ dumpbin /exports D:\Opt\MySQL5.5\lib\libmysql.lib
_load_defaults
_myodbc_remove_escape@8
_mysql_affected_rows@4
_mysql_autocommit@8
_mysql_change_user@16
_mysql_character_set_name@4

Whereas the names in the 64 bit OCI import library that I'm dealing with here appear undecorated:

OCIXmlDbFreeXmlCtx
OCIXmlDbInitXmlCtx
ORLRconNativeInt
ORLRvalNativeInt
OraCoreIsPhysicalRawFile
OraMemAlloc

Wikipedia regarding X86 calling conventions:

When compiling for the x64 architecture in a Windows context (whether
using Microsoft or non-Microsoft tools), there is only one calling
convention — the one described here, so that stdcall, thiscall, cdecl,
fastcall, etc., are now all one and the same.

Also relevant the article on name mangling.

Makes sense to me now. One and only calling convention, hence no name mangling necessary, hence no leading underscore as per cdecl when compiling for X86.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

清风无影 2024-12-19 18:22:30

我认为它只是在检查二进制兼容性之前抱怨缺少符号。这通常会首先发生,x64 符号没有前导下划线,因为 x64 没有任何调用约定。除非您使用 Microsoft 导入库,否则它们根本不会修饰符号。

但我非常同意,首先解决兼容性错误会更有成效。不知道实施起来有多难。询问那些知道并且可以使其像这样工作的人,将功能请求发布到 connect.microsoft.com

I think it simply complains about the missing symbol before getting around to checking the binary compatibility. That will commonly happen first, x64 symbols don't have the leading underscore since x64 doesn't have any calling conventions. Unless you use Microsoft import libraries, they don't decorate the symbols at all.

But I very much agree, getting the compatibility error first would be much more productive. No idea how hard that is to implement. Ask the guys who know and can make it work like that, post a feature request to connect.microsoft.com

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文