为 .net 编写编译器 - IL 还是字节码?

发布于 2024-08-27 18:14:54 字数 325 浏览 5 评论 0原文

我目前正在深入研究 .net(即 IL)的内部运作方式。作为练习,我想为 .net 构建一个 Brainf..k 编译器(是的,它们已经存在,但正如所说,它是用于学习目的)。

目前我只是编写一些包含 .il 的文本文件并使用 ilasm 编译它们,这是有效的。但我想知道我是否可以/应该更深入一层并直接编写字节码?

我的“担忧”是编译 EXE 时的 Windows PE 内容 - 我需要某种字节码链接器而不是 ilasm 来获取我的 MSIL/CIL 字节码并为其生成 PE 内容?

或者编译器“仅”将其语言编译为 IL 并执行 ilasm?是否有一个可以从编译器调用/嵌入的托管版本?

I'm currently diving into the inner workings of .net, which means IL. As an exercise, I want to build a brainf..k compiler for .net (yes, they already exist, but as said it's for learning purposes).

For the moment I'm just writing some text files that contain .il and compile them with ilasm, which works. But I wonder if I could/should go one level deeper and write bytecode directly?

My "concern" is the Windows PE Stuff when compiling an EXE - instead of ilasm I would need some sort of Bytecode linker that would take my MSIL/CIL bytecode and generate the PE Stuff for it?

Or do compilers "only" compile their language to IL and execute ilasm? Is there a managed version of it that I can call/embed from my compiler?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

要走干脆点 2024-09-03 18:14:54

为什么不简单地使用 Reflection.Emit api 来生成内存中用编译后的代码进行汇编,然后将其保存到磁盘?应该比写出 .IL 文件容易得多。

链接:

如果你想走这条路,如果你问更具体的问题在这里 SO 您将获得大量有关如何定义动态程序集并将其保存到磁盘的示例。

这是一个示例:

using System;
using System.Reflection.Emit;
using System.Reflection;

namespace SO2598958
{
    class Program
    {
        static void Main()
        {
            AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
                new AssemblyName("TestOutput"),
                AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder mod = asm.DefineDynamicModule("TestOutput.exe",
                "TestOutput.exe");
            TypeBuilder type = mod.DefineType("Program", TypeAttributes.Class);

            MethodBuilder main = type.DefineMethod("Main",
                MethodAttributes.Public | MethodAttributes.Static);
            ILGenerator il = main.GetILGenerator();
            il.Emit(OpCodes.Ldstr, "Hello world!");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
                BindingFlags.Public | BindingFlags.Static,
                null, new Type[] { typeof(String) }, null));
            il.Emit(OpCodes.Ret);

            type.CreateType();
            asm.SetEntryPoint(main);
            asm.Save("TestOutput.exe");
        }
    }
}

您可以下载测试解决方案从这里获取文件此处直接链接到 zip 文件和解决方案.

如果您首先编译并运行该程序,它将在磁盘上生成一个新的 exe 文件,名为 TestOutput,然后您可以执行该文件以获得“Hello World!”打印在控制台上。

Why not simply use the Reflection.Emit api to produce a in-memory assembly with the compiled code and then save it to disk? Should be a lot easier than writing out .IL files.

Links:

If you want to go down this road, if you ask more specific questions here on SO you'll get plenty of example of how to define a dynamic assembly and save it to disk.

Here's an example:

using System;
using System.Reflection.Emit;
using System.Reflection;

namespace SO2598958
{
    class Program
    {
        static void Main()
        {
            AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
                new AssemblyName("TestOutput"),
                AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder mod = asm.DefineDynamicModule("TestOutput.exe",
                "TestOutput.exe");
            TypeBuilder type = mod.DefineType("Program", TypeAttributes.Class);

            MethodBuilder main = type.DefineMethod("Main",
                MethodAttributes.Public | MethodAttributes.Static);
            ILGenerator il = main.GetILGenerator();
            il.Emit(OpCodes.Ldstr, "Hello world!");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine",
                BindingFlags.Public | BindingFlags.Static,
                null, new Type[] { typeof(String) }, null));
            il.Emit(OpCodes.Ret);

