现在的位置: 首页 > 综合 > 正文

编译原理概述

2018年04月17日 ⁄ 综合 ⁄ 共 2570字 ⁄ 字号 评论关闭
一、编译过程分析
    编译软件读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并按照操作系统对可执行文件格式的要求链接生成可执行程序.
二、编译流程表
    C源程序(.c文件)             (编辑器)-->
    预处理过程(.c文件)                  -->
    编译、优化过程(.s或.asm文件)  (编译器)-->
    汇编过程(.o或.obj文件)       (汇编器)-->
    链接过程(.exe文件、.elf文件、.bin文件等) (链接器LD)
三、预处理过程
    该阶段主要工作是读取C源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理.
 伪指令主要包括以下4个方面:
 (1)宏定义指令,如#define、#undef等.
    对于#define定义的伪指令,预编译所要做的就是将程序中的所有宏定义进行替换.
    对于#undef定义的伪指令,则将取消对某个宏的定义,使以后该串的出现不再被替换.
 (2)条件编译,如#ifdef、#ifndef、#else、#endif等.
    对于这些伪指令的引入,使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理.预编译程序将根据有关的文件,将那些不必要的代码过滤掉.
 (3)头文件包含指令,如#include等.
    采用头文件的目的主要是为了使某些定义可以供多个不同的C源码程序使用.因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍.包含到C源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下.在程序中#include它们要使用尖括号(<>);另外开发人员也可以定义自己的头文件,这些文件一般放在同一目录下,此时在#include中要用双引号("").
 (4)特殊符号,预编译程序可以识别一些特殊符号.
 
    通过上面的描述可知,预编译程序所完成的基本上是对源程序的"替代"工作.经过这种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件.这个文件的含义同没有经过预处理的源程序是相同的,但内容有很大的不同.
   在Linux系统中,编译的各个过程是可控的.用户可通过命令gcc -E hello.c -o hello.i,比较预处理前后文件大小的变化.可以发现,预处理后生成的hello.i文件远大于hello.c,这是因为预处理后将库函数都拷贝到源文件中了.
   预编译结束后,文件仍然是.c文件.在Linux中,预编译后生成了.i文件.
 
四、编译、优化过程
    编译的主要工作是通过词法分析和语法分析,在确认所有的指令都符合语法规则后,将其翻译成等待的中间代码表示或汇编代码.
 
    优化是编译系统中一项比较艰深的计数.它涉及的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系.优化主要有两个方面:
 一是考虑如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对内存的访问次数.
 二是调整使目标代码比较短,且执行效率比较高.
    经过优化得到的汇编代码必须经过汇编程序的汇编转换成相应的机器指令,才可能被机器执行.
 
    编译、优化的C源程序变成了.S或.asm的汇编程序.
 
五、汇编过程
   汇编过程是指将汇编语言代码翻译成目标机器指令.目标文件就是与源程序等效的目标机器语言代码.目标文件由段组成.通常一个目标文件中至少有两个段:
   代码段:该段中所包含的主要是程序的指令.该段一般是可读和可执行的,但不可写.
   数据段:主要存放程序中要用到的各种全局变量或静态的数据.一般数据段都可读、可写、可执行.
 
   实际上,汇编就是查表,根据指令通过查表生成相应的机器代码.
 
   汇编后的C源程序变成了.o或.obj的目标程序.
 
六、链接过程
   由汇编过程生成的目标文件并不能立即被执行.其中还存在着一些问题.
   比如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或函数调用);程序中可能调用了某个库文件中的函数.所有这些问题都需要经过链接过程方能得到处理.
   链接过程的主要工作是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号所在另外
   一个文件中的定义连接起来,使得所有这些目标文件能成为一个能被操作系统装入执行的统一整体.
 举例:
   一工程中包含三个文件,分别是file1.c、file2.c、file3.c,通过编译、汇编分别生成了file1.o、file2.o、file3.o,最后链接器将三个.o文件根据平台的要求链接成一个可执行文件.在x86系统中,生成了.exe文件.在Linux系统中,生成了.elf文件;在嵌入式系统中,生成了.bin文件.
 
 根据开发人员指定的同库函数的链接方式不同,链接处理可分为两种:
 (1)静态链接
    在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中.这种,该程序在被执行时,这些代码将被装入到该进程的虚拟地址空间中.静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或一组相关函数的代码.
   
 (2)动态链接
    在这种链接方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中.链接程序此时所
作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息.在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚拟地址空间.动态链接程序将根据可执行程序中记录的信息找到相应的函数代码.
   
Attention!!!
 (1)一般情况下,只需要知道分成编译和链接两个阶段即可.
    编译阶段是将源程序(.c)转换为目标代码(.obj).
    链接阶段是将源程序转换成的目标代码(.obj)与你程序中调用的库函数对应的代码链接起来形成的可执行文件(.exe等).
 (2)通过上面的描述可知:
    无论是什么平台,如x86平台、Linux平台还是ARM平台,预编译后的.c文件都相同,这与平台无关.但编译后生成的.s或.i文件,根据平台的不同,生成的结果也不同.
    
   
【上篇】
【下篇】

抱歉!评论已关闭.