【问题标题】:Using MinGW-Builds to compile a 32-bit exe on a 64-bit system -- compiles a 32-bit exe but links against 64-bit DLLs使用 MinGW-Builds 在 64 位系统上编译 32 位 exe - 编译 32 位 exe 但链接到 64 位 DLL
【发布时间】:2025-12-27 23:40:07
【问题描述】:

我正在使用 MinGW-Builds 在 64 位系统上编译 32 位 DLL 和 exe。我正在使用m32 位标志。编译和链接阶段不会产生错误。当我尝试运行该程序时,我得到:

应用程序无法正确启动 (0xc000007b)。单击“确定”关闭应用程序。

我加载了 Dependency Walker 并收到以下错误消息:

错误:发现具有不同 CPU 类型的模块。

确实,Dependency walker 显示我的 DLL 和可执行文件是 32 位的。但是,它链接的其他所有内容都是 64 位的。例如,NTDLL.DLL、MSVCRT.DLL、LIBWINPTHREAD-1.DLL 都标记为 64 位。所以,我相信我没有正确链接 32 位 DLL。

让链接器链接到 32 位 DLL 而不是 64 位 DLL 的命令是什么?

更新

当我运行 32 位 Dependency Walker 配置文件模式时,我到底在寻找什么?我在日志窗口中得到这个输出:

--------------------------------------------------------------------------------
Starting profile on 3/31/2014 at 10:14:41 PM

Operating System: Microsoft Windows NT/2000/XP/2003/Vista based Media Center (64-bit), version 6.01.7601 Service Pack 1
Program Executable: c:\mingw\msys\1.0\home\samuel\projects\bmd2\build\debug\32\testcore\BMD2TESTCORE.EXE
Program Arguments: 
Starting Directory: C:\MinGW\msys\1.0\home\samuel\projects\bmd2\build\debug\32\testcore\
Search Path: C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\MinGW\bin;C:\MinGW\libexec\gcc\x86_64-pc-mingw32\4.7.0;C:\Users\samuel\gcc\bin;C:\Users\samuel\gcc\libexec\gcc\x86_64-pc-mingw32\4.7.0;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Eclipse\adt-bundle\sdk\platform-tools;C:\Program Files\Eclipse\adt-bundle\sdk\tools;C:\Program Files (x86)\QuickTime\QTSystem\;C:\ant\bin;C:\Java\bin;C:\Program Files\TortoiseSVN\bin;C:\Users\samuel\Desktop\work\bmd2\build\debug\lib

Options Selected:
     Simulate ShellExecute by inserting any App Paths directories into the PATH environment variable.
     Log DllMain calls for process attach and process detach messages.
     Log DllMain calls for all other messages, including thread attach and thread detach.
     Hook the process to gather more detailed dependency information.
     Log LoadLibrary function calls.
     Log GetProcAddress function calls.
     Log thread information.
     Use simple thread numbers instead of actual thread IDs.
     Log first chance exceptions.
     Log debug output messages.
     Log a time stamp with each line of log.
     Automatically open and profile child processes.
--------------------------------------------------------------------------------

00:00:00.000: Started "BMD2TESTCORE.EXE" (process 0x1DC) at address 0x00400000 by thread 1.  Successfully hooked module.
00:00:00.000: Loaded "NTDLL.DLL" at address 0x778C0000 by thread 1.  Successfully hooked module.
00:00:00.031: Loaded "KERNEL32.DLL" at address 0x75510000 by thread 1.  Successfully hooked module.
00:00:00.031: Loaded "KERNELBASE.DLL" at address 0x77340000 by thread 1.  Successfully hooked module.
00:00:00.031: DllMain(0x77340000, DLL_PROCESS_ATTACH, 0x00000000) in "KERNELBASE.DLL" called by thread 1.
00:00:00.031: DllMain(0x77340000, DLL_PROCESS_ATTACH, 0x00000000) in "KERNELBASE.DLL" returned 1 (0x1) by thread 1.
00:00:00.031: DllMain(0x75510000, DLL_PROCESS_ATTACH, 0x00000000) in "KERNEL32.DLL" called by thread 1.
00:00:00.046: DllMain(0x75510000, DLL_PROCESS_ATTACH, 0x00000000) in "KERNEL32.DLL" returned 1 (0x1) by thread 1.
00:00:00.046: Injected "DEPENDS.DLL" at address 0x08370000 by thread 1.
00:00:00.078: DllMain(0x08370000, DLL_PROCESS_ATTACH, 0x00000000) in "DEPENDS.DLL" called by thread 1.
00:00:00.093: DllMain(0x08370000, DLL_PROCESS_ATTACH, 0x00000000) in "DEPENDS.DLL" returned 1 (0x1) by thread 1.
00:00:00.093: Loaded "MSVCRT.DLL" at address 0x75C90000 by thread 1.  Successfully hooked module.