            type.CreateType();
            asm.SetEntryPoint(main);
            asm.Save("TestOutput.exe");
        }
    }
}

You can download the test solution file from here. Direct link to zip file with solution here.

If you first compile and run this program, it'll produce a new exe file on disk, called TestOutput, which you can then execute in order to have "Hello World!" printed on the console.

甚是思念 2024-09-03 18:14:54

System.Reflection.Emit 提供了以静态类型方式创建 IL 代码的工具,而无需使用 IL 生成和编译文本文件。

System.Reflection.Emit provides facilities to create IL code in a statically-typed way without having to generate and compile text files with IL.

泪眸﹌ 2024-09-03 18:14:54

Reflection.Emit 将更直接地满足您的目的,但您可能需要查看通用编译器基础结构 CodePlex 上的项目也有。

以下是该项目的项目页面的摘要:

微软研究院通用编译器
基础设施(CCI)是一组
库和应用程序
编程接口(API)
支持部分功能
这对于编译器来说是常见的
相关编程工具。

CCI 元数据 API 允许
应用程序来有效地分析或
修改 .NET 程序集、模块和
调试 (PDB) 文件。 CCI 元数据
支持.NET的功能
系统.反射和
System.Reflection.Emit API,但带有
更好的性能。它还
提供额外的功能
.NET API 中均不可用。

该项目有一个 PeWriter/PeReader 以及编写 .net 编译器所需的所有其他东西(ILGenerator、元数据助手等)。

Reflection.Emit is going to be more straight forward for your purposes, but you may want to look at the Common Compiler Infrastructure project on CodePlex too.

Here is the summary from the project page for that project:

Microsoft Research Common Compiler
Infrastructure (CCI) is a set of
libraries and an application
programming interface (API) that
supports some of the functionality
that is common to compilers and
related programming tools.

The CCI Metadata API allows
applications to efficiently analyze or
modify .NET assemblies, modules, and
debugging (PDB) files. CCI Metadata
supports the functionality of the .NET
System.Reflection and
System.Reflection.Emit APIs, but with
much better performance. It also
provides additional functionality that
is not available in either .NET API.

That project has a PeWriter/PeReader among all the other things you would need to write a .net compiler (ILGenerator, Metadata helpers, etc.).

小忆控 2024-09-03 18:14:54

你可以在那里查看一个非常简单的.net编译器:

http://msdn.microsoft .com/en-us/magazine/cc136756.aspx

you can look a .net compiler very simple there :

http://msdn.microsoft.com/en-us/magazine/cc136756.aspx

梦萦几度 2024-09-03 18:14:54

借助新的 DLR,人们应该能够使用 .Net 类创建代码。我不确定它在多大程度上使您免受实际的 IL/字节码的影响,因为这就是您想要学习的内容。

With the new DLR one should be able to do code creation using .Net classes. I'm not sure how much it shields you from the actual IL/bytecode since this is what you are trying to learn.

绮烟 2024-09-03 18:14:54

如果我正确理解你的问题,那么你至少会通过直接实施jitting来违反可移植性。将这些东西留给 .NET、Mono 或其他团队。所以我认为你不应该。但是关于你的问题的“可以”部分 - 我认为你可以跳过IL,并编译成你想要的任何东西(据我所知,MonoTouch,MonoDroid等这样做):
来自维基百科

与 Mono 应用程序不同,MonoTouch“应用程序”被编译为专门针对 Apple iPhone 的机器代码。

If i understood your question correctly, you will at the very least violate portability, by implementing jitting directly. Leave this stuff to .NET, Mono, Whatever teams. So i think you shouldn't. But about a 'could' part of your question - i think you can skip IL, and compile into whatever you want (as far as i know, MonoTouch, MonoDroid, etc do that):
From Wikipedia

Unlike Mono applications MonoTouch "Apps" are compiled down to machine code targeted specifically at the Apple iPhone.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文