【问题标题】:How loader Maps DLL in to Process Address Space加载程序如何将 DLL 映射到进程地址空间
【发布时间】:2010-09-25 02:31:19
【问题描述】:

我很想知道加载程序如何将 DLL 映射到进程地址空间。 loader 是如何做到这一点的。高度赞赏示例。

提前致谢。

【问题讨论】:

    标签: c++ c dll loader


    【解决方案1】:

    假设这是在 Windows 中(DLL 提示),您可能需要阅读 Microsoft 的 Run-Time Dynamic Linking 文档页面。它没有详细说明如何 DLL 映射到地址空间;我想你不应该需要知道这一点。

    【讨论】:

      【解决方案2】:

      您正在寻找什么级别的详细信息?在基本层面上,所有动态链接器的工作方式几乎相同:

      1. 动态库被编译为可重定位代码(例如,使用相对跳转而不是绝对跳转)。
      2. 链接器在应用程序的内存映射中找到一个适当大小的空白空间,并将 DLL 的代码和任何静态数据读取到该空间中。
      3. 动态库包含每个导出函数开头的偏移量表,客户端程序中对 DLL 函数的调用在加载时根据加载库的位置使用新的目标地址进行修补。
      4. 大多数动态链接器系统都有一些系统可以为特定库设置首选基地址。如果库在其首选地址加载,则可以跳过第 2 步和第 3 步中的重定位。

      【讨论】:

      • @Mark Bessey。在机器级别:)。 loader 是如何做到这一点的。我喜欢你的描述,如果你能给出解码的 m/c 代码或 asm 代码的链接/示例来解释一下,我将不胜感激。请慢慢来,不要着急。:)
      【解决方案3】:

      如果你真的有兴趣,你应该阅读本书Linkers and Loaders

      【讨论】:

        【解决方案4】:

        好的,我在这里假设 Windows 方面的事情。当您加载 PE 文件时,加载程序(包含在 NTDLL 中)将执行以下操作:

        1. 使用 DLL 搜索语义(特定于系统和补丁级别)定位每个 DLL,众所周知的 DLL 可以免除此操作
        2. 将文件映射到内存 (MMF),其中页面是写时复制 (CoW)
        3. 遍历导入目录,每次导入从第 1 点开始(递归)。
        4. 解决重定位问题,因为代码本身是与位置无关的代码 (PIC),大多数情况下这只是数量非常有限的实体
        5. (IIRC) 将 EAT 从 RVA(相对虚拟地址)修补到 VA(当前进程内存空间内的虚拟地址)
        6. 修补 IAT(导入地址表)以使用进程内存空间中的实际地址引用导入
        7. 对于 EXE 的 DLL 调用 DLLMain() 创建一个线程,其起始地址位于 PE 文件的入口点(这也过于简单,因为对于 Win32 进程,实际起始地址在 kernel32.dll 中)李>

        现在,当您编译代码时,它取决于链接器如何引用外部函数。一些链接器创建存根,因此——理论上——试图检查函数地址是否为 NULL 总是会说它不是 NULL。您必须注意链接器是否以及何时受到影响,这是一个怪癖。其他人直接引用 IAT 条目,在这种情况下,未引用的函数(认为延迟加载的 DLL)地址可以为 NULL,然后 SEH 处理程序将调用延迟加载帮助程序并(尝试)解析函数地址,然后在指出它失败了。

        上述过程涉及很多繁文缛节,我过于简化了。

        您想知道的要点是,到进程的映射以 MMF 的形式发生,尽管您可以人为地模仿堆空间的行为。但是,如果您还记得关于 CoW 的观点,那就是 DLL 概念的关键所在。实际上,(大部分)DLL 页面的相同副本将在加载特定 DLL 的进程之间共享。未共享的页面是我们写入的页面,例如在解决重定位和类似问题时。在这种情况下,每个进程都有一个 - 现在已修改 - 原始页面的副本。

        还有一个关于 DLL 上的 EXE 加壳程序的警告。它们完全击败了我描述的这种 CoW 机制,因为它们在加载 DLL 的进程的堆上为 DLL 的解压缩内容分配空间。因此,虽然实际文件内容仍映射为 MMF 并共享,但解压后的内容对于每个加载 DLL 的进程占用相同数量的内存,而不是共享。

        【讨论】:

        • 关于 DLL 的 CoW 属性的出色解释。
        猜你喜欢
        • 1970-01-01
        • 2011-05-26
        • 2014-06-28
        • 2017-05-18
        • 2023-03-03
        • 1970-01-01
        • 2017-11-18
        • 2018-01-16
        • 2012-10-12
        相关资源
        最近更新 更多