前言:

.Net7的CLR最具特色的一个地方,就是运行模型。因为它主宰了整个CLR的运行过程。

又因为其庞大的代码量,有的几十万行甚至百万行。所以理解起来非常不容易。本篇拆分来看下,里面一个细节Main函数(注意这里的Main指的是托管Main,因为还有非托管main,所以特别指出下以免混淆)是如何被CLR调用的。

概括

Main函数的调用,基本上是最后才会被CLR引擎所调用。为啥?因为,如果.Net标准类库,以及底层的非托管C++类库没有在Main函数被调用之前,加载完成,那么你强行调用Main函数就会出错。

我们可以在Windows/Linux平台通过Windbg或者是LLDB来看下托管的Main函数的堆栈

00007ff7f55703b0
coreclr.dll!CallDescrWorkerInternal
coreclr.dll!CallDescrWorkerWithHandler
coreclr.dll!MethodDescCallSite::CallTargetWorker
coreclr.dll!MethodDescCallSite::Call C++
coreclr.dll!RunMainInternal C++
coreclr.dll!``RunMain'::`30'
coreclr.dll!`RunMain'::`30'
coreclr.dll!RunMain C++
coreclr.dll!Assembly::ExecuteMainMethod
coreclr.dll!CorHost2::ExecuteAssembly
coreclr.dll!coreclr_execute_assembly C++
corerun.exe!run C++
corerun.exe!wmain C++
corerun.exe!invoke_main C++
corerun.exe!__scrt_common_main_seh C++
corerun.exe!__scrt_common_main C++
corerun.exe!wmainCRTStartup C++
kernel32.dll!BaseThreadInitThunk
ntdll.dll!RtlUserThreadStart

这个堆栈里面我们可以得出很多的信息:

比如:

1.最上面的地址:00007ff7f55703b0是.Net里面的托管Main函数的入口地址。

2.整个程序的运行最开始的代码是ntdll.dll模块里面的RtlUserThreadStart函数。

3.非托管的CLR的入口是wmain函数。

有了以上的信息,我们很容易分析到。托管的Main函数调用是在程序集的ExecuteMainMethod函数里面调用RunMain这个函数,整个函数的名字一看就知道是运行Main函数的。

此后通过CallDescrWorkerInternal来调用RyuJIT编译MSIL代码为机器码。返回到托管Main函数的开头地址。

也就是上面的这个地址:00007ff7f55703b0

分析:

这个过程看似分析非常简单,但是实际上会遇到很多问题。但是如果你只用单一的调试器,比如只用Windbg。你可能完全看不出来以下这些问题。

比如你在调试.Ctor,也就是.Net 7里面默认的构造函数的时候。如果在VS上Debug CLR上面,如果进入到托管Main的机器码当中,运行到.Ctor的机器码的地方。它会报一个不是错误的错误,而跟踪下来居然是MapViewOfFile这个微软的官方函数的错误,关于这一点可以看这里,之前写的一篇文章:点击这里查看之前文章

而另外如果你在Linux上面用LLDB调试的时候,会发现托管的Main入口断点可能会进不去的情况。

当然这些类似Bug但可能不是Bug东西,需要深厚的功力去发现和验证它到底是啥。

结尾:

作者:江湖评谈

欢迎关注我,带你了解.Net7的CLR的各种奇巧淫技。让.Net7,甚至后面的.Net8,9,10。在你面前毫无神秘可言。

