动态链接器如何更改进程的文本段?

How does dynamic linker changes text segment of process?

如果我在用户尝试执行动态链接时理解正确 可执行文件(使用 execve("foo", "", ""))而不是加载 "foo" 动态链接器的文本段被加载(ld-linux.so.2)并执行。它必须加载 程序所需的库 ("foo") 到 运行 并更改一些地址 在 "foo" 并将控制权传递给 foo,但这是如何完成的?

如何(它使用什么系统调用)和在哪里 动态加载程序加载库和内存中的 "foo"s 代码和数据(我猜它不能简单地使用 malloc 或 mmap,然后跳转到代码,因为那应该是不可能的, 正确的?它似乎也不太可能创建完整的临时文件 可执行文件(如静态链接的)并再次调用 exceve。

实际实现相当复杂,因为它建立在 ELF 之上,ELF 非常复杂,因为它试图适应许多场景,但从概念上讲它非常简单。

基本上(在找到库依赖项并 opened 之后)它是几个 mmaps,mprotects ,一些修改以通过绑定符号(可以延迟)实现链接,然后跳转到代码。

理想情况下,链接的共享库将使用 -fpic/-fPIC 进行编译,这将允许链接器将它们放置在进程地址 space 中的任何位置,而无需写入库的 .text 部分(=executable 代码)。 这样的 library/executable 将通过可修改的 table 调用其他库中的函数,链接器将修复(可能是懒惰地)以指向它加载依赖库的实际位置。 从一个共享库到另一个共享库的变量访问同样是间接的。

尽可能限制修改库data/code允许将代码段标记为只读(通过MMU/mprotect系统调用)并映射到所有共享的内存中使用该特定库的进程。


要了解在系统调用级别发生了什么,您可以尝试例如:

strace /bin/echo hello world

以及包括的所有系统调用,直到大约 sbrk(=设置堆/.data 段)应该是动态链接器的工作。


(malloc 确实对链接器不可用,因为 malloc 是 c 库的一个特性,而不是系统。malloc 是关于增长和管理堆部分并可能mmapping 其他单独的块并管理它们以及 writable "heap",并且动态链接器不关心过程映像的这些部分,主要只是它的 writable 间接 tables 及其映射库的位置)。