代码编译过程

来源:互联网 发布:渠道店面管理专员知乎 编辑:程序博客网 时间:2024/06/04 17:45

在编译代码时我们通常使用 gcc hello.c -o hello 即将hello.c文件编译成hello可执行文件。那么这其中编译器做了哪些工作?

从最简单的例子入手hello.c:

#include <stdio.h>int main(){    printf("hello\n");    return 0;}

《深入理解计算机系统》一书中给出编译器详细的工作流程图:

gcc编译过程

预处理

gcc     -E  hello.c     -o hello.i

-E参数是告知编译器只执行预处理工作,不执行后续编译工作。

-E Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.

预处理主要处理“#”开头的语句,具体包括如下过程:

  • 将#define删除并展开所有宏定义。
  • 处理所有条件预编译命令,例如“#if、#ifdef、#endif、#else、#elif”
  • 处理#include命令,将被包含文件插入到命令处,这是一递归的过程,
  • 保留所有#pragma编译器命令。
//短短的一个hello经过预处理后达到了800多行845 extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __lea    f__)) ;846847848 extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __lea    f__));849 # 943 "/usr/include/stdio.h" 3 4850851 # 8 "hello.c" 2852853 int main()854 {855     printf("hello\n");856     return 0;857 }

编译

gcc  -s  hello.i  -o hello.s (或 /usr/lib/gcc/i686-linux-gnu/4.9/cc1 hello.c)

编译过程是把预处理完的文件进行词法、语法、语义分析及优化后产生汇编代码文件
(ccl所在路径和版本与具体系统有关)

//编译后产生的汇编代码文件  1         .file   "hello.c"  2         .section        .rodata  3 .LC0:  4         .string "hello"  5         .text  6         .globl  main  7         .type   main, @function  8 main:  9 .LFB0: 10         .cfi_startproc 11         leal    4(%esp), %ecx 12         .cfi_def_cfa 1, 0 13         andl    $-16, %esp 14         pushl   -4(%ecx) 15         pushl   %ebp 16         .cfi_escape 0x10,0x5,0x2,0x75,0 17         movl    %esp, %ebp 18         pushl   %ecx 19         .cfi_escape 0xf,0x3,0x75,0x7c,0x6 20         subl    $4, %esp 21         subl    $12, %esp 22         pushl   $.LC0 23         call    puts

汇编

gcc -c hello.s -o hello.o(或 as hello.s –o hello.co )

该阶段汇编器(as)将 hello.s 翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在目标文件 hello.o 中。hello.o 文件是一个二进制文件(前面预处理和编译产生的都是可识别的文本文件),它的字节编码是机器语言指令而不是字符。
如果用vim打开,会发现全是看不懂的乱码,原因就在一此。

链接

ld -static crt1.o crti.o crtbeginT.o hello.o -start-group -lgcc -lgcc_eh -lc-end-group crtend.o crtn.o (省略了文件的路径名)此处涉及到很多东西,暂时没弄懂

hello程序调用了 printf 函数,printf 函数存在于一个名为 printf.o 的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的 hello.o 程序中。链接器(ld)就负责处理这种合并。结果就得到 hello 文件,它是一个可执行目标文件。

#have a good day
1 0