【问题标题】:How can two processes share the same Shared Library?两个进程如何共享同一个共享库?
【发布时间】:2019-04-02 01:47:22
【问题描述】:

我一直在努力更好地了解共享库的工作原理,但我无法解决两件事。

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

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

【问题讨论】:

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


    【解决方案1】:

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

    假设您运行一个可执行文件a.out,它初始化一些全局数据,然后运行fork()s。您应该很容易理解a.out 的所有只读(例如代码)页面现在在两个进程之间共享(物理内存的完全相同页面mmaped 到两个虚拟内存空间)。

    现在假设a.outforking 之前也使用了libc.so.6。您应该很容易理解属于libc.so.6 的只读页面也以完全相同的方式在进程之间共享。

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

    那么两个进程怎么会有不同的全局变量副本,

    非常简单:读写映射(可写数据需要)在进程之间共享(这样一个进程可以写入变量,并且该写入对其他进程不可见)。

    【讨论】:

    • 你真的解决了我对第一部分的困惑,谢谢。但第二部分仍然是模糊的。您提到“(这样一个进程可以写入变量,并且该写入对另一个进程不可见)。”但这怎么可能?是不是每个进程都有自己的 GOT 表,所以一个进程中偏移量0x10 处的条目包含的值与其他进程中的值不同?
    • @GamefanA GOT 是可写数据,所以是的:每个进程都有自己的副本。
    【解决方案2】:

    对于第二个问题,GOT 存储偏移量,并且您需要一个基地址来访问 GOT 的每个条目。请记住,我们这里所说的所有地址都是虚拟地址,因此不同的进程可以将相同的虚拟地址映射到不同的物理地址,全局变量就是这种情况。但是,共享库并非如此,它驻留在所有进程的相同物理内存地址中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多