我很想知道加载程序如何将 DLL 映射到进程地址空间。loader 是如何做到这一点的。高度赞赏示例。
提前致谢。
好的,我在这里假设 Windows 方面的事情。加载 PE 文件时会发生什么,加载程序(包含在 NTDLL 中)将执行以下操作:
DLLMain()
,创建一个其起始地址位于 PE 文件入口点的线程(这也过于简单,因为对于 Win32 进程,实际起始地址在 kernel32.dll 内)现在,当您编译代码时,它取决于链接器如何引用外部函数。一些链接器创建存根,因此——理论上——尝试检查函数地址是否为 NULL 总是会说它不是 NULL。您必须注意链接器是否以及何时受到影响,这是一个怪癖。其他人直接引用 IAT 条目,在这种情况下,未引用的函数(认为延迟加载的 DLL)地址可以为 NULL,然后 SEH 处理程序将调用延迟加载帮助程序并(尝试)解析函数地址,然后在点它失败了。
上述过程涉及很多繁文缛节,我过于简化了。
您想知道的要点是,到进程的映射以 MMF 的形式发生,尽管您可以人为地模仿堆空间的行为。但是,如果您还记得关于 CoW 的观点,那就是 DLL 概念的关键所在。实际上(大部分)DLL 页面的相同副本将在加载特定 DLL 的进程之间共享。未共享的页面是我们写入的页面,例如在解决重定位和类似问题时。在这种情况下,每个进程都有一个 - 现在已修改 - 原始页面的副本。
以及关于 DLL 上的 EXE 加壳程序的警告。它们完全击败了我描述的这种 CoW 机制,因为它们在加载 DLL 的进程的堆上为 DLL 的解压缩内容分配空间。因此,虽然实际文件内容仍映射为 MMF 并共享,但解压后的内容对于每个加载 DLL 的进程占用相同数量的内存,而不是共享它。
您在寻找什么级别的详细信息?在基本层面上,所有动态链接器的工作方式几乎相同:
如果你真的感兴趣,你应该阅读Linkers and Loaders一书。
假设这是在 Windows 中(DLL 提示),您可能需要阅读 Microsoft 的运行时动态链接文档页面。它没有详细说明DLL 如何映射到地址空间;我想你不应该需要知道这一点。