Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 共享库如何在每个进程内存中寻址?_C_Linux_Executable_Elf - Fatal编程技术网

C 共享库如何在每个进程内存中寻址?

C 共享库如何在每个进程内存中寻址?,c,linux,executable,elf,C,Linux,Executable,Elf,据我所知: 当您将代码编译成二进制文件时,不需要翻译该二进制文件中的地址。由于每个进程都有自己的内存空间,因此可以在运行时使用二进制文件中使用的地址 但是,如果您有一个共享库,如何将其映射到该进程的内存空间中?如果库代码使用虚拟内存地址,则必须为库映射到不同虚拟内存地址的每个进程更改这些地址 我在这方面不是很有经验(你可能会猜到),所以如果有什么难以置信的错误,我很抱歉 提前感谢。在Linux中,当在代码中有效调用共享库时,默认情况下会解析对共享库的引用。这就是所谓的懒惰投标。因此,处理器不能执

据我所知:

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

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

我在这方面不是很有经验(你可能会猜到),所以如果有什么难以置信的错误,我很抱歉


提前感谢。

在Linux中,当在代码中有效调用共享库时,默认情况下会解析对共享库的引用。这就是所谓的懒惰投标。因此,处理器不能执行所有二进制文件。事实上,它们中的大多数都是经过解释的(请参见
/lib64/ld linux-*.so

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

  • 程序链接表(PLT)
  • 全局偏移表(GOT)
您正在执行的代码引用执行重定向的PLT。在第一次调用中,get将包含一个回调地址,如果执行该回调地址,它将跳转到加载程序,加载程序将解析该地址到动态库。库映射到程序的虚拟内存中,即使它在物理内存中只存在一次

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


如果您愿意,您可以通过设置
LD\u BIND\u NOW
环境变量来禁用延迟竞价。

我不知道Linux,但我的理解是,在Windows上,在进程2中,如果需要加载已加载到进程1中的(共享)dll,如果进程1中加载dll的地址范围在进程2中可用,则共享内存映像,否则内存中有两个映像副本,每个基址一个。可执行文件是每个地址空间中加载的第一个模块(内核除外,内核始终存在),它始终加载在其首选地址,通常为0x400000。这由操作系统及其MMU负责。您要查看位置无关的代码和加载程序修复,但这可能超出了stackoverflow的范围。不确定我看的方向是否正确,但我想我感兴趣的是动态链接器是如何工作的,以及如何在运行时将符号转换为地址。我发现这个答案更重要的是他的答案的第3部分,这表明在运行时,库中的所有函数调用都会添加一个偏移量。在库中的每个函数调用/跳转之前都必须添加一个常量,这听起来效率很低。这个功能是由CPU提供的,还是仅仅是拥有一个共享库的成本?