GCC编译程序是指基于Unix的一类编译程序。GCC编译程序的一趟编译可以包含20~30多遍(由具体编译选项决定),其中绝大部分是用来执行优化功能的。GCC编译程序先将源语言程序转换为语法树的中间表示,然后再转换为RTL中间表示。
GCC简介GCC是一个用C语言实现的优化可移植编译系统,实际上,GCC是编译器的快速开发平台,因为它是一个可重定义目标的编译器(retargetable compiler)。GCC不仅包括了编译器的前端构件(如,面向ANSI C和其他高级语言的词法、语法、语义分析程序)和一些标准的后端构件(如,X86、MIPS等常用系统的代码生成器和优化器),而且对于一种新型体系结构的特定指令系统和硬件资源,它还提供一个配置接口,用于定义和描述这种机器的体系结构,并能根据这种描述自动生成面向该机器体系结构的编译器后端。
GCC的设计思想主要体现在三个方面:目标机器描述与定义机制、RTL中间表示机制以及由机器描述引导中间代码生成和优化策略。
首先,GCC对每个目标机的指令系统都有一个机器描述文件(machine.md),以代数式的形式对每条指令所完成的操作以及各操作数的机器存储模式和数据模式进行描述,对于用此方法难以描述的那些信息,作为特定的参数定义在目标机宏定义文件(tm.h) 中。例如,机器的字长、寄存器的个数及使用约定、内存编址特性等。在RTL中间代码生成阶段,通常有多种生产策略被用于不同的参数定义组合。通过改写这两个文件,可完成GCC向新的目标机的移植。
其次,采用合适的中间语言是实现编译器代码优化和可移植的关键。GCC从不同系统结构的机器语言中抽象出共性的操作,形成了一个适合编译分析加工的中间语言,即RTL(Register Transfer Language),既可以用来描述源语言的各种运算和控制操作,又便于在其上进行深入的优化和汇编代码的生成。
第三,GCC最具特色的设计思想是由目标机的机器描述文件引导中间代码的生成和优化。由于在传统编译器中,中间代码的生成和优化无论是程序代码还是数据结构均是与机器无关的,所生成的中间代码不能体现目标机的指令特点和优化信息,这使目标代码的质量受到很大的限制。GCC利用预定义的独立于具体机器的“原子操作”来设置机器描述中的指令条目,在指令描述中含有对应的中间代码的操作与数据模式,使GCC能在机器描述引导下进行中间代码的生成,机器描述处理程序与机器无关,但所生成的中间代码已含有给定目标机器的指令信息,可在其上进行某些与机器相关的指令归并、窥孔优化及指令重排序等优化工作。
GCC清晰的前端语法树结构、高度概括的抽象机中间语言、简洁的机器描述等为快速地实现多源语言开发、多平台移植提供了有力的支持。1
系统结构GCC编译程序主要由语法分析、语义分析、中间代码生成、优化与寄存器分配以及汇编代码生成等部分组成。
GCC编译程序在一个总控程序的控制下,经过前端分析和后端处理,把一个GCC源程序转换为目标机汇编代码。
总控程序负责初始化、译码参数、打开/关闭文件,并控制各遍的操作。
前端分析完成语法、语义分析和中间代码生成工作,它的输入是预处理后的源程序,
编译原理与技术输出是RTL中间代码。语法分析是核心,在扫描输入文件的过程中实现各种语义成分的翻译和中间代码的生成。当分析一函数时,函数中的语句将被转换成RTI.表示,声明和表达式的翻译经由语法树过渡后再转换成中问代码表示。语法分析程序是利用一个类似于YACC的自动生成工具GNU Bison生成的,该工具接受LALR(1)文法。
后端处理完成各种优化、寄存器分配和汇编代码的生成。
优化包括全部的常规优化,优化相关的代码在GCC中占有相当大的分量,而且每种优化都是对RTL中间代码的一遍处理。这些优化是:转移优化、指令调度优化和延迟分支优化等。其中,转移优化对程序控制流进行优化,分别在RTL中间代码生成、公共子表达式删除和寄存器重载处理之后执行。每次转移优化和循环优化之后进行公共子表达式删除。指令归并优化和重载处理之后进行指令调度优化。循环优化除了执行代码外提之外,还可选择地执行循环展开优化。指令归并优化、指令调度优化和延迟分支优化均是在目标机器描述的引导下,通过模式匹配算法完成的。
局部和全局寄存器的分配是在数据流分析的基础上进行的,前者完成基本块内的寄存器分配优化,后者完成剩余的跨越基本块的寄存器分配优化。
后端的最后一遍处理是汇编代码的生成。经过前面的分析和优化处理后,提交给代码生成模块的RTL代码已经含有汇编指令的雏形。代码生成的主要工作是在机器描述产生的各种数据结构的引导下进行指令识别和获取汇编指令模板,并据此输出汇编指令代码,最终完成对一个GCC源程序的翻译。1
基本过程GCC编译程序的基本过程如下:
(1)arm-elf-gcc根据输入文件的后缀来确定文件的类型,然后根据用户的编译选项(包括优化选项和调试信息选项等)将其编译成相应的汇编临时文件(后缀为.s)。
(2)arm-elf-as将该汇编文件编译成目标文件(后缀为.o)。
(3)arm-elf-ld根据用户的链接选项(包括指定链接命令文件等)将目标文件和各种库链接起来生成可执行文件。2
本词条内容贡献者为:
吴晨涛 - 副研究员 - 上海交通大学