更多精彩内容在公众号。

我们在写程序的时候,windows下通过vs等编译软件,linux通过gcc命令得到程序的可执行文件。在这个过程中,其实大致经历了4个过程。1 预编译 2 编译 3 汇编 4 链接

1 预编译:主要处理那些源代码文件中的以”#”开头的预编译指令,比如”#include”,“#define”等。

2 编译:就是把预处理完的文件进行一系列词法分析,语法分析,语义分析以及优化后生成相应的汇编代码文件

3 汇编:就是将汇编代码转变成机器可以执行的指令。

4 链接:一个工程里面包含很多.c的文件。我们最终工程得到的是.out文件。但是这个是将所有涉及到的文件都链接起来才得到的。这个就是链接的功能。

我们用一个最常见的代码来看下这几个过程

#include <stdio.h>

int main(void){

printf("hello world");

return 0;

}

gcc main.c -o main.i生成预编译文件。通过file main.i可以查看到文件的格式是ELF。这个后面会详细介绍。

root@zhf-maple:/home/zhf/c_prj# file main.i

main.i: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a19f9545eefb261b7ec7d27cf12702c3881c5ea7, not stripped

objdump -i main.i可以看到具体的内容。

通过gcc main.c -o main.s生成编译文件.objdump -S 可以查看具体的汇编代码

root@zhf-maple:/home/zhf/c_prj# objdump -S main.s

main.s:     文件格式 elf64-x86-64

Disassembly of section .init:

00000000000004f0 <_init>:

 4f0: 48 83 ec 08           sub    $0x8,%rsp

 4f4: 48 8b 05 ed 0a 20 00  mov    0x200aed(%rip),%rax        # 200fe8 <__gmon_start__>

 4fb: 48 85 c0              test   %rax,%rax

 4fe: 74 02                 je     502 <_init+0x12>

 500: ff d0                 callq  *%rax

 502: 48 83 c4 08           add    $0x8,%rsp

 506: c3                    retq   

Disassembly of section .plt:

0000000000000510 <.plt>:

 510: ff 35 aa 0a 20 00     pushq  0x200aaa(%rip)        # 200fc0 <_GLOBAL_OFFSET_TABLE_+0x8>

 516: ff 25 ac 0a 20 00     jmpq   *0x200aac(%rip)        # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x10>

 51c: 0f 1f 40 00           nopl   0x0(%rax)

0000000000000520 <printf@plt>:

 520: ff 25 aa 0a 20 00     jmpq   *0x200aaa(%rip)        # 200fd0 <printf@GLIBC_2.2.5>

 526: 68 00 00 00 00        pushq  $0x0

 52b: e9 e0 ff ff ff        jmpq   510 <.plt>

Disassembly of section .plt.got:

