【问题标题】:Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?动态链接器是 Linux 系统上内核或 GCC 库的一部分吗?
【发布时间】:2016-08-09 18:12:57
【问题描述】:

动态链接器(又名程序解释器、链接加载器)是内核或 GCC 库的一部分吗?

更新(28-08-16):

我发现每个二进制文件(即链接到共享库)使用的动态链接器的默认路径/lib64/ld-linux-x86-64.so.2是共享库/lib/x86_64-linux-gnu/ld-2.23.so的链接,这是实际的动态链接器。

它是libc6 (2.23-0ubuntu3) 包的一部分,即。 GNU C Library: Shared libraries 在 ubuntu 中用于 AMD64 架构。

我的实际问题是

如果这个帮助程序 (ld-2.23.so) 不存在,那么所有动态链接的应用程序(现在都是)会发生什么?

对此的回答是“任何应用程序都不会运行,即使是 shell 程序”。我在虚拟机上试过了。

【问题讨论】:

标签: c linux dynamic-linking


【解决方案1】:

在 ELF 可执行文件中,这被称为“ELF 解释器”。在 linux 上(例如)这是 /lib64/ld-linux-x86-64.so.2

不是内核的一部分,并且[通常]与glibc等一起使用。人。

当内核执行 ELF 可执行文件时,它必须将可执行文件映射到用户空间内存。然后它会在内部查找一个称为INTERP [其中包含一个作为完整路径的字符串] 的特殊子部分。

然后内核将解释器映射到用户空间内存并将控制权转移给它。然后,解释器进行必要的链接/加载并启动程序。

因为ELF 代表“可扩展链接器格式”,这允许ELF 文件包含许多不同的子部分。

与文件配对的 ELF 解释器知道,而不是让内核不得不知道所有无数的扩展。

虽然在给定系统上通常只使用一种格式,但系统上可能有几种不同的 ELF 文件变体,每个变体都有自己的 ELF 解释器。

这将允许 [比如说] BSD ELF 文件在 Linux 系统上运行 [带有其他调整/支持],因为 ELF 文件将指向 BSD ELF 解释器而不是 linux 解释器。


更新:

每个进程(vlc 播放器、chrome)都有共享库 ld.so 作为其地址空间的一部分。

是的。我假设您正在查看/proc/<pid>/maps。这些是文件的映射(例如,使用mmap)。这与“加载”有些不同,后者可以暗示 [symbol] 链接

所以主要是加载器在将可执行文件(代码和数据)加载到内存后,它加载并映射动态链接器(.so)到它的地址空间

理解这一点的最好方法是改写你刚才所说的话:

所以主要是内核映射可执行文件(代码和数据)到内存之后,内核映射动态链接器(.所以)到程序地址空间

这基本上是正确的。内核还映射其他东西,例如bss 段和堆栈。然后它将argcargvenvp [环境变量的空间]“推”到堆栈上。

然后,确定ld.so的起始地址[通过读取文件的特殊部分],将其设置为恢复地址并启动线程。

到现在为止,都是内核在做事。内核几乎没有符号链接

现在,ld.so 接管...

进一步加载共享库,映射和解析对库的引用。然后调用入口函数(_start)

由于原始可执行文件(例如vlc)已映射到内存中,ld.so 可以检查它以获取所需的共享库列表。它这些符号映射到内存中,但不一定必须立即链接这些符号。

映射简单快捷——只需拨打mmap

可执行文件的起始地址 [notld.so 的起始地址相混淆,取自 ELF 可执行文件的特殊部分。尽管与此起始地址相关的符号传统上称为_start,但它实际上可以命名为任何名称(例如__my_start),因为它是决定起始地址的节数据中的内容,而不是 em> 符号地址_start

将符号引用链接到符号定义是一个耗时的过程。因此,这会延迟到实际使用该符号。也就是说,如果一个程序引用了printf,链接器实际上不会尝试链接printf,直到程序第一次真正调用 printf

这有时称为“按需链接”或“按需链接”。请在此处查看我的答案:Which segments are affected by a copy-on-write? 以获得更详细的解释以及将可执行文件映射到用户空间时实际发生的情况。

如果您有兴趣,可以通过ldd /usr/bin/vlc 获取它使用的共享库的列表。如果您查看readelf -a /usr/bin/vlc 的输出,您将看到这些相同的共享库。此外,您将获得 ELF 解释器的完整路径,并且可以执行 readelf -a <full_path_to_interpreter> 并注意一些差异。您可以对 vlc 想要的任何 .so 文件重复此过程。

将所有这些与/proc/<pid>maps 等结合起来。人。可能有助于您的理解。

【讨论】:

  • @criag 。正如我所注意到的,每个进程(vlc 播放器、chrome)都将共享库 ld.so 作为其地址空间的一部分。因此,主要是在将可执行文件(代码和数据)加载到内存后的加载程序,它加载和映射 动态链接器 (.so) 到其地址空间,该地址空间进一步加载共享库,映射和解析对库的引用。然后它调用入口函数 (_start) 。这是正确的吗?
  • @craig。我已经使用了打印共享依赖项的程序 ldd
  • 我猜你对ldd很熟悉,我提到它[和其他东西]是为了产生一个完整的答案。实际上,ldd 是一个 shell 脚本。它只是设置环境变量LD_TRACE_LOADED_OBJECTS,然后执行exec/usr/bin/vlc。 ELF 解释器 [for vlc] 注意到这个变量并进行打印(并终止而不是完全执行)。 ld.so 不能使用程序参数,所以要为其提供选项,设置环境变量。手册页有一个相当完整的列表(例如man ld.so
  • @CraigEstey ,好的,我现在知道了。
猜你喜欢
  • 1970-01-01
  • 2015-07-21
  • 2018-05-31
  • 1970-01-01
  • 2013-04-07
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多