C编译器
文章平均质量分 81
leibniz_zsu
这个作者很懒,什么都没留下…
展开
-
[转贴]GCC笔记
The History of GCC 1984年,Richard Stallman发起了自由软件运动,GNU (Gnus Not Unix)项目应运而生,3年后,最初版的GCC横空出世,成为第一款可移植、可优化、支持ANSI C的开源C编译器。GCC最初的全名是GNU C Compiler,之后,随着GCC支持的语言越来越多,它的名称变成了GNU Compiler Collection。这里介绍转载 2007-09-29 13:30:00 · 801 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(56)寄存器分配的属性结构
现在详细地分析寄存器分配的属性结构,它的定义如下:#001 typedef struct {#002 Symbol vbl; //保存变量符号,而不是临时变量.#003 short set; //寄存器类型,比如整数,或者浮点数。#004 short number; //寄存器编号。#005 unsigned mask; //寄存器字节大小,比如转载 2007-08-23 12:43:00 · 507 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(55)最终代码的生成
上次已经说明了怎么样选择合适的指令,现在就来介绍生成最终的代码,如下:#010 mov dword [ebp + -12], 1其实生成上面的代码是通过后面的语句来构造出来的,它的过程如下:ASGNI4(ADDRLP4(nTest1), CNSTI4(1))stmt: ASGNI4(addr,rc) / mov dword %0, %1addr: base / [%0]ba转载 2007-08-23 12:42:00 · 560 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(53)指令的选择
像下面的语句:int nTest1 = 1;选择什么样的汇编指令生成的呢?又是怎么样去选择指令的呢?在本例子里,LCC是选择下面的指令生成的:#010 mov dword [ebp + -12], 1 现在就来分析选择指令过程的代码,先分析函数gen的代码:#001 Node gen(Node forest) {#002 int i;#003 struct no转载 2007-08-23 12:40:00 · 672 阅读 · 0 评论 -
[转载] LCC编译器的源程序分析(52)寄存器溢出
当寄存器分配完了,但又有一些指令需要寄存器,那么就需要把占用寄存器的值保存到内存里,才可以重新分配那些寄存器。下面就来分析LCC的寄存溢出算法。spillee是用来计算那个寄存器最好保存到内存里,然后重新使用的。它的代码如下:#001 static Symbol spillee(Symbol set, unsigned mask[], Node here) {#002 Symbol转载 2007-08-22 13:13:00 · 663 阅读 · 0 评论 -
[转载] LCC编译器的源程序分析(51) 分配一个寄存器
分配一个寄存器的函数是ralloc,它会调用getreg函数来获取一个寄存器。下面先来分析函数ralloc的代码,如下:#001 static void ralloc(Node p) {#002 int i;#003 unsigned mask[2];#004 #005 mask[0] = tmask[0];#006 mask[1] = tmask[1];#00转载 2007-08-22 13:11:00 · 576 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(50) 分配一个寄存器
在代码生成的函数gencode里,需要产生寄存器给临时变量使用。下面就来分析这段代码,如下:#056 case Gen: case Jump:#057 case Label: #058 if (prunetemps)#059 cp->u.forest = prune(cp转载 2007-08-22 13:09:00 · 553 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(49) 寄存器分配
前面已经说到要分配寄存器,下面就来分析寄存器分配的函数askreg。#001 static Symbol askreg(Symbol rs, unsigned rmask[]) {#002 int i;#003 #004 if (rs->x.wildcard == NULL)#005 return askfixedreg(rs);#006 for (i转载 2007-08-22 13:08:00 · 548 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(47)计算需要使用栈大小
计算栈的大小,是通过后端接口的代码来完成计算的。栈的大小,主要就是局部变量、临时变量、调用参数和返回值等使用的字节大小,如果变量可以放到寄存器,就不需加到栈的大小里。上面已经看了下面的代码:#044 case Blockbeg: #045 {#046 Symbol *p = cp->u.block转载 2007-08-22 13:05:00 · 514 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(46)计算需要使用栈大小
从目标代码里,可以看到下面一行:#009 sub esp, 16在这行里是保留栈的大小,值为16。但16个字节是怎么样计算出来的呢?下面就来分析LCC的代码,看它是怎么样计算的。它是在函数gencode里进行计算的,它的代码如下:#001 void gencode(Symbol caller[], Symbol callee[]) #002 {#003 Code cp;转载 2007-08-22 13:05:00 · 492 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(45)函数代码入口和出口的代码生成
由于C语言可以动态地分配局部变量,因此它的运行环境都是基于栈式的分配来实现的,所以在函数的入口就会生成一段分配栈的代码,如下:#002 [section .text]#003 $main:#004 push ebx#005 push esi#006 push edi#007 push ebp#008 mov ebp, esp#009 sub esp, 16第2转载 2007-08-22 13:04:00 · 435 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(44)函数名称的代码生成
当把所有的源程序生成DAG表示后,就进入了编译器的最后处理阶段,LCC是把DAG生成汇编的目标代码。在这一阶段,编译器为源程序定义和使用的变量选择存储单元,并把中间指令翻译成完成相同任务的汇编代码指令序列。在代码生成里,需要处理的问题是存储管理、指令选择、寄存器分配、计算次序等等。在第一节里就已经看到了汇编代码生成,函数的名称生成如下:#001 [global $main]那么在LCC转载 2007-08-22 13:03:00 · 405 阅读 · 0 评论 -
[转载] LCC编译器的源程序分析(43)赋值表达式的有向无环图
由于INDIR树与ADDRL树的类型相同,所以已经转换为ADDRL树,直接对ADDRL树进行进访问了,下面就是在函数listnodes里处理赋值表达式的ADDRL树,它的代码如下:#412 case ADDRL: #413 { #414 assert(tlab == 0 && flab == 0);#415转载 2007-08-22 13:02:00 · 415 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(42)赋值表达式的有向无环图
上一次说到赋值表达式转换为有向无环图的函数listnodes,下面继续来分析这个函数代码。当赋值树处理时,就运行下面的分支来处理:#256 case ASGN: #257 { #258 assert(tlab == 0 && flab == 0);#259 if (tp->kids[0]->op == F转载 2007-08-22 13:00:00 · 460 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(41)赋值表达式的有向无环图
前 面已经介绍怎么样把赋值表达式变换到树的中间表示,接着下来编译器要做的事情就是怎么样把树变换成有向无环图。也许你会问为什么要把树变换成有向无环图, 而不是直接生成最终代码呢?其实,学习过数据结构就很清楚有向无环图的应用,编译器里就是利用有向无环图的特性来进行局部代码优化的,最主要的优化就是删 除公共表达式。下面就来分析LCC从树到有向无环图的实现代码。上面函数dcllocal里调用转换函数如转载 2007-08-22 12:59:00 · 498 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(40)赋值表达式树
前面分析了表达式的语法,也分析了语句的语法,但它们最终的目的就是生成合适的中间表示,在LCC里是采用树作为中间表示的。现在就来分析语句生成什么样的树表示,下面的语句是来自例子里,如下:int nTest1 = 1;这个语句是声明了一个局部变量nTest1,并且给nTest1赋值为1。LCC编译器要把它变换到分析树的表示,这样才利于后面的分析和使用。它的分析树如下: 左子树=右子树转载 2007-08-22 12:59:00 · 436 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(57)不同目标代码生成的接口结构
LCC为了生成不同机器的目标代码,它提供了一个接口给后端的代码生成,以便可以只修改后端,就可以达到生成不同的机器代码。它的接口如下:#001 //后端代码生成接口,可以写生成不同的目标代码。#002 //#003 //蔡军生 2007/07/20 QQ: 9073204#004 //#005 typedef struct {#006 //对齐方式的最大字节。#0转载 2007-08-23 12:44:00 · 554 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(58)后端使用的节点结构
在LCC编译器后端,主要使用下面的节点结构来标识代码属性。#001 #002 //节点注释的扩展,主要是代码生成使用。#003 //#004 //蔡军生 2007/07/21 QQ: 9073204#005 //#006 typedef struct {#007 unsigned listed:1; //标记这是树的根节点。#008 unsigned转载 2007-08-23 12:45:00 · 558 阅读 · 0 评论 -
[转 载]建立交叉编译器 for arm (binutils-2.17 gcc-3.4.6 glibc-2.3.6)
交叉编译器建立过程 准备工作下载一下源码包:可以到ftp://ftp.gnu.org 下载源码包binutils-2.17.tar.gz gcc-3.4.6.tar.gz glibc-2.3.6.tar.gz glibc-linuxthreads-2.3.6.tar.gz 或者到ftp://sourceware.org/pub/下载。将源码包放入/home/zht/cross-compiler/b原创 2007-10-23 15:53:00 · 3436 阅读 · 0 评论 -
IEEE浮点数
做数据压缩读一篇paper:Fast and Efficient Compression of Floating-Point Data,竟然把浮点数的格式都忘了,下面是搜到的资料复习一下。更详细的资料可以看 这里 深入浅出浮点数 IEEE浮点数的存放格式 对于大小为32-bit的浮点数(32-bit为单精度,64-bit浮点数为双精度 ,80-bit为扩展精度浮点数), 1、其第31 bit为符号转载 2007-09-04 16:32:00 · 668 阅读 · 0 评论 -
Linux下AT&T汇编语法格式简介
一、AT&T 格式Linux 汇编语法格式在 AT&T 汇编格式中,寄存器名要加上 % 作为前缀;而在 Intel 汇编格式中,寄存器名不需要加前缀。例如:AT&T 格式 Intel 格式pushl %eax push eax在 AT&T 汇编格式中,用 $ 前缀表示一个立即操作数;而在 Intel 汇编格式中,立即数的表示不用带任何前缀。例如:AT&T 格式 Intel转载 2007-08-31 13:51:00 · 769 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(66)DAG树分析例子
前面已经介绍创建分析树,下面就来详细地说明一个例子,看看到底生成什么样的分析树,C源程序如下:#005 int nTest1 = 1;#006 int nTest2 = 2;#007 int nTest3;#008 int i;#009 #010 nTest3 = nTest1 + nTest2; 把上面的源程序分析后,就生成下面的DAG树,如下:#转载 2007-08-23 12:52:00 · 673 阅读 · 0 评论 -
[转载] LCC编译器的源程序分析(64)符号表的结构注释
符号表是用来保存每个符号信息的,因为编译器分析源程序的过程会生成很多符号的属性,后端根据这些属性来生成合适的指令和代码的格式。 #001 //符号表结构.#002 //#003 //蔡军生 2007/08/10 QQ:9073204#004 //#005 struct symbol #006 {#007 char *name; //符号的名称,大多数情况是源程序的转载 2007-08-23 12:50:00 · 570 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(60)代码表的结构
在LCC里使用代码表来表示代码块,前端把所有代码属性放到代码表里,后端根据代码表来生成代码,它的结构如下:#001 //代码表结构定义.#002 //蔡军生 2007/07/27#003 struct code#004 {#005 //代码表的类型.#006 enum KindType#007 {#008 Blockbeg,转载 2007-08-23 12:47:00 · 558 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(54)指令模式匹配
在LCC编译器里,先把下面的语句翻译成中间表示,int nTest1 = 1;其中间表示的树如下:ASGNI4(ADDRLP4(nTest1), CNSTI4(1))然后根据上述的中间表示进行指令模式匹配。下面的函数_label就是进行这样的工作:#001 static void _label(NODEPTR_TYPE a) {#002 int c;#003 s转载 2007-08-23 12:41:00 · 619 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(48) 寄存器分配
在LCC里是使用非常简单的寄存器分配算法,并且局限于森林里的临时变量的分配。下面就来分析寄存器分配的代码:#001 int askregvar(Symbol p, Symbol regs) {#002 Symbol r;#003 #004 assert(p);#005 if (p->sclass != REGISTER)#006 return 0;转载 2007-08-22 13:06:00 · 466 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(37)default语句
default语句是使用在switch语句的复合语句里,它是所有其它分支不能处理时的分支处理。在LCC里是如下处理的: #001 case DEFAULT: #002 if (swp == NULL)#003 error("illegal default label/n");#004 else if (swp->def转载 2007-08-22 12:56:00 · 455 阅读 · 0 评论 -
IEEE制定的浮点数格式
IEEE制定的浮点数格式 鉴于有人问到在C语言中float和double型态的储存格式的问题,所以我就在这边献丑一翻,讲讲我所了解的部份,如有任何错误,请各位大哥多多指教... IEEE制定之浮点数格式说明: float型态:用4个bytes储存,也就是32 bits. 各个bit的用途如下: bit 31转载 2007-08-22 09:34:00 · 1208 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(65)后端接口的结构注释
因为LCC后端可以生成不同机器结构的代码,所以需要定义后端的接口结构,当不同的模块实现这些接口时,就可以实现不同的机器代码生成。下面就是这个接口的结构定义注释。 #001 //后端代码生成的接口.#002 typedef struct interface #003 {#004 //数据类型.#005 Metrics charmetric;#006 Metrics转载 2007-08-23 12:51:00 · 561 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(63)创建DAG森林的源程序
#001 //#002 void walk(Tree tp, int tlab, int flab) #003 {#004 //创建DAG森林.#005 listnodes(tp, tlab, flab);#006 #007 //如果DAG森林生成.#008 if (forest) #009 {#010 Node list = fore转载 2007-08-23 12:49:00 · 531 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(62)生成常量树节点的流程
在LCC里分析下面的语句:#005 int nTest1 = 1;就需要把1生成一个常量树节点,那么在LCC里用怎么样的流程来创建这个树节点的呢?这个过程大体是这样的:当碰到赋值符号后,就需要分析表达式,于是调用函数获取记号函数CCaiCompiler::Instance()->GetLex()->GetToken(),接着下来就调用构造常量符号项的函数Symbol CCaiLex:转载 2007-08-23 12:49:00 · 591 阅读 · 0 评论 -
[转载] LCC编译器的源程序分析(61)复合语句的代码块流程
LCC编译器要分析下面的程序,大体流程是这样的。#001 #include #002 #003 int main(void)#004 {#005 int nTest1 = 1;#006 int nTest2 = 2;#007 int nTest3;#008 int i;#009 #010 nTest3 = nTest1 + nTest2;#0转载 2007-08-23 12:48:00 · 543 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(59)代码生成的源程序注释
下面详细地注释了gen.c的源程序,这样看起来就比较容易理解,希望对你有所帮助。#001 #include "c.h"#002 #003 static char rcsid[] = "$Id: gen.c 355 2007-02-18 22:08:49Z drh $";#004 #005 #define readsreg(p) /#006 (generic((p)-转载 2007-08-23 12:46:00 · 837 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(39)goto语句
在现代设计的程序里,很少再用到goto语句了。虽然使用goto语句是比较高效,但它使程序也会得非常难懂,非常难维护,比较容易出错,所以很少使用goto语句的。goto语句为无条件跳转语句,它的一般形式为: goto 标号;在LCC里的是用下面的代码来处理:#001 case GOTO: #002 walk(NULL, 0, 0);#003转载 2007-08-22 12:58:00 · 472 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(38)return语句
在实现中,程序其实就是处理数据,然后输出处理过的结果,在C语句里最直接的方式就是函数的返回值。比如求两个数据的最大值,就可以通过函数返回值来返回最大值。而函数的返回值是通过函数中的return语句获得的。return语句后面是一个表达式,需要调用表达式函数来处理。下面来分析LCC里的代码:#001 case RETURN: #002 {#003转载 2007-08-22 12:57:00 · 563 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(36)case语句
case语句是使用在switch语句之中,它实现了选择一个分支执行。当表达式的值与case后面的常量表达式的值相等时,就执行此case语句后面的语句。LCC处理这个语句的代码如下:#001 case CASE: #002 {#003 int lab = genlabel(1);#004 if (swp转载 2007-08-22 12:54:00 · 468 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(21)局部变量的声明
<!--google_ad_client = "pub-0904655026211899";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";google_ad_channel = "";google_color转载 2007-08-21 12:44:00 · 611 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(18)函数定义
激动人心的时刻就要开始了,从这节开始,就进入处理实际的代码了。由于C语言是函数式的语言,也就是每个程序都是有一个一个的函数组成的,一个C源程序至少包含一个函数(main函数),也可以包含一个main函数和若干个其它函数。因此,函数是C程序的基本单位。仔细地查看一下第一节里的例子代码,它是如下:#001 #include #002 #003 int main(void)#004 {转载 2007-08-20 13:01:00 · 522 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(10)声明类型
上一次把声明的说明符已经分析得很清楚,也就是把C的变量和函数声明都已经了解了。最后还剩下一个问题没有解决,这个问题就是声明后面的ID是变量呢?还是函数?或者是指针?为了识别后面的ID,下面来看一个例子。如下的语句:typedef unsigned int size_t;这是第一行处理的代码,它通过函数specifier处理后,已经就把typedef、unsigned、int处理完成,还剩下转载 2007-08-20 12:36:00 · 496 阅读 · 0 评论 -
[转载]LCC编译器的源程序分析(6)词法分析
在最开始的例子程序里,程序是由一些单词和符号组成的。其实程序就是一串长长的字符串,这些字符串是按一定的规则编写的,那么就需要检查这些单词和符号是否符合定义的规则。在C语言里,就是定义了C语法和语义。在最开始的例子里,C编译器最先进行词法分析的语句是下面这句:typedef unsigned int size_t;那么C编译器是怎么样把上面的字符串识别出来的呢?其实词法分析就是把上面的字符串转载 2007-08-17 13:34:00 · 580 阅读 · 0 评论