预处理->编译->汇编->链接
1、预编译(main.c-->main.i)
预编译主要处理代码中以#开头的预编译指令,其编译的规则如下:
- 展开宏定义
- 处理预编译指令,如#include预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件包含其他文件
- 删除注释,例如://、/**/
- 保留#pragma编译器指令,例如:#pragma once是为了防止有文件重复引用
- 添加行号和文件标识(便于编译时编译器产生调试用的行号信息,编译时产生错误或警告能够显示在第几行)
- 预编译是由main.c文件生成main.i文件
指令操作:gcc -E main.c -o main.i
2、编译(main.i-->main.s)
将上面预编译阶段生成的main.i文件进行操作:
- 词法分析、语法分析、语义分析
- 生成目标代码并进行优化
- 在编译阶段main.i文件生成main.s
指令操作:gcc -S main.i -o main.s
3、汇编(main.s-->main.o)
汇编过程相对来说比较简单,没有复杂的语法,也没有语义,更不需要做指令优化,只是根据汇编指令和机器指令的对照表意义翻译过来,生成可重定位的二进制文件。
- 生成二进制文件
- 在汇编阶段main.s文件生成main.o
指令操作:gcc -c main.s -o main.o
4、链接(main.o-->main)
链接分为静态链接和动态链接。
生成可执行目标文件。
主要处理了如下几件事情,合并段表,调整偏移量,合并符号表,完成符号重定位,分配地址和空间。
- 合并段表:将多个二进制可重定位文件中的段信息整合到一个文件中去。
- 调整偏移量:段表经过合并之后大小发生了变化,所以地址需要适当的偏移。
- 合并符号表:将多个二进制可重定位文件中的符号整合到一个文件中。
- 完成符号的重定位:链接器把每个符号定义与一个虚拟地址联系起来,然后修改所有对这些符号的引用,使得他们指向这个存储位置,从而重定位这些符号。
指令操作:gcc main.o -o main