程序的预编译,编译,汇编,链接过程

来源:互联网 发布:java jdbc mysql 编辑:程序博客网 时间:2024/05/22 17:15

预编译过程:

这里写图片描述

预编译过程主要处理那些源代码文件中的以”#”开始的预编译指令。比如:”#include”,”#define”等,主要处理规则如下:
(1)将所有的”#define”删除,并且展开所有的宏定义。
(2)处理所有条件预编译指令,
比如”#if”,”#ifdef”,”#elif”,”#else”,”#endif”.
(3)处理”#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意:这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
(4)删除所有注释”//”和”/**/.
(5)添加行号和文件名标识,比如#2 ”hello.c” 2,以便与变异是编译器产生条使用的行号信息以及用于编译时产生编译错误或警告时能够显示行号。
(6)保留所有的”#pragma”编译器指令,因为编译器需要使用它们。
经过编译后的.i文件不包含任何宏定义,因为所有的宏定义都已经展开,并且包含的文件也已经被插入到.i文件中。

这里写图片描述

编译:

编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析,优化后生成相应的汇编代码文件。

这里写图片描述

(1)词法分析:

词法分析产生的记号一般可分为以下几类:关键字,标识符,字面量(包含数字,字符串等)和特殊符号(如加号,等号等)。

实现词法扫描的工具是lex,他会按照用户之前描述好的词法规则将输入号的字符串分割成一个个记号。

(2)语法分析:

语法分析器将对由扫描器产生的记号进行语法分析,从而产生语法树(以表达式为节点的树)。

实现语法分析的工具是yacc,可以根据用户给定的语法规则对输入的记号序列进行解析,从而构建出一颗语法树。

(3)语义分析:
编译器能进行的语义分析是静态语义分析(指在编译器期间可以确定的语义),静态语义经常包括声明和类型的匹配,类型的转换。

(4)中间语言生成:
源码级优化器在不同编译器中可能有不同的定义或有一些差异,源代码级优化器会在源代码级别进行优化,源代码级优化器往往将整个语法书转换成中间代码,它是语法树的顺序表示。

中间代码有多种类型,在不同的编译器中有不同的形式,常见的有:三地址码和P-代码。
中间代码将编译器分为前端和后端,编译器前端负责产生机器无关的中间代码,编译器后端将中间代码转换成目标机器代码。

(5)目标代码生成与优化:
编译器后端主要包括代码生成器和目标代码优化器,代码生成器将中间代码转换成目标代码,目标代码优化器将对上述的目标代码进行优化,比如选择合适的寻址方式,使用位移来代替乘法运算,删除多余的指令等等。

汇编:

汇编器是将汇编代码转变为机器可执行指令,每一汇编语句几乎对应一条机器指令。

两种方法都可使用生成机器指令:
as指令和gcc -c 指令:

这里写图片描述

链接:

重定位:重新计算各个目标的地址过程叫做重定位。

符号:用来表示一个地址,这个地址可能是一段子程序(后来发展成函数)的起始地址,也可以是一个变量的起始地址。

静态语言的C/C++模块之间通信之间有两种方式:一种是模块间的变量访问,一种是模块间的函数调用,函数访问需要知道目标函数的地址,变量访问也需要知道目标变量的地址,因此可以将两种方式归结为一种方式,即就是模块间符号的引用

链接:把源代码模块独立的编译,然后按照需要将他们“组装”起来,这个组装“模块”的过程叫做链接。

链接的主要内容就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正确的链接。

链接过程包括了地址和空间分配,符号决议,重定位等这些步骤。

符号决议:也被叫做符号绑定,名称绑定,名称决议,甚至叫做地址绑定,指令绑定。

静态链接的基本过程和作用:
使用链接器可以直接引用其他模块的函数和全局变量而无需知道他们的地址,因为链接器在连接的时候,会根据所引用的符号foo,自动去相应的func.c模块去查找符号foo的地址,然后将main.c模块中所有引用到foo的指令重新修正,让他们的目标地址为真正的foo函数的地址。

0 0
原创粉丝点击