【问题标题】:How are shared libraries addressed in each processes memory?每个进程内存中的共享库如何寻址?
【发布时间】:2021-04-11 11:24:54
【问题描述】:

据我了解:

当您将代码编译成二进制文件时,无需转换该二进制文件中的地址。由于每个进程都有自己的内存空间,所以二进制文件中使用的地址可以在运行时使用。

但是,如果您有一个共享库,如何将其映射到该进程的内存空间?如果库代码使用虚拟内存地址,则必须为每个将库映射到不同虚拟内存地址的进程更改它们。

我在这方面不是很有经验(您可能已经猜到了),如果有什么令人难以置信的错误,请见谅。

提前致谢。

【问题讨论】:

  • 我不了解Linux,但据我了解,在Windows上,在进程2中,如果需要加载已经加载到进程1中的(共享)dll,则共享内存映像如果进程1中加载dll的地址范围在进程2中可用,否则内存中有两个图像副本,每个基地址一个。可执行文件是每个地址空间中加载的第一个模块(除了内核,它始终存在)总是加载到其首选地址,通常是 0x400000。
  • 由 OS 及其 MMU more read987654321@ 处理
  • 您想查看与位置无关的代码和加载程序修复,但这可能超出了 stackoverflow 的范围。
  • 不确定我是否在寻找正确的方向,但我认为我感兴趣的是动态链接器如何工作以及如何在运行时将符号转换为地址
  • @user1937198 我不认为它超出了 Stack Overflow 的范围

标签: c linux executable elf


【解决方案1】:

在 Linux 中,当您在代码中有效调用该库时,默认情况下会解析对共享库的引用。这称为惰性投标。因此,处理器不能执行所有二进制文件。他们中的大多数实际上是被解释的(参见/lib64/ld-linux-*.so)。

为此,ELF 二进制文件包含两个特定的表:

  • 过程链接表 (PLT)
  • 全局偏移表 (GOT)

您正在执行的代码引用执行重定向的 PLT。在第一次调用时,GOT 将包含一个回调地址,如果执行该地址,则会跳转到加载程序,加载程序会将地址解析为动态库。该库映射到程序的虚拟内存中,即使它只在物理内存中出现一次。

您正在使用虚拟内存,因此您的进程看到的地址可能会有所不同,因此每个进程使用一个 GOT。至于使用两个表:主要是出于安全原因,因此您永远不会从可写页面执行指令。

如果您愿意,可以通过设置 LD_BIND_NOW 环境变量来禁用延迟出价。

【讨论】:

    猜你喜欢
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    相关资源
    最近更新 更多