一:背景

1.讲故事

前几天 B 站上有位朋友让我从高级调试的角度来解读下 .NET7 新出来的 AOT,毕竟这东西是新的,所以这一篇我就简单摸索一下。

二:AOT 的几个问题

1. 如何在 .NET7 中开启 AOT 功能

在 .NET7 中开启 AOT 非常方便,先来段测试代码。

internal class Program{static void Main(string[] args){Console.WriteLine("hello world!");Debugger.Break();}}

然后在项目配置上新增 <PublishAot>true</PublishAot> 节点,如下输出:


<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net7.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><PublishAot>true</PublishAot></PropertyGroup>
</Project>

接下来在项目中右键选择 发布,选择一个输出地,这样一个 AOT 程序就完成了。

2. SOS 可以调试 AOT 程序吗

这是很多朋友关心的话题,我们都知道 SOS 是用来撬开 CoreCLR 的,只要能看到 CoreCLR.dll,那 SOS 就能用,接下来用 WinDbg 附加到 ConsoleApp2.exe 上,使用 lm 观察。


0:000> lm
start             end                 module name
00007ff6`11680000 00007ff6`1196f000   ConsoleApp2 C (private pdb symbols)  C:\test\ConsoleApp2.pdb
00007ffe`692b0000 00007ffe`692c3000   kernel_appcore   (deferred)
00007ffe`6b3e0000 00007ffe`6b47d000   msvcp_win   (deferred)
00007ffe`6b480000 00007ffe`6b4ff000   bcryptPrimitives   (deferred)
00007ffe`6b660000 00007ffe`6b687000   bcrypt     (deferred)
00007ffe`6b690000 00007ffe`6b6b2000   win32u     (deferred)
00007ffe`6b720000 00007ffe`6b82a000   gdi32full   (deferred)
00007ffe`6b830000 00007ffe`6b930000   ucrtbase   (deferred)
00007ffe`6b9e0000 00007ffe`6bca7000   KERNELBASE   (deferred)
00007ffe`6bcb0000 00007ffe`6bd5a000   ADVAPI32   (deferred)
00007ffe`6be50000 00007ffe`6be7a000   GDI32      (deferred)
00007ffe`6be80000 00007ffe`6bf1b000   sechost    (deferred)
00007ffe`6c180000 00007ffe`6c2a3000   RPCRT4     (deferred)
00007ffe`6c440000 00007ffe`6c470000   IMM32      (deferred)
00007ffe`6c600000 00007ffe`6c729000   ole32      (deferred)
00007ffe`6c730000 00007ffe`6c7ce000   msvcrt     (deferred)
00007ffe`6cc50000 00007ffe`6cfa4000   combase    (deferred)
00007ffe`6d160000 00007ffe`6d300000   USER32     (deferred)
00007ffe`6d410000 00007ffe`6d4cd000   KERNEL32   (deferred)
00007ffe`6dc50000 00007ffe`6de44000   ntdll      (pdb symbols)          c:\mysymbols\ntdll.pdb\63E12347526A46144B98F8CF61CDED791\ntdll.pdb

从上面的输出中惊讶的发现,居然没有 clrjit.dllcoreclr.dll,前者没有很好理解,后者没有就很奇怪了。。。

既然没看到 coreclr.dll 这个动态链接库,那至少目前用 sos 肯定是无法调试的,即使你强制加载也会报错。


0:000> .load  C:\Users\Administrator\.dotnet\sos64\sos.dll
0:000> !t
Failed to find runtime module (coreclr.dll or clr.dll or libcoreclr.so), 0x80004002
Extension commands need it in order to have something to do.
For more information see https://go.microsoft.com/fwlink/?linkid=2135652

到这里我的个人结论是:目前SOS无法对这类程序进行调试,如果大家用在生产上出现各种内存暴涨CPU爆高问题,就要当心了。

3. AOT 真的没有 CoreCLR 吗

其实仔细想一想,这是不可能的,C# 的出发点就是作为一门托管语言而存在,再怎么发展也不会忘记这个初衷,所谓不忘初心,方得始终。

我们回过头看下 ConsoleApp.exe 这个程序,有没有发现,它居然有 3M 大小。

聪明的朋友应该猜到了,对,就是把 CoreCLR 打包到 exe 中了,这个太牛了,那怎么验证呢? 可以用 IDA 打开一下。

