重新定基 DLL(或提供适当的默认加载地址)值得这么麻烦吗?
变基 DLL 意味着修复 DLL,使其首选加载地址是加载器实际上能够加载 DLL 的加载地址。
这可以通过 Rebase.exe
等工具来实现,也可以通过为所有(自己的)dll 指定默认加载地址,以便它们“适合”您的可执行进程来实现。
以这种方式管理 DLL 基地址的全部目的是加快应用程序加载速度。 (或者我是这么理解的。)
现在问题是:值得这么麻烦吗?
我有这本书Windows via C/C++ by Richter/Nazarre 他们强烈建议[a]确保加载地址全部匹配这样加载器就不必重新设置加载的 DLL 的基址。
然而,他们没有争论这是否会显着加快应用程序加载时间。
另外,对于 ASLR ,这是否有任何价值似乎值得怀疑全部,因为加载地址无论如何都会被随机化。
对此的优点/缺点有任何确凿的事实吗?
[a]:在我的 WvC++/第 5 版中,它位于第 568ff 页上标题为“Rebasing Modules”和“Binding Modules”的部分。第 20 章,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.
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.
The whole point of managing the DLL base addresses this way is to speed up application loads. (Or so I understand.)
The question is now: Is it worth the trouble?
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.
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]: 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
修补可重定位地址并不是什么大问题,它以微秒的内存速度运行。更大的问题是,包含此代码的页面现在需要由页面文件而不是 DLL 文件来备份。换句话说,当包含代码的页面未映射时,需要将它们写入分页文件,而不是直接丢弃。
其成本并不容易衡量,尤其是在具有大量 RAM 的现代机器上。仅当机器开始承受大量进程争夺内存的负载时,它才有意义。以及分页文件的碎片。
但显然,变基是一种非常廉价的优化。在 Debug + Windows + Modules 窗口中很容易看到,rebased DLL 上有一个明亮的图标。地址列为您提供了一个很好的提示,什么基地址是一个不错的选择。在它们之间留出足够的空间,这样您就不必随着程序的增长而不断调整。
Patching the relocatable addresses isn't the big deal, that runs at memory speeds, microseconds. The bigger issue is that the pages that contains this code now need to be backed up by the paging file instead of the DLL file. In other words, when pages containing code are unmapped, they need to be written to the paging file instead of just getting discarded.
The cost of this isn't that easy to measure, especially on modern machines with lots of RAM. It only counts when the machine starts to get under load with lots of processes competing for memory. And the fragmentation of the paging file.
But clearly, rebasing is a very cheap optimization. And it is very easy to see in the Debug + Windows + Modules window, there's a bright icon on the rebased DLLs. The Address column gives you a good hint what base address would be a good choice. Leave ample space between them so you don't constantly have to tweak this as your program grows.
我想自己提供一个答案,尽管 Hans Passant 和其他人的回答已经很好地描述了权衡。
最近在我们的应用程序中摆弄了 DLL 基地址之后,我将在这里给出我的结论:
我认为,除非您能证明相反,否则为 DLL 提供非默认基地址是徒劳的。这包括重新调整我的 DLL 的基础。
对于我控制的DLL,对于一般的应用程序,每个DLL无论如何都只会加载到内存中一次,因此分页文件上的负载应该是最小的。 (但是请参阅 Michal Burr 在有关终端服务器环境的另一个答案中的评论。)
如果 DLL 提供了固定的基地址(没有变基),它实际上会增加地址空间碎片,因为迟早这些地址不会不再匹配了在我们的应用程序中,我们为所有 DLL 指定了固定的基地址(出于其他遗留原因,而不是因为地址空间碎片),而没有使用 rebase.exe,这显着增加了我们的地址空间碎片,因为您确实无法手动解决此问题。
变基(通过 rebase.exe)并不便宜。这是构建过程中必须维护和检查的另一个步骤,因此它必须有一些好处。
大型应用程序总是会加载一些基地址不匹配的 DLL,因为有一些钩子 DLL (AV) 并且因为您没有对第 3 方 DLL 进行变基(或者至少我不会)。
如果您将 RAM 磁盘用于分页文件< /a>,如果加载的 DLL 被调出页面,您实际上可能会更好:-)
所以总而言之,我认为变基 不值得这么麻烦,除了像系统 DLL 这样的特殊情况。
我想添加我在 Old New Thing 上找到的历史文章: Windows 95 是如何做到的变基 DLL? --
看看这个过程是如何完成的(阅读全文),我个人怀疑“变基是邪恶的”立场的一部分可以追溯到 Win9x 的旧时代和低内存条件。
看,现在有一个关于旧新事物的非历史文章:
I'd like to provide one answer myself, although the answers of Hans Passant and others are describing the tradeoffs already pretty well.
After recently fiddling with DLL base addresses in our application, I will here give my conclusion:
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.
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.)
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.
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.
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).
If you're using a RAM disk for the paging file, you might actually be better of if loaded DLLs get paged out :-)
So to sum up, I think that rebasing isn't worth the trouble except for special cases like the system DLLs.
I'd like to add a historical piece that I found on Old New Thing: How did Windows 95 rebase DLLs? --
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.
Look, now there's a non-historical piece on Old New Thing:
加载时间的变化很小,因为虚拟表是用新地址更新的。但是,如果内存不足 - 足以将内容加载到页面文件中/从页面文件中加载出来,那么系统必须将 dll 保留在页面文件中(因为地址已更改)。如果 dll 被重新设置基数 - 并且重新设置基数的 dll 不会与任何其他 dll 发生冲突 - 那么系统不会将它们换出到页面文件(或换回),而是覆盖内存并从硬盘上的原始文件重新加载 dll驾驶。
仅当系统将内容调入或调出主内存时,这种好处才有意义。上一次我努力保存应用程序及其基址的数据库是在 VB6 时代,当时我们办公室和数据中心的计算机幸运地拥有 256MB 的 RAM。
目前,ASLR 仅影响设置了动态重定位标志的 dll 和可执行文件。这包括 Vista/Win7 系统 dll 和可执行文件,以及任何开发人员在构建期间故意设置该标志的项目。
如果您要设置动态重定位标志,则不必费心重新确定 dll 的基础。如果您的所有客户端都有 4GB RAM,那就不用担心。如果你的老板是个小气鬼,那么也许吧。
The load time change is minimal, because the v-table is what gets updated with the new addresses. However, if you have low memory - enough that stuff gets loaded in/out of the page file, then the system has to keep the dll in the page file (since the addresses are changed). If the dlls were rebased - and the rebased dlls don't collide with any other dlls - then instead of swapping them out to the page file (and back), the system just overwrites the memory and reloads the dll from the original on the hard drive.
The benefit is only relevant when systems are paging stuff in and out of main memory. The last time I made efforts to keep databases of applications and their base addresses was back in VB6 days, when the computers in our offices and data centers were lucky to have even 256MB of RAM.
At the moment ASLR only affects dlls and executables with the dynamic-relocation flag set. This includes Vista/Win7 system dlls and executables, and any developer made items where the developer intentionally set that flag during the build.
If you are going to set the dynamic-relocation flag, then don't bother rebasing the dlls. If all your clients have 4GB of RAM, then don't bother. If your boss is a cheapskate, then maybe.
您必须考虑必须从 HDD 读取用户 DLL(尚未加载到其他进程中)。通常,内存映射用于此目的(并且它使用延迟加载),因此如果必须重新定位它们,则必须在进程启动之前从 HDD 实际读取它们。
对于那些由其他进程加载的数据,使用写时复制机制。因此,重新安置它们将意味着额外的操作。
ASLR 是怎么回事,它是为了安全目的,而不是为了性能。
You have to consider that user DLLs (that are not already loaded into another processes) has to be read from HDD. Usually the memory mapping is used for that (and it uses lazy loading), so if they have to be relocated, they'll have to be actually read from HDD before the process can start.
For those loaded by other processes the copy-on-write mechanism is used. So, again, relocating them will mean additional operations.
What's about ASLR, it's intended for security purposes, not for performance.
是的,你应该这样做。
ASLR 仅影响“系统”DLL,因此您正在编写的 DLL 不应受到 ASLR 的影响。此外,ASLR 并没有完全“随机”这些系统二进制文件的位置,它只是将它们重新排列在虚拟机映射的基本位置上。
Yes, you should do it.
ASLR only impacts "system" DLLs and therefore the ones you are writing should not be impacted by ASLR. Additionally, ASLR doesn't completely "randomize" the location of these system binaries, it simply shuffles them around in the basic spot in the vm map.