0000000000000530 <__cxa_finalize@plt>:

 530: ff 25 c2 0a 20 00     jmpq   *0x200ac2(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>

 536: 66 90                 xchg   %ax,%ax

Disassembly of section .text:

0000000000000540 <_start>:

 540: 31 ed                 xor    %ebp,%ebp

 542: 49 89 d1              mov    %rdx,%r9

 545: 5e                    pop    %rsi

 546: 48 89 e2              mov    %rsp,%rdx

 549: 48 83 e4 f0           and    $0xfffffffffffffff0,%rsp

 54d: 50                    push   %rax

 54e: 54                    push   %rsp

 54f: 4c 8d 05 8a 01 00 00  lea    0x18a(%rip),%r8        # 6e0 <__libc_csu_fini>

 556: 48 8d 0d 13 01 00 00  lea    0x113(%rip),%rcx        # 670 <__libc_csu_init>

 55d: 48 8d 3d e6 00 00 00  lea    0xe6(%rip),%rdi        # 64a <main>

 564: ff 15 76 0a 20 00     callq  *0x200a76(%rip)        # 200fe0 <__libc_start_main@GLIBC_2.2.5>

 56a: f4                    hlt    

 56b: 0f 1f 44 00 00        nopl   0x0(%rax,%rax,1)

0000000000000570 <deregister_tm_clones>:

 570: 48 8d 3d 99 0a 20 00  lea    0x200a99(%rip),%rdi        # 201010 <__TMC_END__>

 577: 55                    push   %rbp

 578: 48 8d 05 91 0a 20 00  lea    0x200a91(%rip),%rax        # 201010 <__TMC_END__>

 57f: 48 39 f8              cmp    %rdi,%rax

 582: 48 89 e5              mov    %rsp,%rbp

 585: 74 19                 je     5a0 <deregister_tm_clones+0x30>

 587: 48 8b 05 4a 0a 20 00  mov    0x200a4a(%rip),%rax        # 200fd8 <_ITM_deregisterTMCloneTable>

 58e: 48 85 c0              test   %rax,%rax

 591: 74 0d                 je     5a0 <deregister_tm_clones+0x30>

 593: 5d                    pop    %rbp

 594: ff e0                 jmpq   *%rax

 596: 66 2e 0f 1f 84 00 00  nopw   %cs:0x0(%rax,%rax,1)

 59d: 00 00 00 

 5a0: 5d                    pop    %rbp

 5a1: c3                    retq   

 5a2: 0f 1f 40 00           nopl   0x0(%rax)

 5a6: 66 2e 0f 1f 84 00 00  nopw   %cs:0x0(%rax,%rax,1)

 5ad: 00 00 00 

00000000000005b0 <register_tm_clones>:

 5b0: 48 8d 3d 59 0a 20 00  lea    0x200a59(%rip),%rdi        # 201010 <__TMC_END__>

 5b7: 48 8d 35 52 0a 20 00  lea    0x200a52(%rip),%rsi        # 201010 <__TMC_END__>

 5be: 55                    push   %rbp

 5bf: 48 29 fe              sub    %rdi,%rsi

 5c2: 48 89 e5              mov    %rsp,%rbp

 5c5: 48 c1 fe 03           sar    $0x3,%rsi

 5c9: 48 89 f0              mov    %rsi,%rax

 5cc: 48 c1 e8 3f           shr    $0x3f,%rax

 5d0: 48 01 c6              add    %rax,%rsi

 5d3: 48 d1 fe              sar    %rsi

 5d6: 74 18                 je     5f0 <register_tm_clones+0x40>

 5d8: 48 8b 05 11 0a 20 00  mov    0x200a11(%rip),%rax        # 200ff0 <_ITM_registerTMCloneTable>

 5df: 48 85 c0              test   %rax,%rax

 5e2: 74 0c                 je     5f0 <register_tm_clones+0x40>

 5e4: 5d                    pop    %rbp

 5e5: ff e0                 jmpq   *%rax

 5e7: 66 0f 1f 84 00 00 00  nopw   0x0(%rax,%rax,1)

 5ee: 00 00 

 5f0: 5d                    pop    %rbp

 5f1: c3                    retq   

 5f2: 0f 1f 40 00           nopl   0x0(%rax)

 5f6: 66 2e 0f 1f 84 00 00  nopw   %cs:0x0(%rax,%rax,1)

 5fd: 00 00 00 

0000000000000600 <__do_global_dtors_aux>:

 600: 80 3d 09 0a 20 00 00  cmpb   $0x0,0x200a09(%rip)        # 201010 <__TMC_END__>

 607: 75 2f                 jne    638 <__do_global_dtors_aux+0x38>

 609: 48 83 3d e7 09 20 00  cmpq   $0x0,0x2009e7(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>

 610: 00 

 611: 55                    push   %rbp

 612: 48 89 e5              mov    %rsp,%rbp

 615: 74 0c                 je     623 <__do_global_dtors_aux+0x23>

 617: 48 8b 3d ea 09 20 00  mov    0x2009ea(%rip),%rdi        # 201008 <__dso_handle>

 61e: e8 0d ff ff ff        callq  530 <__cxa_finalize@plt>

 623: e8 48 ff ff ff        callq  570 <deregister_tm_clones>

 628: c6 05 e1 09 20 00 01  movb   $0x1,0x2009e1(%rip)        # 201010 <__TMC_END__>

 62f: 5d                    pop    %rbp

 630: c3                    retq   

 631: 0f 1f 80 00 00 00 00  nopl   0x0(%rax)

 638: f3 c3                 repz retq 

 63a: 66 0f 1f 44 00 00     nopw   0x0(%rax,%rax,1)

0000000000000640 <frame_dummy>:

 640: 55                    push   %rbp

 641: 48 89 e5              mov    %rsp,%rbp

 644: 5d                    pop    %rbp

 645: e9 66 ff ff ff        jmpq   5b0 <register_tm_clones>

000000000000064a <main>:

 64a: 55                    push   %rbp

 64b: 48 89 e5              mov    %rsp,%rbp

 64e: 48 8d 3d 9f 00 00 00  lea    0x9f(%rip),%rdi        # 6f4 <_IO_stdin_used+0x4>

 655: b8 00 00 00 00        mov    $0x0,%eax

 65a: e8 c1 fe ff ff        callq  520 <printf@plt>

 65f: b8 00 00 00 00        mov    $0x0,%eax

 664: 5d                    pop    %rbp

 665: c3                    retq   

 666: 66 2e 0f 1f 84 00 00  nopw   %cs:0x0(%rax,%rax,1)

 66d: 00 00 00 

0000000000000670 <__libc_csu_init>:

 670: 41 57                 push   %r15

 672: 41 56                 push   %r14

 674: 41 89 ff              mov    %edi,%r15d

 677: 41 55                 push   %r13

 679: 41 54                 push   %r12

 67b: 4c 8d 25 36 07 20 00  lea    0x200736(%rip),%r12        # 200db8 <__frame_dummy_init_array_entry>

 682: 55                    push   %rbp

 683: 48 8d 2d 36 07 20 00  lea    0x200736(%rip),%rbp        # 200dc0 <__init_array_end>

 68a: 53                    push   %rbx

 68b: 49 89 f6              mov    %rsi,%r14

 68e: 49 89 d5              mov    %rdx,%r13

 691: 4c 29 e5              sub    %r12,%rbp

 694: 48 83 ec 08           sub    $0x8,%rsp

 698: 48 c1 fd 03           sar    $0x3,%rbp

 69c: e8 4f fe ff ff        callq  4f0 <_init>

 6a1: 48 85 ed              test   %rbp,%rbp

 6a4: 74 20                 je     6c6 <__libc_csu_init+0x56>

 6a6: 31 db                 xor    %ebx,%ebx

 6a8: 0f 1f 84 00 00 00 00  nopl   0x0(%rax,%rax,1)

 6af: 00 

 6b0: 4c 89 ea              mov    %r13,%rdx

 6b3: 4c 89 f6              mov    %r14,%rsi

 6b6: 44 89 ff              mov    %r15d,%edi

 6b9: 41 ff 14 dc           callq  *(%r12,%rbx,8)

 6bd: 48 83 c3 01           add    $0x1,%rbx

 6c1: 48 39 dd              cmp    %rbx,%rbp

 6c4: 75 ea                 jne    6b0 <__libc_csu_init+0x40>

 6c6: 48 83 c4 08           add    $0x8,%rsp

 6ca: 5b                    pop    %rbx

 6cb: 5d                    pop    %rbp

 6cc: 41 5c                 pop    %r12

 6ce: 41 5d                 pop    %r13

 6d0: 41 5e                 pop    %r14

 6d2: 41 5f                 pop    %r15

 6d4: c3                    retq   

 6d5: 90                    nop

 6d6: 66 2e 0f 1f 84 00 00  nopw   %cs:0x0(%rax,%rax,1)

 6dd: 00 00 00 

00000000000006e0 <__libc_csu_fini>:

 6e0: f3 c3                 repz retq 

Disassembly of section .fini:

00000000000006e4 <_fini>:

 6e4: 48 83 ec 08           sub    $0x8,%rsp

 6e8: 48 83 c4 08           add    $0x8,%rsp

 6ec: c3                    retq   

.o文件的格式如下。分为.text/.data/.bss/.comment/.note.GNU-stack/.eh_frame 5个段。

root@zhf-maple:/home/zhf/c_prj# objdump -h main.o

main.o:     文件格式 elf64-x86-64

节:

Idx Name          Size      VMA               LMA               File off  Algn

  0 .text         00000015  0000000000000000  0000000000000000  00000040  2**0

                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE

  1 .data         00000000  0000000000000000  0000000000000000  00000055  2**0

                  CONTENTS, ALLOC, LOAD, DATA

  2 .bss          00000000  0000000000000000  0000000000000000  00000055  2**0

                  ALLOC

  3 .comment      00000024  0000000000000000  0000000000000000  00000055  2**0

                  CONTENTS, READONLY

  4 .note.GNU-stack 00000000  0000000000000000  0000000000000000  00000079  2**0

                  CONTENTS, READONLY

  5 .eh_frame     00000038  0000000000000000  0000000000000000  00000080  2**3

                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

.o文件又称为目标文件。在linux下目标文件的格式为ELF。ELF格式的文件可以归纳为下面4类

ELF文件类型

说明

实例

可重定位文件(Relocatable File)

包含代码和数据,可以被用来链接成可执行文件或共享目标文件

.o文件

可执行文件

包含了可以直接执行的程序,代表就是ELF可执行文件

比如/bin/bash文件windows的exe文件

共享目标文件

包含代码和数据,2种情况下使用

1 链接器可以使用这种文件跟其他的可重定位文件和共享文件链接产生新的目标文件

2 动态链接将几个这种共享目标文件与可执行文件结合,做和进程映射的一部分来运行

linux的.so

windows的dll

核心转储文件

当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转储到核心文件

linux下的core dump

通过file命令查看相应的文件格式

root@zhf-maple:/home/zhf/c_prj# file main.o

main.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

前面在用objdum -h main.o的时候看到了有

text/.data/.bss/.comment/.note.GNU-stack/.eh_frame 5个段。那么这些段的意义是什么呢。代码段最常见的就是.text和.data。 作用如下

1 一般c语言编译后的执行语句都编译成机器代码,保存在.text段

2 已初始化的全局变量和局部静态变量都保存在.data段

3 未初始化的全局变量和局部静态变量放在.bss段里面

ELF文件分别由4部分组成:1 ELF头,2 程序头表,3 节section,4 节头表。如下图。

通过readelf -a main.o命令来看到具体的信息。比如在ELF头中描述了文件属性,入口地址,程序头地址,操作系统等。

ELF 头:

  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 

  类别:                              ELF64

  数据:                              2 补码,小端序 (little endian)

  版本:                              1 (current)

  OS/ABI:                            UNIX - System V

  ABI 版本:                          0

  类型:                              DYN (共享目标文件)

  系统架构:                          Advanced Micro Devices X86-64

  版本:                              0x1

  入口点地址:               0x540

  程序头起点:          64 (bytes into file)

  Start of section headers:          6592 (bytes into file)

  标志:             0x0

  本头的大小:       64 (字节)

  程序头大小:       56 (字节)

  Number of program headers:         9

  节头大小:         64 (字节)

  节头数量:         29

  字符串表索引节头: 28

节头中能看到对应的sectioni信息

节头:

  [号] 名称              类型             地址              偏移量

       大小              全体大小          旗标   链接   信息   对齐

  [ 0]                   NULL             0000000000000000  00000000

       0000000000000000  0000000000000000           0     0     0

  [ 1] .interp           PROGBITS         0000000000000238  00000238

       000000000000001c  0000000000000000   A       0     0     1

  [ 2] .note.ABI-tag     NOTE             0000000000000254  00000254

       0000000000000020  0000000000000000   A       0     0     4

  [ 3] .note.gnu.build-i NOTE             0000000000000274  00000274

       0000000000000024  0000000000000000   A       0     0     4

  [ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298

       000000000000001c  0000000000000000   A       5     0     8

  [ 5] .dynsym           DYNSYM           00000000000002b8  000002b8

       00000000000000a8  0000000000000018   A       6     1     8

  [ 6] .dynstr           STRTAB           0000000000000360  00000360

       0000000000000084  0000000000000000   A       0     0     1

  [ 7] .gnu.version      VERSYM           00000000000003e4  000003e4

       000000000000000e  0000000000000002   A       5     0     2

  [ 8] .gnu.version_r    VERNEED          00000000000003f8  000003f8

       0000000000000020  0000000000000000   A       6     1     8

  [ 9] .rela.dyn         RELA             0000000000000418  00000418

       00000000000000c0  0000000000000018   A       5     0     8

  [10] .rela.plt         RELA             00000000000004d8  000004d8

       0000000000000018  0000000000000018  AI       5    22     8

  [11] .init             PROGBITS         00000000000004f0  000004f0

       0000000000000017  0000000000000000  AX       0     0     4

  [12] .plt              PROGBITS         0000000000000510  00000510

       0000000000000020  0000000000000010  AX       0     0     16

  [13] .plt.got          PROGBITS         0000000000000530  00000530

       0000000000000008  0000000000000008  AX       0     0     8

  [14] .text             PROGBITS         0000000000000540  00000540

       00000000000001a2  0000000000000000  AX       0     0     16

  [15] .fini             PROGBITS         00000000000006e4  000006e4

       0000000000000009  0000000000000000  AX       0     0     4

  [16] .rodata           PROGBITS         00000000000006f0  000006f0

       0000000000000010  0000000000000000   A       0     0     4

  [17] .eh_frame_hdr     PROGBITS         0000000000000700  00000700

       000000000000003c  0000000000000000   A       0     0     4

  [18] .eh_frame         PROGBITS         0000000000000740  00000740

       0000000000000108  0000000000000000   A       0     0     8

  [19] .init_array       INIT_ARRAY       0000000000200db8  00000db8

       0000000000000008  0000000000000008  WA       0     0     8

  [20] .fini_array       FINI_ARRAY       0000000000200dc0  00000dc0

       0000000000000008  0000000000000008  WA       0     0     8

  [21] .dynamic          DYNAMIC          0000000000200dc8  00000dc8

       00000000000001f0  0000000000000010  WA       6     0     8

  [22] .got              PROGBITS         0000000000200fb8  00000fb8

       0000000000000048  0000000000000008  WA       0     0     8

  [23] .data             PROGBITS         0000000000201000  00001000

       0000000000000014  0000000000000000  WA       0     0     8

  [24] .bss              NOBITS           0000000000201014  00001014

       0000000000000014  0000000000000000  WA       0     0     4

  [25] .comment          PROGBITS         0000000000000000  00001014

       0000000000000023  0000000000000001  MS       0     0     1

  [26] .symtab           SYMTAB           0000000000000000  00001038

       0000000000000648  0000000000000018          27    45     8

  [27] .strtab           STRTAB           0000000000000000  00001680

       0000000000000240  0000000000000000           0     0     1

  [28] .shstrtab         STRTAB           0000000000000000  000018c0

       00000000000000fe  0000000000000000           0     0     1

Key to Flags:

  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),

  L (link order), O (extra OS processing required), G (group), T (TLS),

  C (compressed), x (unknown), o (OS specific), E (exclude),

  l (large), p (processor specific)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