从C源代码到可执行文件的总体过程框架

16 篇文章 0 订阅

出处:http://blog.csdn.net/gabriel1026/article/details/6321701  

使用gcc进行编译c语言文件很简单:

      gabriel@gabriel-laptop:~$ gcc hello.c -o hello

      但是事实上,这个过程可分为4步,分别是预处理(Prepressing),编译(Compilation),汇编(Assembly)和链接(Linking),下面分别简述以下这四个过程,并辅以实例给大家以感性认识。

 

预编译

      预编译过程主要是处理源文件中#开头的预编译指令,主要规则如下

  1. 将所有的#define删除,并且展开所有的宏定义
  2. 处理所有的条件编译指令:#if #ifdef #elif #else #endif
  3. 处理#include,将被包含的文件插入到该预编译指令的位置
  4. 删除所有的注释//和/* */
  5. 添加行号和文件名标识,便于编译时产生调试用的行号信息
  6. 保留所有的#pragma,因为编译器需要

 

      下面就只预编译一个简单的程序看看,这里只使用#include引入自己定义的头文件。

       头文件hello.h如下:

[cpp]  view plain copy
  1. int headeri = 10;  
 

       主文件hello.c如下:

  1. #include "hello.h"  
  2. #define HELLO 3  
  3. int main()  
  4. {  
  5. #if HELLO  
  6.     int a[HELLO];  
  7. #else  
  8.     int a[10];  
  9. #endif  
  10.     int b = 2, c = 3, sum;  
  11.     sum = b + c;            /* sum */  
  12.     return 0;  
  13. }  

 

      .c文件经过预编译之后将变成.i文件 .cpp文件经过预编译之后将会变为.ii文件

      预编译可使用如下指令,其中gcc中-E选项代表只进行预编译

      gabriel@gabriel-laptop:~$ gcc -E hello.c -o hello.i

      或

      gabriel@gabriel-laptop:~$ cpp hello.c > hello.i

 

查看文件hello.i

  1. # 1 "hello.c"  
  2. # 1 "<built-in>"  
  3. # 1 "<command-line>"  
  4. # 1 "hello.c"  
  5. # 1 "hello.h" 1  
  6. int headeri = 10;  
  7. # 2 "hello.c" 2  
  8. int main()  
  9. {  
  10.  int a[3];  
  11.  int b = 2, c = 3, sum;  
  12.  sum = b + c;  
  13.  return 0;  
  14. }  


可以看到
  1. 头文件hello.h已经被包含进来,在hello.i的第五行显示了hello.h里面的内容;
  2. 而hello.h前前后后带#加数字的行则是告诉编译器这里是源文件hello.c中的哪一行;
  3. 再来对照hello.c看,其中条件编译语句已经被删去,取而代之的是条件编译语句中编译条件成立的那一句;
  4. 另外,同样是在hello.c中的预处理#define HELLO 3在hello.c中已经不见了,并且main()函数中使用HELLO定义的数组a也被3代替;
  5. 最后,原本在第八行的注释在预编译后的文件中也不再显示了。

      这样之后预编译的过程就算结束了

 

编译

      编译的过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编文件代码(属于编译原理的内容)

 

      编译之后将生成.s文件,即汇编代码的文件,继续使用上一步预编译完成的hello.i文件进行编译,使用如下命令,其中-S选项代表进行到编译

      gabriel@gabriel-laptop:~$ gcc -S hello.i -o hello.s

      同样,也可以直接从源文件进行预处理和编译

      gabriel@gabriel-laptop:~$ gcc -S hello.c -o hello.s

      另外,gcc专门有一个程序是完成以上编译加汇编两个步骤的,是位于/usr/lib/gcc/i486-linux-gnu/4.4/下的cc1(对于C++程序来说是cc1plus)

      gabriel@gabriel-laptop:~$ /usr/lib/gcc/i486-linux-gnu/4.4/cc1 hello.c

 

      可以看一下汇编出来的代码hello.s

 

[cpp]  view plain copy
  1.     .file   "hello.c"  
  2. .globl headeri  
  3.     .data  
  4.     .align 4  
  5.     .type   headeri, @object  
  6.     .size   headeri, 4  
  7. headeri:  
  8.     .long   10  
  9.     .text  
  10. .globl main  
  11.     .type   main, @function  
  12. main:  
  13.     pushl   %ebp  
  14.     movl    %esp, %ebp  
  15.     subl    $32, %esp  
  16.     movl    $2, -12(%ebp)  
  17.     movl    $3, -8(%ebp)  
  18.     movl    -8(%ebp), %eax  
  19.     movl    -12(%ebp), %edx  
  20.     leal    (%edx,%eax), %eax  
  21.     movl    %eax, -4(%ebp)  
  22.     movl    $0, %eax  
  23.     leave  
  24.     ret  
  25.     .size   main, .-main  
  26.     .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"  
  27.     .section    .note.GNU-stack,"",@progbits  
 

      汇编代码就不过多解释了,呵呵

 

汇编

 

      汇编器是将汇编代码转变为机器可以执行的指令,也就是机器代码,由于每一个汇编语句几乎都对应一条机器指令,所以相对编译来说比较简单

 

      汇编之后生成的是目标文件.o,这已经是机器代码的文件了。继续使用上一步编译之后的hello.s文件进行汇编,使用如下指令,其中-c代表汇编

      gabriel@gabriel-laptop:~$ gcc -c hello.s -o hello.o

      或者直接使用汇编器as

      gabriel@gabriel-laptop:~$ as hello.s -o hello.o

 

      若要从源文件直接获得目标文件,则可以

      gabriel@gabriel-laptop:~$ gcc -c hello.c -o hello.o

 

 

 

链接

      最后是链接,链接是一个非常复杂的过程,虽然目标文件已经是机器代码了,但是仍要通过各种链接才能最终变成可执行文件,linux下的链接器是ld。本书前半部分大部分篇幅都会讨论链接,所以具体内容后文将给出。

 

 

总结一下

      一个c语言文件从源码文件编译链接成为可执行文件的整个过程如下所示

.c -> 预编译 -> .i -> 编译(cc1) -> .s -> 汇编(as) -> .o -> 链接(ld) -> 可执行文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值