.net7的 nativeaot基本原理

以helloworld为例,核心代码:

Console.WriteLine("hello world");

通过被csc编译过后,得到可执行文件或者dll,比如名为app.exe,ilc将app.exe和托管System核心库作为输入,调用JIT编译器

将ILcode变为机器码,比如ILcode:

helloworld字符串入栈;

调用 System库下Method方法中下标是0x11223344的函数;

被转换成机器码:

push "hell world"

Call System::Console

就完事了。

然后形成.o文件,通过LINK可以直接和其他.o链接成exe/ELF/DLL.


 

还有个特殊点,在BCL库中,只用了C# 的基本语法,相当于只用了C#子集,可以这么理解,把C#当作C语言用了。

BCL里面用了new 这个关键字,我们知道在CPP里面,是可以重定位new 函数的,比如

void *operator new(size_t size)

{

    void *p = pvPortMalloc(size);//你自己的内存分配函数接口,这里用的是FreeRTOS的函数接口

    memset(p, 0, size);

    return p;

}

这样就完成了new的重定位。因此我想这可能有类似的写法:

[MethodImpl(MethodImplOptions.InternalCall)]

[RuntimeImport(RuntimeLibrary, "RhpNew")]

private static extern IntPtr RhpNew(函数参数);

unsafe  Intptr operator new(函数参数)

{

    巴拉巴拉;

    return RhpNew(........);

}

但是我翻遍了runtime和BCL库都没有这个函数的重定位,百思不得其解:如果不是在runtime/BCL里,那就是在编译时

用了函数替换,把new IL code替换成相应的函数了,果不其然,在ILC编译器源码里,有如下代码:

 if (opcode == ILOpcode.newobj)

 {

    巴拉巴拉;

    _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewObject), reason);

 }

 ....

 巴拉巴拉;

 case ReadyToRunHelper.NewObject:

mangledName = "RhNewObject";

break;

然后在BCL库里就找到了RhNewObject:

[RuntimeExport("RhNewObject")]

public static unsafe object RhNewObject(MethodTable* pEEType)

{

    巴拉巴拉;

    return InternalCalls.RhpNewFast(pEEType);

}

这个RhpNewFast函数Runtime CPP文件里面实现的

从此完成了new的操作。

总结一下,调用new,相当于调用RhNewObject/RhNewArray函数(不同场景下的new有不同的函数替换)

就是函数替换魔法!读取il,然后完成函数替换.


 

PS:

我觉得MichalStrehovsky他这个人很牛逼,他的zerosharp C#写的8KB程序可以运行在DOS下

有没有发现BCL库都是用C#写的,包括非常底层的new和反射,都是C#写的

在编译器做了魔法处理,所以我觉得他的目标远不止这些,我认为后期,极有可能在C#层面完成一个VM+JIT+GC,

也就是说使用C#的子集开发一个VM+JIT+GC,

最底层CPP只提供最基本的函数接口,比如:CreateThread Open Write这就是一个完整的CLR.

那到时候coreCLR就可以退出历史舞台了

你可能感兴趣的:(c#,开发语言)