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