.NET9 AOT编译器ILC--约定

💡 原文中文,约10300字,阅读约需25分钟。
📝

内容提要

本文介绍了.NET7之后的AOT编译器ILC的生成机器码和引导文件中的符号设置,以及ILC的JIT编译和机器码的重定位。推荐了一个学习交流圈,教授最新的.NET8/9核心CLR/JIT知识。

🔎

延伸解读

约定式符号命名:简化配置的关键

ILC 与引导程序通过固定命名规则实现调用,例如模块名__Module___StartupCodeMain。这种约定避免了复杂的配置文件,使 AOT 编译更自动化。开发者需注意模块名会影响生成的符号,若模块名变更,引导程序需相应调整。

机器码重定位:并行编译的细节

ILC 编译方法时,初始生成的 call 指令指向地址 0,后续并行编译阶段会替换为实际函数地址。这要求编译过程能正确处理重定位,确保最终可执行文件中的调用指向正确目标。

托管 Main 的调用链:从引导到入口

引导程序调用 repro__Module___StartupCodeMain 后,会初始化 CoreLib 并最终通过 repro__Module___MainMethodWrapper 跳转到托管 Main(如 repro_Program__Main)。这一链条体现了 AOT 程序从非托管入口到托管代码的过渡。

❓

Q&A

ILC编译器是什么?它和CoreRT项目有什么区别?

ILC是.NET7之后用C#重写的AOT编译器,基于CLR/JIT(C++)重写,不是之前的CoreRT项目。

ILC生成的目标文件包含哪些内容?

ILC生成的目标文件包含可执行文件所需的所有机器码符号以及机器码内容。

AOT引导程序如何调用约定函数来初始化运行环境?

引导程序初始化运行时后,会调用约定函数:模块名__Module___StartupCodeMain。例如托管DLL名为repro.dll,则调用repro___Module___StartupCodeMain。

ILC中机器码编译时如何处理call重定位?

初始编译时call指向call 0,后续编译(并行编译)时会替换为正确的函数头地址。

托管Main函数在AOT中是如何被调用的?

在约定函数模块名__Module___StartupCodeMain中,会调用真正的托管Main入口,即模块名_Program_Main,例如repro_Program_Main。

ILC编译器如何生成约定函数的符号?

ILC会构建一个{[模块名]<Module>.StartupCodeMain(int32,native int)}节点,例如{[repro]<Module>.StartupCodeMain(int32,native int)},该符号在引导文件中变为repro__Module___StartupCodeMain。

🏷️

标签

➡️

继续阅读