.Net8的AOT是如何被C++操控运行的

前言

.Net目前有两条线,一条是正宗的.Net虚拟机CLR调用JIT的即时编译,另外一条就是通过ILC编译成本地的机器码也即是AOT。上一篇【C++是如何运行C#/.Net的?】说的是前者,本篇来看下后者。

概括

前情提要:本篇以最新的.Net8 PreView5为蓝本,进行的描述。

1.不同简要比较

AOT相当于一个全新的缩减.Net版本,它和即时编译器也即JIT机器码照样不同,这里举一个例子,比如以下代码:

static void Main(string[] args)
{
    Program pm = new Program();
}

简单的一个对象实例化,即时编译里面:

call        JIT_TrialAllocSFastMP_InlineGetThread (07FFC4C650650h)  
 mov         qword ptr [rbp+20h],rax  
 mov         rcx,qword ptr [rbp+20h]  
 call        Program..ctor() (07FFBECC2C078h)

可以看到它先分配内存,然后调用默认的构造函数.ctor

那么AOT呢?

00007FF72AD459E8 48 8D 0D E1 55 17 00 lea         rcx,[repro_Program::`vftable' (07FF72AEBAFD0h)]  
00007FF72AD459EF E8 9C 0A C9 FF       call        RhpNewFast (07FF72A9D6490h)

它这里很明显用了虚函数表指针作为参数,调用了RhpNewFast。完全是不一样的。

2.整体过程AOT的编译如下:C#源码-》Roslyn(DLL)->ILC(Obj)->Link(Exe)写好了C#源代码之后,Roslyn会接管C#源代码把它编译成中间语言MSIL,存放在托管的动态链接库即DLL里面。ILC会接管托管的DLL把它生成目标文件.Obj,然后用NativeAot的引导程序也即Bootstrap引导Link.exe工具链接.Obj目标文件生成可执行文件。

3.细节生成的目标文件也即Obj依旧是通过开源界三大编译器之一的LLVM来生成的.在Windows/Linux/MaoOS上的动态链接库分别是:

objwriter.dll(pe)/libobjwriter.so(elf)/libobjwriter.dylib(Mach-O)

他们分别封装了各个平台的llvm后端代码生成来完成了Obj目标文件的生成。

4.C++和AOT无论是Roslyn,或者ILC或者引导程序BootStrap都是通过C++来启动运行的。1.Roslyn的运行实质上是运行在虚拟机CLR上面的2.ILC同上3.BootStrap它本身就是cpp项目而llvm本身就是一套超级底层的C/C++项目,可以看到在一整套的AOT编译运行流程中,C++始终操控C#的运行。

5.核心代码

为了更为透彻的了解到ILC调用Objwriter.dll动态链接库操控llvm生成obj目标文件。在WinX64平台上,这里演示一段简单的代码,步骤如下:

一.首先在nuget上面下载一个ILC编译器,也即是:

runtime.win-x64.Microsoft.DotNet.ILCompiler

二.找到nuget目录,里面有个objwriter.dll一般的在如下路径:

C:\Users\Administrator\.nuget\packages\runtime.win-x64.microsoft.dotnet.ilcompiler\7.0.8\tools

三.新建一个C#控制台项目名字Obj,把上面的路径找到的objwriter.dll放入到

Obj项目bin/Debug/net7.0目录下面。

四.Obj项目bin/Debug/net7.0目录下面新建一个Demo.obj目标文件

五.Program.cs里面填写如下代码:

internal class Program
{
    [DllImport("objwriter.dll")]
    private static extern IntPtr InitObjWriter([MarshalAs(UnmanagedType.LPUTF8Str)] string objectFilePath, string triple = null);


    [DllImport("objwriter.dll")]
    private static extern void FinishObjWriter(IntPtr objWriter);


    [DllImport("objwriter.dll")]
    private static extern void EmitIntValue(IntPtr objWriter, ulong value, int size);


    private IntPtr _nativeObjectWriter = IntPtr.Zero;


    static void Main(string[] args)
    {
            IntPtr objectWriter = InitObjWriter("Demo.obj", "x86_64-pc-win32-windows");
            EmitIntValue(objectWriter, 0x10, 4);
            FinishObjWriter(objectWriter);
    }
}

运行这段代码之后,打开Demo.obj可以看到文件里面写入了一段内容,这就是ILC编译器往obj目标文件里面写入被JIT编译后的机器码的核心部分代码的原型。这里因为封装了llvm的细节,又因托管省略了大部分,看起来比较简洁。综合起来实际上的代码高达百万行之巨,暂不赘述此部分。

以上代码GitHub下载地址:

https://github.com/tangyanzhi/jianghupt/releases/download/llvm/Obj.rar

文章版权声明

 1 原创文章作者:七微电脑 /bangbangt,如若转载,请注明出处: https://www.52hwl.com/32205.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年7月14日 上午12:00
下一篇 2023年7月15日