我正在阅读有关ELF文件格式的文章,我注意到用C ++编写的一个小型hello world测试程序在_start
符号中包含一些额外的初始化:
0000000000400770 <_start>:
...
40077f: 49 c7 c0 60 09 40 00 mov $0x400960,%r8
400786: 48 c7 c1 f0 08 40 00 mov $0x4008f0,%rcx
40078d: 48 c7 c7 5d 08 40 00 mov $0x40085d,%rdi
...
40077f
是__libc_csu_fini
。
4008f0
是__libc_csu_init
。
40085d
是main
。
_start
main
不应该只是40077f
吗?为什么不?如果我刚刚删除了对40008f0
和nop
的所有来电并替换为{{1}},会发生什么?基本上,需要libc的意义是什么?
答案 0 :(得分:2)
/* These functions are passed to __libc_start_main by the startup code.
These get statically linked into each program. For dynamically linked
programs, this module will come from libc_nonshared.a and differs from
the libc.a module in that it doesn't call the preinit array. */
void
__libc_csu_init (int argc, char **argv, char **envp)
{
/* For dynamically linked executables the preinit array is executed by
the dynamic linker (before initializing any shared object). */
#ifndef LIBC_NONSHARED
/* For static executables, preinit happens right before init. */
{
const size_t size = __preinit_array_end - __preinit_array_start;
size_t i;
for (i = 0; i < size; i++)
(*__preinit_array_start [i]) (argc, argv, envp);
}
#endif
#ifndef NO_INITFINI
_init ();
#endif
const size_t size = __init_array_end - __init_array_start;
for (size_t i = 0; i < size; i++)
(*__init_array_start [i]) (argc, argv, envp);
}
/* This function should not be used anymore. We run the executable's
destructor now just like any other. We cannot remove the function,
though. */
void
__libc_csu_fini (void)
{
#ifndef LIBC_NONSHARED
size_t i = __fini_array_end - __fini_array_start;
while (i-- > 0)
(*__fini_array_start [i]) ();
# ifndef NO_INITFINI
_fini ();
# endif
#endif
}
这允许库初始化代码运行。链接到程序中的库可以使用gcc中的__attribute__((constructor))
标记函数,此机制将在main
之前运行这些函数,允许库在程序启动之前初始化它们。