2、编译与链接

gcc编译过程

编译过程可以分为四个步骤,入下图所示

gcc hello.c
2、编译与链接_第1张图片
gcc编译过程

1、预处理,展开宏定义,处理预编译指令,引入include文件,添加行号和文件标识等

gcc -E hello.c -o hello.i
cpp hello.c > hello.i

2、编译,将预处理的文件转化为汇编代码的过程

gcc -S hello.i -o hello.s 
cc1 hello.c (包含了预处理和编译过程)

3、汇编,对汇编文件的每一句汇编指令翻译为机器指令,生成目标文件的过程

gcc -c hello.s -o hello.o

4、链接,处理各个目标文件中相互引用的部分,使各个模块可以正常的衔接。

简化版
ld -static crt1.o crti.o crtBegin.o hello.o -start-group -lgcc -lc-end-group crtend.o crtn.o 
编译器作用

上图中绿色编译框图其作用实际上是将预处理的文件转化为汇编代码的过程,编译器通常通过一下六个步骤实现该过程,如下图所示

2、编译与链接_第2张图片
编译工作流

1、扫描,将代码分割成一系列记号,lex
2、语法分析,生成以表达式为节点的语法树,yacc
3、语义分析,静态语义分析,包括声明和类型的匹配、类型转换等
4、源代码优化,源代码级别优化,一般会将语法树转换为一个中间代码(三地址码、p-code),然后在中间代码上进行优化
5、代码生成,生成汇编代码(目标代码)
6、目标代码优化,在汇编代码上进行优化,寻找合适的选址方式、位移代替除法等

链接器作用

经过上述编译器的重重步骤后,通过一个源代码文件(.c/.cpp)得到了目标代码文件(.o),但有时一个.c文件会引用其他.c文件中符号,编译后该符号的地址还是未确定的,针对这种目标文件中变量定义在其他目标文件的情况,引入了链接器。

早期的计算机程序的黑暗时代使用的是机器语言,即编程过程中直接使用相应的地址进行编码,并且是采用纸带上打孔的方式记录程序,这将引出一个问题,程序的修改将变得异常的麻烦,修改一个地方后,需要程序员手动的重新计算每个引用地址,这个过程被叫做重定位relocation。由于这个过程异常的麻烦,先驱们发明的了汇编语言,采用易于记忆的符号和标记进行编码,同时使用符号表示目标地址后,重定位的工作就交由汇编程序去完成了。有了汇编语言大大的提高了先驱们的生产力,随着软件规模的日渐庞大,人们开始按照代码的功能和性质将代码分成了不同的模块。一个程序被划分成多个模块后将引入一个新的问题,模块间的通信问题,即如何确定跨模块间的函数调用和变量引用的地址(模块间的符号引用问题),这就引入了一个新的主题:链接

链接:把各个模块间相互引用的部分处理好修正确定跨模块符号的地址,使模块间可以正确的衔接,主要包括
1、地址和空间分配
2、符号决议
3、重定位
下一章将详细介绍上述三个过程~

你可能感兴趣的:(2、编译与链接)