程序的编译链接过程

来源:互联网 发布:局域网屏幕监控软件 编辑:程序博客网 时间:2024/05/22 17:07

平常在编程完之后,点击生成解决方案,然后运行,就会得到我们需要的结果,这个结果是怎么来的,在这个过程,会发生错误,错误又分为几类错误呢?它们分别发生在编译连接的哪个阶段?是什么问题造成的呢?
在这个过程中,能看到现象却看不到本质,面对各种问题,让我们无所适从,现在就先对编译链接过程进行一个简单的剖析。

#include<stdio.h>int main(){    printf("hello world\n");    return 0;}

这是c语言入门的经典程序。在linux中,只需要“gcc hello.c””./a.out”这两个命令就能编译出这个程序,在屏幕上打印出结果来。
事实上,完成上述两个命令,完成编译过程,能分为4个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)、链接(Linking)。
这里写图片描述
上图为linux中进行完每一步之后的产生的文件。然后再接着说每一步。


1. 预编译
预编译命令:gcc -E hello.c -o hello.i//cpp hello.c > hello.i
预编译处理规则:
1.将所有的“#define”删除,并且展开所有的宏定义
2.处理所有条件预编译指令。如“#if”,”#ifdef”
3.处理“#include”预编译指令,把文件插入进来,以递归的方式
4.删除所有注释。
5.添加行号和文件名标识(错误发生时能够显示行号)
6.保留所有的#pragma编译器指令,编译器要使用它们。
2. 编译
编译命令:gcc -S hello.i -o hello.s
gcc -S hello.c -o hello.s
/user/lib/gcc/i486-linux_gnu/4.1/ccl hello.c
其中ccl程序将预编译和编译两个步骤合二为一。
这里写图片描述
编译器所做的事情:扫描,语法分析,语义分析,优化源码,优化目标代码


扫描器:进行简单的词法分析,运用一种类似于有限状态机的算法可以轻松的将源代码的字符序列分割成一系列的记号(token)
记号种类:关键字。标识符,字面量(数字,常量字符串),特殊符号(+,=,*)
标识符存储在符号表中,字面量存储在文字表中。
总结:将代码字符序列分割成独立的记号,并将记号归类 。
所用到的工具:lex的程序。
这里写图片描述
语法分析:语法分析器对扫描器产生的记号进行语法分析,从而产生语法树,整个分析过程采用上下文无关语法。
所用到的工具:yacc(yet another compiler compiler)
所做的事情:
1.确定运算符优先级及含义
2.表达式合法性分析(括号匹配不匹配,表达式是否缺少操作符?)

语义分析:
语义分析器:分析这个语句是否真的有意义。分为静态语义(在编译器可以确定的语义),动态语义(在运行期才能确定的语义)
静态语义:查看声明和类型的匹配否(char * p=123则会报错),类型的转换(int a=123,double b=a,其中存在类型隐式转换)
动态语义:如除运算时,除以0,则会报错,是在程序动态运行过程中发生的算术错误。
语义分析完成后:
1.语法树的表达式都标识了类型。
2.如果有些类型需要隐式转换,语义分析程序会在语法树中插入相应的转换节点。
这里写图片描述
中间语言生成:
这一步是实现源代码级别的一个优化过程。
源代码器往往将整个语法树转换成中间代码,他是语法树的顺序表示,非常接近目标代码了。中间代码与运行环境和目标及其无关(因为中间代码不包含名称地址)
中间代码有很多类型,常用的有两种:三地址码,和P-代码。
中间代码将编译器分为前端和后端,前端产生于机器无关的中间代码,后端将中间代码转换成目标机器代码。

目标代码生成和优化
编译器后端包括:代码生成器,目标代码优化器
代码生成器:将中间代码转换成目标机器代码(十分依赖目标机器,不同的编译器,产生的目标机器代码是不同的)
目标代码优化器:对目标代码进行优化:
1.选择合适的寻址地址
2.使用位移来代替乘法运算。
3.删除多余的指令。
目标代码生成但标识符的地址还没有确定。

这里写图片描述


3. 汇编
汇编:将汇编代码转换成机器可执行的命令。
汇编命令:as hello.s -o hello.o
gcc -c hello.s -o hello.o
gcc -c hello.c -o hello.o
4. 链接
链接:一堆.o/.obj文件和静态链接库文件进行链接得到最终的可执行文件。
链接阶段1:
1.合并.obj的各个段(段合并)。
2.合并符号表(将相同的符号进行合并)
2.符号解析(对所有符号的引用查找其定义,若找到多个定义,则发生重定义错误,若没有找到定义,则发生符号未定义错误)。
3.给符号分配地址(虚拟地址)
链接阶段2:
符号重定向(将引用符号中不确定的地址改为分配好的地址)

。。。。未完待续

原创粉丝点击