Get reason that LoadLibrary cannot load DLL
在 Linux 和 Mac 上,当使用
1 | dlopen failed: cannot locate symbol"foo" |
在 Windows 上,当使用
我想出了一个使用 MSYS2 终端的方法。其他方法可能适用于 GUI 软件。
一个主要的警告是,这不能在纯 C/C 中完成并为最终用户发布。它仅供开发人员使用,但总比没有好。
通过下载 Windows SDK 并取消选中除调试工具之外的所有内容来安装 Windows 调试工具。
我可能是错的,但似乎安装此软件会在 Windows 内核中安装一个挂钩,以允许
以管理员身份打开MSYS2 Mingw64终端并运行
1 | '/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/gflags.exe' -i main.exe +sls |
这会将以下内容打印到终端以确认注册表已更改。
1 2 | Current Registry Settings for main.exe executable are: 00000002 sls - Show Loader Snaps |
如果您需要撤消,请使用
然后运行 ??
但由于某种原因,使用 MSYS2 的 gdb 运行二进制文件允许将调试信息打印到 stderr。
使用 MSYS2 安装
搜索类似于以下内容的部分。
1 2 3 4 5 6 7 8 | warning: 1ec8:43a0 @ 764081125 - LdrpNameToOrdinal - WARNING: Procedure"foo" could not be located in DLL at base 0x000000006FC40000. warning: 1ec8:43a0 @ 764081125 - LdrpReportError - ERROR: Locating export"foo" for DLL"C:\\whatever\\plugin.dll" failed with status: 0xc0000139. warning: 1ec8:43a0 @ 764081125 - LdrpGenericExceptionFilter - ERROR: Function LdrpSnapModule raised exception 0xc0000139 Exception record: .exr 00000000050BE5F0 Context record: .cxr 00000000050BE100 warning: 1ec8:43a0 @ 764081125 - LdrpProcessWork - ERROR: Unable to load DLL:"C:\\whatever\\plugin.dll", Parent Module:"(null)", Status: 0xc0000139 warning: 1ec8:43a0 @ 764081171 - LdrpLoadDllInternal - RETURN: Status: 0xc0000139 warning: 1ec8:43a0 @ 764081171 - LdrLoadDll - RETURN: Status: 0xc0000139 |
太棒了!它说
虽然 Remy Lebeau 的回答在技术上是正确的,但在 Windows 平台上仍然可以通过 GetLastError() 确定丢失的符号。要了解究竟缺少什么,了解术语至关重要。
符号:
When a DLL is compiled, it's functions are referenced by symbols.
These symbols directly relate to the functions name (the symbols are
represented by visible and readable strings), its return type, and
it's parameters. The symbols can actually be read directly through a
text editor although difficult to find in large DLLs.DLL Symbols - C++ Forum
缺少符号意味着无法找到其中的函数。如果在使用 GetProcAddress() 之前发生此错误,则可能由于缺少先决条件而无法加载任意数量的函数。这意味着您尝试加载的库可能还需要第一个无法加载的库。这些依赖级别可能会持续到未知数量的层,但 GetLastError() 可以确定的唯一答案是缺少符号。一种这样的方法是使用 Dependency Walker 来确定第一个库所需的缺失库。一旦所有需要的库都可用并且可以被该库找到(可以是它自己的蠕虫罐),该库就可以通过 LoadLibrary() 加载。