当前位置:  开发笔记 > 编程语言 > 正文

加载程序如何将DLL映射到进程地址空间

如何解决《加载程序如何将DLL映射到进程地址空间》经验,为你挑选了2个好方法。

我很想知道Loader如何将DLL映射到处理地址空间.装载机如何做到这一点.例子非常受欢迎.

提前致谢.



1> 0xC0000022L..:

好的,我在这里假设Windows方面.加载PE文件时会发生的情况是加载程序(包含在NTDLL中)将执行以下操作:

    使用DLL搜索语义(系统和补丁级别特定)找到每个DLL,众所周知的DLL是免除这种

    将文件映射到内存(MMF),其中页面是写时复制(CoW)

    遍历导入目录以及每个导入在第1点开始(递归).

    解析重定位,大部分时间只是非常有限的实体,因为代码本身是与位置无关的代码(PIC)

    (IIRC)将EAT从RVA(相对虚拟地址)修补到VA(当前进程内存空间内的虚拟地址)

    修补IAT(导入地址表)以使用进程内存空间中的实际地址引用导入

    对于DLLMain()EXE 的DLL调用,创建一个线程,其起始地址位于PE文件的入口点(这也是过于简化的,因为实际的起始地址位于kernel32.dll for Win32进程内)

现在,当您编译代码时,它取决于链接器如何引用外部函数.一些链接器创建存根,以便 - 理论上 - 尝试检查函数地址与NULL将始终说它不是NULL.如果链接器受到影响,您必须注意这一点.其他直接引用IAT入口在这种情况下,不再被引用的函数(认为延迟加载的DLL)地址可以为NULL,然后SEH处理程序会在恢复执行之前调用延迟加载助手和(尝试)解析函数的地址,指出它失败了.

上面的过程涉及很多繁文缛节,我过于简单了.

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

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



2> Mark Bessey..:

你在寻找什么程度的细节?在基本层面上,所有动态链接器的工作方式大致相同:

    动态库被编译为可重定位代码(例如,使用相对跳转而不是绝对跳转).

    链接器在应用程序的内存映射中找到适当大小的空白空间,并将DLL的代码和任何静态数据读入该空间.

    动态库包含每个导出函数的开始的偏移表,并且在加载时对客户端程序中DLL函数的调用使用新的目标地址进行修补,具体取决于库的加载位置.

    大多数动态链接器系统都有一些系统用于为特定库设置首选基址.如果在其首选地址加载库,则可以跳过步骤2和3中的重定位.

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有