【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
Linux gcc论应用程序是如何跑起来的
相信我, 我真的只写了file.c这一个文件.
代码及编译指令交代:
#include<stdio.h>
void func(void)
{
printf("hello\n");
}
int main(void)
{
func();
return 0;
}
$gcc -c file.c -o file.o
$gcc file.o -o file
未链接前:
$nm file.o
0000000000000000 T func
U _GLOBAL_OFFSET_TABLE_
0000000000000013 T main
U puts
链接后:
$nm file
0000000000000830 t atexit
0000000000201010 B __bss_start
0000000000201010 b called.4604
0000000000201014 b completed.7698
U __cxa_atexit@@GLIBC_2.2.5
w __cxa_finalize@@GLIBC_2.2.5
0000000000201000 D __data_start
0000000000201000 W data_start
00000000000006a0 t deregister_tm_clones
0000000000000690 T _dl_relocate_static_pie
0000000000000730 t __do_global_dtors_aux
0000000000200da8 t __do_global_dtors_aux_fini_array_entry
0000000000201008 D __dso_handle
0000000000200db0 d _DYNAMIC
0000000000201010 D _edata
0000000000201018 B _end
0000000000000849 T etext
0000000000000840 T _fini
0000000000000770 t frame_dummy
0000000000200da0 t __frame_dummy_init_array_entry
0000000000000a1c r __FRAME_END__
000000000000077a T func
0000000000200fa0 d _GLOBAL_OFFSET_TABLE_
0000000000000640 T __gmon_start__
0000000000000858 r __GNU_EH_FRAME_HDR
00000000000005a0 T _init
0000000000200da8 t __init_array_end
0000000000200da0 t __init_array_start
000000000000084c R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000000820 T __libc_csu_fini
00000000000007b0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000000793 T main
U _mcleanup@@GLIBC_2.2.5
U mcount@@GLIBC_2.2.5
U __monstartup@@GLIBC_2.2.5
U puts@@GLIBC_2.2.5
00000000000006e0 t register_tm_clones
0000000000000610 T _start
0000000000201010 D __TMC_END__
因为链接器的缘故, func.o的0000000000000000 T func和0000000000000013 T main被成功整合到了最终的可执行文件中, 且由相对地址变成了绝对地址(即当程序运行时会被放置的地址): 000000000000077a T func和0000000000000793 T main.
但是相对于file.o的寥寥几行, 为什么被链接之后多了这么多呢?
在链接过程中, 链接器将我们的file.o与众多我们所依赖的库链接到了一起, 使得我们的程序可以正常且正确地运行!
那么, 其他同在代码段的函数会被执行吗? 会的, 将在main函数被执行的之前或之后!
论应用程序是如何跑起来的:
在默认的Linux gcc编译出来的应用程序, 程序加载后, _init()是第一个被调用执行的函数. 具体的流程如下: (我们可以使用objdump来验证我们的说法)$objdump -d file
file: file format elf64-x86-64
Disassembly of section .init:
00000000000005a0 <_init>:
5a0: 48 83 ec 08 sub $0x8,%rsp
5a4: 48 8d 05 95 00 00 00 lea 0x95(%rip),%rax # 640 <__gmon_start__>
5ab: 48 85 c0 test %rax,%rax
5ae: 74 02 je 5b2 <_init+0x12>
5b0: ff d0 callq *%rax
5b2: 48 83 c4 08 add $0x8,%rsp
5b6: c3 retq
Disassembly of section .plt:
00000000000005c0 <.plt>:
5c0: ff 35 e2 09 20 00 pushq 0x2009e2(%rip) # 200fa8 <_GLOBAL_OFFSET_TABLE_+0x8>
5c6: ff 25 e4 09 20 00 jmpq *0x2009e4(%rip) # 200fb0 <_GLOBAL_OFFSET_TABLE_+0x10>
5cc: 0f 1f 40 00 nopl 0x0(%rax)
00000000000005d0 <puts@plt>:
5d0: ff 25 e2 09 20 00 jmpq *0x2009e2(%rip) # 200fb8 <puts@GLIBC_2.2.5>
5d6: 68 00 00 00 00 pushq $0x0
5db: e9 e0 ff ff ff jmpq 5c0 <.plt>
00000000000005e0 <__monstartup@plt>:
5e0: ff 25 da 09 20 00 jmpq *0x2009da(%rip) # 200fc0 <__monstartup@GLIBC_2.2.5>
5e6: 68 01 00 00 00 pushq $0x1
5eb: e9 d0 ff ff ff jmpq 5c0 <.plt>
00000000000005f0 <__cxa_atexit@plt>:
5f0: ff 25 d2 09 20 00 jmpq *0x2009d2(%rip) # 200fc8 <__cxa_atexit@GLIBC_2.2.5>
5f6: 68 02 00 00 00 pushq $0x2
5fb: e9 c0 ff ff ff jmpq 5c0 <.plt>
Disassembly of section .plt.got:
0000000000000600 <__cxa_finalize@plt>:
600: ff 25 f2 09 20 00 jmpq *0x2009f2(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
606: 66 90 xchg %ax,%ax
Disassembly of section .text:
0000000000000610 <_start>:
610: 31 ed xor %ebp,%ebp
612: 49 89 d1 mov %rdx,%r9
615: 5e pop %rsi
616: 48 89 e2 mov %rsp,%rdx
619: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
61d: 50 push %rax
61e: 54 push %rsp
61f: 4c 8d 05 fa 01 00 00 lea 0x1fa(%rip),%r8 # 820 <__libc_csu_fini>
626: 48 8d 0d 83 01 00 00 lea 0x183(%rip),%rcx # 7b0 <__libc_csu_init>
62d: 48 8d 3d 5f 01 00 00 lea 0x15f(%rip),%rdi # 793 <main>
634: ff 15 a6 09 20 00 callq *0x2009a6(%rip) # 200fe0 <__libc_start_main@GLIBC_2.2.5>
63a: f4 hlt
63b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000000640 <__gmon_start__>:
640: 8b 05 ca 09 20 00 mov 0x2009ca(%rip),%eax # 201010 <__TMC_END__>
646: 85 c0 test %eax,%eax
648: 74 06 je 650 <__gmon_start__+0x10>
64a: f3 c3 repz retq
64c: 0f 1f 40 00 nopl 0x0(%rax)
650: 48 83 ec 08 sub $0x8,%rsp
654: 48 8d 3d b5 ff ff ff lea -0x4b(%rip),%rdi # 610 <_start>
65b: 48 8d 35 e7 01 00 00 lea 0x1e7(%rip),%rsi # 849 <etext>
662: c7 05 a4 09 20 00 01 movl $0x1,0x2009a4(%rip) # 201010 <__TMC_END__>
669: 00 00 00
66c: e8 6f ff ff ff callq 5e0 <__monstartup@plt>
671: 48 8b 3d 60 09 20 00 mov 0x200960(%rip),%rdi # 200fd8 <_mcleanup@GLIBC_2.2.5>
678: 48 83 c4 08 add $0x8,%rsp
67c: e9 af 01 00 00 jmpq 830 <atexit>
681: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
688: 00 00 00
68b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000000690 <_dl_relocate_static_pie>:
690: f3 c3 repz retq
692: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
699: 00 00 00
69c: 0f 1f 40 00 nopl 0x0(%rax)
00000000000006a0 <deregister_tm_clones>:
6a0: 48 8d 3d 69 09 20 00 lea 0x200969(%rip),%rdi # 201010 <__TMC_END__>
6a7: 55 push %rbp
6a8: 48 8d 05 61 09 20 00 lea 0x200961(%rip),%rax # 201010 <__TMC_END__>
6af: 48 39 f8 cmp %rdi,%rax
6b2: 48 89 e5 mov %rsp,%rbp
6b5: 74 19 je 6d0 <deregister_tm_clones+0x30>
6b7: 48 8b 05 12 09 20 00 mov 0x200912(%rip),%rax # 200fd0 <_ITM_deregisterTMCloneTable>
6be: 48 85 c0 test %rax,%rax
6c1: 74 0d je 6d0 <deregister_tm_clones+0x30>
6c3: 5d pop %rbp
6c4: ff e0 jmpq *%rax
6c6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
6cd: 00 00 00
6d0: 5d pop %rbp
6d1: c3 retq
6d2: 0f 1f 40 00 nopl 0x0(%rax)
6d6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
6dd: 00 00 00
00000000000006e0 <register_tm_clones>:
6e0: 48 8d 3d 29 09 20 00 lea 0x200929(%rip),%rdi # 201010 <__TMC_END__>
6e7: 48 8d 35 22 09 20 00 lea 0x200922(%rip),%rsi # 201010 <__TMC_END__>
6ee: 55 push %rbp
6ef: 48 29 fe sub %rdi,%rsi
6f2: 48 89 e5 mov %rsp,%rbp
6f5: 48 c1 fe 03 sar $0x3,%rsi
6f9: 48 89 f0 mov %rsi,%rax
6fc: 48 c1 e8 3f shr $0x3f,%rax
700: 48 01 c6 add %rax,%rsi
703: 48 d1 fe sar %rsi
706: 74 18 je 720 <register_tm_clones+0x40>
708: 48 8b 05 e1 08 20 00 mov 0x2008e1(%rip),%rax # 200ff0 <_ITM_registerTMCloneTable>
70f: 48 85 c0 test %rax,%rax
712: 74 0c je 720 <register_tm_clones+0x40>
714: 5d pop %rbp
715: ff e0 jmpq *%rax
717: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
71e: 00 00
720: 5d pop %rbp
721: c3 retq
722: 0f 1f 40 00 nopl 0x0(%rax)
726: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
72d: 00 00 00
0000000000000730 <__do_global_dtors_aux>:
730: 80 3d dd 08 20 00 00 cmpb $0x0,0x2008dd(%rip) # 201014 <completed.7698>
737: 75 2f jne 768 <__do_global_dtors_aux+0x38>
739: 48 83 3d b7 08 20 00 cmpq $0x0,0x2008b7(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
740: 00
741: 55 push %rbp
742: 48 89 e5 mov %rsp,%rbp
745: 74 0c je 753 <__do_global_dtors_aux+0x23>
747: 48 8b 3d ba 08 20 00 mov 0x2008ba(%rip),%rdi # 201008 <__dso_handle>
74e: e8 ad fe ff ff callq 600 <__cxa_finalize@plt>
753: e8 48 ff ff ff callq 6a0 <deregister_tm_clones>
758: c6 05 b5 08 20 00 01 movb $0x1,0x2008b5(%rip) # 201014 <completed.7698>
75f: 5d pop %rbp
760: c3 retq
761: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
768: f3 c3 repz retq
76a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000000770 <frame_dummy>:
770: 55 push %rbp
771: 48 89 e5 mov %rsp,%rbp
774: 5d pop %rbp
775: e9 66 ff ff ff jmpq 6e0 <register_tm_clones>
000000000000077a <func>:
77a: 55 push %rbp
77b: 48 89 e5 mov %rsp,%rbp
77e: ff 15 64 08 20 00 callq *0x200864(%rip) # 200fe8 <mcount@GLIBC_2.2.5>
784: 48 8d 3d c5 00 00 00 lea 0xc5(%rip),%rdi # 850 <_IO_stdin_used+0x4>
78b: e8 40 fe ff ff callq 5d0 <puts@plt>
790: 90 nop
791: 5d pop %rbp
792: c3 retq
0000000000000793 <main>:
793: 55 push %rbp
794: 48 89 e5 mov %rsp,%rbp
797: ff 15 4b 08 20 00 callq *0x20084b(%rip) # 200fe8 <mcount@GLIBC_2.2.5>
79d: e8 d8 ff ff ff callq 77a <func>
7a2: b8 00 00 00 00 mov $0x0,%eax
7a7: 5d pop %rbp
7a8: c3 retq
7a9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000000007b0 <__libc_csu_init>:
7b0: 41 57 push %r15
7b2: 41 56 push %r14
7b4: 49 89 d7 mov %rdx,%r15
7b7: 41 55 push %r13
7b9: 41 54 push %r12
7bb: 4c 8d 25 de 05 20 00 lea 0x2005de(%rip),%r12 # 200da0 <__frame_dummy_init_array_entry>
7c2: 55 push %rbp
7c3: 48 8d 2d de 05 20 00 lea 0x2005de(%rip),%rbp # 200da8 <__init_array_end>
7ca: 53 push %rbx
7cb: 41 89 fd mov %edi,%r13d
7ce: 49 89 f6 mov %rsi,%r14
7d1: 4c 29 e5 sub %r12,%rbp
7d4: 48 83 ec 08 sub $0x8,%rsp
7d8: 48 c1 fd 03 sar $0x3,%rbp
7dc: e8 bf fd ff ff callq 5a0 <_init>
7e1: 48 85 ed test %rbp,%rbp
7e4: 74 20 je 806 <__libc_csu_init+0x56>
7e6: 31 db xor %ebx,%ebx
7e8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
7ef: 00
7f0: 4c 89 fa mov %r15,%rdx
7f3: 4c 89 f6 mov %r14,%rsi
7f6: 44 89 ef mov %r13d,%edi
7f9: 41 ff 14 dc callq *(%r12,%rbx,8)
7fd: 48 83 c3 01 add $0x1,%rbx
801: 48 39 dd cmp %rbx,%rbp
804: 75 ea jne 7f0 <__libc_csu_init+0x40>
806: 48 83 c4 08 add $0x8,%rsp
80a: 5b pop %rbx
80b: 5d pop %rbp
80c: 41 5c pop %r12
80e: 41 5d pop %r13
810: 41 5e pop %r14
812: 41 5f pop %r15
814: c3 retq
815: 90 nop
816: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
81d: 00 00 00
0000000000000820 <__libc_csu_fini>:
820: f3 c3 repz retq
822: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
829: 00 00 00
82c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000000830 <atexit>:
830: 48 8b 15 d1 07 20 00 mov 0x2007d1(%rip),%rdx # 201008 <__dso_handle>
837: 31 f6 xor %esi,%esi
839: e9 b2 fd ff ff jmpq 5f0 <__cxa_atexit@plt>
Disassembly of section .fini:
0000000000000840 <_fini>:
840: 48 83 ec 08 sub $0x8,%rsp
844: 48 83 c4 08 add $0x8,%rsp
848: c3 retq
_init
__gmon_start__
_start
main
....
可见, 链接器为我们main()函数的正确运行做了许多工作, 使得我们不需要在意这些通用且重要的事情, 这也告诉了我们, 为什么我们的主程序需要是main(), 因为链接器在链接时, 只会找这个main()函数!