从图中可以清晰的看到各种 gc_heap 相关的函数,这也验证了为什么一个简简单单的 ConsoleApp.exe 有这么大Size的原因。

4. 真的无法调试 AOT 程序吗

在 Windows 平台上就没有 WinDbg 不能调试的程序,所以 AOT 程序自然不在话下,毕竟按托管不行,大不了按非托管调试,这里我们举一个 GC.Collect() 的源码调试吧。

  1. 一段简单的测试代码。
internal class Program{static void Main(string[] args){Debugger.Break();GC.Collect();}}
  1. 下断点

熟悉 GC 的朋友应该知道我只需用 bp coreclr!WKS::GCHeap::GarbageCollect 下一个断点就可以了,但刚才我也说了,内存中并没有 coreclr 模块,下面的 x 写法肯定会报错。


0:000> x coreclr!WKS::GCHeap::GarbageCollect^ Couldn't resolve 'x coreclr'

那怎么下呢? 先输个 k 观察下调用栈有没有什么新发现。


0:000> k# Child-SP          RetAddr               Call Site
00 00000011`5e52f628 00007ff6`7f288c5a     ConsoleApp2!RhDebugBreak+0x2 [D:\a\_work\1\s\src\coreclr\nativeaot\Runtime\MiscHelpers.cpp @ 45]
01 00000011`5e52f630 00007ff6`7f2f0e28     ConsoleApp2!S_P_CoreLib_System_Diagnostics_Debugger__Break+0x3a [/_/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/Debugger.cs @ 17]
02 00000011`5e52f6c0 00007ff6`7f1fe37e     ConsoleApp2!ConsoleApp2__Module___StartupCodeMain+0x118
03 00000011`5e52f720 00007ff6`7f1f9540     ConsoleApp2!wmain+0xae [D:\a\_work\1\s\src\coreclr\nativeaot\Bootstrap\main.cpp @ 205]
04 (Inline Function) --------`--------     ConsoleApp2!invoke_main+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90]
05 00000011`5e52f770 00007ffe`6d426fd4     ConsoleApp2!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
06 00000011`5e52f7b0 00007ffe`6dc9cec1     KERNEL32!BaseThreadInitThunk+0x14
07 00000011`5e52f7e0 00000000`00000000     ntdll!RtlUserThreadStart+0x21

我去,int 3 函数也换了,成了 ConsoleApp2!RhDebugBreak+0x2,不过也能看出来,应该将 coreclr 改成 ConsoleApp2 即可,输出如下:


0:000> bp ConsoleApp2!WKS::GCHeap::GarbageCollect
breakpoint 0 redefined
0:000> g
Breakpoint 0 hit
ConsoleApp2!WKS::GCHeap::GarbageCollect:
00007ff6`7f1a9410 48894c2408      mov     qword ptr [rsp+8],rcx ss:00000011`5e52f5f0=0000000000000000

源码也看的清清楚楚,路径也是在 gc 目录下。如下图所示:

4. AOT 的实现源码在哪里

观察刚才的线程栈中的 D:\a\_work\1\s\src\coreclr\nativeaot\Bootstrap\main.cpp 可以发现,新增了一个名为 nativeaot 的目录,这在 .NET 6 的 coreclr 源码中是没有的。

如果有感兴趣的朋友,可以研究下源码。

三:总结

总的来说,AOT 目前还是一个雏形阶段,大家慎用吧,一旦出了问题,可不好事后调试哦,希望后续加强对 SOS 的支持。

从 WinDbg 角度理解 .NET7 的AOT玩法相关推荐

  1. 从玩法、叙事、主题三个角度浅要谈谈《死亡搁浅》的好与坏

    <死亡搁浅>是一部优点和缺点都非常明显的作品,它的口碑也注定因为其在3A游戏中大逆不道的基础玩法设计而两极分化(当然<死亡搁浅>自己并不完全算传统意义上的3A游戏).但抛开&q ...

  2. 《惢客创业日记》2019.07.24(周三)从产品角度理解“为腹不为目”

    每天早晨,利用马桶时间学习一篇交互设计的知识,到今天为止,已经坚持20多天了,虽然进度很慢,但随着20多天的积累,这个月差不多能系统的看完了,也截屏了一些笔记,下个月就可以整理出来交互设计的流程和笔记 ...

  3. 读易[15]·用软件的角度理解易经

    俗话说,隔行如隔山.一般我们会对自己领域内的东西比较敏感,也更加容易接受.这里不仅包括专业的术语,更多的是一种思想. 我写易经相关的文章也有十几篇了,有些文章很受欢迎,有些文章看的人比较少.不过不管是 ...

  4. 【C 语言】数组 ( 多维数组本质 | 步长角度 理解 多维数组本质 )

    文章目录 一.从 步长角度 理解 多维数组本质 二.代码示例 一.从 步长角度 理解 多维数组本质 声明一个二维数组 ; // 声明一个多维数组int array[2][3]; 二级指针 : arra ...

  5. 谷歌Deep Bootstrap Framework:在线优化角度理解神经网络

    The Deep Bootstrap Framework: Good Online Learners are Good Offline Generalizers(ICLR21) 一元@炼丹笔记 理解深 ...

  6. 从另一个角度理解分布式系统与CAP定理

    从另一个角度理解分布式系统与CAP定理 参考:性能之殇(七)-- 分布式计算.超级计算机与神经网络共同的瓶颈 分布式计算的本质 分布式系统的产生,来源于源于人们日益增长的性能需求与落后的x86架构之间 ...

  7. 以吃货的角度理解 IaaS,PaaS,SaaS 是什么

    转载自 以吃货的角度理解 IaaS,PaaS,SaaS 是什么 随着云计算时代的到来,越来越多的软件,开始采用云服务.越来越多的概念也随之而来.云服务只是一个统称,可以分成三大类. IaaS:基础设施 ...

  8. linux线程handler,Handler从源码角度理解

    上一个文章讲解了Handler的基本使用,同时也有一些问题没有解决,本篇带你从源码的角度理解. 首先让我们来看看Handler的构造方法: image.png 我靠这么多的构造方法啊,我们上一篇只用了 ...

  9. python拼图游戏代码的理解_有意思的JS(1)拼图游戏 玩法介绍及其代码实现

    我是你们的索儿呀,很幸运我的文章能与你相见,愿萌新能直观的感受到Javascript的趣味性,愿有一定基础者有所收获,愿大佬不吝赐教 拼图游戏是一张图片分为若干块,打乱次序,将其中一块变为空白块,其只 ...

最新文章

  1. leetcode题解:Construct Binary Tree from Preorder and Inorder Traversal (根据前序和中序遍历构造二叉树)...
  2. 我们能从大学里学到什么
  3. 超可爱 纯CSS3实现的小猪、小老鼠、小牛
  4. 模态对话框和全选反选
  5. Exynos4412 中断驱动开发相关问题总结
  6. JS 字符串编码函数(解决URL特殊字符传递问题):escape()、encodeURI()、encodeURIComponent()区别详解...
  7. (JAVA)复制文件test.txt,并且排序。文件重新命名为test1.txt
  8. 文件字符串变量插入linux,Linux Shell脚本实现在文件指定的行插入字符串
  9. ubuntu networking 与 network-manager
  10. opa847方波放大电路_电子设计竞赛教程-放大器类
  11. 剑指 Offer 10- I. 斐波那契数列/剑指 Offer 10- II. 青蛙跳台阶问题
  12. eclipse一些实用小技巧
  13. matlab——knnsearch用法介绍
  14. QT软件开发: 基于QT设计的完整版视频播放器、多媒体播放器(mdk-sdk)
  15. Adobe Reader PDF阅读器闪退问题解决(批处理)
  16. 道一HTTP测试工具功能升级
  17. 利用STM32F103最小系统做C2接口离线烧录器
  18. 一维卷积的意义和二维卷积(图像处理)的简单理解
  19. 高分七号(GF-7)
  20. 在linux下解压rar文件

热门文章

  1. 云计算大会第三批议题:金融、医疗等六大行业
  2. 智慧农业发展,商业计划书撰写,商业模式,ppt亮点
  3. 网站建设常用的cms建站系统推荐
  4. Python 将英语单词列表,转换为听写使用的MP3格式(每个单词朗读两遍)
  5. 适合用于听写的新型语音识别技术 可将单词错误率低于5%
  6. bilibiliclass76-80_C语言_程序的编译(预处理操作)+链接
  7. Elasticsearch搭建
  8. PASCAL VOC
  9. 内核调试:一次多线程调试与KASAN检测实例
  10. Fresco的使用一