LoadLibrary无法加载DLL的原因

问题描述 投票:1回答:2

[在Linux和Mac上,当使用dlopen()加载链接到另一个库的共享库时,如果由于缺少符号而导致链接失败,则可以使用dlerror()获取缺少符号的名称。它说像

dlopen failed: cannot locate symbol "foo"

[在Windows上,当使用LoadLibrary()加载缺少符号的DLL时,您只能从GetLastError()中获取错误代码,对于该类型的问题,该错误代码始终为127。如何确定缺少的符号,或者来自LoadLibrary()的更详细的错误消息,说明功能为何失败?

c++ winapi loadlibrary
2个回答
0
投票

我想出了一种使用MSYS2端子的方法。 GUI软件也可以使用其他方法。一个主要的警告是,这不能在纯C / C ++中完成并且不能发布给最终用户。它仅适用于开发人员,但总比没有好。

通过下载Windows SDK并取消选中除调试工具以外的所有内容,来安装Debugging Tools for Windows。我可能是错的,但似乎安装此软件会在Windows内核中安装一个钩子,以允许LoadLibrary()将详细信息写入stderr。

以管理员身份打开MSYS2 Mingw64终端并运行

'/c/Program Files (x86)/Windows Kits/10/Debuggers/x64/gflags.exe' -i main.exe +sls

这将以下内容打印到终端以确认注册表已被更改。

Current Registry Settings for main.exe executable are: 00000002
    sls - Show Loader Snaps

如果您需要撤消,请使用-sls而不是+sls,因为我认为更改是在全局范围内针对Windows中所有名为main.exe的程序进行的,而不仅仅是针对您的文件。

然后运行main.exe 应该将调试信息打印到stderr,但是由于我正在调试-mwindows应用程序,因此它不适用于我。

但是由于某些原因,使用MSYS2的gdb运行二进制文件可以将该调试信息打印到stderr。将mingw-w64-x86_64-gdb与MSYS2一起安装并运行gdb ./main.exe,然后键入runr。搜索类似于以下内容的部分。

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

太好了!它说Procedure "foo" could not be located in DLL,所以我们有缺少的符号,就像在POSIX / UNIX的dlopen()中一样。


0
投票

尽管Remy Lebeau的答案在技术上是正确的,但在Windows平台上仍然可以从GetLastError()确定丢失的符号。要了解确切缺少的内容,了解术语至关重要。

符号:

编译DLL时,其功能由符号引用。这些符号与功能名称直接相关(符号为由可见和可读的字符串表示),其返回类型以及它是参数。这些符号实际上可以通过文本编辑器,尽管很难在大型DLL中找到。DLL Symbols - C++ Forum

具有缺失的符号表示无法找到其中的功能。如果在使用GetProcAddress()之前发生此错误,则可能由于缺少先决条件而无法加载任何数量的函数。这意味着您尝试加载的库可能还需要第一个无法加载的库。这些依赖级别可能会持续未知数量的层,但是GetLastError()可以确定的唯一答案是缺少符号。一种这样的方法是使用Dependency Walker确定第一个库所需的缺少的库。一旦所有必需的库都可​​用并且可以通过该库找到(可以是蠕虫自身的罐头),则可以通过LoadLibrary()加载该库。

© www.soinside.com 2019 - 2024. All rights reserved.