代码之家  ›  专栏  ›  技术社区  ›  Martin Ba

重新设置DLL(或提供适当的默认加载地址)是否值得麻烦?

  •  26
  • Martin Ba  · 技术社区  · 14 年前

    重新设置dll的位置意味着修复dll,这样,加载程序实际能够加载dll的加载地址就是首选的加载地址。

    这可以通过以下工具实现: Rebase.exe 或者为所有(自己的)DLL指定默认加载地址,以便它们“适合”您的可执行进程。

    以这种方式管理DLL基地址的关键是加快应用程序加载。(我大概是这么理解的。)

    这个 问题 现在是: 值得麻烦吗?

    我有这本书 Windows via C/C++ 里克特/纳扎尔,他们强烈推荐 [A] 确保加载地址都匹配,这样加载程序就不必重新设置加载的DLL的基址。

    但是,如果这将应用程序加载时间加速到任何显著的数量,他们就不会争论。

    此外,与 ASLR 这看起来有点可疑,因为加载地址无论如何都是随机的。

    任何硬事实 关于这个的利弊?

    【A】:在我的wvc++/5th版中,它在标题为 再平衡模块 绑定模块 第568FF页。在第20章中, DLL高级技巧 .

    5 回复  |  直到 8 年前
        1
  •  12
  •   Hans Passant    14 年前

    修补可重定位地址并不是什么大问题,它以微秒级的内存速度运行。更大的问题是,包含此代码的页面现在需要由分页文件而不是dll文件进行备份。换句话说,当包含代码的页面被取消映射时,它们需要被写入分页文件,而不是被丢弃。

    这种方法的成本并不容易测量,尤其是在拥有大量RAM的现代机器上。它只在机器开始承受大量进程争用内存的负载时才起作用。以及分页文件的碎片。

    但显然,重新平衡是一种非常廉价的优化。在debug+window s+modules窗口中很容易看到,重新设定的DLL上有一个明亮的图标。地址列给您一个很好的提示,什么基地址是一个好的选择。在它们之间留有足够的空间,这样你就不必随着程序的增长而不断地调整它。

        2
  •  7
  •   Community CDub    8 年前

    我想自己提供一个答案,尽管 answers of Hans Passant 其他人已经很好地描述了这种权衡。

    最近在我们的应用程序中处理了dll基地址之后,我将在这里给出我的结论:

    我认为,除非您能够证明,否则为DLL提供一个非默认的基地址是徒劳的。这包括重新设置我的DLL。

    • 为了 我控制的DLL ,考虑到平均应用程序,每个DLL将只加载一次到内存中,因此分页文件上的负载应该是最小的。(但请参阅另一个有关终端服务器环境的回答中MichalBurr的评论。)

    • 如果DLL提供了一个固定的基地址(不重新调整基地址),它实际上会增加地址空间碎片,因为迟早这些地址将不再匹配。在我们的应用程序中,我们在不使用rebase.exe的情况下为所有DLL提供了一个固定的基地址(出于其他遗留原因,而不是因为地址空间碎片),并且 明显地 增加了我们的地址空间碎片,因为您真的无法手动获得正确的地址空间碎片。

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

    • 一个大的应用程序总是会在基址不匹配的地方加载一些DLL,因为有些钩子DLL(AV)和因为您没有重新设置第三方DLL的基址(或者至少我不会)。

    • 如果你是 using a RAM disk for the paging file ,实际上,如果加载的DLL被调出,您可能会更好:-)

    综上所述,我认为重新平衡 不值得麻烦 除了特殊情况,如系统DLL。


    我想添加一个我在旧的新事物上发现的历史片段: How did Windows 95 rebase DLLs? ——

    当一个DLL需要重新设定时,Windows95只会做一个注释。 动态链接库的新基地址,但不会做太多其他事情。真实的 当DLL的页面最终被调入时,工作就发生了。这个 原始页已从磁盘换出,然后修复应用于 飞到原始页,从而重新定位它。固定页面是 然后映射到进程的地址空间,程序 允许继续。

    看看这个过程是如何完成的( read the whole thing )我个人怀疑“重新平衡是邪恶的”立场的一部分可以追溯到旧时代的Win9x和低内存条件。


    看,现在有一个 non-historical piece on Old New Thing :

    现在确保我的所有DLL都有无冲突的基址有多重要?

    回到那一天,你被劝告做的事情之一就是重新平衡 您的DLL使它们都具有不重叠的地址范围,因此 避免运行时重新定位的成本。这还重要吗 现在?

    在存在aslr的情况下,重新设置您的dll没有效果,因为aslr是 无论如何都要忽略您的基址 并将DLL重新定位到其伪随机选择的位置。

    结论:只是以防万一,重新平衡并不会造成伤害,但要理解 那个 回报将极其罕见 . 用创建DLL /DYNAMICBASE 启用(和 /HIGHENTROPYVA 为了更好的测量) 让ASLR做确保没有基地址冲突的工作 发生。这将涵盖几乎所有的现实场景。 如果你碰巧遇到了一个非常罕见的案例 不可用,则您的程序仍将工作。它可能会运行一个 由于搬迁处罚,速度稍慢。

    …实际上,ASLR在避免碰撞方面比手动操作做得更好。 重新平衡,因为ASLR可以查看整个系统,而手动 重新定位需要您知道加载到您的 处理和协调多个供应商的基地址是 一般不可能。

        3
  •  4
  •   Tangurena    14 年前

    但是,如果这将应用程序加载时间加速到任何显著的数量,他们就不会争论。

    加载时间的变化是最小的,因为v-table是用新地址更新的。但是,如果您的内存不足,以至于页面文件中的内容被加载/加载,那么系统必须将DLL保存在页面文件中(因为地址被更改)。如果重新设定了DLL的基-并且重新设定的DLL不会与任何其他DLL发生冲突-那么,系统只会覆盖内存并从硬盘驱动器上的原始DLL重新加载DLL,而不是将它们交换到页面文件(和背面)。

    只有当系统对主存中的东西进行分页时,这个好处才是相关的。上次我努力保存应用程序数据库及其基地址的时间是在vb6天,那时我们办公室和数据中心的计算机甚至幸运地拥有256MB的RAM。

    此外,对于aslr,这似乎有点可疑,因为加载地址无论如何都是随机的。

    目前,ASLR只影响具有动态重定位标志集的DLL和可执行文件。这包括Vista/Win7系统DLL和可执行文件,以及任何开发人员制作的项目。 在构建期间,开发人员故意设置该标志 .

    如果您要设置动态重定位标志,那么就不必重新设置DLL。如果您的所有客户机都有4GB的RAM,那么就不用麻烦了。如果你的老板是个小气鬼,那也许吧。

        4
  •  3
  •   ruslik    14 年前

    您必须考虑必须从HDD读取用户DLL(尚未加载到其他进程中)。通常内存映射用于此目的(它使用延迟加载),因此如果必须重新定位它们,则必须在进程启动之前从HDD中实际读取它们。

    对于由其他进程加载的那些进程,使用copy-on-write机制。因此,同样地,重新定位它们意味着额外的操作。

    ASLR的目的是为了安全,而不是为了性能。

        5
  •  1
  •   John    14 年前

    是的,你应该这样做。 ASLR只影响“系统”DLL,因此您正在编写的DLL不应受到ASLR的影响。此外,ASLR并没有完全“随机化”这些系统二进制文件的位置,它只是简单地将它们在VM映射的基本位置上随机移动。