JIT
使用JIT技术的脚本引擎
【源码下载】JIT脚本引擎:CMinus 0.1版开放下载
摘要: 说明:CMinus是一个读入修改过语法的C源程序,然后编译成x86指令集写入内存,最后用__stdcall调用约定跟C++互相交流的脚本引擎。
目标:CMinus的定位是中间语言,用于将其他语言编译到CMinus上,享受本地指令带来的好处。
进度:完成所有功能,但是由于指令集生成的算法不好,打算修改。
下载:【内详】。
阅读全文
posted @
2009-05-22 00:32 陈梓瀚(vczh) 阅读(9893) |
评论 (24) 编辑
JIT脚本引擎:CMinus编译冒泡排序程序
摘要: 虽然CMinus到中间指令的代码是精心控制的,但是中间指令到x86的代码却是很随意写出来的。现在看来用窥孔优化只是一种治标不治本的方法。打算在CMinus整个都完成了之后,将中间指令到x86的代码生成那部分重写,使用一种广为人知的寄存器分配算法来做。下面是冒泡排序的程序:
阅读全文
posted @
2009-05-19 16:51 陈梓瀚(vczh) 阅读(2959) |
评论 (3) 编辑
JIT脚本引擎:第一个CMinus程序运行成功
摘要: 目前其实只能编译单目运算符和return语句,主要是为了看看整个大框架有没有错误。如果没有发现错误的话,其他种类的表达式和语句的代码生成很容易加上去。下面是一个CMinus程序的例子和编译结果(汇编):
阅读全文
posted @
2009-05-17 23:00 陈梓瀚(vczh) 阅读(2581) |
评论 (1) 编辑
JIT脚本引擎:基本完成CMinus的语义分析
摘要: 整整写了一天,终于基本写完了CMinus的语义分析的代码,只剩下一个检查struct是否可以计算出长度的问题(环引用造成的)。下面贴出语义分析的结果,从结果中可以看出符号表的结构以及构造方法:
阅读全文
posted @
2009-05-06 08:13 陈梓瀚(vczh) 阅读(3011) |
评论 (4) 编辑
JIT脚本引擎:CMinus大部分语法测试通过
摘要: 今天写了一些CMinus程序供语法分析器分析,然后程序从语法树重新生成格式化后的代码,两边比较检查优先级什么的是否正确处理。下面是CMinus写的冒泡排序、菲薄纳气数列、链表操作函数以及其他程序:
阅读全文
posted @
2009-05-04 19:44 陈梓瀚(vczh) 阅读(1973) |
评论 (1) 编辑
JIT脚本引擎:实现CMinus语法分析器
摘要: 这一次的语法分析器,我使用Vczh Combinator Parser,按照文法的定义,将字符串转换成了语法树。Vczh Combinator Parser构造较大规模的编译器的时候还是较为吃力,主要原因出在Visual C++竟然限制一个类型全名不能超过某个长度T_T……下面是代码:
阅读全文
posted @
2009-05-03 19:25 陈梓瀚(vczh) 阅读(2838) |
评论 (11) 编辑
JIT脚本引擎:C Minus语言语法树定型
摘要: 今天照着C Minus的语法(略有修改)设计出了C Minus的语法树。语法树的设计尽量让生成语法树的代码易于编写。每一个结构的意义十分明确,而且结构与结构之间不需要有相互联系。下面是语法树的代码:
阅读全文
posted @
2009-04-24 00:58 陈梓瀚(vczh) 阅读(3056) |
评论 (5) 编辑
JIT脚本引擎:开始做第一门编译成机器码的脚本引擎
摘要: 把中间指令都搞定了之后,得开始做一门JIT的脚本引擎了。但是这门脚本引擎不是用来写的,而是用来给更高级的语言编译的。这是什么意思呢?虽然我现在写了个语法分析器,提供了语法树,但是我的目的是让我以后设计的更高级的语言可以编译成这门相对底层的语言,而不是直接编译成中间指令。这样很多事情都会好做很多。
这一门语言主要模仿C,提供指针、结构、数组、基本类型和函数指针。还有extern函数做外部链接用。因为编译成机器码,所以可以直接把一个函数指针丢进我的脚本引擎,就可以这么用了。而且我的脚本里面的函数也可以直接作为一个函数指针提供出来。复合类型组要勇于跟C++交互。在C++与脚本里面声明同样的struct,不需要做额外工作,就可以互相使用了。
阅读全文
posted @
2009-04-18 00:17 陈梓瀚(vczh) 阅读(3150) |
评论 (7) 编辑
JIT脚本引擎:完成20个浮点函数
摘要:
FPU写起来还真是囧啊,下面20个函数实现到想死……
Sin,Cos,Tan,Cot,Sec,Csc,ASin,ACos,ATan,ACot,ASec,ACsc,Sqrt,Exp,Ln,Abs,Round,Trunc,Ceil,Floor
下面是这20个函数的汇编代码,其中Exp更是登峰造极……
阅读全文
posted @
2009-04-16 05:39 陈梓瀚(vczh) 阅读(4897) |
评论 (3) 编辑
JIT脚本引擎:测试除特殊浮点函数外的所有指令通过
摘要: 昨天为机器码编译程序写了个专用的unit test框架,今天用中间语言在这个框架上写了个程序。程序将12个字符串连接起来,然后跟另外一个字符串进行比较,如果相等返回true。当然程序如果返回false了,要么就是程序有问题,要么就是编译器有问题。当然现在是测试通过了。程序如下:
阅读全文
posted @
2009-04-15 21:15 陈梓瀚(vczh) 阅读(2120) |
评论 (1) 编辑
JIT脚本引擎:成功将第一个脚本编译成机器码
摘要: 这次工作将一个中间语言的程序翻译成了汇编,然后再翻译成机器码。这一次产生的汇编比较烂,到时候做个窥孔优化稍微处理一下就好了。等上层的设施搞定之后再将这个中间语言到汇编的程序重写。下面是一个菲薄纳气数列的例子。
阅读全文
posted @
2009-04-14 00:11 陈梓瀚(vczh) 阅读(2705) |
评论 (9) 编辑
JIT脚本引擎:继续工作
摘要: 大约两个多星期没做JIT了,经过之前些其他代码消遣,现在还是继续做下去的好。目前的成果是完成了汇编数据结构、完成了汇编到机器码的转换器、知道了成员对齐、调用转换的约定、知道如何实现异常处理以及完成了中间指令的数据结构和检查。现在需要做的事中间指令到汇编的转换程序。
阅读全文
posted @
2009-04-10 23:30 陈梓瀚(vczh) 阅读(1906) |
评论 (1) 编辑
JIT脚本引擎:中间语言定稿并完成验证工作
摘要: 经过一个多星期的推敲,终于将中间语言定稿。为了屏蔽寄存器、堆栈、数值比较逻辑、跳转、变量参数存放位置等,设计了以下中间语言。
阅读全文
posted @
2009-03-19 20:49 陈梓瀚(vczh) 阅读(2191) |
评论 (1) 编辑
JIT脚本引擎:中间指令草稿
摘要: 中间指令主要用于解决以下问题:
1、不同大小的整数、浮点、指针的互相转换和计算
2、寄存器分配
3、跳转
4、调用转换(stdcall、cdecl、fastcall)
5、临时存储单位(变量等)
因此指令在设计的时候需要
1、不让用户知道东西是放在哪里的(没有堆栈给你push和pop,而且变量在物理上不一定存在,譬如说可能在寄存器里面,或者直接优化没了等等)
2、不让用户接触到各种标志位(譬如说那个恶心的浮点比较)
3、不让用户接触到stdcall、cdecl和fastcall的区别(因此call指令需要将所有参数一起写入,而不是在之前push)
4、不让用户接触不同类型数据的转换过程(全自动处理,就算你int32=fp32+int16,也是一条指令。)
5、为了保持灵活性,声明变量的时候只指出其大小,在使用变量的每一处地方标记类型(因此可以在不同的地方标记为不同的,可以救急)
阅读全文
posted @
2009-03-10 21:05 陈梓瀚(vczh) 阅读(1800) |
评论 (0) 编辑
JIT脚本引擎:成员对齐详解
摘要: 为了让编译成x86后的代码可以转换成C++的函数指针,我们也必须处理成员对齐的事情。如果脚本里的结构成员对齐跟C++不一致的话,会造成很多麻烦。下面是成员对齐的计算方法:
阅读全文
posted @
2009-03-09 20:46 陈梓瀚(vczh) 阅读(3736) |
评论 (2) 编辑
JIT脚本引擎:浮点运算
摘要: x87的FPU支持很多种浮点运算,其中浮点运算的比较结果不放在EFLAGS里,我们需要人手取出。在比较a和b的时候,C2=0,C3=(a==b),C0=(a<b)。我们可以将FNSTSW AX指令将浮点标志位复制到AX,然后通过读取C3、C2和C0(分别位于第14、10、8位)来判断结果。下面是一个求浮点数组最大值的汇编函数:
阅读全文
posted @
2009-03-06 04:56 陈梓瀚(vczh) 阅读(1488) |
评论 (0) 编辑
JIT脚本引擎:关于自己的异常处理函数在Release下失效的解决办法
摘要: 本来昨天搞定了异常处理之后决定狂喜一天,谁知道今天用release编译了一下之后竟然挂了!资料找了半天发现是Windows XP之后提供的一项保护SAFESEH搞的鬼。于是需要将自己的异常处理函数添加进PE头的SAFESEH列表中。方法如下:
阅读全文
posted @
2009-03-04 08:40 陈梓瀚(vczh) 阅读(1882) |
评论 (2) 编辑
JIT脚本引擎:使用汇编实现__try和__catch
摘要: 使用上一篇文章的资料,就可以使用汇编实现异常处理了。下面来看一个例子。
阅读全文
posted @
2009-03-03 00:20 陈梓瀚(vczh) 阅读(2268) |
评论 (1) 编辑
JIT脚本引擎:stdcall、cdecl和fastcall
摘要: stdcall、cdecl和fastcall的参数都是从右到左入栈,并且返回值遵循以下规律:
小于等于4字节结构用EAX
小于等于8字节结构用EDX:EAX
浮点数用ST(0)
其他则在EAX放置一个指针,供返回值使用
stdcall被调用者清栈,cdecl调用者清栈,fastcall被调用者清栈并且前两个小于等于4字节的参数放入ECX和EDX。返回值和参数如果一方有构造函数或析构函数则不使用寄存器。
于是今天用字符串形式的汇编写了三种调用方法的求和函数:
阅读全文
posted @
2009-03-01 05:27 陈梓瀚(vczh) 阅读(1792) |
评论 (9) 编辑
JIT脚本引擎:用汇编写了一个四则运算字符串分析程序
摘要: 这个汇编程序读入一个字符串,并计算结果。支持加减乘除括号,不支持浮点数,不支持查错。以下是汇编以及注释。汇编程序使用这篇文章的程序编译并执行。
阅读全文
posted @
2009-02-26 09:05 陈梓瀚(vczh) 阅读(2203) |
评论 (0) 编辑
JIT脚本引擎:动态运行文本格式的汇编代码
摘要: 今天完成了文本格式汇编代码的编译工作。这主要是为了调试,因为编译器不可能产生文本格式的汇编代码,这样会很浪费资源。翻译过程如下:
阅读全文
posted @
2009-02-26 01:27 陈梓瀚(vczh) 阅读(3346) |
评论 (2) 编辑
JIT脚本引擎:完成链接器的核心功能
摘要: 光能编译汇编还是不行的,因为很多东西在编译的时候不知道,典型的比如放常量那部分的指针等等。主要原因还是因为x87(指FPU部分)没有指令包含浮点立即数,所有装载浮点常数的指令都要求提供指针。所以诸如double a=1.2;之类的代码,需要将1.2预先放置在一个地方然后确定指针的位置。
于是就遇到了一个问题,如何将编译后才知道的指针地址写进去呢?
阅读全文
posted @
2009-02-22 22:41 陈梓瀚(vczh) 阅读(1919) |
评论 (1) 编辑
JIT脚本引擎:将汇编语言编译成机器码写进内存并在C++中调用
摘要: 在完成了这里和这里的工作之后,就可以写程序生成机器码了。在生成机器码的时候有如下注意事项:
1:可执行代码所在的空间必须使用VirtualAlloc与PAGE_EXECUTE_READWRITE标记分配。
2:程序需要的常量空间、全局变量空间和指令空间需要分开在三个不同的地方。
下面的例子使用一个struct保存指令的每一个部分,并且结合之前产生的指令译码表生成二进制码。
阅读全文
posted @
2009-02-22 07:08 陈梓瀚(vczh) 阅读(4931) |
评论 (11) 编辑
JIT脚本引擎:识别需要使用66H前缀区分的相同opcode指令的16位版本和32位版本
摘要: 关于这个问题实在没有一个特别好的方法,基本方法还是来源于对intel手册的观察。因为指令表是从手册上面复制出来的,但是上面又没有标明66H前缀,怎么办呢?人肉找规律。这里贴出了区分的代码(进对于之前挑选出来的绝大多数x86与x87指令)以及生成后的一个很有规则的文件以供参考。
阅读全文
posted @
2009-02-16 21:53 陈梓瀚(vczh) 阅读(2357) |
评论 (1) 编辑
JIT脚本引擎:将汇编指令转换为机器码
摘要: 完整的转换方法需要intel提供免费翻印下载的那本手册。手册过于精简,因此这里给出的例子用于辅助对手册进行理解。假设读者阅读过intel提供的手册,或其他相关资料。
阅读全文
posted @
2009-02-15 23:45 陈梓瀚(vczh) 阅读(3631) |
评论 (5) 编辑
JIT脚本引擎:x86子集汇编二进制码表整理完成
摘要: 为了节省工作量,我打开intel的手册,然后将那些框框里面的字符串复制到一个文本文件里面,最后写一个C++程序用正则表达式处理。流程如下(含代码和文件):
阅读全文
posted @
2009-02-14 20:21 陈梓瀚(vczh) 阅读(3114) |
评论 (2) 编辑