【问题讨论】:

  • 您不需要使用清单文件构建,以便在应用程序加载时知道要使用哪个版本的 DLL 吗?如果它们具有相同的名称,Windows 不会区分 32 位或 64 位 DLL。操作系统将尝试加载它找到的第一个,如果模块由于模块的“位数”错误而无法加载,则会给您该错误。 (注意——我是 Visual Studio 用户,不是 MingW,但应该是相同类型的设置)
  • 为了证明我的观点,将这些 32 位 DLL 与您的程序一起复制到本地目录。我敢打赌你的程序正常启动没有错误。
  • 我不确定这是否是您的问题的实际根源。 This 是我的 32 位程序中的 Dependency Walker 的屏幕截图,您可以看到它也显示并抱怨 64 位 DLL,但程序运行良好。
  • 我认为这是一个清单问题,或者在基本层面上,是程序加载时的 DLL 模块搜索问题。基本上,Windows 使用 LoadLibrary 算法进行模块搜索,并尝试加载它找到的第一个与名称匹配的——msdn.microsoft.com/en-us/library/windows/desktop/… 这就是为什么如果我们有 32 位和 64 位版本(或在至少我希望大多数人这样做)。为什么 Windows 走这条路线,将它们的 32 位和 64 位 DLL 命名相同,我不知道...
  • @DavidHeffernan - 各有各的。我觉得处理名为 MyDLL32.dll 和 MyDLL64.dll 的 DLL 比使用相同的名称更容易。

标签: c++ windows dll compiler-construction mingw


【解决方案1】:

链接时不指定 DLL 的位数。您只需指定 DLL 的名称。由加载程序来查找具有您指定的名称的 DLL。

您命名的两个 DLL,ntdll 和 msvcrt,是系统组件。它们位于 system32 目录中。您的 32 位进程受文件系统重定向器的约束。这意味着当加载器在 system32 中查找时,重定向器会静默地将其映射到 syswow64,即 32 位系统目录。这是透明地发生的,因此加载器会找到 ntdll 和 msvcrt 的 32 位版本。

您报告的错误代码是0xC000007B。那是一个NTSTATUS 错误代码。特别是STATUS_INVALID_IMAGE_FORMAT。这确实是您尝试在 32 位进程中加载​​ 64 位 DLL 时报告的错误。所以看起来这就是正在发生的事情。

您已经使用 Dependency Walker 进行了一些调试。这是一项出色的工作工具,但在您使用它的模式(静态模式)中,它有时会报告误报。听起来您正在使用 64 位版本的 Dependency Walker。使用 32 位版本可能会获得更好的诊断。

话虽如此,您真正需要做的是在 Dependency Walker 的 Profile 模式下运行您的程序。这可以在配置文件菜单下找到。执行此操作时,您将从加载程序获得诊断流,包括加载失败并出现错误STATUS_INVALID_IMAGE_FORMAT 的 DLL 的名称。到那时,应该清楚哪里出了问题。

【讨论】:

  • 不幸的是,depends.exe 配置文件模式很容易中断。为了将它与 .NET 一起使用(作为示例),您必须关闭所有有用的挂钩选项。
  • @BenVoigt 这里没有 .net 的证据。不过,使用 x86 版本进行静态分析可能会奏效。
【解决方案2】:

您使用 Dependency Walker 错误。

64 位版本的 Dependency Walker 不够智能,无法搜索 32 位 DLL 路径(David 的回答解释了在程序运行时如何通过重定向实际使用这些路径)。

您需要使用 32 位 Dependency Walker 来分析 32 位代码。

【讨论】:

  • 这可能会奏效。我会说即使是依赖的静态分析也可能是错误的。唯一 100% 确定的调试方法是动态分析负载。
  • @DavidHeffernan:100% 确定 50% 的时间。其他 50% 的案例,分析本身会引入新的失败。
  • @DavidHeffernan:我可能有观察偏差。脆弱(和棘手)的情况是我更有可能首先尝试分析。失败更令人难忘。