C 源程序到可执行文件的过程

时间:2021-04-20 02:19:48

C源程序->编译预处理->编译->(优化程序->)汇编程序->链接程序->可执行文件

1.预处理

在该阶段,编译器将C源代码中的包含的头文件如stdio.h编译进来,可通过gcc 的选项 -E 进行查看

如:[root@localhost 0001]#gcc -E main.c -o main.i

将main.c预处理输出 main.i 文件

2.编译

这个阶段中,编译器首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作。用户可以使用”-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
选项 -S
如:[root@localhost 0001]# gcc –S main.i –o main.s 
将预处理输出文件main.i汇编成main.s文件。

*3.优化程序

-O0:无优化(默认)
-O和-O1:使用能减少目标文件大小以及执行时间并且不会使编译时间明显增加的优化.在编译大型程序的时候会显著增加编译时内存的使用.
-O2: 包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化.编译器不执行循环展开以及函数内联.此选项将增加编译时间和目标文件的执行性能.
-Os:专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项.并且执行专门减小目标文件大小的优化选项.
-O3: 打开所有-O2的优化选项并且增加 -finline-functions, -funswitch-loops,-fpredictive-commoning, -fgcse-after-reload and -ftree-vectorize优化选项. 4.汇编 汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码.
选项 -c
如:[root@localhost 0001]#gcc –c main.s –o main.o
将汇编输出文件main.s编译输出main.o文件

5.链接
  链接就是将不同部分的代码和数据收集和组合成为一个单一文件的过程,这个文件可被加载或拷贝到存储器执行.

        在成功编译之后,就进入了链接阶段。
        无选项链接

        如:[root@localhost 0001]# gcc main.o –o main.exe
        将编译输出文件main.o链接成最终可执行文件main.elf

————————
  链接可以执行与编译时(源代码被翻译成机器代码时),也可以执行与加载时(在程序被加载器加载到存储器并执行时),甚至执行与运行时,由应用程序来执行.在现代系统中,链接是由链接器自动执行的.
  链接器分为:静态链接器和动态链接器两种.


静态链接器
  静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出.

  静态链接器主要完成两个任务:
  1>符号解析:目标文件定义和引用符号.符号解析的目的在于将每个符号引用和一个符号定义联系起来.
  2>重定位:编译器和汇编器生成从地址零开始的代码和数据节.链接器通过把每个符号定义和一个存储器位置联系起来,然后修改所有对这些符号的引用,使得他们执行这个存储位置,从而重定位这些节.

动态链接器

 动态链接方式下,函数的定义在动态链接库或共享对象的目标文件中。在编译的链接阶段,动态链接库只提供符号表和其他少量信 息用于保证所有符号引用都有定义,保证编译顺利通过。动态链接器(ld-linux.so)链接程序在运行过程中根据记录的共享对象的符号定义来动态加载共享库,然后完成重定位。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。  

  目标文件:
  目标文件有三种形式:
  1>可重定位的目标文件:
  包含二进制代码和数据,其形式可以再编译时与其他可定位目标文件合并起来,创建一个可执行目标文件.
  2>可执行目标文件:
  包含二进制代码和数据,其形式可以被直接拷贝到存储器并执行.
  3>共享目标文件:
  一种特殊的可重定位目标文件,可以再加载或运行时,被动态地夹在到存储器并执行.
  编译器和汇编器生成可重定位目标文件(包括共享目标文件),链接器生成可执行目标文件.