为什么在_start之前调用glibc的csu/init-first.c _init,即使_start是ELF入口点?

Cir*_*四事件 7 c linux gcc gdb glibc

我在玩GDB时首先注意到它rbreak .,然后做了一个最小的例子:

(gdb) file hello_world.out
Reading symbols from hello_world.out...done.
(gdb) b _init
Breakpoint 1 at 0x4003e0
(gdb) b _start
Breakpoint 2 at 0x400440
(gdb) run
Starting program: /home/ciro/bak/git/cpp/cheat/gdb/hello_world.out

Breakpoint 1, _init (argc=1, argv=0x7fffffffd698, envp=0x7fffffffd6a8) at ../csu/init-first.c:52
52  ../csu/init-first.c: No such file or directory.
(gdb) continue
Continuing.

Breakpoint 2, 0x0000000000400440 in _start ()
(gdb) continue
Continuing.

Breakpoint 1, 0x00000000004003e0 in _init ()
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>
    breakpoint already hit 2 times
1.1                         y     0x00000000004003e0 <_init>
1.2                         y     0x00007ffff7a36c20 in _init at ../csu/init-first.c:52
2       breakpoint     keep y   0x0000000000400440 <_start>
    breakpoint already hit 1 time
Run Code Online (Sandbox Code Playgroud)

请注意,有两个_init:一个csu/init-first.c,另一个似乎来自sysdeps/x86_64/crti.S.我在谈论那个csu.

_start应该是链接器设置的入口点,并存储在ELF头中?什么机制_init首先运行?它的目的是什么?

测试了GCC 4.8,glibc 2.19,GDB 7.7.1和Ubuntu 14.04.

456*_*976 8

调试器在您的示例中首先停止的位置不是该过程的真正开始.

在ELF头中,有一个程序解释器的条目(动态链接器).在Linux 64位上它的值是/lib64/ld-linux-x86-64.so.2.内核将初始指令指针设置为该程序解释器的入口点.它的符号名称也是_start如此,就像程序一样_start.

在动态链接器完成其工作之后,调用程序中的函数,就像_init在glibc中一样,它调用程序的入口点.

断点at _start对动态链接器不起作用,因为它只接受程序的地址_start.

您可以找到入口点地址readelf -h /lib64/ld-linux-x86-64.so.2.

您还可以设置断点_dl_start并打印回溯,以查看是否从动态链接器调用此函数_start.

如果您下载glibc的当前源代码,您可以glibc-2.21/sysdeps/x86_64/dl-machine.h在第121行开始找到动态加载程序的入口点.