我正在尝试为.NET平台创建我的语言的后端。 用Delphi编写的前端和解释器。 非托管API只允许类型定义,但不会发出MSIL。
从非托管代码生成MSIL有哪些方法? 不使用Reflection.Emit并使用ILasm来实现这一目标? 谢谢。
答案 0 :(得分:5)
Delphi的.NET代码生成器将IL作为字节码直接发送到内存中,与x86代码生成非常相似,但具有适当的标头等。也就是说,代码生成器直接发出字节,异常表等,对应于编码的IL格式。它不是用API做的,而是用老式的方式:一次写一个字节的代码。
稍后,Delphi的内置链接器与IMetaDataEmit
等一起生成元数据,IMetaDataEmit::SetRVA
告诉元数据代码将在可执行文件中的位置。使用IMetaDataEmit::SaveToMemory
复制元数据,然后将其复制到链接器已构建的PE中,并相应地修补CLR标头以指向元数据开始。
这是很多代码,其中一些是繁琐的,因为它的大部分内容都是通过Delphi现有的x86链接器进行的,它实现了分支优化和消除未使用代码(智能链接)之类的功能,严格来说通常不需要对于.NET。
如果我们再次这样做,我们可能会很好地避免使用.NET API来创建元数据,并直接从规范生成整个内容。 API最终成为优化的黑盒子,并且累积了大量的编译时间。
答案 1 :(得分:3)
来自非托管代码? TBH,我最好的建议是“使用P / Invoke”,或者“弄清楚它的意图,并重新实现它”。
即使你可以找到一些东西来移植非托管代码,即使它有效 - 它也不会完全利用框架。并且在非托管和托管之间并不完全是1:1。
答案 2 :(得分:2)
你让它变得困难。 Codeplex.com上提供的反讽和通用编译器基础结构库已经完成,它们的目标是以托管代码实现的编译器。下一个选项是使用非托管元数据接口,如IMetaDataAssemblyEmit,IMetaDataAssemblyImport,IMetaDataEmit2。但是,这些COM接口在cor.h SDK头文件中声明,仅适用于C / C ++程序。没有可用的类型库。除了精心复制界面声明之外,您需要某种工具将这些声明转换为Delphi声明。不确定是否存在。
答案 3 :(得分:2)
MSIL或CIL本质上是机器代码的.Net等价物。解析语言并将其转换为机器代码时,您所拥有的是编译器。任何语言的早期编译器通常都会手动生成机器代码。也就是说,对于源语言中的每种命令或表达式,编写汇编程序指令的“模板”以将其转换为。在处理程序的中间表示时,选择相应的模板,填写程序特定的详细信息,然后发出CIL。对于像CIL这样的基于堆栈的语言,将多个语句中的模板链接在一起应该相当容易;一个语句的输出堆栈是下一个输入堆栈。
您需要熟悉CIL instruction set。
您的编译器是非托管代码这一事实并不重要。您可以从任何类型的程序生成CIL文本。当它准备好后,通过ilasm
发送它以从中创建一个程序集。