unix - 两个进程如何共享同一个共享库?
问题描述
我一直在尝试更好地了解共享库的工作原理,但我无法解决两件事。
1-每个进程都有自己的虚拟内存空间和页表,所以如果一个共享库被加载到一个进程的虚拟内存空间中,那么第二个进程如何访问该共享库,因为它不在其内存空间中?
2-我知道只有文本部分被共享而全局数据不被共享,这怎么可能?我的理解是,对全局变量的每个引用都是通过全局偏移表(简称 GOT)完成的。所以,如果我有这行代码,x = glob
那么这将大致等于mov eax,DWORD PTR [ecx-0x10]
汇编中ecx
的内容,其中用作 GOT 的基值。但如果是这种情况,那么很明显,无论哪个进程调用该行,它总是会访问同一个全局变量,其地址位于 GOT 中的偏移量 0x10。那么,如果两个进程使用引用相同 GOT 条目的相同文本部分,那么它们如何拥有不同的全局变量副本呢?
解决方案
大概您了解页表和写时复制语义。
假设您运行一个可执行文件a.out
,它初始化一些全局数据,然后fork()
s. 您应该毫不费力地理解所有只读(例如代码)页面a.out
现在在两个进程之间共享(完全相同的物理内存页面被mmap
编入两个虚拟内存空间)。
现在假设在ing之前a.out
也使用libc.so.6
过。fork
您应该可以毫不费力地理解,属于的只读页面libc.so.6
也以完全相同的方式在进程之间共享。
现在假设您有两个单独的可执行文件,a.out
并且b.out
都使用libc.so.6
. 假设 a.out 首先运行。动态加载器将只读映射libc.so.6
到a.out
虚拟内存空间,现在它的一些页面在物理内存中。此时,b.out
启动和动态加载器mmap
将相同的libc.so.6
页面放入其虚拟内存中。由于内核已经有这些页面的映射,内核没有理由创建新的物理页面来保存映射——它可以重用以前映射的物理页面。最终结果与fork
ed 二进制文件相同——相同的物理页面在多个虚拟内存空间(和多个进程)之间共享。
那么两个进程如何拥有不同的全局变量副本,
非常简单:读写映射(这是可写数据所必需的)在进程之间不共享(因此一个进程可以写入变量,而该写入对另一个进程不可见)。
推荐阅读
- sql - 如何在postgres中将数组元素从字符串转换为int?
- python - 在函数调用中指定 webdriver 定位器
- javascript - JavaScript 映射和过滤基本对象数组
- ms-access - MS Access 错误 91:对象变量或未设置块变量
- sockets - 接受 udp 选择的错误
- css - Flex Layout 混合行和列
- validation - AMP 验证错误
- codeigniter - 如何从对象字符串中获取所需的标签
- javascript - 其他块不符合我的条件
- jenkins - 如何将文件从 SSH 远程主机复制到 Jenkins 服务器。sshpass 不起作用