同一个 DLL 是不是保证在每个使用它的进程中都映射到同一个虚拟地址?

Posted

技术标签:

【中文标题】同一个 DLL 是不是保证在每个使用它的进程中都映射到同一个虚拟地址?【英文标题】:Is the same DLL guaranteed to be mapped to the same virtual address in every process using it?同一个 DLL 是否保证在每个使用它的进程中都映射到同一个虚拟地址? 【发布时间】:2017-04-25 14:18:03 【问题描述】:

我正在研究 Windows 系统内部,问题只是猜测。

我了解到 DLL 是共享库的一种形式,因此至少同一个 DLL 的代码部分在使用它的进程之间共享。 (通过将相同的页条目添加到这些进程的页表中)代码段通常有类似跳转表的东西,在它准备好执行之前需要重新定位(即写入运行时虚拟地址以修复指针) .

假设同一个 DLL aa.dll 映射到不同虚拟地址的两个不同进程中。 (例如a.exe 0x00400000 b.exe 0x00410000)相同的指针(.text+0x100)将被固定到不同的地址。 (例如a.exe 0x00400100 b.exe 0x004100100)。因此,我们必须复制代码部分并对其进行更改以适应一个流程。那么代码段怎么共享呢?

我说的对吗?

【问题讨论】:

RAM 页面当然不能共享。 我投票结束这个问题,因为它不是(还)一个编程问题。你能解释一下你的程序遇到的问题吗?然后我们可以尝试解决它。​​ @RaymondChen 我不同意,关于操作系统内部的问题are, in fact, on topic。事实上,程序员甚至能够理解这样的问题(远远不能回答它)。 @EJoshuaS 感谢指正 如果可能的话,共享 DLL通常会被加载到不同进程的相同地址。但是,据我所知,无法保证。 (实际上无法保证,因为第二个进程可能已经在使用相关地址空间。) 【参考方案1】:

回答我自己的问题。第一次加载 DLL 时,Windows 会尝试将其加载到不需要重定位的首选地址(即由于代码段位于 x 处而固定地址)。如果它不能在首选地址加载,它将在由 DLL 文件本身(不是交换文件)备份但标记为 Copy-On-Write 的空闲地址分配虚拟页面。现在 Windows 必须使用重定位表修复汇编代码。希望只需要修复一小部分代码,并且每个更改的代码段都将在写入时复制并放入某个物理内存中。 每次进程无法在首选地址加载 DLL 时,我相信这个过程会发生。这就是为什么有时需要重新设置流行的 DLL 的基础,以便它们的首选地址不会冲突。

【讨论】:

真的ASLR改变了局面。带有重定位的 DLL(几乎)从未通过文件中的地址(IMAGE_OPTIONAL_HEADER.ImageBase)加载。当第一次创建 dll 部分时,系统(在内核中)随机将 dll 重新定位到选定范围内的另一个地址。然后尝试通过此地址加载 dll(在所有进程中)。现在在 rebase 中没有任何意义

以上是关于同一个 DLL 是不是保证在每个使用它的进程中都映射到同一个虚拟地址?的主要内容,如果未能解决你的问题,请参考以下文章

是否在每个 Windows 安装中都可以找到声音库 WINMM.DLL?

线程安全的了解

在调用导入之前将挂钩 DLL 注入进程?

当它的所有者进程退出时,你如何让一个 DLL 被删除?

从另一个 DLL 加载 MFC 应用程序对话框

C ++获取正在运行的进程的DLL的基地址