- 博客(76)
- 资源 (20)
- 收藏
- 关注
转载 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 792
转载 [转载]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 684
转载 [转载]LCC编译器的源程序分析(65)后端接口的结构注释
因为LCC后端可以生成不同机器结构的代码,所以需要定义后端的接口结构,当不同的模块实现这些接口时,就可以实现不同的机器代码生成。下面就是这个接口的结构定义注释。 #001 //后端代码生成的接口.#002 typedef struct interface #003 {#004 //数据类型.#005 Metrics charmetric;#006 Metrics
2007-08-23 12:51:00 570
转载 [转载] LCC编译器的源程序分析(64)符号表的结构注释
符号表是用来保存每个符号信息的,因为编译器分析源程序的过程会生成很多符号的属性,后端根据这些属性来生成合适的指令和代码的格式。 #001 //符号表结构.#002 //#003 //蔡军生 2007/08/10 QQ:9073204#004 //#005 struct symbol #006 {#007 char *name; //符号的名称,大多数情况是源程序的
2007-08-23 12:50:00 579
转载 [转载]LCC编译器的源程序分析(62)生成常量树节点的流程
在LCC里分析下面的语句:#005 int nTest1 = 1;就需要把1生成一个常量树节点,那么在LCC里用怎么样的流程来创建这个树节点的呢?这个过程大体是这样的:当碰到赋值符号后,就需要分析表达式,于是调用函数获取记号函数CCaiCompiler::Instance()->GetLex()->GetToken(),接着下来就调用构造常量符号项的函数Symbol CCaiLex:
2007-08-23 12:49:00 600
转载 [转载]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 537
转载 [转载] 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 557
转载 [转载]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 573
转载 [转载]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 869
转载 [转载]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 566
转载 [转载]LCC编译器的源程序分析(57)不同目标代码生成的接口结构
LCC为了生成不同机器的目标代码,它提供了一个接口给后端的代码生成,以便可以只修改后端,就可以达到生成不同的机器代码。它的接口如下:#001 //后端代码生成接口,可以写生成不同的目标代码。#002 //#003 //蔡军生 2007/07/20 QQ: 9073204#004 //#005 typedef struct {#006 //对齐方式的最大字节。#0
2007-08-23 12:44:00 565
转载 [转载]LCC编译器的源程序分析(56)寄存器分配的属性结构
现在详细地分析寄存器分配的属性结构,它的定义如下:#001 typedef struct {#002 Symbol vbl; //保存变量符号,而不是临时变量.#003 short set; //寄存器类型,比如整数,或者浮点数。#004 short number; //寄存器编号。#005 unsigned mask; //寄存器字节大小,比如
2007-08-23 12:43:00 517
转载 [转载]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 571
转载 [转载]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 633
转载 [转载]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 685
转载 如何使用 aMule 从 verycd 下载东西?
手工添加最常用的aMule服务器列表: 华语p2p:61.152.93.254:4661 Razorback 2:195.245.244.243:4661 ID最好设置成[CHN][VeryCD]XXXX的样子。 会自动加上其他的服务器地址,这样就可以了。 其他的设置不说,就说如何设置成HighID Preferences Settings -> Connections 把里面TCP port改成
2007-08-22 15:30:00 13257 1
转载 [转载] LCC编译器的源程序分析(52)寄存器溢出
当寄存器分配完了,但又有一些指令需要寄存器,那么就需要把占用寄存器的值保存到内存里,才可以重新分配那些寄存器。下面就来分析LCC的寄存溢出算法。spillee是用来计算那个寄存器最好保存到内存里,然后重新使用的。它的代码如下:#001 static Symbol spillee(Symbol set, unsigned mask[], Node here) {#002 Symbol
2007-08-22 13:13:00 673
转载 [转载] 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 587
转载 [转载]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 568
转载 [转载]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 573
转载 [转载]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 475
转载 [转载]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 501
转载 [转载]LCC编译器的源程序分析(47)计算需要使用栈大小
计算栈的大小,是通过后端接口的代码来完成计算的。栈的大小,主要就是局部变量、临时变量、调用参数和返回值等使用的字节大小,如果变量可以放到寄存器,就不需加到栈的大小里。上面已经看了下面的代码:#044 case Blockbeg: #045 {#046 Symbol *p = cp->u.block
2007-08-22 13:05:00 528
转载 [转载]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 453
转载 [转载]LCC编译器的源程序分析(44)函数名称的代码生成
当把所有的源程序生成DAG表示后,就进入了编译器的最后处理阶段,LCC是把DAG生成汇编的目标代码。在这一阶段,编译器为源程序定义和使用的变量选择存储单元,并把中间指令翻译成完成相同任务的汇编代码指令序列。在代码生成里,需要处理的问题是存储管理、指令选择、寄存器分配、计算次序等等。在第一节里就已经看到了汇编代码生成,函数的名称生成如下:#001 [global $main]那么在LCC
2007-08-22 13:03:00 412
转载 [转载] 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 423
转载 [转载]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 470
转载 [转载]LCC编译器的源程序分析(40)赋值表达式树
前面分析了表达式的语法,也分析了语句的语法,但它们最终的目的就是生成合适的中间表示,在LCC里是采用树作为中间表示的。现在就来分析语句生成什么样的树表示,下面的语句是来自例子里,如下:int nTest1 = 1;这个语句是声明了一个局部变量nTest1,并且给nTest1赋值为1。LCC编译器要把它变换到分析树的表示,这样才利于后面的分析和使用。它的分析树如下: 左子树=右子树
2007-08-22 12:59:00 447
转载 [转载]LCC编译器的源程序分析(41)赋值表达式的有向无环图
前 面已经介绍怎么样把赋值表达式变换到树的中间表示,接着下来编译器要做的事情就是怎么样把树变换成有向无环图。也许你会问为什么要把树变换成有向无环图, 而不是直接生成最终代码呢?其实,学习过数据结构就很清楚有向无环图的应用,编译器里就是利用有向无环图的特性来进行局部代码优化的,最主要的优化就是删 除公共表达式。下面就来分析LCC从树到有向无环图的实现代码。上面函数dcllocal里调用转换函数如
2007-08-22 12:59:00 505
转载 [转载]LCC编译器的源程序分析(39)goto语句
在现代设计的程序里,很少再用到goto语句了。虽然使用goto语句是比较高效,但它使程序也会得非常难懂,非常难维护,比较容易出错,所以很少使用goto语句的。goto语句为无条件跳转语句,它的一般形式为: goto 标号;在LCC里的是用下面的代码来处理:#001 case GOTO: #002 walk(NULL, 0, 0);#003
2007-08-22 12:58:00 482
转载 [转载]LCC编译器的源程序分析(38)return语句
在实现中,程序其实就是处理数据,然后输出处理过的结果,在C语句里最直接的方式就是函数的返回值。比如求两个数据的最大值,就可以通过函数返回值来返回最大值。而函数的返回值是通过函数中的return语句获得的。return语句后面是一个表达式,需要调用表达式函数来处理。下面来分析LCC里的代码:#001 case RETURN: #002 {#003
2007-08-22 12:57:00 569
转载 [转载]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 470
转载 [转载]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 481
转载 [转载]LCC编译器的源程序分析(35)switch语句
switch语句是多分支选择语句,主要方便多个选择的情况使用,当然也可以使用if语句来实现,但嵌套的if语句过多会使用程序的可读性降低。switch(表达式){ case 常量表达式1: 语句1; case 常量表达式2: 语句2; … case 常量表达式n: 语句n; default: 语句n+1}
2007-08-22 12:51:00 500
转载 [转载] LCC编译器的源程序分析(34)continue语句
continue语句的作用是跳过循环体中后面尚未执行的语句,接着进行下一次是否执行循环的判断。比如下面的例子: while(表达式1) { … if(表达式2) continue; … }下面就来仔细地分析LCC里处理continue语句的源程序:#001 case CONTINUE: #002 walk(
2007-08-22 12:48:00 526
转载 IEEE制定的浮点数格式
IEEE制定的浮点数格式 鉴于有人问到在C语言中float和double型态的储存格式的问题,所以我就在这边献丑一翻,讲讲我所了解的部份,如有任何错误,请各位大哥多多指教... IEEE制定之浮点数格式说明: float型态:用4个bytes储存,也就是32 bits. 各个bit的用途如下: bit 31
2007-08-22 09:34:00 1229
转载 [转载]LCC编译器的源程序分析(33)break语句
break语句可以使用流程跳出switch语句的分支选择,当然它还可以用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句。但它不能用于循环语句和switch语句之外的其它语句中。比如下面的例子:for(;;){ if( a++ > 100) break;} 现在就来分析一下面处理break的代码:#001 case BREAK:
2007-08-21 13:08:00 498
转载 [转载] LCC编译器的源程序分析(32)for循环语句
C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况。因此,这个语句的使用频率是最高的,当然它的处理情况比上面两种循环要复杂一些。它的形式如下: for(表达式1;表达式2;表达式3) 语句1它的执行过程是先求解表达式1的值,然后再计算表达式2的值。如果其值为真,就执行语句1,然后再执行表达式3。如果其值
2007-08-21 13:05:00 509
转载 [转载]LCC编译器的源程序分析(31)do while循环语句
do—while语句是实现“直到型”循环结构。一般形式如下:do{ 语句1}while(表达式) 上面的语句是这样的执行的,先执行一次语句1,然后判断表达式的值,如果表达式的值为真,也就是非零时,返回重新执行语句1,如此反复,直到表达式的值等于0为止。这个表达式与前面一个while语句的区别,就是表达式值的判断和语句1执行先后的问题。前面while语句先判断后执行语句1,
2007-08-21 13:04:00 516
转载 [转载]LCC编译器的源程序分析(30)while循环语句
while语句的语义是这样定义的:while(表达式) 语句1当表达式为非0值时执行while语句中的内嵌语句1。其特点就是先判断表达式的值,然后再执行语句。LCC是通过下面的代码来处理这个语句的:#015 case WHILE: #016 whilestmt(genlabel(3), swp, lev + 1); #017 break;
2007-08-21 13:02:00 461
uc-USB and the Altera NIOS II Soft Core Processor
2007-05-27
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人