编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

了解.Net Native编译器(.net core编译)

wxchong 2025-04-09 21:33:20 开源技术 21 ℃ 0 评论

起因

在.Net6中 Native程序生成的过程 说到*.ilc.rsp这个文件,其实rsp格式文件很早都在.Net中使用了,最早知道这个格式文件是在<>这本书,我觉得这是我看C#最认真的一本书了.继续说*.ilc.rsp文件这个是谁使用? 是ILCompiler(简写ilc)编译器使用,这个编译器将.Net (exe/dll)编译为obj目标文件.

ILCompiler源码地址
:https://github.com/dotnet/runtimelab.git ,在Github上看到好像在.Net 7中要将ILCompiler合到.Net Runtime中.

准备工作

ILCompiler源码在runtimelab下,runtimelab是包含CoreCLR和BCL库.所以要执行根目录下的build.cmd/build.sh

Bash
//Windows下执行,这里和执行编译Runtime源码不太一样,增加了nativeaot.packages参数
build.cmd nativeaot+libs+nativeaot.packages -rc Debug -lc Debug

//Linux下执行
build.sh nativeaot+libs+nativeaot.packages -rc Debug -lc Debug

编译前,还是需要一个.Net版本,这里就不说了,具体可以看 如何编译.Net 6 Runtime源码 ,编译完成后,是有ILCompiler的nupkg包,可以在源码根目录下,去这个路径
artifacts/packages/Debug/Shipping/

ILCompiler的解决方案文件,在这个目录下
src/coreclr/tools/aot/ilc.sln,打开解决方案后:

  1. 设置ILCompiler为启动项目
  2. 设置工作目录 F:\GitCode\runtimelab-feature-NativeAOT\samples\HelloWorld
  3. 设置命令行参数 以@开头. 如@obj/Debug/net6.0/win-x64/native/HelloWorld.ilc.rsp

然后启动ILCompiler项目,会将obj文件生成到 工作目录加命令行参数所在的目录.

生成Native程序

找到reproNative项目,在该项目属性中,找到链接器→输入: F:\GitCode\
runtimelab-feature-NativeAOT\samples\HelloWorld\obj\Debug\net6.0\win-x64\native\HelloWorld.obj

链接obj目标文件,和cpp文件编译成原生程序

在reproNativew项目的cpp文件看到这一段代码比较有意思:

Bash
#if defined(_MSC_VER)

#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 };

//
// Each obj file compiled from managed code has a .modules$I section containing a pointer to its ReadyToRun
// data (which points at eager class constructors, frozen strings, etc).
//
// The #pragma ... /merge directive folds the book-end sections and all .modules$I sections from all input
// obj files into .rdata in alphabetical order.
//
#pragma comment(linker, "/merge:.modules=.rdata")

//
// Unboxing stubs need to be merged, folded and sorted. They are delimited by two special sections (.unbox$A
// and .unbox$Z). All unboxing stubs are in .unbox$M sections.
//
#pragma comment(linker, "/merge:.unbox=.text")

char _bookend_a;
char _bookend_z;

//
// Generate bookends for the managed code section.
// We give them unique bodies to prevent folding.
//

#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()

//
// Generate bookends for the unboxing stub section.
// We give them unique bodies to prevent folding.
//

#pragma code_seg(".unbox$A")
void* __unbox_a() { return &_bookend_a; }
#pragma code_seg(".unbox$Z")
void* __unbox_z() { return &_bookend_z; }
#pragma code_seg()

这一段代码,应该就是将obj的module放到节(这是可执行程序的知识,后面会在PE中说这个).

下面看main方法代码:

#if defined(_WIN32)
int __cdecl wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
#ifdef ENSURE_PRIMARY_STACK_SIZE
    // TODO: https://github.com/dotnet/runtimelab/issues/791
    EnsureStackSize(1536 * 1024);
#endif

    int initval = InitializeRuntime();                 //初始化runtime
    if (initval != 0)
        return initval;

    int retval = __managed__Main(argc, argv); //调用.net的main方法

    RhpShutdown();  

    return retval;
}

后面就可以看为什么没法在C程序调用.Net Native生成的静态库了.

个人能力有限,如果您发现有什么不对,请私信我

如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表