程序从代码到可执行文件的过程简述
2015-09-16 22:30
363 查看
代码编写结束后,使用IDE(集成开发环境)直接编译就可以得到可执行文件。在这个过程中,IDE进行了很多内部操作。分别为:预处理,编译,汇编,链接。之后按序简述每一个步骤的执行
预编译步骤主要操作源代码文件中以“#” 开始的预编译指令。主要处理规则如下:
a) 将所有的 “#define” 指令删除,并展开内容中的宏定义
b) 处理所有条件预编译指令,如 “#if”等
c) 处理“#include” 预编译指令,将被包含的文件插入到该预编译指令的位置,递归包含
d) 删除所有注释行
e) 添加行号与文件名标识
f) 保留所有#pragma 编译器指令
编译过程经历了扫描器(词法分析),语法分析,语义分析,源代码优化,产生目标代码,目标代码优化的过程,产生对应的汇编代码文件。
a) 扫描器:源代码被输入到扫描器中,扫描器进行简单的词法分析,运用有限状态机的算法,将源代码分割为一系列的记号(关键字,标识符,字面值和特殊符号<+,-,*,/等>)。有一个叫做 len 的程序可以实现词法扫描,按照用户之前描述好的词法规则将输入的字符串分割为一个个记号
b) 语法分析:对扫描器产生的记号进行语法分析,从而产生一棵语法树,其叶子节点通常是标识符或者字面值。有一个叫yacc的工具,可以根据用户定义的语法规则对输入的记号序列进行解析,构建出一棵语法树
c) 语义分析:语法分析完成了表达式语法层面的解析,但它并不了解这个语句是否有意义,如 C语言中,两个指针做乘法运算时没有意义的,但是这个语句在语法层面是合法的。编译器只能进行静态语义分析(如类型转换,声明匹配等),不能进行动态语法分析(如除数为0的除法操作)。经过语义分析阶段后,整个语法树的表达式都被标识了类型,如果存在类型转换,还会在语法树中插入相应的转换节点。
e)源代码优化:源代码优化器将整个语法树转换为中间代码(如三地址代码等),并对三地址代码进行优化。
举个例子,以下代码:
源代码优化产生的中间代码将编译器分为前端和后端两个部分,前端负责产生并优化与机器无关的中间代码,后端则负责则将中间代码转换为目标机器代码。到目前的操作,都属于前端部分
f) 产生目标代码:代码生成器将中间代码转换成目标机器代码(汇编语言),这个过程依赖与不同的主机,属于编译器的后端部分。因此,对跨平台的编译器而言,可以针对不同的平台使用同一个前端,而使用不同的对应平台的后端
g) 目标代码的优化:这个是对产生的汇编代码进行优化,此处不涉及汇编,不举例了
汇编器将汇编代码转换为机器可以执行的指令,每一个汇编语句几乎对应一条机器指令。该过程相对简单,只是根据汇编指令和机器指令的对照表一一翻译即可
其中,这个地址修正的过程被称为重定位,而每一个要被修正的地方称为重定位入口。链接过程包括了地址和空间分配,符号决议与重定位等步骤
1.预处理
GCC预编译的指令为:$gcc -E hello.c -o hello.i ,C++文件预编译后的扩展名为:hello.ii预编译步骤主要操作源代码文件中以“#” 开始的预编译指令。主要处理规则如下:
a) 将所有的 “#define” 指令删除,并展开内容中的宏定义
b) 处理所有条件预编译指令,如 “#if”等
c) 处理“#include” 预编译指令,将被包含的文件插入到该预编译指令的位置,递归包含
d) 删除所有注释行
e) 添加行号与文件名标识
f) 保留所有#pragma 编译器指令
2.编译过程
GCC编译过程的指令为:$gcc -S hello.i -o hello.s 或者 $gcc -S hello.c -o hello.s编译过程经历了扫描器(词法分析),语法分析,语义分析,源代码优化,产生目标代码,目标代码优化的过程,产生对应的汇编代码文件。
a) 扫描器:源代码被输入到扫描器中,扫描器进行简单的词法分析,运用有限状态机的算法,将源代码分割为一系列的记号(关键字,标识符,字面值和特殊符号<+,-,*,/等>)。有一个叫做 len 的程序可以实现词法扫描,按照用户之前描述好的词法规则将输入的字符串分割为一个个记号
b) 语法分析:对扫描器产生的记号进行语法分析,从而产生一棵语法树,其叶子节点通常是标识符或者字面值。有一个叫yacc的工具,可以根据用户定义的语法规则对输入的记号序列进行解析,构建出一棵语法树
c) 语义分析:语法分析完成了表达式语法层面的解析,但它并不了解这个语句是否有意义,如 C语言中,两个指针做乘法运算时没有意义的,但是这个语句在语法层面是合法的。编译器只能进行静态语义分析(如类型转换,声明匹配等),不能进行动态语法分析(如除数为0的除法操作)。经过语义分析阶段后,整个语法树的表达式都被标识了类型,如果存在类型转换,还会在语法树中插入相应的转换节点。
e)源代码优化:源代码优化器将整个语法树转换为中间代码(如三地址代码等),并对三地址代码进行优化。
举个例子,以下代码:
array[index] = (index + 4)*(2+6);其被源代码优化器转换为三地址码如下:
t1 = 2 + 6; t2 = index + 4; t3 = t1 * t2; array[index] = t3;转为三地址代码后又进行源代码优化,优化结果如下:
t2 = index + 4; t2 = t2 * 8; array[index] = t2;
源代码优化产生的中间代码将编译器分为前端和后端两个部分,前端负责产生并优化与机器无关的中间代码,后端则负责则将中间代码转换为目标机器代码。到目前的操作,都属于前端部分
f) 产生目标代码:代码生成器将中间代码转换成目标机器代码(汇编语言),这个过程依赖与不同的主机,属于编译器的后端部分。因此,对跨平台的编译器而言,可以针对不同的平台使用同一个前端,而使用不同的对应平台的后端
g) 目标代码的优化:这个是对产生的汇编代码进行优化,此处不涉及汇编,不举例了
3. 汇编过程
GCC汇编过程的指令为:$gcc -c hello.s -o hello.o 或 $gcc -c hello.c -o hello.o汇编器将汇编代码转换为机器可以执行的指令,每一个汇编语句几乎对应一条机器指令。该过程相对简单,只是根据汇编指令和机器指令的对照表一一翻译即可
4.链接过程
对C/C++等语言而言,其不同的模块(源文件)之间的通信方式有两种:一种是模块间的函数调用,另一种是模块间的变量访问。编译器在编译到目标文件的过程中,将引用别的模块中的函数与变量的地址都暂时搁置(设为0x00000000),等待链接器对这些模块进行链接时将这些含有引用的指令进行修正,调整至正确的地址。其中,这个地址修正的过程被称为重定位,而每一个要被修正的地方称为重定位入口。链接过程包括了地址和空间分配,符号决议与重定位等步骤
相关文章推荐
- JVM系列文章(一):Java内存区域分析
- java__IO_02
- java 编程思想 阅读笔记(2)
- 看别人写的Java中String的一些方法
- eclipse安装spring tool suite插件
- JAVA基础--db01_入门-软件安装-环境变量
- 使用 ASP.NET 和 WCF 4.0 开发 RESTful 服务
- C++Primer Plus 第十章-类的构造和析构函数
- spring 事务传播行为
- Ubuntu编写C++程序
- 代码中特殊的注释技术——TODO、FIXME和XXX的用处
- [Spring]Spring AOP学习笔记(2)---5种切入方式、AOP优先级及切面表达式的重用
- python 实现红包随机生成算法
- 《head first python》——web开发
- 零基础学python-17.3 特定的参数匹配模型快速入门
- 二叉树 - 建立与遍历使用Java
- 零基础学python-17.3 特定的参数匹配模型快速入门
- Python的logging,记录log的包
- LeetCode 10 正则表达式匹配
- Servlet---JavaWeb技术的核心基础,JavaWeb框架的基石(二)