不同的 MinGW-w64 版本会中断 DLL 加载
Different MinGW-w64 version breaks DLL loading
我有一个 open-source 游戏项目,主要是在 Ubuntu 下开发的。最近我将它移植到 Windows,只包含一些小的调整,然后为 Windows 构建它,因为我只使用了 cross-platform 库和功能。
为了构建它,最初我 cross-compiled 使用 Ubuntu 的 19.04 存储库中的 MinGW-w64,它的效果非常好。这是它报告的版本:
$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 9.2-posix 20191008
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
当我更新到 Ubuntu 20.04 时,MinGW-w64 的版本号出现了一个小问题:
$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 9.3-posix 20200320
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
更新破坏了我的构建,因为新版本的 MinGW-w64 生成的可执行文件无法运行。在 Windows 机器上执行时,它无法从其 DLL 依赖项中找到符号,并且出现以下弹出错误:
错误消息的英文版应翻译为(填充变量):
glome.exe - Entry Point Not Found
The procedure entry point ogg_page_bos could not be located in the dynamic link library «path to glome.exe».
这里需要注意的有趣点是:
- 它把glome.exe当作一个DLL,不同于我在网上找到的所有错误实例,它把可执行文件放在标题上,但实际的DLL在body消息;
- 所需的符号可以在配套文件 libogg-0.dll;
中找到
- 如果我 运行 在 Linux 上使用 Wine,它就可以工作;
- 如果我将二进制 glome.exe 与 Ubuntu 19.10 中内置的交换,它就可以工作;
- 两个版本(Ubuntu 19.10 和 Ubuntu 20.04)使用由 CMake 生成的完全相同的编译器参数。
这是游戏其中一个文件的编译命令行(文件很多,但都是同一个编译方式):
cd /home/lucas/glome/ubuntu-20.04-win-build/src/sdl && /usr/bin/x86_64-w64-mingw32-g++-posix @CMakeFiles/glome.dir/includes_CXX.rsp -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ -g -std=gnu++17 -o CMakeFiles/glome.dir/input.cpp.obj -c /home/lucas/glome/src/src/sdl/input.cpp
其中 CMakeFiles/glome.dir/includes_CXX.rsp
仅包含 -I
个指令:
-I/home/lucas/glome/src/src/common/. -I/home/lucas/glome/src/external/concurrentqueue -I/home/lucas/glome/ubuntu-20.04-win-build/src -I/home/lucas/glome/src/src/sdl
可执行文件的链接命令是:
/usr/bin/x86_64-w64-mingw32-g++-posix -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ -g -Wl,--whole-archive CMakeFiles/glome.dir/objects.a -Wl,--no-whole-archive -o glome.exe -Wl,--out-implib,libglome.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/glome.dir/linklibs.rsp
其中 CMakeFiles/glome.dir/linklibs.rsp
包含:
../common/libcommon.a -lopengl32 -lglu32 -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ /home/lucas/glome/windows-deps/OpenAL-1.1-SDK/libs/Win64/OpenAL32.lib /home/lucas/glome/windows-deps/glew-2.1.0/lib/Release/x64/glew32.lib /home/lucas/glome/windows-deps/opusfile/lib/libopusfile.a /home/lucas/glome/windows-deps/opus/lib/libopus.dll.a /home/lucas/glome/windows-deps/libogg/lib/libogg.dll.a -L/home/lucas/glome/windows-deps/SDL2-2.0.12/lib/x64/ -lSDL2main -lSDL2 -static-libgcc -static-libstdc++ -Wl,-allow-multiple-definition -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
除了路径(ubuntu-20.04-win-build
vs ubuntu-19.10-win-build
)之外,编译和链接命令完全相同,使用相同的参数从相同的CMakeLists.txt
.[=24生成=]
问题:
- 为什么 Ubuntu 20.04 构建适用于 Wine 但不适用于 Windows,而 Ubuntu 19.10 构建适用于两者?
- 如何修复 Ubuntu 20.04 版本以在 Windows 上运行?
在 mingw-w64 IRC 频道闲逛后,那里的人建议我在依赖跟踪器中打开可执行文件,这突出了工作二进制文件和损坏二进制文件之间的巨大差异:它看起来像是从一个 DLL 中“泄漏”的符号要求进入另一个不相关的 DLL。
是什么促使那里的人们仔细研究 DLL 导入库。特别是,我通过 MSVC 生成的导入库 link 对某些 DLL 进行了攻击,即:glew32.lib
、OpenAL32.lib
和 SDL2.lib
.
似乎 GNU ld
在处理从 MSVC 导入库时遇到问题,修复只是 link 直接针对 DLL 文件,在这种情况下,符号加载代码由 ld
本身(这实际上是一个更好的支持操作:如果可能,总是 link 直接针对 .dll,GNU 工具链中不需要导入库)。
我不知道为什么它以前能工作,显然我使用的版本在 GNU ld
中出现了回归。
我有一个 open-source 游戏项目,主要是在 Ubuntu 下开发的。最近我将它移植到 Windows,只包含一些小的调整,然后为 Windows 构建它,因为我只使用了 cross-platform 库和功能。
为了构建它,最初我 cross-compiled 使用 Ubuntu 的 19.04 存储库中的 MinGW-w64,它的效果非常好。这是它报告的版本:
$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 9.2-posix 20191008
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
当我更新到 Ubuntu 20.04 时,MinGW-w64 的版本号出现了一个小问题:
$ x86_64-w64-mingw32-g++-posix --version
x86_64-w64-mingw32-g++-posix (GCC) 9.3-posix 20200320
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
更新破坏了我的构建,因为新版本的 MinGW-w64 生成的可执行文件无法运行。在 Windows 机器上执行时,它无法从其 DLL 依赖项中找到符号,并且出现以下弹出错误:
错误消息的英文版应翻译为(填充变量):
glome.exe - Entry Point Not Found
The procedure entry point ogg_page_bos could not be located in the dynamic link library «path to glome.exe».
这里需要注意的有趣点是:
- 它把glome.exe当作一个DLL,不同于我在网上找到的所有错误实例,它把可执行文件放在标题上,但实际的DLL在body消息;
- 所需的符号可以在配套文件 libogg-0.dll; 中找到
- 如果我 运行 在 Linux 上使用 Wine,它就可以工作;
- 如果我将二进制 glome.exe 与 Ubuntu 19.10 中内置的交换,它就可以工作;
- 两个版本(Ubuntu 19.10 和 Ubuntu 20.04)使用由 CMake 生成的完全相同的编译器参数。
这是游戏其中一个文件的编译命令行(文件很多,但都是同一个编译方式):
cd /home/lucas/glome/ubuntu-20.04-win-build/src/sdl && /usr/bin/x86_64-w64-mingw32-g++-posix @CMakeFiles/glome.dir/includes_CXX.rsp -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ -g -std=gnu++17 -o CMakeFiles/glome.dir/input.cpp.obj -c /home/lucas/glome/src/src/sdl/input.cpp
其中 CMakeFiles/glome.dir/includes_CXX.rsp
仅包含 -I
个指令:
-I/home/lucas/glome/src/src/common/. -I/home/lucas/glome/src/external/concurrentqueue -I/home/lucas/glome/ubuntu-20.04-win-build/src -I/home/lucas/glome/src/src/sdl
可执行文件的链接命令是:
/usr/bin/x86_64-w64-mingw32-g++-posix -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ -g -Wl,--whole-archive CMakeFiles/glome.dir/objects.a -Wl,--no-whole-archive -o glome.exe -Wl,--out-implib,libglome.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/glome.dir/linklibs.rsp
其中 CMakeFiles/glome.dir/linklibs.rsp
包含:
../common/libcommon.a -lopengl32 -lglu32 -march=haswell -mtune=generic -Ofast -fno-fat-lto-objects -flto=12 -I/home/lucas/glome/windows-deps/opusfile/include/opus/ -I/home/lucas/glome/windows-deps/opus/include/opus/ -I/home/lucas/glome/windows-deps/libogg/include/ogg/ -I/home/lucas/glome/windows-deps/glew-2.1.0/include/ -I/home/lucas/glome/windows-deps/OpenAL-1.1-SDK/include -I/home/lucas/glome/windows-deps/libogg/include -I/home/lucas/glome/windows-deps/SDL2-2.0.12/include/ -I/home/lucas/glome/windows-deps/boost_1_72_0/ /home/lucas/glome/windows-deps/OpenAL-1.1-SDK/libs/Win64/OpenAL32.lib /home/lucas/glome/windows-deps/glew-2.1.0/lib/Release/x64/glew32.lib /home/lucas/glome/windows-deps/opusfile/lib/libopusfile.a /home/lucas/glome/windows-deps/opus/lib/libopus.dll.a /home/lucas/glome/windows-deps/libogg/lib/libogg.dll.a -L/home/lucas/glome/windows-deps/SDL2-2.0.12/lib/x64/ -lSDL2main -lSDL2 -static-libgcc -static-libstdc++ -Wl,-allow-multiple-definition -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
除了路径(ubuntu-20.04-win-build
vs ubuntu-19.10-win-build
)之外,编译和链接命令完全相同,使用相同的参数从相同的CMakeLists.txt
.[=24生成=]
问题:
- 为什么 Ubuntu 20.04 构建适用于 Wine 但不适用于 Windows,而 Ubuntu 19.10 构建适用于两者?
- 如何修复 Ubuntu 20.04 版本以在 Windows 上运行?
在 mingw-w64 IRC 频道闲逛后,那里的人建议我在依赖跟踪器中打开可执行文件,这突出了工作二进制文件和损坏二进制文件之间的巨大差异:它看起来像是从一个 DLL 中“泄漏”的符号要求进入另一个不相关的 DLL。
是什么促使那里的人们仔细研究 DLL 导入库。特别是,我通过 MSVC 生成的导入库 link 对某些 DLL 进行了攻击,即:glew32.lib
、OpenAL32.lib
和 SDL2.lib
.
似乎 GNU ld
在处理从 MSVC 导入库时遇到问题,修复只是 link 直接针对 DLL 文件,在这种情况下,符号加载代码由 ld
本身(这实际上是一个更好的支持操作:如果可能,总是 link 直接针对 .dll,GNU 工具链中不需要导入库)。
我不知道为什么它以前能工作,显然我使用的版本在 GNU ld
中出现了回归。