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

时间:2016-05-04 11:14:01

标签: linux-kernel linker ld loader

enter image description here

仅仅是好奇心,Linux动态链接器/加载器ld-linux.so*本身是如何链接和加载的?

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

  2. 然后如何装载装载器?

2 个答案:

答案 0 :(得分:2)

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

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

  3.   

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

    1. file读取幻数或精灵标头以确定对象是动态链接还是静态链接,它可能会输出ldd
    2. 的不同值

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

答案 1 :(得分:1)

@Zang MingJie

你的回答给了我很多帮助,但下面的话可能会让一些人感到困惑:

  

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

我们应该将“所有动态链接对象”分为两部分,我们称之为“共享对象”的一种是这样生成的:

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

另一种称为“动态链接可执行文件”:

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

两点很重要:

1,共享对象没有'.iNTERP'段,而动态链接可执行文件有。

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

由于ld-linux.so是一个常见的共享对象,因此她不拥有.INTERP段并不奇怪。并且她可以作为可执行文件运行并不奇怪。每个共享对象都可以。

编写如下代码:

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

将其编译为共享对象(使用上面的命令行)。 跑吧:

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
$1 = (void (*)()) 0x80000183 <foobar+3>
(gdb) 

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

我不知道我是如何偏离主题的......