.Net8的AOT載入程式BootStrap

2023-07-13 12:00:49

前言

.Net8的本地預編機器碼AOT,它幾乎進行了100%的自舉。微軟為了擺脫C++的鉗制,做了很多努力。也就是程式碼幾乎是用C#重寫,包括了虛擬機器器,GC,記憶體模型等等。而需要C++做的,也就僅僅是載入程式,本篇通過程式碼來看下這段至關重要的載入程式的運作模式。原文:.Net8的AOT載入程式BootStrap


概括

所謂的載入程式,也就是引導被ILC生成的目標檔案編譯成可執行檔案,然後在相應的平臺上(MacoS/Linux/Win)進行二進位制執行。這裡以微軟自家的Windows平臺為例來剖析下這段載入程式。

載入程式分為兩個階段,其一初始化執行時,其二執行託管的Main入口程式碼。分別看下,最後就是程式碼展示了。

1.範例化執行時
這個很好理解,你如果需要執行.Net程式那麼必須有一個執行的環境,第一步就是初始化這個執行環境。它主要包括以下步驟:
一:環境變數的初始化
環境變數的初始化主要是指設定的環境變數,對於GC或者JIT的控制。在這裡進行一個初始化和區分。比如開啟了了記憶體對映的環境變數
DOTNET_EnableWriteXorExecute=1.它就是此時被AOT識別並進行區分。
二:註冊AOT的模組
AOT程式需要用到哪些模組,比如

Runtime.WorkstationGC.lib
System.Globalization.Native.Aot.lib
System.IO.Compression.Native.Aot.lib
eventpipe-disabled.lib
Runtime.VxsortDisabled.lib

等一些模組需要用到,那麼這裡進行註冊下,以便後續呼叫。
三:模組的初始化
這裡的模組初始化實際上,R2R的部分預編譯函數替代。

2.託管的Main入口
.Net裡面託管的Main函數是一切託管函數的入口點,所以託管Main入口是必須設定正確,並且能夠執行完整受控程式碼。本例展示的託管Main如下:

static void Main()
{
   Program pm=new Program();
   pm = null;
   GC.Collect();
   Console.WriteLine("This is Ce Shi");
   Console.ReadLine();
}

3.程式碼展示
上面只是一些概念,具體的行為落實,還得程式碼來。這裡看下BootStrap載入程式的程式碼。

一:節操作:
1.節存變數
主要是在初始化執行時的模組初始化階段需要用到

#pragma section(".modules$A", read)
#pragma section(".modules$Z", read)
extern "C" __declspec(allocate(".modules$A")) void* __modules_a[];
extern "C" __declspec(allocate(".modules$Z")) void* __modules_z[];
__declspec(allocate(".modules$A")) void* __modules_a[] = { nullptr };
__declspec(allocate(".modules$Z")) void* __modules_z[] = { nullptr };

2.節合併
這裡主要是然連結器進行一個節的合併

#pragma comment(linker, "/merge:.modules=.rdata")
#pragma comment(linker, "/merge:.unbox=.text")

3.節宣告函數
範例化執行時註冊AOT模組的時候要用到

char _bookend_a;
char _bookend_z;

#pragma code_seg(".managedcode$A")
void* __managedcode_a() { return &_bookend_a; }
#pragma code_seg(".managedcode$Z")
void* __managedcode_z() { return &_bookend_z; }
#pragma code_seg()

4.AOT執行環境的初始化

static int InitializeRuntime()
{
    //環境變數的初始化
    if (!RhInitialize())
        return -1;
    //獲取當前模組的控制程式碼
    void* osModule = PalGetModuleHandleFromPointer((void*)&__managed__Main);

    //註冊AOT模組
    if (!RhRegisterOSModule(
        osModule,
        (void*)&__managedcode_a, (uint32_t)((char*)&__managedcode_z - (char*)&__managedcode_a),
        (void*)&__unbox_a, (uint32_t)((char*)&__unbox_z - (char*)&__unbox_a),
        (void**)&c_classlibFunctions, _countof(c_classlibFunctions)))
    {
        return -1;
    }
    //初始化需要的模組
    InitializeModules(osModule, __modules_a, (int)((__modules_z - __modules_a)), (void**)&c_classlibFunctions, _countof(c_classlibFunctions));

#ifdef NATIVEAOT_DLL
    // Run startup method immediately for a native library
    __managed__Startup();
#endif // NATIVEAOT_DLL

    return 0;
}

5.託管入口

return __managed__Main(argc, argv);

以上是.Net8的AOT載入程式的完整運作模式。


結尾

作者:江湖評談
關注下面公眾號:jianghupt。後臺回覆暗號:AOT。獲取全部以上AOT載入程式Bootstrap全部原始碼。