重新绑定 DLL(或提供适当的默认加载地址)值得麻烦吗?

2021-12-25 00:00:00 windows dll c c++

重新绑定 DLL 意味着修复 DLL,使其首选加载地址是加载器实际能够加载 DLL 的加载地址.

Rebasing a DLL means to fix up the DLL such, that it's preferred load adress is the load address that the Loader is actually able to load the DLL at.

这可以通过诸如 Rebase.exe 之类的工具来实现,也可以通过为所有(自己的)dll 指定默认加载地址来实现,以便它们适合"您的可执行进程.

This can either be achieved by a tool such as Rebase.exe or by specifying default load addresses for all your (own) dlls so that they "fit" in your executable process.

以这种方式管理 DLL 基地址的全部目的是加速应用程序加载.(或者我是这么理解的.)

The whole point of managing the DLL base addresses this way is to speed up application loads. (Or so I understand.)

问题现在是:这样做值得吗?

我有这本书 Windows via C/C++ 由 Richter/Nazarre 提供,他们强烈建议[a]确保加载地址全部匹配,以便加载器不必重新设置加载的 DLL.

I have the book Windows via C/C++ by Richter/Nazarre and they strongly recommend[a] making sure that the load addresses all match up so that the Loader doesn't have to rebase the loaded DLLs.

然而,他们没有争论,如果这将应用程序加载时间加快到任何显着的程度.

They fail to argue however, if this speeds up application load times to any significant amount.

此外,对于 ASLR,这似乎令人怀疑任何值都可以,因为无论如何加载地址都是随机的.

Also, with ASLR it seems dubious that this has any value at all, since the load addresses will be randomized anyway.

是否有任何关于此利弊的确凿事实?

Are there any hard facts on the pro/cons of this?

[a]:在我的 WvC++/第 5 版中,它位于第 568 页的 Rebase Modules 和 Binding Modules 部分.在第 20 章,DLL 高级技术.

[a]: In my WvC++/5th ed it is in the sections titled Rebasing Modules and Binding Modules on pages 568ff. in Chapter 20, DLL Advanced Techniques.

推荐答案

我想自己提供一个答案,尽管 Hans Passant 和其他人的答案 已经很好地描述了权衡.

I'd like to provide one answer myself, although the answers of Hans Passant and others are describing the tradeoffs already pretty well.

最近在我们的应用程序中摆弄了 DLL 基地址后,我将在这里给出我的结论:

After recently fiddling with DLL base addresses in our application, I will here give my conclusion:

我认为,除非你能证明,否则为 DLL 提供一个非默认的基地址是徒劳的.这包括重新调整我的 DLL.

I think that, unless you can prove otherwise, providing DLLs with a non-default Base Address is an exercise in futility. This includes rebasing my DLLs.

  • 对于我控制的 DLL,对于一般的应用程序,每个 DLL 无论如何只会被加载到内存中一次,因此分页文件上的负载应该是最小的.(但请参阅 Michal Burr 在有关终端服务器环境的另一个答案中的评论.)

  • For the DLLs I control, given the average application, each DLL will be loaded into memory only once anyway, so the load on the paging file should be minimal. (But see the comment of Michal Burr in another answer about Terminal Server environment.)

如果为 DLL 提供了一个固定的基地址(没有变基),它实际上会增加地址空间碎片,因为这些地址迟早会不再匹配.在我们的应用程序中,我们为所有 DLL 提供了一个固定的基地址(出于其他遗留原因,而不是因为地址空间碎片)而没有使用 rebase.exe,这显着为我们增加了地址空间碎片,因为您确实无法手动正确设置.

If DLLs are provided with a fixed base address (without rebasing) it will actually increase address space fragmentation, as sooner or later these addresses won't match anymore. In our app we had given all DLLs a fixed base address (for other legacy reasons, and not because of address space fragmentation) without using rebase.exe and this significantly increased address space fragmentation for us because you really can't get this right manually.

变基(通过 rebase.exe)并不便宜.这是构建过程中必须维护和检查的另一个步骤,因此它必须有一些好处.

Rebasing (via rebase.exe) is not cheap. It is another step in the build process that has to be maintained and checked, so it has to have some benefit.

