即使 _start 是 ELF 入口点,为什么在 _start 之前调用来自 glibc 的 csu/init-first.c 的 _init? [英] Why is _init from glibc's csu/init-first.c called before _start even if _start is the ELF entry point?

查看:27
本文介绍了即使 _start 是 ELF 入口点,为什么在 _start 之前调用来自 glibc 的 csu/init-first.c 的 _init?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I first noticed it while playing with GDB's rbreak ., and then made a minimal example:

(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

注意有2个_init:一个在csu/init-first.c,另一个似乎来自sysdeps/x86_64/crti.S.我说的是 csu 之一.

Note that there are 2 _init: one in csu/init-first.c, and the other seems to come from sysdeps/x86_64/crti.S. I'm talking about the csu one.

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

Isn't _start supposed to be the entry point set by the linker, and stored in the ELF header? What mechanism makes _init run first? What is its purpose?

在 GCC 4.8、glibc 2.19、GDB 7.7.1 和 Ubuntu 14.04 上测试.

Tested on GCC 4.8, glibc 2.19, GDB 7.7.1 and Ubuntu 14.04.

推荐答案

在您的示例中,调试器首先停止的地方并不是过程的真正开始.

Where the debugger halts first in your example isn't the real beginning of the process.

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

In the ELF header there is an entry for the program interpreter (dynamic linker). On Linux 64 bit its value is /lib64/ld-linux-x86-64.so.2. The kernel sets the initial instruction pointer to the entry point of this program interpreter. The symbol name of it is _start too, like the programs _start.

动态链接器完成它的工作后,也调用程序中的函数,如glibc中的_init,它调用程序的入口点.

After the dynamic linker has done its work, calling also functions in the program, like _init in glibc, it calls the entry point of the program.

_start 处的断点不适用于动态链接器,因为它只需要程序的 _start 的地址.

The breakpoint at _start doesn't work for the dynamic linker because it takes only the address of the program's _start.

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

You can find the entry point address with readelf -h /lib64/ld-linux-x86-64.so.2.

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

You could also set a breakpoint at _dl_start and print a backtrace to see that this function is called from dynamic linker's _start.

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

If you download glibc's current source code you can find the entry point of the dynamic loader at glibc-2.21/sysdeps/x86_64/dl-machine.h starting on line 121.

这篇关于即使 _start 是 ELF 入口点,为什么在 _start 之前调用来自 glibc 的 csu/init-first.c 的 _init?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