Linux内核如何确定ld.so的加载地址?

How does the Linux kernel determine ld.so's load address?

我知道动态链接器使用 mmap() 加载库。我猜是内核将可执行文件及其 .interpreter 加载到同一地址 space,但它如何确定位置?我注意到禁用 ASLR 的 ld.so 的加载地址是 0x555555554000(在 x86_64 上)——这个地址来自哪里?我尝试遵循 do_execve() 的代码路径,但它太复杂了,我不至于被搞糊涂。

阅读更多关于 ELF, in particular elf(5), and about the execve(2) 系统调用的信息。

ELF 文件可能包含解释器。 elf(5) 提及:

PT_INTERP The array element specifies the location and size of a null-terminated pathname to invoke as an interpreter. This segment type is meaningful only for executable files (though it may occur for shared objects). However it may not occur more than once in a file. If it is present, it must precede any loadable segment entry.

那个口译员几乎总是ld-linux(8) (e.g. with GNU glibc), more precisely (on my Debian/Sid) /lib64/ld-linux-x86-64.so.2. If you compile musl-libc then build some software with it you'll get a different interpreter, /lib/ld-musl-x86_64.so.1. That ELF interpreter is the dynamic linker

execve(2) 系统调用正在使用该解释器:

If the executable is a dynamically linked ELF executable, the interpreter named in the PT_INTERP segment is used to load the needed shared libraries. This interpreter is typically /lib/ld-linux.so.2 for binaries linked with glibc.

另见 Levine 关于 Linkers and loaders, and Drepper's paper: How To Write Shared Libraries

的书

注意 execve 也在处理 shebang(即第一行以 #! 开头);请参阅 execve(2) 解释器脚本 部分。顺便说一句,对于 ELF 二进制文件,execve 在某些段上执行 等效 mmap(2)

另请参阅 vdso(7), proc(5) & ASLR。在 shell.

中输入 cat /proc/self/maps

(我猜,但我不确定,0x55​​5555554000 地址在您的可执行文件的 ELF 程序头中,或者可能在 ld-linux.so 中;它也可能来自内核, 因为 0x55555555 似乎出现在内核源代码中)