一个大型应用程序总是会在基地址不匹配的情况下加载一些 DLL,因为一些钩子 DLL (AV) 并且因为您没有重新设置第 3 方 DLL(或者至少我不会).

A large application will always have some DLLs loaded where the base address does not match, because of some hook DLLs (AV) and because you don't rebase 3rd party DLLs (or at least I wouldn't).

如果您将 RAM 磁盘用于分页文件,如果加载的 DLL 被分页,您实际上可能会更好:-)

If you're using a RAM disk for the paging file, you might actually be better of if loaded DLLs get paged out :-)

总而言之,我认为 rebase 不值得麻烦 除了像系统 DLL 这样的特殊情况.

So to sum up, I think that rebasing isn't worth the trouble except for special cases like the system DLLs.

我想添加我在 Old New Thing 上找到的历史片段:HowWindows 95 是否重新定义了 DLL? --

I'd like to add a historical piece that I found on Old New Thing: How did Windows 95 rebase DLLs? --

当一个 DLL 需要重新定位时,Windows 95 只会做一个注释DLL 的新基地址,但不会做太多其他事情.真正的当 DLL 的页面最终被换入时,工作发生了.原始页面从磁盘交换,然后应用修复飞到原始页面,从而重新定位它.固定页面是然后映射到进程的地址空间,程序被允许继续.

When a DLL needed to be rebased, Windows 95 would merely make a note of the DLL's new base address, but wouldn't do much else. The real work happened when the pages of the DLL ultimately got swapped in. The raw page was swapped off the disk, then the fix-ups were applied on the fly to the raw page, thereby relocating it. The fixed-up page was then mapped into the process's address space and the program was allowed to continue.

看看这个过程是如何完成的(阅读全文),我个人怀疑变基是邪恶的"立场的一部分可以追溯到 Win9x 和低内存条件的旧时代.

Looking at how this process is done (read the whole thing), I personally suspect that part of the "rebasing is evil" stance dates back to the olden days of Win9x and low memory conditions.

看,现在有一个关于旧新事物的非历史性文章:

在过去,您被劝告要做的一件事就是重新设定基准您的 DLL 使它们都具有不重叠的地址范围,从而避免运行时重定位的成本.这还重要吗现在?

How important is it nowadays to ensure that all my DLLs have non-conflicting base addresses?

Back in the day, one of the things you were exhorted to do was rebase your DLLs so that they all had nonoverlapping address ranges, thereby avoiding the cost of runtime relocation. Is this still important nowadays?

...

在存在 ASLR 的情况下,重新设置 DLL 的基数无效,因为 ASLR 无论如何都会忽略您的基地址并将 DLL 重新定位到其伪随机选择的位置.

In the presence of ASLR, rebasing your DLLs has no effect because ASLR is going to ignore your base address anyway and relocate the DLL into a location of its pseudo-random choosing.

...

结论:rebase 没有坏处,以防万一,但要理解回报将非常罕见.构建你的 DLL/DYNAMICBASE 已启用(并使用 /HIGHENTROPYVA 进行测量)并让 ASLR 做确保没有基地址冲突的工作发生.这将涵盖几乎所有的现实世界场景.如果您碰巧陷入 ASLR 的极少数情况之一不可用,那么您的程序仍然可以运行.它可能只是运行一个由于搬迁惩罚,速度稍慢.

Conclusion: It doesn't hurt to rebase, just in case, but understand that the payoff will be extremely rare. Build your DLL with /DYNAMICBASE enabled (and with /HIGHENTROPYVA for good measure) and let ASLR do the work of ensuring that no base address collision occurs. That will cover pretty much all of the real-world scenarios. If you happen to fall into one of the very rare cases where ASLR is not available, then your program will still work. It just may run a little slower due to the relocation penalty.

... ASLR 实际上在避免碰撞方面比手动做得更好rebasing,因为 ASLR 可以从整体上查看系统,而手动变基要求您知道加载到您的所有 DLL 中过程,并协调多个供应商的基地址是一般不可能.

... ASLR actually does a better job of avoiding collisions than manual rebasing, since ASLR can view the system as a whole, whereas manual rebasing requires you to know all the DLLs that are loaded into your process, and coordinating base addresses across multiple vendors is generally not possible.

相关文章