gcc 简单的 hello-world 到底连接了什么

gcc hello 到底连接了什么
------------------------------------------------------------
源代码:
------------------------------------------------------------
[hjj@hjj ~]$ cat test.c
#include <stdio.h>

unsigned char d[]={
    0x12,0x34,0x56,0x78
};
int main(int argc, char *argv[])
{
    printf("data: %x\n", (*(int *)d));
    return 0;
}

------------------------------------------------------------
编译为.o
gcc -c -o test.o test.c
------------------------------------------------------------
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtbegin.o   /usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtend.o test.o -L/usr/lib64   -lc
至于第二行命令的来历,是如下实验,简化来的。
gcc -v -o test test.o
它有详细的输出,我们去掉无用部分,尝试修改一部分。简化得到

对hello 而言, crtbegin.o crtend.o 可以省略,如下示:
------------------------------------------------------------
简化的连接:
[hjj@hjj ~]$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o test.o -L/usr/lib64   -lc
------------------------------------------------------------
运行:
[hjj@hjj ~]$ ./test
data: 78563412
------------------------------------------------------------
删除crt1.o 连接错,找不到_start
------------------------------------------------------------
[hjj@hjj ~]$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib64/crti.o /usr/lib64/crtn.o test.o -L/usr/lib64   -lc
ld: warning: cannot find entry symbol _start; defaulting to 00000000004002d0
------------------------------------------------------------
删除crti.o 连接错,找不到_init
------------------------------------------------------------
[hjj@hjj ~]$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib64/crt1.o /usr/lib64/crtn.o test.o -L/usr/lib64   -lc
/usr/lib64/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x51): undefined reference to `_init'
------------------------------------------------------------
删除crtn.o 运行错, segmentation fault
------------------------------------------------------------
[hjj@hjj ~]$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib64/crt1.o /usr/lib64/crti.o test.o -L/usr/lib64   -lc
[hjj@hjj ~]$ ./test
Segmentation fault (core dumped)
------------------------------------------------------------
删除libc 库, 连接错, 找不到__libc_start_main 等
------------------------------------------------------------
[hjj@hjj ~]$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o test.o -L/usr/lib64   
/usr/lib64/crt1.o: In function `_start':
(.text+0x12): undefined reference to `__libc_csu_fini'
/usr/lib64/crt1.o: In function `_start':
(.text+0x19): undefined reference to `__libc_csu_init'
/usr/lib64/crt1.o: In function `_start':
(.text+0x25): undefined reference to `__libc_start_main'
test.o: In function `main':
test.c:(.text+0x26): undefined reference to `printf'
------------------------------------------------------------
不用dynamic-linker, 因找不到连接解释器,不能运行
------------------------------------------------------------
[hjj@hjj ~]$ ld  -o test /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o test.o -L/usr/lib64   -lc
[hjj@hjj ~]$ ./test
bash: ./test: /lib/ld64.so.1: bad ELF interpreter: No such file or directory

------------------------------------------------------------
c runtime obj 分析
------------------------------------------------------------
[hjj@hjj /usr/lib64]$ ls crt*
crt1.o  crti.o  crtn.o
[Hjjhjj /usr/lib64]$ nm crt1.o
0000000000000000 R _IO_stdin_used
0000000000000000 D __data_start
                 U __libc_csu_fini
                 U __libc_csu_init
                 U __libc_start_main
0000000000000000 T _start
0000000000000000 W data_start
                 U main
[hjj@hjj /usr/lib64]$ nm crti.o
                 U _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000000000 T _fini
0000000000000000 T _init
0000000000000000 t call_gmon_start
[hjj@hjj /usr/lib64]$ nm crtn.o
nm: crtn.o: no symbols

crt1.o中的未定义符号main在main.o中定义了,所以链接在一起就没问题了。
crt1.o还有未定义符号__libc_start_main .__libc_... 这些符号是在libc中定义的,
libc并不像其它目标文件一样链接到可执行文件main中,而是在运行时做动态链接:

1. 操作系统在加载执行main这个程序时,首先查看它有没有需要动态链接的符号。
2. 如果需要做动态链接,就查看这个程序指定了哪些共享库(我们用-lc指定了libc)
   以及用什么动态链接器来做动态链接(我们用-dynamic-linker /lib/ld-linux.so.2指定了动态链接器)。
3. 动态链接器在共享库中查找这些符号的定义,完成链接过程。

objdump -x -d crt1.o

还可以结合ida 分析.

------------------------------------------------------------
在crt1.o 中, 包含有代码的运行入口_start:
crt1.o 的前身叫crt0.o, 它的作用是作为连接的首个模块。
为了实现C++的全局构造和析构。改进crt0.o 为crt1.o
运行库在目标文件后引入了.init和.finit段,
.init在main函数前运行
.finit在main函数后运行
链接器将所有目标文件的init段和finit段合并,并产生两个函数:_init()和_finit()。
.init段,.finit 段需要的一些辅助代码,分别位于crti.o和crtn.o。
开始是来自crti.o的,而末尾是来自crtn.o的,中间才是真正程序的全局构造或者析构函数,
也就是说程序的全局构造和析构仅仅是_init和_finit的中间部分.

_start 函数调用: __libc_start_main 函数
__libc_start_main 会调用 __libc_csu_init, __libc_csu_fini,及main 函数
简单表示为如下:
__libc_start_main (main,__libc_csu_init,__libc_csu_fini)
__libc_csu_init, 负责调用_init()

__libc_csu_fini, 负责调用_finit()

------------------------------------------------------------

crt1.o 反编译.考虑上重定位信息

------------------------------------------------------------                       

                        public _start
                        _start proc near
31 ED                   xor     ebp, ebp
49 89 D1                mov     r9, rdx         ; rtld_fini
5E                      pop     rsi             ; argc
48 89 E2                mov     rdx, rsp        ; ubp_av
48 83 E4 F0             and     rsp, 0FFFFFFFFFFFFFFF0h
50                      push    rax
54                      push    rsp             ; stack_end
49 C7 C0 68 00 00 00    mov     r8, offset __libc_csu_fini ; fini
48 C7 C1 6C 00 00 00    mov     rcx, offset __libc_csu_init ; init
48 C7 C7 70 00 00 00    mov     rdi, offset main ; main
E8 4B 00 00 00          call    __libc_start_main

crti.o 反汇编, 考虑上重定位xinx

						; ===========================================================================
						; Segment type: Pure code
						; Segment permissions: Read/Execute
						_init           segment dword public 'CODE' use64
						                assume cs:_init
						                ;org 4
						                assume es:nothing, ss:nothing, ds:_text, fs:nothing, gs:nothing
						
						; =============== S U B R O U T I N E =======================================
                                         public _init_proc
                         _init_proc      proc near
48 83 EC 08                             sub     rsp, 8          ; _init
48 8B 05 19 00 00 00                    mov     rax, cs:__gmon_start___ptr
48 85 C0                                test    rax, rax
74 05                                   jz      short near ptr 19h
E8 07 00 00 00                          call    __gmon_start__  ; PIC mode
                         _init_proc      endp

						_init           ends


                         ; ===========================================================================
                         ; Segment type: Pure code
                         ; Segment permissions: Read/Execute		
                         _fini           segment dword public 'CODE' use64
                                         assume cs:_fini
                                         ;org 1Ch
                                         assume es:nothing, ss:nothing, ds:_text, fs:nothing, gs:nothing

                         ; =============== S U B R O U T I N E =======================================


                                         public _term_proc
                         _term_proc      proc near
 48 83 EC 08                             sub     rsp, 8          ; _fini
                         _term_proc      endp ; sp-analysis failed

                         _fini           ends

可见_init 就是调用__gmon_start__, 而_fini 只是恢复堆栈平衡.

------------------------------------------------------------

crtn.o 反编译. 直接用objdump 查看, 其符号是.init, .fini, 仅用来维护堆栈.

------------------------------------------------------------  

 objdump -d crtn.o

crtn.o:     file format elf64-x86-64


Disassembly of section .init:

0000000000000000 <.init>:
   0:	48 83 c4 08          	add    $0x8,%rsp
   4:	c3                   	retq   

Disassembly of section .fini:

0000000000000000 <.fini>:
   0:	48 83 c4 08          	add    $0x8,%rsp
   4:	c3                   	retq   



glic只是一个c语言库, crti.o和crtn.o只是提供了main之前和之后执行代码的机制,
真正C++全局构造和析构是由crtbegin.o和crtend.o实现的。
GCC是C++的真正实现者。这两个文件是用于配合glibc实现C++全局构造和析构的。

构造过程:
 _start-->__lib_start_main-->__libc_csu_init-->_init--> __do_global_ctors
析构过程: 执行与构造相反的过程

以下分析可执行文件test.

------------------------------------------------------------
反汇编代码分析
------------------------------------------------------------
[hjj@hjj ~]$ objdump -d test
test:     file format elf64-x86-64
Disassembly of section .init:

0000000000400330 <_init>:
  400330:    48 83 ec 08              sub    $0x8,%rsp
  400334:    e8 63 00 00 00           callq  40039c <call_gmon_start>
  400339:    48 83 c4 08              add    $0x8,%rsp
  40033d:    c3                       retq   

Disassembly of section .plt:

0000000000400340 <printf@plt-0x10>:
  400340:    ff 35 7a 03 20 00        pushq  0x20037a(%rip)        # 6006c0 <_GLOBAL_OFFSET_TABLE_+0x8>
  400346:    ff 25 7c 03 20 00        jmpq   *0x20037c(%rip)        # 6006c8 <_GLOBAL_OFFSET_TABLE_+0x10>
  40034c:    0f 1f 40 00              nopl   0x0(%rax)

0000000000400350 <printf@plt>:
  400350:    ff 25 7a 03 20 00        jmpq   *0x20037a(%rip)        # 6006d0 <_GLOBAL_OFFSET_TABLE_+0x18>
  400356:    68 00 00 00 00           pushq  $0x0
  40035b:    e9 e0 ff ff ff           jmpq   400340 <_init+0x10>

0000000000400360 <__libc_start_main@plt>:
  400360:    ff 25 72 03 20 00        jmpq   *0x200372(%rip)        # 6006d8 <_GLOBAL_OFFSET_TABLE_+0x20>
  400366:    68 01 00 00 00           pushq  $0x1
  40036b:    e9 d0 ff ff ff           jmpq   400340 <_init+0x10>

Disassembly of section .text:

0000000000400370 <_start>:
  400370:    31 ed                    xor    %ebp,%ebp
  400372:    49 89 d1                 mov    %rdx,%r9
  400375:    5e                       pop    %rsi
  400376:    48 89 e2                 mov    %rsp,%rdx
  400379:    48 83 e4 f0              and    $0xfffffffffffffff0,%rsp
  40037d:    50                       push   %rax
  40037e:    54                       push   %rsp
  40037f:    49 c7 c0 f0 03 40 00     mov    $0x4003f0,%r8
  400386:    48 c7 c1 00 04 40 00     mov    $0x400400,%rcx
  40038d:    48 c7 c7 b4 03 40 00     mov    $0x4003b4,%rdi
  400394:    e8 c7 ff ff ff           callq  400360 <__libc_start_main@plt>
  400399:    f4                       hlt    
  40039a:    90                       nop
  40039b:    90                       nop

000000000040039c <call_gmon_start>:
  40039c:    48 83 ec 08              sub    $0x8,%rsp
  4003a0:    48 8b 05 09 03 20 00     mov    0x200309(%rip),%rax        # 6006b0 <_DYNAMIC+0x190>
  4003a7:    48 85 c0                 test   %rax,%rax
  4003aa:    74 02                    je     4003ae <call_gmon_start+0x12>
  4003ac:    ff d0                    callq  *%rax
  4003ae:    48 83 c4 08              add    $0x8,%rsp
  4003b2:    c3                       retq   
  4003b3:    90                       nop

00000000004003b4 <main>:
  4003b4:    55                       push   %rbp
  4003b5:    48 89 e5                 mov    %rsp,%rbp
  4003b8:    48 83 ec 10              sub    $0x10,%rsp
  4003bc:    89 7d fc                 mov    %edi,-0x4(%rbp)
  4003bf:    48 89 75 f0              mov    %rsi,-0x10(%rbp)
  4003c3:    b8 e4 06 60 00           mov    $0x6006e4,%eax
  4003c8:    8b 10                    mov    (%rax),%edx
  4003ca:    b8 9c 04 40 00           mov    $0x40049c,%eax
  4003cf:    89 d6                    mov    %edx,%esi
  4003d1:    48 89 c7                 mov    %rax,%rdi
  4003d4:    b8 00 00 00 00           mov    $0x0,%eax
  4003d9:    e8 72 ff ff ff           callq  400350 <printf@plt>
  4003de:    b8 00 00 00 00           mov    $0x0,%eax
  4003e3:    c9                       leaveq
  4003e4:    c3                       retq   
  4003e5:    90                       nop
  4003e6:    90                       nop
  4003e7:    90                       nop
  4003e8:    90                       nop
  4003e9:    90                       nop
  4003ea:    90                       nop
  4003eb:    90                       nop
  4003ec:    90                       nop
  4003ed:    90                       nop
  4003ee:    90                       nop
  4003ef:    90                       nop

00000000004003f0 <__libc_csu_fini>:
  4003f0:    f3 c3                    repz retq
  4003f2:    66 66 66 66 66 2e 0f     data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
  4003f9:    1f 84 00 00 00 00 00

0000000000400400 <__libc_csu_init>:
  400400:    48 89 6c 24 d8           mov    %rbp,-0x28(%rsp)
  400405:    4c 89 64 24 e0           mov    %r12,-0x20(%rsp)
  40040a:    48 8d 2d 0f 01 20 00     lea    0x20010f(%rip),%rbp        # 600520 <_DYNAMIC>
  400411:    4c 8d 25 08 01 20 00     lea    0x200108(%rip),%r12        # 600520 <_DYNAMIC>
  400418:    4c 89 6c 24 e8           mov    %r13,-0x18(%rsp)
  40041d:    4c 89 74 24 f0           mov    %r14,-0x10(%rsp)
  400422:    4c 89 7c 24 f8           mov    %r15,-0x8(%rsp)
  400427:    48 89 5c 24 d0           mov    %rbx,-0x30(%rsp)
  40042c:    48 83 ec 38              sub    $0x38,%rsp
  400430:    4c 29 e5                 sub    %r12,%rbp
  400433:    41 89 fd                 mov    %edi,%r13d
  400436:    49 89 f6                 mov    %rsi,%r14
  400439:    48 c1 fd 03              sar    $0x3,%rbp
  40043d:    49 89 d7                 mov    %rdx,%r15
  400440:    e8 eb fe ff ff           callq  400330 <_init>
  400445:    48 85 ed                 test   %rbp,%rbp
  400448:    74 1c                    je     400466 <__libc_csu_init+0x66>
  40044a:    31 db                    xor    %ebx,%ebx
  40044c:    0f 1f 40 00              nopl   0x0(%rax)
  400450:    4c 89 fa                 mov    %r15,%rdx
  400453:    4c 89 f6                 mov    %r14,%rsi
  400456:    44 89 ef                 mov    %r13d,%edi
  400459:    41 ff 14 dc              callq  *(%r12,%rbx,8)
  40045d:    48 83 c3 01              add    $0x1,%rbx
  400461:    48 39 eb                 cmp    %rbp,%rbx
  400464:    72 ea                    jb     400450 <__libc_csu_init+0x50>
  400466:    48 8b 5c 24 08           mov    0x8(%rsp),%rbx
  40046b:    48 8b 6c 24 10           mov    0x10(%rsp),%rbp
  400470:    4c 8b 64 24 18           mov    0x18(%rsp),%r12
  400475:    4c 8b 6c 24 20           mov    0x20(%rsp),%r13
  40047a:    4c 8b 74 24 28           mov    0x28(%rsp),%r14
  40047f:    4c 8b 7c 24 30           mov    0x30(%rsp),%r15
  400484:    48 83 c4 38              add    $0x38,%rsp
  400488:    c3                       retq   

Disassembly of section .fini:

000000000040048c <_fini>:
  40048c:    48 83 ec 08              sub    $0x8,%rsp
  400490:    48 83 c4 08              add    $0x8,%rsp
  400494:    c3                       retq   
[hjj@hjj ~]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值