动态链接可执行文件运行
_start 定义于glibc/sysdeps/i386/start.S
__libc_start_main 定义于glibc/csu/libc-start.c
__libc_csu_init定义于glibc/csu/elf-init.c
__libc_init_first定义于glibc/csu/init-first.c
__gmon_start__定义于glibc/csu/gmon-start.c
exit定义于 glibc/stdlib/exit.c
frame_dummy __do_global_dtors_aux register_tm_clones deregister_tm_clones都定义于gcc/libgcc/crtstuff.c.)
一个包含一些特殊函数的c程序 excute.c :
#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
extern int* __libc_stack_end;
extern char **__environ;
extern int __libc_enable_secure;
//extern unsigned int * __stack_chk_guard;
extern int __libc_argc;
extern unsigned int *_GLOBAL_OFFSET_TABLE_;
extern void (**__init_array_start)();
void preinit_array(){
puts(__FUNCTION__);
}
__attribute__((section(".preinit_array"))) typeof(preinit_array) *__preinit_array = preinit_array;
__attribute__((constructor))void construct(){
puts(__FUNCTION__);
}
__attribute__((constructor))void construct1(){
puts(__FUNCTION__);
}
void init_array(){
puts(__FUNCTION__);
}
__attribute__((section(".init_array"))) typeof(init_array) *__init=init_array;
void at_exit1(){
puts(__FUNCTION__);
}
__attribute__((destructor))void destruct1(){
puts(__FUNCTION__);
}
void fini_array(){
puts(__FUNCTION__);
}
__attribute__((section(".fini_array"))) typeof(fini_array) *__fini=fini_array;
int main(int argc,char *argv[],char *envp[])
{
atexit(at_exit1);
return 0;
}
生成的可执行文件汇编结果
excute: 文件格式 elf32-i386
Contents of section .interp:
8048154 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so
8048164 2e3200 .2.
Contents of section .note.ABI-tag:
8048168 04000000 10000000 01000000 474e5500 ............GNU.
...........
Contents of section .note.gnu.build-id:
8048188 04000000 14000000 03000000 474e5500 ............GNU.
...........
Contents of section .gnu.hash:
80481ac 02000000 05000000 01000000 05000000 ................
...........
Contents of section .dynsym:
80481cc 00000000 00000000 00000000 00000000 ................
...........
Contents of section .dynstr:
804822c 006c6962 632e736f 2e36005f 494f5f73 .libc.so.6._IO_s
...........
Contents of section .gnu.version:
...........
Contents of section .gnu.version_r:
...........
Contents of section .rel.dyn:
80482cc fc9f0408 06030000 ........
Contents of section .rel.plt:
80482d4 0ca00408 07010000 10a00408 07020000 ................
80482e4 14a00408 07030000 18a00408 07040000 ................
Contents of section .init:
80482f4 5383ec08 e8a30000 0081c303 1d00008b S...............
8048304 83fcffff ff85c074 05e83e00 000083c4 .......t..>.....
8048314 085bc3 .[.
Contents of section .plt:
8048320 ff3504a0 0408ff25 08a00408 00000000 .5.....%........
8048330 ff250ca0 04086800 000000e9 e0ffffff .%....h.........
8048340 ff2510a0 04086808 000000e9 d0ffffff .%....h.........
8048350 ff2514a0 04086810 000000e9 c0ffffff .%....h.........
8048360 ff2518a0 04086818 000000e9 b0ffffff .%....h.........
Contents of section .text:
8048370 31ed5e89 e183e4f0 50545268 90850408 1.^.....PTRh....
...........
Contents of section .eh_frame_hdr:
804863c 011b033b 60000000 0b000000 e4fcffff ...;`...........
...........
Contents of section .eh_frame:
80486a0 14000000 00000000 017a5200 017c0801 .........zR..|..
...........
Contents of section .preinit_array:
8049ee4 6b840408 k...
Contents of section .init_array:
8049ee8 40840408 84840408 9d840408 @...........
Contents of section .fini_array:
8049ef4 20840408 cf840408 e8840408 ...........
Contents of section .jcr:
8049f00 00000000 ....
Contents of section .dynamic:
8049f04 01000000 01000000 0c000000 f4820408 ................
...........
Contents of section .got:
8049ffc 00000000 ....
Contents of section .got.plt:
804a000 049f0408 00000000 00000000 36830408 ............6...
804a010 46830408 56830408 66830408 F...V...f...
Contents of section .data:
804a01c 00000000 00000000 ........
Disassembly of section .init:
080482f4 <_init>:
80482f4: 53 push %ebx
80482f5: 83 ec 08 sub $0x8,%esp
80482f8: e8 a3 00 00 00 call 80483a0 <__x86.get_pc_thunk.bx>
80482fd: 81 c3 03 1d 00 00 add $0x1d03,%ebx
8048303: 8b 83 fc ff ff ff mov -0x4(%ebx),%eax
8048309: 85 c0 test %eax,%eax
804830b: 74 05 je 8048312 <_init+0x1e>
804830d: e8 3e 00 00 00 call 8048350 <__gmon_start__@plt>
8048312: 83 c4 08 add $0x8,%esp
8048315: 5b pop %ebx
8048316: c3 ret
Disassembly of section .plt:
08048320 <__cxa_atexit@plt-0x10>:
8048320: ff 35 04 a0 04 08 pushl 0x804a004
8048326: ff 25 08 a0 04 08 jmp *0x804a008
804832c: 00 00 add %al,(%eax)
...
08048330 <__cxa_atexit@plt>:
8048330: ff 25 0c a0 04 08 jmp *0x804a00c
8048336: 68 00 00 00 00 push $0x0
804833b: e9 e0 ff ff ff jmp 8048320 <_init+0x2c>
08048340 <puts@plt>:
8048340: ff 25 10 a0 04 08 jmp *0x804a010
8048346: 68 08 00 00 00 push $0x8
804834b: e9 d0 ff ff ff jmp 8048320 <_init+0x2c>
08048350 <__gmon_start__@plt>:
8048350: ff 25 14 a0 04 08 jmp *0x804a014
8048356: 68 10 00 00 00 push $0x10
804835b: e9 c0 ff ff ff jmp 8048320 <_init+0x2c>
08048360 <__libc_start_main@plt>:
8048360: ff 25 18 a0 04 08 jmp *0x804a018
8048366: 68 18 00 00 00 push $0x18
804836b: e9 b0 ff ff ff jmp 8048320 <_init+0x2c>
Disassembly of section .text:
08048370 <_start>:
080483a0 <__x86.get_pc_thunk.bx>:
80483a0: 8b 1c 24 mov (%esp),%ebx
80483a3: c3 ret
80483a4: 66 90 xchg %ax,%ax
80483a6: 66 90 xchg %ax,%ax
80483a8: 66 90 xchg %ax,%ax
80483aa: 66 90 xchg %ax,%ax
80483ac: 66 90 xchg %ax,%ax
80483ae: 66 90 xchg %ax,%ax
080483b0 <deregister_tm_clones>:
80483b0: b8 27 a0 04 08 mov $0x804a027,%eax
80483b5: 2d 24 a0 04 08 sub $0x804a024,%eax
80483ba: 83 f8 06 cmp $0x6,%eax
80483bd: 76 1a jbe 80483d9 <deregister_tm_clones+0x29>
80483bf: b8 00 00 00 00 mov $0x0,%eax
80483c4: 85 c0 test %eax,%eax
80483c6: 74 11 je 80483d9 <deregister_tm_clones+0x29>
80483c8: 55 push %ebp
80483c9: 89 e5 mov %esp,%ebp
80483cb: 83 ec 14 sub $0x14,%esp
80483ce: 68 24 a0 04 08 push $0x804a024
80483d3: ff d0 call *%eax
80483d5: 83 c4 10 add $0x10,%esp
80483d8: c9 leave
80483d9: f3 c3 repz ret
80483db: 90 nop
80483dc: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
080483e0 <register_tm_clones>:
80483e0: b8 24 a0 04 08 mov $0x804a024,%eax
80483e5: 2d 24 a0 04 08 sub $0x804a024,%eax
80483ea: c1 f8 02 sar $0x2,%eax
80483ed: 89 c2 mov %eax,%edx
80483ef: c1 ea 1f shr $0x1f,%edx
80483f2: 01 d0 add %edx,%eax
80483f4: d1 f8 sar %eax
80483f6: 74 1b je 8048413 <register_tm_clones+0x33>
80483f8: ba 00 00 00 00 mov $0x0,%edx
80483fd: 85 d2 test %edx,%edx
80483ff: 74 12 je 8048413 <register_tm_clones+0x33>
8048401: 55 push %ebp
8048402: 89 e5 mov %esp,%ebp
8048404: 83 ec 10 sub $0x10,%esp
8048407: 50 push %eax
8048408: 68 24 a0 04 08 push $0x804a024
804840d: ff d2 call *%edx
804840f: 83 c4 10 add $0x10,%esp
8048412: c9 leave
8048413: f3 c3 repz ret
8048415: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
8048419: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
08048420 <__do_global_dtors_aux>:
8048420: 80 3d 24 a0 04 08 00 cmpb $0x0,0x804a024
8048427: 75 13 jne 804843c <__do_global_dtors_aux+0x1c>
8048429: 55 push %ebp
804842a: 89 e5 mov %esp,%ebp
804842c: 83 ec 08 sub $0x8,%esp
804842f: e8 7c ff ff ff call 80483b0 <deregister_tm_clones>
8048434: c6 05 24 a0 04 08 01 movb $0x1,0x804a024
804843b: c9 leave
804843c: f3 c3 repz ret
804843e: 66 90 xchg %ax,%ax
08048440 <frame_dummy>:
8048440: b8 00 9f 04 08 mov $0x8049f00,%eax
8048445: 8b 10 mov (%eax),%edx
8048447: 85 d2 test %edx,%edx
8048449: 75 05 jne 8048450 <frame_dummy+0x10>
804844b: eb 93 jmp 80483e0 <register_tm_clones>
804844d: 8d 76 00 lea 0x0(%esi),%esi
8048450: ba 00 00 00 00 mov $0x0,%edx
8048455: 85 d2 test %edx,%edx
8048457: 74 f2 je 804844b <frame_dummy+0xb>
8048459: 55 push %ebp
804845a: 89 e5 mov %esp,%ebp
804845c: 83 ec 14 sub $0x14,%esp
804845f: 50 push %eax
8048460: ff d2 call *%edx
8048462: 83 c4 10 add $0x10,%esp
8048465: c9 leave
8048466: e9 75 ff ff ff jmp 80483e0 <register_tm_clones>
0804846b <preinit_array>:
804846b: 55 push %ebp
804846c: 89 e5 mov %esp,%ebp
804846e: 83 ec 08 sub $0x8,%esp
8048471: 83 ec 0c sub $0xc,%esp
8048474: 68 f0 85 04 08 push $0x80485f0
8048479: e8 c2 fe ff ff call 8048340 <puts@plt>
804847e: 83 c4 10 add $0x10,%esp
8048481: 90 nop
8048482: c9 leave
8048483: c3 ret
08048484 <construct>:
8048484: 55 push %ebp
8048485: 89 e5 mov %esp,%ebp
8048487: 83 ec 08 sub $0x8,%esp
804848a: 83 ec 0c sub $0xc,%esp
804848d: 68 00 86 04 08 push $0x8048600
8048492: e8 a9 fe ff ff call 8048340 <puts@plt>
8048497: 83 c4 10 add $0x10,%esp
804849a: 90 nop
804849b: c9 leave
804849c: c3 ret
0804849d <init_array>:
804849d: 55 push %ebp
804849e: 89 e5 mov %esp,%ebp
80484a0: 83 ec 08 sub $0x8,%esp
80484a3: 83 ec 0c sub $0xc,%esp
80484a6: 68 0c 86 04 08 push $0x804860c
80484ab: e8 90 fe ff ff call 8048340 <puts@plt>
80484b0: 83 c4 10 add $0x10,%esp
80484b3: 90 nop
80484b4: c9 leave
80484b5: c3 ret
080484b6 <at_exit1>:
80484b6: 55 push %ebp
80484b7: 89 e5 mov %esp,%ebp
80484b9: 83 ec 08 sub $0x8,%esp
80484bc: 83 ec 0c sub $0xc,%esp
80484bf: 68 18 86 04 08 push $0x8048618
80484c4: e8 77 fe ff ff call 8048340 <puts@plt>
80484c9: 83 c4 10 add $0x10,%esp
80484cc: 90 nop
80484cd: c9 leave
80484ce: c3 ret
080484cf <destruct1>:
80484cf: 55 push %ebp
80484d0: 89 e5 mov %esp,%ebp
80484d2: 83 ec 08 sub $0x8,%esp
80484d5: 83 ec 0c sub $0xc,%esp
80484d8: 68 24 86 04 08 push $0x8048624
80484dd: e8 5e fe ff ff call 8048340 <puts@plt>
80484e2: 83 c4 10 add $0x10,%esp
80484e5: 90 nop
80484e6: c9 leave
80484e7: c3 ret
080484e8 <fini_array>:
80484e8: 55 push %ebp
80484e9: 89 e5 mov %esp,%ebp
80484eb: 83 ec 08 sub $0x8,%esp
80484ee: 83 ec 0c sub $0xc,%esp
80484f1: 68 30 86 04 08 push $0x8048630
80484f6: e8 45 fe ff ff call 8048340 <puts@plt>
80484fb: 83 c4 10 add $0x10,%esp
80484fe: 90 nop
80484ff: c9 leave
8048500: c3 ret
08048501 <main>:
8048501: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048505: 83 e4 f0 and $0xfffffff0,%esp
8048508: ff 71 fc pushl -0x4(%ecx)
804850b: 55 push %ebp
804850c: 89 e5 mov %esp,%ebp
804850e: 51 push %ecx
804850f: 83 ec 04 sub $0x4,%esp
8048512: 83 ec 0c sub $0xc,%esp
8048515: 68 b6 84 04 08 push $0x80484b6
804851a: e8 81 00 00 00 call 80485a0 <atexit>
804851f: 83 c4 10 add $0x10,%esp
8048522: b8 00 00 00 00 mov $0x0,%eax
8048527: 8b 4d fc mov -0x4(%ebp),%ecx
804852a: c9 leave
804852b: 8d 61 fc lea -0x4(%ecx),%esp
804852e: c3 ret
804852f: 90 nop
08048530 <__libc_csu_init>:
08048590 <__libc_csu_fini>:
8048590: f3 c3 repz ret
8048592: 66 90 xchg %ax,%ax
8048594: 66 90 xchg %ax,%ax
8048596: 66 90 xchg %ax,%ax
8048598: 66 90 xchg %ax,%ax
804859a: 66 90 xchg %ax,%ax
804859c: 66 90 xchg %ax,%ax
804859e: 66 90 xchg %ax,%ax
080485a0 <atexit>:
80485a0: 53 push %ebx
80485a1: e8 fa fd ff ff call 80483a0 <__x86.get_pc_thunk.bx>
80485a6: 81 c3 5a 1a 00 00 add $0x1a5a,%ebx
80485ac: 83 ec 08 sub $0x8,%esp
80485af: 8d 83 20 00 00 00 lea 0x20(%ebx),%eax
80485b5: 85 c0 test %eax,%eax
80485b7: 74 17 je 80485d0 <atexit+0x30>
80485b9: 8b 00 mov (%eax),%eax
80485bb: 83 ec 04 sub $0x4,%esp
80485be: 50 push %eax
80485bf: 6a 00 push $0x0
80485c1: ff 74 24 1c pushl 0x1c(%esp)
80485c5: e8 66 fd ff ff call 8048330 <__cxa_atexit@plt>
80485ca: 83 c4 18 add $0x18,%esp
80485cd: 5b pop %ebx
80485ce: c3 ret
80485cf: 90 nop
80485d0: 31 c0 xor %eax,%eax
80485d2: eb e7 jmp 80485bb <atexit+0x1b>
Disassembly of section .fini:
080485d4 <_fini>:
80485d4: 53 push %ebx
80485d5: 83 ec 08 sub $0x8,%esp
80485d8: e8 c3 fd ff ff call 80483a0 <__x86.get_pc_thunk.bx>
80485dd: 81 c3 23 1a 00 00 add $0x1a23,%ebx
80485e3: 83 c4 08 add $0x8,%esp
80485e6: 5b pop %ebx
80485e7: c3 ret
当目标文件运行时,在可执行文件的段头表的指导下,加载器加载可执行文件的相关部分加载到代码段和数据段,然后跳转到_start的地址,_start的启动代码是定义在crt1.o中,在从.text和.init节调用了初始化例程后,启动atexit注册的函数,附加一系列在调用exit时应该调用的程序,exit函数运行atexit注册的函数然后调用_exit将控制返回给操作系统.启动main程序,返回之后启动代码调用_exit程序,将控制返回给操作系统.
运行流程:
- shell 加载可执行文件到内存 并完成部分初始化工作 待研究
- 跳入_start
- 跳入__libc_start_main
- 调用__libc_init_first
- 调用__libc_csu_init
- 调用main
- 调用exit 不再返回
跳入_start
/* This is the canonical entry point, usually the first thing in the text
segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
point runs, most registers' values are unspecified, except for:
%edx Contains a function pointer to be registered with `atexit'.
This is how the dynamic linker arranges to have DT_FINI
functions called for shared libraries that have been loaded
before this code runs.
%esp The stack contains the arguments and environment:
0(%esp) argc
4(%esp) argv[0]
...
(4*argc)(%esp) NULL
(4*(argc+1))(%esp) envp[0]
...
NULL
*/
start:
/* Clear the frame pointer. The ABI suggests this be done, to mark
the outermost frame obviously. */
xorl %ebp, %ebp
/* Extract the arguments as encoded on the stack and set up
the arguments for `main': argc, argv. envp will be determined
later in __libc_start_main. */
popl %esi /* Pop the argument count. */
movl %esp, %ecx /* argv starts just at the current stack top.*/
/* Before pushing the arguments align the stack to a 16-byte
(SSE needs 16-byte alignment) boundary to avoid penalties from
misaligned accesses. Thanks to Edward Seidl <seidl@janed.com>
for pointing this out. */
andl $0xfffffff0, %esp
pushl %eax /* Push garbage because we allocate
28 more bytes. */
/* Provide the highest stack address to the user code (for stacks
which grow downwards). */
pushl %esp
pushl %edx /* Push address of the shared library
termination function. */
/* Push address of our own entry points to .fini and .init. */
pushl $__libc_csu_fini
pushl $__libc_csu_init
pushl %ecx /* Push second argument: argv. */
pushl %esi /* Push first argument: argc. */
pushl $main /* Call the user's main function, and exit with its value.But let the libc call main. */
call __libc_start_main
08048370 <_start>:
8048370: 31 ed xor %ebp,%ebp
8048372: 5e pop %esi
8048373: 89 e1 mov %esp,%ecx
8048375: 83 e4 f0 and $0xfffffff0,%esp
8048378: 50 push %eax
8048379: 54 push %esp
804837a: 52 push %edx
804837b: 68 90 85 04 08 push $0x8048590
8048380: 68 30 85 04 08 push $0x8048530
8048385: 51 push %ecx
8048386: 56 push %esi
8048387: 68 01 85 04 08 push $0x8048501
804838c: e8 cf ff ff ff call 8048360 <__libc_start_main@plt>
8048391: f4 hlt
8048392: 66 90 xchg %ax,%ax
8048394: 66 90 xchg %ax,%ax
8048396: 66 90 xchg %ax,%ax
8048398: 66 90 xchg %ax,%ax
804839a: 66 90 xchg %ax,%ax
804839c: 66 90 xchg %ax,%ax
804839e: 66 90 xchg %ax,%ax
所以跳入_start相当于调用函数
__libc_start_main(int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char **argv,
__typeof (main) init,
void (*fini) (void),
void (*rtld_fini) (void), void *stack_end)
跳入__libc_start_main:
将libc_start.c单独编译
gcc -m32 -E libc-start.c -I../sysdeps/generic
注 并不清楚编译选项
玄学事件: 一旦-o选项或者将输出重定向就报错 也是没谁了….
int __libc_start_main (int (*main) (int, char **, char ** ),int argc, char **argv,__typeof (main) init,void (*fini) (void),void (*rtld_fini) (void), void *stack_end)
{
int result;
__libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
char **ev = &argv[argc + 1];
__environ = ev;
__libc_stack_end = stack_end;
{
extern const Elf32_Ehdr __ehdr_start __attribute__ ((weak, visibility ("hidden")));
if (&__ehdr_start != ((void *)0)) {
((__ehdr_start.e_phentsize == sizeof *_dl_phdr) ? (void) (0) : __assert_fail ("__ehdr_start.e_phentsize == sizeof *_dl_phdr", "./src/libc-start.c", 175, __PRETTY_FUNCTION__));
_dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff;
_dl_phnum = __ehdr_start.e_phnum;
}
}
/* Perform IREL{,A} relocations. */
apply_irel ();
/* Initialize the thread library at least a bit since the libgcc
functions are using thread functions if these are available and
we need to setup errno. */
__pthread_initialize_minimal ();
/* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
__stack_chk_guard = stack_chk_guard;
/* Set up the pointer guard value. */
uintptr_t pointer_chk_guard = _dl_setup_pointer_guard(_dl_random,stack_chk_guard);
__pointer_chk_guard_local = pointer_chk_guard;
/* Register the destructor of the program, if any. */
if (__builtin_expect ((rtld_fini != ((void *)0)), 1))
__cxa_atexit ((void (*) (void *)) rtld_fini,((void *)0),((void *)0));
/* Call the initializer of the libc. This is only needed here if we
are compiling for the static library in which case we haven't
run the constructors in `_dl_start_user'. */
__libc_init_first (argc, argv, __environ);
/* Register the destructor of the program, if any. */
if (fini)
__cxa_atexit ((void (*) (void *)) fini,((void *)0),((void *)0));
/* Some security at this point. Prevent starting a SUID binary where
the standard file descriptors are not opened. We have to do this
only for statically linked applications since otherwise the dynamic
loader did the work already. */
if (__builtin_expect (__libc_enable_secure, 0))
__libc_check_standard_fds ();
if (init)
(*init) (argc, argv, __environ );
_dl_debug_initialize (0, LM_ID_BASE);
result = main (argc, argv, __environ );
exit (result);
}
功能为: (摘自http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html)
Takes care of some security problems with setuid setgid programs
Starts up threading
Registers the fini (our program), and rtld_fini (run-time loader) arguments to get run by at_exit to run the program’s and the loader’s cleanup routines
Calls the init argument
Calls the main with the argc and argv arguments passed to it and with the global __environ argument as detailed above.
Calls exit with the return value of main
所以_libc_start_main的执行过程为
call __libc_init_first;
call __libc_csu_init;
call main
call exit
1. 调用__libc_init_first:
void
__libc_init_first (int argc, char **argv, char **envp)
{
#ifdef USE_NONOPTION_FLAGS
extern void __getopt_clean_environment (char **);
#endif
__libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
/* Make sure we don't initialize twice. */
if (!__libc_multiple_libcs)
{
/* Set the FPU control word to the proper default value if the
kernel would use a different value. */
if (__fpu_control != GLRO(dl_fpu_control))
__setfpucw (__fpu_control);
}
/* Save the command-line arguments. */
__libc_argc = argc;
__libc_argv = argv;
__environ = envp;
#ifndef SHARED
__libc_init_secure ();
/* First the initialization which normally would be done by the
dynamic linker. */
_dl_non_dynamic_init ();
#endif
#ifdef VDSO_SETUP
VDSO_SETUP ();
#endif
__init_misc (argc, argv, envp);
#ifdef USE_NONOPTION_FLAGS
/* This is a hack to make the special getopt in GNU libc working. */
__getopt_clean_environment (envp);
#endif
/* Initialize ctype data. */
__ctype_init ();
}
调用_libc_init_first的作用为?待研究
2. 调用__libc_csu_init:
void __libc_csu_init (int argc, char **argv, char **envp)
{
/*
*这只是静态可执行文件中,但是动态可执行文件中__preinit_不是在此时执行
*经过gdb的运行验证 preinit是在动态链接时执行的 早于_start
*/
#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
_init ();
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);
}
08048530 <__libc_csu_init>:
8048530: 55 push %ebp
8048531: 57 push %edi
8048532: 31 ff xor %edi,%edi
8048534: 56 push %esi
8048535: 53 push %ebx
8048536: e8 65 fe ff ff call 80483a0 <__x86.get_pc_thunk.bx>
804853b: 81 c3 c5 1a 00 00 add $0x1ac5,%ebx //ebx存储着.got段的地址
8048541: 83 ec 0c sub $0xc,%esp
8048544: 8b 6c 24 20 mov 0x20(%esp),%ebp
8048548: 8d b3 f4 fe ff ff lea -0x10c(%ebx),%esi //esi存储着.fini_array的地址 __init_array_end
804854e: e8 a1 fd ff ff call 80482f4 <_init>
8048553: 8d 83 e8 fe ff ff lea -0x118(%ebx),%eax //%eax中存储着.init_array的地址 __init_array_start
8048559: 29 c6 sub %eax,%esi
804855b: c1 fe 02 sar $0x2,%esi //esi 存储着init_array的大小
804855e: 85 f6 test %esi,%esi
8048560: 74 23 je 8048585 <__libc_csu_init+0x55>
8048562: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
8048568: 83 ec 04 sub $0x4,%esp
804856b: ff 74 24 2c pushl 0x2c(%esp)
804856f: ff 74 24 2c pushl 0x2c(%esp)
8048573: 55 push %ebp
8048574: ff 94 bb e8 fe ff ff call *-0x118(%ebx,%edi,4)
804857b: 83 c7 01 add $0x1,%edi
804857e: 83 c4 10 add $0x10,%esp
8048581: 39 f7 cmp %esi,%edi
8048583: 75 e3 jne 8048568 <__libc_csu_init+0x38>
8048585: 83 c4 0c add $0xc,%esp
8048588: 5b pop %ebx
8048589: 5e pop %esi
804858a: 5f pop %edi
804858b: 5d pop %ebp
804858c: c3 ret
804858d: 8d 76 00 lea 0x0(%esi),%esi
Contents of section .preinit_array:
8049ee4 6b840408(preinit地址) k...
Contents of section .init_array:
8049ee8 40840408(frame_dummy) 84840408(construct ) 9d840408(init_array) @...........
__libc_csu_init先后执行_init和__init_array中定义的函数
此处__init_array_start为.init_array段的开始位置__init_array_end为.fini_array的开始地址
所以__libc_cus_init相当于执行了
call _init
call frame_dummy //?作用待研究
call construct
call init_array (可以定义多个)
(相当于执行了在.init_array储存的函数指针)
1. 调用_init:
Disassembly of section .init:
080482f4 <_init>:
80482f4: 53 push %ebx
80482f5: 83 ec 08 sub $0x8,%esp
80482f8: e8 a3 00 00 00 call 80483a0 <__x86.get_pc_thunk.bx>
80482fd: 81 c3 03 1d 00 00 add $0x1d03,%ebx
8048303: 8b 83 fc ff ff ff mov -0x4(%ebx),%eax
8048309: 85 c0 test %eax,%eax
804830b: 74 05 je 8048312 <_init+0x1e>
804830d: e8 3e 00 00 00 call 8048350 <__gmon_start__@plt>
8048312: 83 c4 08 add $0x8,%esp
8048315: 5b pop %ebx
8048316: c3 ret
gmon_start:用于辅助gprof分析程序所用的 一般不会执行(除非gcc编译时 开启-pg选项) 关于其的介绍可以参考http://www.cnblogs.com/lenolix/archive/2010/12/13/1904868.html
void
__gmon_start__ (void)
{
/* Protect from being called more than once. Since crti.o is linked
into every shared library, each of their init functions will call us. */
static int called;
if (called)
return;
called = 1;
/* Start keeping profiling records. */
__monstartup ((u_long) TEXT_START, (u_long) &etext);
/* Call _mcleanup before exiting; it will write out gmon.out from the
collected data. */
atexit (&_mcleanup);
}
调用.init_array段中函数
- frame_dummy:
08048440 <frame_dummy>:
8048440: b8 00 9f 04 08 mov $0x8049f00,%eax //.jcr段的数据
8048445: 8b 10 mov (%eax),%edx
8048447: 85 d2 test %edx,%edx
8048449: 75 05 jne 8048450 <frame_dummy+0x10>
804844b: eb 93 jmp 80483e0 <register_tm_clones>
804844d: 8d 76 00 lea 0x0(%esi),%esi
8048450: ba 00 00 00 00 mov $0x0,%edx
8048455: 85 d2 test %edx,%edx
8048457: 74 f2 je 804844b <frame_dummy+0xb>
8048459: 55 push %ebp
804845a: 89 e5 mov %esp,%ebp
804845c: 83 ec 14 sub $0x14,%esp
804845f: 50 push %eax
8048460: ff d2 call *%edx
8048462: 83 c4 10 add $0x10,%esp
8048465: c9 leave
8048466: e9 75 ff ff ff jmp 80483e0 <register_tm_clones>
由汇编代码分析有:其作用在于检查是否.jcr段中的数据为0 为0 则直接跳入register_tm_clones; 不为0则陷入死循环?
register_tm_clones:
080483e0 <register_tm_clones>:
80483e0: b8 24 a0 04 08 mov $0x804a024,%eax
80483e5: 2d 24 a0 04 08 sub $0x804a024,%eax
80483ea: c1 f8 02 sar $0x2,%eax
80483ed: 89 c2 mov %eax,%edx
80483ef: c1 ea 1f shr $0x1f,%edx
80483f2: 01 d0 add %edx,%eax
80483f4: d1 f8 sar %eax
80483f6: 74 1b je 8048413 <register_tm_clones+0x33>
80483f8: ba 00 00 00 00 mov $0x0,%edx
80483fd: 85 d2 test %edx,%edx
80483ff: 74 12 je 8048413 <register_tm_clones+0x33>
8048401: 55 push %ebp
8048402: 89 e5 mov %esp,%ebp
8048404: 83 ec 10 sub $0x10,%esp
8048407: 50 push %eax
8048408: 68 24 a0 04 08 push $0x804a024
804840d: ff d2 call *%edx
804840f: 83 c4 10 add $0x10,%esp
8048412: c9 leave
8048413: f3 c3 repz ret
8048415: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
8048419: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
作用为:?
3.调用main函数
返回值赋予result 作为exit的参数
4.调用exit函数
void
exit (int status)
{
__run_exit_handlers (status, &__exit_funcs, true);
}
libc_hidden_def (exit)
0002edd0 <exit>:
2edd0: 53 push %ebx
2edd1: e8 0f 43 0f 00 call 1230e5 <__frame_state_for+0x375>
2edd6: 81 c3 2a 82 18 00 add $0x18822a,%ebx
2eddc: 83 ec 0c sub $0xc,%esp
2eddf: 8d 83 1c 04 00 00 lea 0x41c(%ebx),%eax
2ede5: 6a 01 push $0x1
2ede7: 50 push %eax
2ede8: ff 74 24 1c pushl 0x1c(%esp)
2edec: e8 bf fe ff ff call 2ecb0 <__libc_secure_getenv+0x30>
2edf1: 66 90 xchg %ax,%ax
2edf3: 66 90 xchg %ax,%ax
2edf5: 66 90 xchg %ax,%ax
2edf7: 66 90 xchg %ax,%ax
2edf9: 66 90 xchg %ax,%ax
2edfb: 66 90 xchg %ax,%ax
2edfd: 66 90 xchg %ax,%ax
2edff: 90 nop
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
void
attribute_hidden
__run_exit_handlers (int status, struct exit_function_list **listp,
bool run_list_atexit)
{
/* First, call the TLS destructors. */
#ifndef SHARED
if (&__call_tls_dtors != NULL)
#endif
__call_tls_dtors ();
/* We do it this way to handle recursive calls to exit () made by
the functions registered with `atexit' and `on_exit'. We call
everyone on the list and use the status value in the last
exit (). */
while (*listp != NULL)
{
struct exit_function_list *cur = *listp;
while (cur->idx > 0)
{
const struct exit_function *const f =
&cur->fns[--cur->idx];
switch (f->flavor)
{
void (*atfct) (void);
void (*onfct) (int status, void *arg);
void (*cxafct) (void *arg, int status);
case ef_free:
case ef_us:
break;
case ef_on:
onfct = f->func.on.fn;
#ifdef PTR_DEMANGLE
PTR_DEMANGLE (onfct);
#endif
onfct (status, f->func.on.arg);
break;
case ef_at:
atfct = f->func.at;
#ifdef PTR_DEMANGLE
PTR_DEMANGLE (atfct);
#endif
atfct ();
break;
case ef_cxa:
cxafct = f->func.cxa.fn;
#ifdef PTR_DEMANGLE
PTR_DEMANGLE (cxafct);
#endif
cxafct (f->func.cxa.arg, status);
break;
}
}
*listp = cur->next;
if (*listp != NULL)
/* Don't free the last element in the chain, this is the statically
allocate element. */
free (cur);
}
if (run_list_atexit)
RUN_HOOK (__libc_atexit, ());
_exit (status);
}
__run_exit_handlers的汇编代码:
2ecb1: 57 push %edi
2ecb2: 56 push %esi
2ecb3: 53 push %ebx
2ecb4: e8 2c 44 0f 00 call 1230e5 <__frame_state_for+0x375>
2ecb9: 81 c3 47 83 18 00 add $0x188347,%ebx
2ecbf: 83 ec 1c sub $0x1c,%esp
2ecc2: 8b 44 24 38 mov 0x38(%esp),%eax
2ecc6: 8b 74 24 30 mov 0x30(%esp),%esi
2ecca: 8b 7c 24 34 mov 0x34(%esp),%edi
2ecce: 89 44 24 0c mov %eax,0xc(%esp)
2ecd2: e8 39 06 00 00 call 2f310 <__call_tls_dtors>
2ecd7: 8b 2f mov (%edi),%ebp
2ecd9: 85 ed test %ebp,%ebp
2ecdb: 74 42 je 2ed1f <__libc_secure_getenv+0x9f>
2ecdd: 8d 76 00 lea 0x0(%esi),%esi
2ece0: 8b 45 04 mov 0x4(%ebp),%eax //从此处开始while 循环
2ece3: 89 c2 mov %eax,%edx
2ece5: c1 e2 04 shl $0x4,%edx
2ece8: 85 c0 test %eax,%eax
2ecea: 8d 4c 15 f8 lea -0x8(%ebp,%edx,1),%ecx
2ecee: 74 22 je 2ed12 <__libc_secure_getenv+0x92>
2ecf0: 8b 11 mov (%ecx),%edx
2ecf2: 83 e8 01 sub $0x1,%eax
2ecf5: 89 45 04 mov %eax,0x4(%ebp)
2ecf8: 83 fa 03 cmp $0x3,%edx
2ecfb: 0f 84 9f 00 00 00 je 2eda0 <__libc_secure_getenv+0x120>
2ed01: 83 fa 04 cmp $0x4,%edx
2ed04: 74 72 je 2ed78 <__libc_secure_getenv+0xf8>
2ed06: 83 fa 02 cmp $0x2,%edx
2ed09: 74 45 je 2ed50 <__libc_secure_getenv+0xd0>
2ed0b: 83 e9 10 sub $0x10,%ecx
2ed0e: 85 c0 test %eax,%eax
2ed10: 75 de jne 2ecf0 <__libc_secure_getenv+0x70>
2ed12: 8b 45 00 mov 0x0(%ebp),%eax
2ed15: 85 c0 test %eax,%eax
2ed17: 89 07 mov %eax,(%edi)
2ed19: 0f 85 99 00 00 00 jne 2edb8 <__libc_secure_getenv+0x138>
2ed1f: 80 7c 24 0c 00 cmpb $0x0,0xc(%esp)
2ed24: 74 19 je 2ed3f <__libc_secure_getenv+0xbf> //此处结束
2ed26: 8d bb ac df ff ff lea -0x2054(%ebx),%edi
2ed2c: 8d ab b0 df ff ff lea -0x2050(%ebx),%ebp
2ed32: 39 ef cmp %ebp,%edi
2ed34: 73 09 jae 2ed3f <__libc_secure_getenv+0xbf>
2ed36: ff 17 call *(%edi)
2ed38: 83 c7 04 add $0x4,%edi
2ed3b: 39 ef cmp %ebp,%edi
2ed3d: 72 f7 jb 2ed36 <__libc_secure_getenv+0xb6>
2ed3f: 83 ec 0c sub $0xc,%esp
2ed42: 56 push %esi
2ed43: e8 2c 4f 08 00 call b3c74 <_exit>
2ed48: 90 nop
2ed49: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
2ed50: c1 e0 04 shl $0x4,%eax
2ed53: 83 ec 08 sub $0x8,%esp
2ed56: 01 e8 add %ebp,%eax
2ed58: 8b 50 0c mov 0xc(%eax),%edx
2ed5b: ff 70 10 pushl 0x10(%eax)
2ed5e: 56 push %esi
2ed5f: c1 ca 09 ror $0x9,%edx
2ed62: 65 33 15 18 00 00 00 xor %gs:0x18,%edx
2ed69: ff d2 call *%edx
2ed6b: 83 c4 10 add $0x10,%esp
2ed6e: e9 6d ff ff ff jmp 2ece0 <__libc_secure_getenv+0x60>
2ed73: 90 nop
2ed74: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
2ed78: c1 e0 04 shl $0x4,%eax
2ed7b: 83 ec 08 sub $0x8,%esp
2ed7e: 01 e8 add %ebp,%eax
2ed80: 8b 50 0c mov 0xc(%eax),%edx
2ed83: 56 push %esi
2ed84: ff 70 10 pushl 0x10(%eax)
2ed87: c1 ca 09 ror $0x9,%edx
2ed8a: 65 33 15 18 00 00 00 xor %gs:0x18,%edx
2ed91: ff d2 call *%edx
2ed93: 83 c4 10 add $0x10,%esp
2ed96: e9 45 ff ff ff jmp 2ece0 <__libc_secure_getenv+0x60>
2ed9b: 90 nop
2ed9c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
2eda0: c1 e0 04 shl $0x4,%eax
2eda3: 8b 44 05 0c mov 0xc(%ebp,%eax,1),%eax
2eda7: c1 c8 09 ror $0x9,%eax
2edaa: 65 33 05 18 00 00 00 xor %gs:0x18,%eax
2edb1: ff d0 call *%eax
2edb3: e9 28 ff ff ff jmp 2ece0 <__libc_secure_getenv+0x60>
2edb8: 83 ec 0c sub $0xc,%esp
2edbb: 55 push %ebp
2edbc: e8 1f 87 fe ff call 174e0 <free@plt>
2edc1: 83 c4 10 add $0x10,%esp
2edc4: e9 0e ff ff ff jmp 2ecd7 <__libc_secure_getenv+0x57>
2edc9: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
/* Call the destructors. This is called either when a thread returns from the
initial function or when the process exits via the exit function. */
void
__call_tls_dtors (void)
{
while (tls_dtor_list)
{
struct dtor_list *cur = tls_dtor_list;
dtor_func func = cur->func;
#ifdef PTR_DEMANGLE
PTR_DEMANGLE (func);
#endif
tls_dtor_list = tls_dtor_list->next;
func (cur->obj);
/* Ensure that the MAP dereference happens before
l_tls_dtor_count decrement. That way, we protect this access from a
potential DSO unload in _dl_close_worker, which happens when
l_tls_dtor_count is 0. See CONCURRENCY NOTES for more detail. */
atomic_fetch_add_release (&cur->map->l_tls_dtor_count, -1);
free (cur);
}
}
libc_hidden_def (__call_tls_dtors)
__call_tls_dtors 的汇编代码:
2f310: 55 push %ebp
2f311: 57 push %edi
2f312: 8d 3d 20 00 00 00 lea 0x20,%edi
2f318: 56 push %esi
2f319: 53 push %ebx
2f31a: e8 c6 3d 0f 00 call 1230e5 <__frame_state_for+0x375>
2f31f: 81 c3 e1 7c 18 00 add $0x187ce1,%ebx
2f325: 83 ec 0c sub $0xc,%esp
2f328: 8d 83 7c fe ff ff lea -0x184(%ebx),%eax
2f32e: e8 9d 81 fe ff call 174d0 <___tls_get_addr@plt>
2f333: 8b 34 07 mov (%edi,%eax,1),%esi
2f336: 8b 83 b0 fe ff ff mov -0x150(%ebx),%eax
2f33c: 85 f6 test %esi,%esi
2f33e: 8d a8 c4 04 00 00 lea 0x4c4(%eax),%ebp
2f344: 75 37 jne 2f37d <__call_tls_dtors+0x6d>
2f346: e9 95 00 00 00 jmp 2f3e0 <__call_tls_dtors+0xd0>
2f34b: 90 nop
2f34c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
2f350: 83 ec 0c sub $0xc,%esp
2f353: 8b 83 b0 fe ff ff mov -0x150(%ebx),%eax
2f359: 55 push %ebp
2f35a: ff 90 fc 07 00 00 call *0x7fc(%eax)
2f360: 89 34 24 mov %esi,(%esp)
2f363: e8 78 81 fe ff call 174e0 <free@plt>
2f368: 8d 83 7c fe ff ff lea -0x184(%ebx),%eax
2f36e: e8 5d 81 fe ff call 174d0 <___tls_get_addr@plt>
2f373: 83 c4 10 add $0x10,%esp
2f376: 8b 34 07 mov (%edi,%eax,1),%esi
2f379: 85 f6 test %esi,%esi
2f37b: 74 63 je 2f3e0 <__call_tls_dtors+0xd0>
2f37d: 8d 83 7c fe ff ff lea -0x184(%ebx),%eax
2f383: e8 48 81 fe ff call 174d0 <___tls_get_addr@plt>
2f388: 8b 56 0c mov 0xc(%esi),%edx
2f38b: 83 ec 0c sub $0xc,%esp
2f38e: 89 14 07 mov %edx,(%edi,%eax,1)
2f391: ff 76 04 pushl 0x4(%esi)
2f394: ff 16 call *(%esi)
2f396: 8b 83 b0 fe ff ff mov -0x150(%ebx),%eax
2f39c: 89 2c 24 mov %ebp,(%esp)
2f39f: ff 90 f8 07 00 00 call *0x7f8(%eax)
2f3a5: 8b 56 08 mov 0x8(%esi),%edx
2f3a8: 83 c4 10 add $0x10,%esp
2f3ab: 8b 82 48 02 00 00 mov 0x248(%edx),%eax
2f3b1: 83 e8 01 sub $0x1,%eax
2f3b4: 85 c0 test %eax,%eax
2f3b6: 89 82 48 02 00 00 mov %eax,0x248(%edx)
2f3bc: 75 92 jne 2f350 <__call_tls_dtors+0x40>
2f3be: 0f b6 82 94 01 00 00 movzbl 0x194(%edx),%eax
2f3c5: 83 e0 03 and $0x3,%eax
2f3c8: 3c 02 cmp $0x2,%al
2f3ca: 75 84 jne 2f350 <__call_tls_dtors+0x40>
2f3cc: 83 a2 04 02 00 00 f7 andl $0xfffffff7,0x204(%edx)
2f3d3: e9 78 ff ff ff jmp 2f350 <__call_tls_dtors+0x40>
2f3d8: 90 nop
2f3d9: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
2f3e0: 83 c4 0c add $0xc,%esp
2f3e3: 5b pop %ebx
2f3e4: 5e pop %esi
2f3e5: 5f pop %edi
2f3e6: 5d pop %ebp
2f3e7: c3 ret
2f3e8: 66 90 xchg %ax,%ax
2f3ea: 66 90 xchg %ax,%ax
2f3ec: 66 90 xchg %ax,%ax
2f3ee: 66 90 xchg %ax,%ax
/* The function `_exit' should take a status argument and simply
terminate program execution, using the low-order 8 bits of the
given integer as status. */
void
_exit (int status)
{
status &= 0xff;
abort ();
}
libc_hidden_def (_exit)
根据gdb的运行结果分析
while循环中首先调用的是atexit中注册的函数 然后是一个函数调用了ldlinuxso.txt(objdump -d ld-linux.so得到的文件)在17171-17448的指令
然后在循环中按照在.fini_array段中由后向前的顺序执行fini_array和destruct,__do_global_dtors_auxContents of section .fini_array: 8049ef4 20840408(__do_global_dtors_aux) cf840408(destruct1) e8840408(fini_array)
之后位于ld-linux.so中的指令执行了_fini
返回__run_exit_handlers 调用_exit
f370: 8b 45 e0 mov -0x20(%ebp),%eax
f373: 8b 4d e4 mov -0x1c(%ebp),%ecx
f376: 8b 34 88 mov (%eax,%ecx,4),%esi
f379: 0f b6 86 94 01 00 00 movzbl 0x194(%esi),%eax
f380: a8 08 test $0x8,%al
f382: 0f 84 80 00 00 00 je f408 <_dl_rtld_di_serinfo+0x6c68>
f388: 83 e0 f7 and $0xfffffff7,%eax
f38b: 88 86 94 01 00 00 mov %al,0x194(%esi)
f391: 8b 86 88 00 00 00 mov 0x88(%esi),%eax
f397: 85 c0 test %eax,%eax
f399: 0f 84 e1 00 00 00 je f480 <_dl_rtld_di_serinfo+0x6ce0>
f39f: f6 83 00 fd ff ff 02 testb $0x2,-0x300(%ebx)
f3a6: 0f 85 f4 00 00 00 jne f4a0 <_dl_rtld_di_serinfo+0x6d00>
f3ac: 8b 3e mov (%esi),%edi
f3ae: 03 78 04 add 0x4(%eax),%edi
f3b1: 8b 86 90 00 00 00 mov 0x90(%esi),%eax
f3b7: 8b 40 04 mov 0x4(%eax),%eax
f3ba: 89 f9 mov %edi,%ecx
f3bc: c1 e8 02 shr $0x2,%eax
f3bf: 85 c0 test %eax,%eax
f3c1: 74 19 je f3dc <_dl_rtld_di_serinfo+0x6c3c>
f3c3: 89 75 d8 mov %esi,-0x28(%ebp)
f3c6: 89 cf mov %ecx,%edi
f3c8: 89 c6 mov %eax,%esi
> f3ca: 8d b6 00 00 00 00 lea 0x0(%esi),%esi //入口地址 从函数跳入存储
f3d0: ff 54 b7 fc call *-0x4(%edi,%esi,4)
f3d4: 83 ee 01 sub $0x1,%esi
f3d7: 75 f7 jne f3d0 <_dl_rtld_di_serinfo+0x6c30> //这个循环逆序执行了.fini_array中存储的函数地址
f3d9: 8b 75 d8 mov -0x28(%ebp),%esi
f3dc: 8b 56 54 mov 0x54(%esi),%edx
f3df: 85 d2 test %edx,%edx
f3e1: 74 07 je f3ea <_dl_rtld_di_serinfo+0x6c4a>
f3e3: 8b 06 mov (%esi),%eax
f3e5: 03 42 04 add 0x4(%edx),%eax
f3e8: ff d0 call *%eax
f3ea: 8b 7d d4 mov -0x2c(%ebp),%edi
f3ed: 85 ff test %edi,%edi
f3ef: 75 17 jne f408 <_dl_rtld_di_serinfo+0x6c68>
f3f1: 8b 8b c8 fe ff ff mov -0x138(%ebx),%ecx
f3f7: 8d 05 00 fd ff ff lea 0xfffffd00,%eax
f3fd: 89 45 d8 mov %eax,-0x28(%ebp)
f400: 85 c9 test %ecx,%ecx
f402: 0f 85 d8 00 00 00 jne f4e0 <_dl_rtld_di_serinfo+0x6d40>
f408: 83 45 e4 01 addl $0x1,-0x1c(%ebp)
f40c: 83 ae 90 01 00 00 01 subl $0x1,0x190(%esi)
f413: 8b 45 e4 mov -0x1c(%ebp),%eax
f416: 3b 45 dc cmp -0x24(%ebp),%eax
f419: 0f 85 51 ff ff ff jne f370 <_dl_rtld_di_serinfo+0x6bd0>
f41f: 83 6d d0 01 subl $0x1,-0x30(%ebp)
f423: 83 6d c4 4c subl $0x4c,-0x3c(%ebp)
f427: 8b 45 d0 mov -0x30(%ebp),%eax
f42a: 83 f8 ff cmp $0xffffffff,%eax
f42d: 0f 85 3d fe ff ff jne f270 <_dl_rtld_di_serinfo+0x6ad0>
f433: 8b 55 d4 mov -0x2c(%ebp),%edx
f436: 85 d2 test %edx,%edx
f438: 75 2a jne f464 <_dl_rtld_di_serinfo+0x6cc4>
f43a: 8b 83 c8 fe ff ff mov -0x138(%ebx),%eax
f440: 85 c0 test %eax,%eax
f442: 74 20 je f464 <_dl_rtld_di_serinfo+0x6cc4>
f444: 8b 45 c8 mov -0x38(%ebp),%eax
f447: c7 45 d4 01 00 00 00 movl $0x1,-0x2c(%ebp)
f44e: 8b 84 18 c0 04 00 00 mov 0x4c0(%eax,%ebx,1),%eax
f455: 89 45 e4 mov %eax,-0x1c(%ebp)
f458: 83 e8 01 sub $0x1,%eax
f45b: 89 45 d0 mov %eax,-0x30(%ebp)
f45e: 0f 89 cb fd ff ff jns f22f <_dl_rtld_di_serinfo+0x6a8f>
f464: f6 83 00 fd ff ff 80 testb $0x80,-0x300(%ebx)
f46b: 0f 85 13 01 00 00 jne f584 <_dl_rtld_di_serinfo+0x6de4>
f471: 8d 65 f4 lea -0xc(%ebp),%esp
f474: 5b pop %ebx
f475: 5e pop %esi
f476: 5f pop %edi
f477: 5d pop %ebp
f478: c3 ret
__libc_csu_fini : 已经不再使用
/* 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)
{
size_t i = __fini_array_end - __fini_array_start;
while (i-- > 0)
(*__fini_array_start [i]) ();
_fini ();
}
参考:
1. how linux Program Startup