两个进程如何共享同一个共享库?
How can two processes share the same Shared Library?
我一直在努力更好地了解共享库的工作原理,但我就是无法理解两件事。
1- 每个进程都有自己的虚拟内存 space 和页面 table,所以如果共享库被加载到一个进程的虚拟内存 space 那么第二个进程如何加载访问共享库,因为它不在内存中 space?
2- 我知道只有文本部分是共享的,而全局数据不是,这怎么可能?我的理解是,每个对全局变量的引用都是通过 Global Offset Table (简称 GOT)完成的。所以,如果我有这行代码 x = glob
那么这将大致等于汇编中的 mov eax,DWORD PTR [ecx-0x10]
,其中 ecx
用作 GOT 的基值。但如果是这样的话,那么很明显无论哪个进程调用该行,它总是会访问同一个全局变量,该变量的地址在 GOT 中的偏移量为 0x10。那么,如果两个进程使用引用相同 GOT 条目的相同文本部分,它们怎么会有不同的全局变量副本呢?
想必您了解页表和写时复制语义。
假设您 运行 一个可执行文件 a.out
,它初始化一些全局数据,然后 fork()
s。您应该不难理解 a.out
的所有只读(例如代码)页面现在在两个进程之间共享(完全相同的 物理内存页面是 mmap
ed 到两个虚拟内存 spaces).
现在假设 a.out
在 fork
ing 之前也使用了 libc.so.6
。您应该不难理解属于 libc.so.6
的只读页面也以完全相同的方式在进程之间共享。
现在假设您有两个单独的可执行文件,a.out
和 b.out
,都使用 libc.so.6
。先假设a.out运行s。动态加载器将执行 libc.so.6
到 a.out
虚拟内存 space 的只读映射,现在它的一些页面在物理内存中。那时,b.out
启动,动态加载程序 mmap
将相同的 libc.so.6
页放入其虚拟内存中。由于内核已经有了这些页面的映射,因此内核没有理由创建新的物理页面来保存映射——它可以重新使用以前映射的物理页面。最终结果与 fork
ed 二进制文件相同——相同的物理页面在多个虚拟内存 space(和多个进程)之间 共享 。
So how can two processes have different copies of global variable,
非常简单:读写映射(可写数据需要)在进程之间不共享(因此一个进程可以写入变量,并且该写入对其他进程不可见)。
对于你的第二个问题,GOT存储偏移量,你需要一个基地址来访问GOT的每个条目。请记住,我们这里所说的所有地址都是虚拟地址,因此不同的进程可以将相同的虚拟地址映射到不同的物理地址,全局变量就是这种情况。但是共享库就不是这样了,它对于所有进程都驻留在同一个物理内存地址。
我一直在努力更好地了解共享库的工作原理,但我就是无法理解两件事。
1- 每个进程都有自己的虚拟内存 space 和页面 table,所以如果共享库被加载到一个进程的虚拟内存 space 那么第二个进程如何加载访问共享库,因为它不在内存中 space?
2- 我知道只有文本部分是共享的,而全局数据不是,这怎么可能?我的理解是,每个对全局变量的引用都是通过 Global Offset Table (简称 GOT)完成的。所以,如果我有这行代码 x = glob
那么这将大致等于汇编中的 mov eax,DWORD PTR [ecx-0x10]
,其中 ecx
用作 GOT 的基值。但如果是这样的话,那么很明显无论哪个进程调用该行,它总是会访问同一个全局变量,该变量的地址在 GOT 中的偏移量为 0x10。那么,如果两个进程使用引用相同 GOT 条目的相同文本部分,它们怎么会有不同的全局变量副本呢?
想必您了解页表和写时复制语义。
假设您 运行 一个可执行文件 a.out
,它初始化一些全局数据,然后 fork()
s。您应该不难理解 a.out
的所有只读(例如代码)页面现在在两个进程之间共享(完全相同的 物理内存页面是 mmap
ed 到两个虚拟内存 spaces).
现在假设 a.out
在 fork
ing 之前也使用了 libc.so.6
。您应该不难理解属于 libc.so.6
的只读页面也以完全相同的方式在进程之间共享。
现在假设您有两个单独的可执行文件,a.out
和 b.out
,都使用 libc.so.6
。先假设a.out运行s。动态加载器将执行 libc.so.6
到 a.out
虚拟内存 space 的只读映射,现在它的一些页面在物理内存中。那时,b.out
启动,动态加载程序 mmap
将相同的 libc.so.6
页放入其虚拟内存中。由于内核已经有了这些页面的映射,因此内核没有理由创建新的物理页面来保存映射——它可以重新使用以前映射的物理页面。最终结果与 fork
ed 二进制文件相同——相同的物理页面在多个虚拟内存 space(和多个进程)之间 共享 。
So how can two processes have different copies of global variable,
非常简单:读写映射(可写数据需要)在进程之间不共享(因此一个进程可以写入变量,并且该写入对其他进程不可见)。
对于你的第二个问题,GOT存储偏移量,你需要一个基地址来访问GOT的每个条目。请记住,我们这里所说的所有地址都是虚拟地址,因此不同的进程可以将相同的虚拟地址映射到不同的物理地址,全局变量就是这种情况。但是共享库就不是这样了,它对于所有进程都驻留在同一个物理内存地址。