Linux 系统上的动态链接器是内核或 GCC 库的一部分吗?
Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?
动态 Linker(又名程序解释器,Link 加载器)是内核或 GCC 库的一部分吗?
更新 (28-08-16) :
我发现 dynamic linker 的默认路径,每个二进制文件(即 linked 针对共享库)使用 /lib64/ld-linux-x86-64.so.2
是共享库 /lib/x86_64-linux-gnu/ld-2.23.so
的 link,它是实际的动态 linker.
并且它是 libc6 (2.23-0ubuntu3)
包的一部分,即。 GNU C Library: Shared libraries 在 ubuntu 中用于 AMD64 架构。
我的实际问题是
如果这个辅助程序 (ld-2.23.so) 不存在?
对此的回答是“没有应用程序 运行,甚至 shell 程序也不行”。我已经在虚拟机上试过了。
在 ELF 可执行文件中,这称为 "ELF interpreter"。在 linux 上(例如)这是 /lib64/ld-linux-x86-64.so.2
这是不是内核的一部分,并且[通常]与glibc
等一起使用。其他
当内核执行ELF可执行文件时,它必须将可执行文件映射到用户space内存中。然后它会在内部查找称为 INTERP
的特殊子部分 [其中包含一个作为完整路径的字符串]。
然后内核将解释器映射到用户space内存并将控制转移给它。然后,解释器执行必要的 linking/loading 并启动程序。
因为 ELF
代表 "extensible linker format",这允许 ELF 文件有许多不同的子部分。
与文件配对的 ELF 解释器知道所有无数的扩展,而不是给内核增加负担。
虽然在一个给定的系统上通常只使用一种格式,但在一个系统上可以有几种不同的 ELF 文件变体,每一种都有自己的 ELF 解释器。
这将允许[说] BSD ELF 文件在linux 系统[与其他adjustments/support] 上运行,因为ELF 文件将指向BSD ELF 解释器而不是 linux 一个。
更新:
every process(vlc player, chrome) had the shared library ld.so as part of their address space.
是的。我假设您正在查看 /proc/<pid>/maps
。这些是文件的映射(例如使用mmap
)。这与 "loading" 有点不同,它可以暗示 [symbol] linking.
So primarily loader after loading the executable(code & data) onto memory , It loads& maps dynamic linker (.so) to its address space
理解这一点的最好方法是重新表述你刚才所说的话:
所以主要是内核在映射可执行文件(代码和数据)到内存之后,内核将动态linker (.so)映射到程序地址space
基本上是正确的。内核还映射了其他东西,例如 bss
段和堆栈。然后 "pushes" argc
、argv
和 envp
[环境变量的 space] 入栈。
然后,[通过读取文件的一个特殊部分]确定了 ld.so
的起始地址,它将其设置为恢复地址并启动线程。
到目前为止,都是内核在做事。内核几乎不做符号 linking.
现在,ld.so
接管...
which further Loads shared Libraries , map & resolve references to libraries. It then calls entry function (_start)
因为原始可执行文件(例如 vlc
)已映射到内存中,ld.so
可以检查它以获取所需的共享库列表。它 将这些 映射到内存中,但 而不是 必须立即 link 符号。
映射简单快捷 -- 只需一个 mmap
调用。
可执行文件的起始地址[不要与ld.so
]的起始地址混淆,取自ELF可执行文件的一个特殊部分。尽管与此起始地址关联的符号传统上称为 _start
,但它实际上可以命名为任何名称(例如 __my_start
),因为它是确定起始地址的节数据中的内容,并且 不是符号的地址_start
将符号引用链接到符号定义是一个耗时的过程。因此,这被推迟到实际使用该符号为止。也就是说,如果一个程序引用了 printf
,那么 linker 实际上不会尝试 printf
中的 link,直到程序第一次实际 通话printf
这有时称为 "link-on-demand" 或 "on-demand-linking"。请在此处查看我的回答: 以获得更详细的解释以及将可执行文件映射到用户 space.
时实际发生的情况
如果您有兴趣,可以 ldd /usr/bin/vlc
获取它使用的共享库的列表。如果您查看 readelf -a /usr/bin/vlc
的输出,您会看到这些相同的共享库。此外,您将获得 ELF 解释器的完整路径,并且可以执行 readelf -a <full_path_to_interpreter>
并注意一些差异。您可以对 vlc
想要的任何 .so
个文件重复该过程。
将所有这些与 /proc/<pid>maps
等结合起来。阿尔。可能有助于您的理解。
动态 Linker(又名程序解释器,Link 加载器)是内核或 GCC 库的一部分吗?
更新 (28-08-16) :
我发现 dynamic linker 的默认路径,每个二进制文件(即 linked 针对共享库)使用 /lib64/ld-linux-x86-64.so.2
是共享库 /lib/x86_64-linux-gnu/ld-2.23.so
的 link,它是实际的动态 linker.
并且它是 libc6 (2.23-0ubuntu3)
包的一部分,即。 GNU C Library: Shared libraries 在 ubuntu 中用于 AMD64 架构。
我的实际问题是
如果这个辅助程序 (ld-2.23.so) 不存在?
对此的回答是“没有应用程序 运行,甚至 shell 程序也不行”。我已经在虚拟机上试过了。
在 ELF 可执行文件中,这称为 "ELF interpreter"。在 linux 上(例如)这是 /lib64/ld-linux-x86-64.so.2
这是不是内核的一部分,并且[通常]与glibc
等一起使用。其他
当内核执行ELF可执行文件时,它必须将可执行文件映射到用户space内存中。然后它会在内部查找称为 INTERP
的特殊子部分 [其中包含一个作为完整路径的字符串]。
然后内核将解释器映射到用户space内存并将控制转移给它。然后,解释器执行必要的 linking/loading 并启动程序。
因为 ELF
代表 "extensible linker format",这允许 ELF 文件有许多不同的子部分。
与文件配对的 ELF 解释器知道所有无数的扩展,而不是给内核增加负担。
虽然在一个给定的系统上通常只使用一种格式,但在一个系统上可以有几种不同的 ELF 文件变体,每一种都有自己的 ELF 解释器。
这将允许[说] BSD ELF 文件在linux 系统[与其他adjustments/support] 上运行,因为ELF 文件将指向BSD ELF 解释器而不是 linux 一个。
更新:
every process(vlc player, chrome) had the shared library ld.so as part of their address space.
是的。我假设您正在查看 /proc/<pid>/maps
。这些是文件的映射(例如使用mmap
)。这与 "loading" 有点不同,它可以暗示 [symbol] linking.
So primarily loader after loading the executable(code & data) onto memory , It loads& maps dynamic linker (.so) to its address space
理解这一点的最好方法是重新表述你刚才所说的话:
所以主要是内核在映射可执行文件(代码和数据)到内存之后,内核将动态linker (.so)映射到程序地址space
基本上是正确的。内核还映射了其他东西,例如 bss
段和堆栈。然后 "pushes" argc
、argv
和 envp
[环境变量的 space] 入栈。
然后,[通过读取文件的一个特殊部分]确定了 ld.so
的起始地址,它将其设置为恢复地址并启动线程。
到目前为止,都是内核在做事。内核几乎不做符号 linking.
现在,ld.so
接管...
which further Loads shared Libraries , map & resolve references to libraries. It then calls entry function (_start)
因为原始可执行文件(例如 vlc
)已映射到内存中,ld.so
可以检查它以获取所需的共享库列表。它 将这些 映射到内存中,但 而不是 必须立即 link 符号。
映射简单快捷 -- 只需一个 mmap
调用。
可执行文件的起始地址[不要与ld.so
]的起始地址混淆,取自ELF可执行文件的一个特殊部分。尽管与此起始地址关联的符号传统上称为 _start
,但它实际上可以命名为任何名称(例如 __my_start
),因为它是确定起始地址的节数据中的内容,并且 不是符号的地址_start
将符号引用链接到符号定义是一个耗时的过程。因此,这被推迟到实际使用该符号为止。也就是说,如果一个程序引用了 printf
,那么 linker 实际上不会尝试 printf
中的 link,直到程序第一次实际 通话printf
这有时称为 "link-on-demand" 或 "on-demand-linking"。请在此处查看我的回答:
如果您有兴趣,可以 ldd /usr/bin/vlc
获取它使用的共享库的列表。如果您查看 readelf -a /usr/bin/vlc
的输出,您会看到这些相同的共享库。此外,您将获得 ELF 解释器的完整路径,并且可以执行 readelf -a <full_path_to_interpreter>
并注意一些差异。您可以对 vlc
想要的任何 .so
个文件重复该过程。
将所有这些与 /proc/<pid>maps
等结合起来。阿尔。可能有助于您的理解。