ld-linux.so* 本身是如何链接和加载的?

how is ld-linux.so* itself linked and loaded?

出于好奇,Linux 动态 linker/loader ld-linux.so* 本身是如何链接和加载的?

  1. 上面的截图显示fileldd似乎给出了矛盾的结果:一个说静态链接,另一个说动态链接.

  2. 那么loader本身是如何加载的呢?

  1. ld-linux.so* 不依赖任何其他库。加载到内存后可自行运行。

  2. ldd是一个脚本,它通过加载器加载目标文件,加载器检查对象是动态链接还是静态链接,试试这个:

LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2

  1. file读取magic number或elf header来判断对象是动态链接还是静态链接,它可能输出与ldd
  2. 不同的值

IMO,ld-linux.so 是静态链接的,因为它没有所有动态链接对象必须具有的 .interp 部分。

@臧明杰

你的回答对我帮助很大,但以下的话可能会让一些人感到困惑:

IMO, ld-linux.so is static linked, because it doesn't have an .interp >section which all dynamically linked object must have.

我们应该把"all dynamic linked object"分成两部分,我们称之为'shared object'的一种是这样生成的:

gcc -c -o test.o test.c -fPIC
ld -o test.so test.o -shared

还有一种叫做'dynamic linked executable file':

gcc -c -o test.o test.c -fPIC
ld -o test.so test.o

有两点很重要:

1,Shared object 没有 '.iNTERP' 段,而 Dynamic 链接的可执行文件有。

2, Linux 内核不关心ELF 文件是由elf header 指示的EXEC 还是DYN。他首先搜索.INTERP 段,如果失败,他对每个LOAD 类型段进行mmap(),并将控制权传递给eheader->e_entry,无论他是加载可执行文件还是共享object.

因为 ld-linux.so 是一个共同的共享 object,所以她不拥有 .INTERP 段也就不足为奇了。而且她可以 运行 作为可执行文件并不奇怪。每个共享 object 都可以。

这样写代码:

   void foobar(void){ while(1); }

将其编译成共享文件 object(使用上面的命令行)。 运行它:

gdb ./test.so

你会得到一个陷入死循环的进程。 使用 Ctrl-C 打断它。你会看到(需要 gcc 的 -g 选项)

Program received signal SIGINT, Interrupt.
foobar (void) at test.c:1
1       while(1);
(gdb) 

你可以走得更远:

(gdb) p $eip
 = (void (*)()) 0x80000183 <foobar+3>
(gdb) 

如果你熟悉linux内核,你应该知道0x80000000与内核变量'mmap_min_addr'的值有关。因为test.so是一个共享的object,她的load-address是零,所以内核为她找到了一个默认的虚拟地址,也就是0x80000000,而不是0x804000。

我不知道我怎么会这样off-topic ...