.Net7运行模型之托管Main函数的调用的更多相关文章

  1. VS2010-如何建立并运行多个含有main函数的文件

    一.先说两个概念,解决方案与工程 在VS2010中,工程都是在解决方案管理之下的.一个解决方案可以管理多个工程,可以把解决方案理解为多个有关系或者没有关系的工程的集合. 每个应用程序都作为一个工程来处 ...

  2. java中main函数怎么调用外部非static方法

    使用外部方法时(不管是static还是非static),都要先new一个对象,才能使用该对象的方法. 举例如下: 测试函数(这是错误的): public class Test { public sta ...

  3. java 运行指定类的main函数

    运行jar文件的方法是: java -jar xxx.jar 但是有时,我们希望运行里面的具体某个类,这时可以通过: java -cp xxx.jar xxx.com.xxxx  它会找到这个类的ma ...

  4. python+unnitest时运行后不执行main函数里面的内容

    1.使用工具pycharm运行unnitest程序遇到的问题 1) 问题:运行后无法生成报告:经print()发现未执行main函数里的内容 2) 原因:使用unnitest测试框架,pycharm运 ...

  5. Java中main函数只能调用同类中的静态方法?

    如果想调用本类中的非静态方法可以这么来写: public class TT{ public static void main(String[] args){ TT t = new TT(); t.fu ...

  6. C# Main函数中调用异步方法的2种实现

    As you discovered, in VS11 the compiler will disallow an async Main method. This was allowed (but ne ...

  7. main函数如何调用文件外的函数

  8. 为什么c程序里一定要写main函数

    一. 学习过程 编写程序f.c: 对其进行编译,正常通过,再对其进行连接,出现错误: 显示的出错信息为: 翻译成中文是:在c0s模块没有定义符号’_main’. 那么这个错误信息可能与文件c0s.ob ...

  9. main函数的参数argc和argv

    版权声明:本文为博主原创文章,转载请注明CSDN博客源地址!共同学习,一起进步~ https://blog.csdn.net/Eastmount/article/details/20413773 该篇 ...

  10. c语言中的main函数讨论

    **从刚开始写C程序,相比大家便开始写main()了.虽然无数的教科书和老师告诉我们main是程序的入口.那么main函数是怎么被调用的,怎么传入参数,返回的内容到哪里了,返回的内容是什么?接下来我们 ...

随机推荐

  1. 如何判断多个url的状态 即是否能成功访问?

    假设我们所有的url在excel种我们可以用loadwork 这个库 遍历所有的url 放入 列表 再通过request 或者 httpx 来判断 这个网址status_code 进而放入mongo种 ...

  2. Scrapy 之 docker splash

    Scrapy 之 docker splash 1. ubuntu 安装docker 命令 curl -sSL https://get.daocloud.io/docker | sh 或者 curl - ...

  3. HTML5和CSS3新特性

    1.HTML5新标签和属性 1.1 兼容性前缀与语义化 兼容低版本的写法.比较新的浏览器,可以直接写.兼容性前缀,是每个浏览器私有的. 内核 兼容性前缀 浏览器 Gecko -moz- Firefox ...

  4. 设置CMD命令的初始目录

    本文提供两种方式,第一种通过打开桌面上的快捷方式实现,第二种可以通过 CMD 命令直接进入. 快捷方式 "开始 ---> 程序 ---> 附件",右键单击 " ...

  5. java学习之JSON

    0X00前言 JSON可以说是javascript的一种数据类型,我们学习JSON是为了在客户端的数据给读取出来,官方的解释是:概述:JSON(JavaScript Object Notation, ...

  6. C#.NET实现二分查找

    二分搜索法 定义 二分法查找,也称为折半法,是一种在有序数组中查找特定元素的搜索算法. 适用范围 当数据量很大并且有序时,适宜采用该方法. 基本思想 假设数据是按升序排序的,对于给定值key,从序列的 ...

  7. Debian Linux 的安装

    Debian Linux 的安装 作者:Grey 原文地址: 博客园:Debian Linux 的安装 CSDN:Debian Linux 的安装 说明 本安装说明是基于 Windows 10 下 V ...

  8. C ++:树

    C++:树 树的概念: 所谓"树"是输就结构的一种,树大概可以分为两大类: 有根树 和 无根树 有根树使有一个确定的根节点,反之为无根树 · 子节点:从树根开始,通过树边向下扩展的 ...

  9. 1 c++编程基础

    重新系统学习c++语言,并将学习过程中的知识在这里抄录.总结.沉淀.同时希望对刷到的朋友有所帮助,一起加油哦! 生命就像一朵花,要拼尽全力绽放!死磕自个儿,身心愉悦! 1 c++揭开面纱 1.1 编程 ...

  10. combotree 的简单使用2

    上一次我在 combotree 的简单使用 中介绍了一种combotree的写法,不过有一个缺点,就是当输的结构非常大的时候,分级较多时,消耗内存的现象会比较严重,下面介绍的一种方法,使combotr ...