更改 Windows DLL 加载顺序? (加载顺序,不是搜索顺序)

发布于 2024-11-15 20:59:05 字数 2060 浏览 3 评论 0原文

假设我有一个可执行文件:app.exe

我在此可执行文件中使用了 2 个不同的第 3 方 DLL:foo.dll bar.dll 和应用程序必须隐式链接到这些 DLL,也就是说我无法使用 ::LoadLibrary 来加载它们。

(注意:并不是我不能调用 LoadLibrary,而是这些 DLL 需要静态链接(带有 __declspec(dllexport) 的 C++ DLL),所以我调用 LoadLibrary code>没有任何意义,因为可执行加载程序已经调用了它。)

这两个 DLL 彼此之间没有任何依赖关系,也就是说,它们的加载顺序是据我所知未定义(并且应该是不相关的)。 (两者的依赖关系基本上只依赖于标准的 Windows dll(kernel32、msvcrt 等)。

我现在遇到的问题是我希望控制这些 DLL 的加载顺序,即我希望 foo.dll 始终是 在 bar.dll 之前加载 (DLL_PROCESS_ATTACH)。

是否可以以某种方式告诉 Windows DLL 加载器先加载一个 DLL?

编辑:检查 DLL可执行文件的加载顺序,可以使用 DUMPBIN.exe 实用程序:(只需启动 Visual Studio 命令提示符)

编辑:根据 这个答案 / 此博客条目, NT 加载器确实按顺序遍历导入部分(这将导致独立 DLL 按照它们在导入部分中出现的顺序加载。)

C:\path\to\program> dumpbin /IMPORTS app.exe | grep -i \.dll
  MSVCR80D.dll
  KERNEL32.dll
  OLEAUT32.dll
  MSVCP80D.dll
  foo.dll
  bar.DLL

此输出意味着 MSVCR80D。动态链接库(及其依赖项[a])将首先加载,bar.DLL 将最后加载。卸载将以相反的顺序进行。

还没有发现的是如何影响这个加载顺序 ...


(注释)

[a]:这当然意味着例如kernel32.dll将是首先加载,因为 msvcr80d.dll 将依赖于 kernel32.dll。


根据一些要求,我为此添加了一个理由:(但是,我仍然对此普遍感兴趣。我知道如何解决 MFC 问题。

Microsoft MFC DLL 的调试版本内置了内存泄漏检测功能。(据我所知,它与 _CrtSetDbgFlag 和相关工具。)

MFC debug DLL 在卸载时将转储所有未释放的内存。现在,如果您的进程中有第二个独立于 MFC 的 DLL,并且该第二个 DLL 在 DLL_PROCESS_DETACH 上释放内存,则当 MFC DLL 在其他 DLL 之前卸载时,MFC 报告机制将报告错误的内存泄漏。

如果可以确保调试 MFC DLL 在所有独立 DLL 中首先加载/最后卸载,那么所有其他 DLL 都已经在自身之后清理完毕,并且 MFC 不会报告错误泄漏。

Say I have one executable: app.exe

I use 2 different 3rd party DLLs in this executable: foo.dll bar.dll and the Application must link implicitly to these DLLs, that is I cannot use ::LoadLibrary to load them.

(Note: It's not that I cannot call LoadLibrary, but these DLLs require static linking (C++ DLLs with __declspec(dllexport)), so me calling LoadLibrarydoesn't make any sense because the excutable loader has already called it.)

These two DLLs do not have any dependencies on each other, that is, their load order is undefined as far as I can tell (and should be irrelevant). (Dependencies of both are basically only on the standard windows dlls (kernel32, msvcrt, etc.)

I now have the problem that I wish to control the load order of these DLLs, that is I wish that foo.dll is always loaded (DLL_PROCESS_ATTACH) before bar.dll.

Is it somehow possible to tell the Windows DLL Loader to load one DLL before another?

Edit: To check the DLL load order of an executable, one can use the DUMPBIN.exe utility: (Just launch the Visual Studio Command Prompt)

Edit: As per this answer / this blog entry, the NT Loader does walk the import section sequentially. (Which will result in independent DLLs being loaded in the order they appear in the import section.)

C:\path\to\program> dumpbin /IMPORTS app.exe | grep -i \.dll
  MSVCR80D.dll
  KERNEL32.dll
  OLEAUT32.dll
  MSVCP80D.dll
  foo.dll
  bar.DLL

This output means that MSVCR80D.dll (and its dependecies[a]) will be loaded first and that bar.DLL will be loaded last. Unload will happen in reverse order.

What I haven't found out yet is how to influence this load order ...


(Notes)

[a] : This means of course that e.g. kernel32.dll will be loaded first, because msvcr80d.dll will depend on kernel32.dll.


As per some requests, I'm adding a rationale for this: (But please, I'm still interested in this generally. I know how to work around the MFC problem.)

The Microsoft MFC DLL in it's debug version has memory leak detection built in. (As far as I can tell, it's the same mechanism used by _CrtSetDbgFlag and related tools.)

The MFC debug DLL will dump all unfreed memory when it is unloaded. Now, if you have a second DLL in your process, that is independent of MFC, and this second DLL deallocates memory on DLL_PROCESS_DETACH, the MFC reporting mechanism will report false memory leaks, if the MFC DLL is unloaded before the other dll.

If one could make sure that the debug MFC DLL is loaded first / unloaded last of all independent DLLs, then all other DLLs would already have cleaned up after themselves and MFC wouldn't report false leaks.

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

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

发布评论

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

评论(4

初吻给了烟 2024-11-22 20:59:05

我还没有找到的是如何影响这个加载顺序......

我不知道为什么我没有尝试这个,但似乎结果模块的导入部分顺序确实取决于 < 的顺序code>lib 文件被提供给链接器。

Configuration Properties -> Linker -> Additional Dependencies ...

这里首先列出的 lib 文件也是导入部分中的第一个,意味着加载器将按顺序导入这些文件(模依赖项) 。

因此,回答这一部分: 只需以正确的顺序向链接器提供 lib 文件即可。

注意:我已经在 VS2005 上尝试过,它似乎可以工作。我不知道是否在某处记录了这一点,也不知道它是否在新版本的 VC++ 中发生了变化。


更新:虽然当时它可以工作,但今天我遇到了加载顺序受到链接器命令行顺序影响的情况 lib 文件。 (仍然)不知道为什么。 (仍然是VS2005)

但是,我通过将有问题的DLL添加到延迟加载的DLL列表中,设法使其工作(就像Macke的回答< /a>)。


What I haven't found out yet is how to influence this load order ...

I have no clue why I hadn't tried this, but it seems the import section order of the resulting module does depend on the order in which the lib files are provided to the linker.

Configuration Properties -> Linker -> Additional Dependencies ...

The lib files listed here first are also first in the import section, meaning the loader will import these in order (modulo dependencies).

So, to answer that part: Just provide the lib files in the correct order to the linker.

Note: I have tried that on VS2005 and it appears to work. I don't know whether that is documented somewhere or if it changed in newer versions of VC++.


Update: While it worked back then, today I hit the case that the load order was not to be influenced by the linker command line order of the lib files. (Still) No clue why. (Still VS2005)

I have however managed to make it work by adding the problematic DLLs to the list of delay loaded DLLs (like in Macke's answer).


帝王念 2024-11-22 20:59:05

这里有一个想法:如何在 app.exe 的链接器选项中将它们标记为“延迟加载的 dll”?

延迟加载将允许您“静态”链接(即不使用 LoadLibrary() 等),但不会加载 DLL 并在实际需要时进行链接。

如果这是一个选项,那么(假设您可以等待这么长时间,即在 main() 之前不要访问 foo/bar dll 函数),您可以在 main() 中访问一个函数(只需获取函数 ptr 或其他东西)首先在 foo.dll 中,哪个会加载它并绑定所有“静态”链接的函数?

(也许 LoadLibrary() 会在需要时触发相同的链接过程。不确定。不过,它在您的代码中看起来会更干净。)

Here's an idea: How about marking them as "Delay Loaded dlls" in the linker options of app.exe?

Delay-loading will allow you to link "statically" (i.e. without LoadLibrary() et.al) but will not load the DLL and do the linking until it's actually needed.

If that is an option, then (assuming you can wait so long, i.e. do not access foo/bar dll functions before main()), you could, in main(), access a function (just fetch a function ptr or something) in foo.dll first, which would load it and bind all "statically" linked functions?

(Maybe LoadLibrary() triggers the same link-when-needed procedure. Not sure. It would look cleaner in your code though.)

若水般的淡然安静女子 2024-11-22 20:59:05

只需将 foo.dll 添加到 bar.dll 的导入表中,操作系统加载程序将处理其余的事情。

您应该能够在没有 bar.dll 源代码的情况下执行此操作,不确定 editbin 工具是否有这样的选项,但这是对PE 文件。

您也许可以使用预加载 DLL 的注册表设置,但我不会这样做,您不希望 foo.dll 加载到不需要它的其他进程中。

Just add foo.dll to the import table of bar.dll, the OS loader will handle the rest.

You should be able to do this without the source code for bar.dll, not sure if the editbin tool has such an option, but this is a fairly trivial edit to the PE file.

You might instead be able to use the registry setting that preloads DLLs, but I wouldn't do that, you don't want foo.dll getting loaded into other processes that don't need it.

眼泪淡了忧伤 2024-11-22 20:59:05

如果您不链接导入库(foo.lib 和 bar.lib),那么加载程序将不会在启动时自动加载 DLL,您可以随时调用 LoadLibrary()。

If you don't link the import library (foo.lib & bar.lib), then the loader will not automatically load the DLLs upon startup and you can call LoadLibrary() whenever you want.

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