两个进程如何共享同一共享库?

时间:2018-10-29 06:55:45

标签: unix shared-libraries dynamic-linking position-independent-code got

我一直在试图更好地了解共享库的工作方式,但是我只是无法围绕两件事说服自己。

1-每个进程都有其自己的虚拟内存空间和页表,因此,如果将共享库加载到一个进程虚拟内存空间中,那么第二个进程如何访问该共享库,因为它不在其内存空间中? >

2-我知道仅共享文本部分,而不共享全局数据,这怎么可能?我的理解是,对全局变量的每个引用都是通过GOT完成的。因此,如果我有这行代码x = glob,那么这将大致等于汇编中的mov eax,DWORD PTR [ecx-0x10],其中ecx被用作GOT的基本值。但是,如果是这种情况,那么很明显,无论哪个进程调用该行,它都将始终访问地址位于GOT中偏移量0x10的同一全局变量。那么,如果两个进程使用引用相同GOT条目的相同文本部分,那么两个进程如何具有不同的全局变量副本?

1 个答案:

答案 0 :(得分:1)

大概您了解页表和写时复制语义。

假设您运行一个可执行文件a.out,该文件将初始化一些全局数据,然后初始化fork() s。您应该毫不费力地了解到a.out的所有只读(例如代码)页现在已在两个进程之间共享(物理内存的完全相同页是mmap放入两个虚拟内存空间。

现在假设a.outlibc.so.6之前也使用过fork。您不难理解,属于libc.so.6的只读页面也以完全相同的方式在进程之间共享。

现在假设您有两个单独的可执行文件a.outb.out,都使用libc.so.6。假设a.out首先运行。动态加载器将执行libc.so.6a.out虚拟内存空间的只读映射,现在它的某些页面在物理内存中。此时,b.out启动,动态加载程序mmap将相同的libc.so.6页放入其虚拟内存。由于内核已经为这些页面建立了映射,因此内核没有理由创建新的物理页面来保存映射-它可以重新使用先前映射的物理页面。最终结果与fork二进制文件相同-在多个虚拟内存空间(和多个进程)之间共享相同的物理页面。

  

那么两个进程如何具有不同的全局变量副本,

非常简单:进程之间共享读写映射(可写数据所必需的)(以便一个进程可以写入变量,并且该写操作将对其他进程不可见。