.Net 7里的函数.Ctor和.CCtor是干啥用的呢?你知道吗

楔子有小伙伴被面试官问到这个问题 , 本篇彻底解析下这个问题 。
为了彻底点,注意本篇是最底层的.Net 7 RC CLR运行模型(汇编)为基础进行全局剖析 , 局部业务分析 。
如有疏漏,请斧正 。
目的非手段这两个函数比较特殊的存在,.Ctor是非静态默认实例化 。.CCtor是静态默认实例化 。这两个函数伴随着.Net 任何对象的实例化都自动存在于这个对象当中 。
跟踪.CCtor可以在全局静态对象下断点,观察它的里面运行 。跟踪.Ctor可以通过!name2ee 模块 模块.类名..Ctor找到JITTED Code Address , 观察它的运行 。正如本段题所说 , 这只是手段 , 不是目的 。所以下面看目的 。
.Ctor目的先来看下非静态默认构造函数.Ctor 。上一段代码:
internal class Program{public class ABC{}static void Main(string[] args){ABC abc = new ABC();Console.ReadLine();}}直接给它反编译:
00007FFDF2FA03B0 55pushrbp00007FFDF2FA03B1 48 83 EC 40subrsp,40h00007FFDF2FA03B5 48 8D 6C 24 40learbp,[rsp+40h]00007FFDF2FA03BA C5 D8 57 E4vxorpsxmm4,xmm4,xmm400007FFDF2FA03BE C5 FA 7F 65 E8vmovdquxmmword ptr [rbp-18h],xmm400007FFDF2FA03C3 33 C0xoreax,eax00007FFDF2FA03C5 48 89 45 F8movqword ptr [rbp-8],rax00007FFDF2FA03C9 48 89 4D 10movqword ptr [rbp+10h],rcx00007FFDF2FA03CD 83 3D BC E9 19 00 00 cmpdword ptr [7FFDF313ED90h],000007FFDF2FA03D4 74 05je00007FFDF2FA03DB00007FFDF2FA03D6 E8 B5 BF 79 5EcallJIT_DbgIsJustMyCode (07FFE5173C390h)00007FFDF2FA03DB 90nop00007FFDF2FA03DC 48 B9 30 F6 5B F3 FD 7F 00 00 movrcx,7FFDF35BF630h00007FFDF2FA03E6 E8 75 7C C1 5EcallJIT_TrialAllocSFastMP_InlineGetThread (07FFE51BB8060h)00007FFDF2FA03EB 48 89 45 F0movqword ptr [rbp-10h],rax00007FFDF2FA03EF 48 8B 4D F0movrcx,qword ptr [rbp-10h]// 这个地方是调用了.Ctor00007FFDF2FA03F3 FF 15 0F 8D 60 00callqword ptr [7FFDF35A9108h]00007FFDF2FA03F9 48 8B 45 F0movrax,qword ptr [rbp-10h]00007FFDF2FA03FD 48 89 45 F8movqword ptr [rbp-8],rax00007FFDF2FA0401 FF 15 A9 93 60 00callqword ptr [7FFDF35A97B0h]00007FFDF2FA0407 48 89 45 E8movqword ptr [rbp-18h],rax00007FFDF2FA040B 90nop00007FFDF2FA040C 90nop00007FFDF2FA040D 48 83 C4 40addrsp,40h00007FFDF2FA0411 5Dpoprbp00007FFDF2FA0412 C3ret调用.Ctor的地方注释了下,如果直接进入会调用到PrecodeFixupThunk 。所以这里需要在PreStubWorker下断点 。一路跟踪下去发现这个.Ctor是利用预备的IL代码,让RyuJIt对它进行一个编译
.Ctor调用堆栈:
coreclr.dll!MethodDesc::JitCompileCodeLocked 行 952 C++coreclr.dll!MethodDesc::JitCompileCodeLockedEventWrapper 行 823 C++coreclr.dll!MethodDesc::JitCompileCode 行 763 C++coreclr.dll!MethodDesc::PrepareILBasedCode 行 426 C++coreclr.dll!MethodDesc::PrepareCode 行 323 C++coreclr.dll!CodeVersionManager::PublishVersionableCodeIfNecessary 行 1698 C++coreclr.dll!MethodDesc::DoPrestub 行 2109 C++coreclr.dll!PreStubWorker 行 1938coreclr.dll!ThePreStub(JitCompileCodeLocked里面调用了UnsafeJitFunction为止,因为后面都是RyuJit的复杂编译过程,此处不述 。
我们来看下UnsafeJitFunction返回的pCode地址处的汇编代码:
00007FFDF2F80430 55pushrbp00007FFDF2F80431 57pushrdi00007FFDF2F80432 48 83 EC 28subrsp,28h00007FFDF2F80436 48 8D 6C 24 30learbp,[rsp+30h]00007FFDF2F8043B 48 89 4D 10movqword ptr [rbp+10h],rcx00007FFDF2F8043F 83 3D 4A E9 19 00 00 cmpdword ptr [7FFDF311ED90h],000007FFDF2F80446 74 05je00007FFDF2F8044D00007FFDF2F80448 E8 43 BF 7B 5EcallJIT_DbgIsJustMyCode (07FFE5173C390h)00007FFDF2F8044D 48 8B 4D 10movrcx,qword ptr [rbp+10h]00007FFDF2F80451 FF 15 D9 0B E5 FFcallqword ptr [7FFDF2DD1030h]00007FFDF2F80457 90nop00007FFDF2F80458 90nop00007FFDF2F80459 48 83 C4 28addrsp,28h00007FFDF2F8045D 5Fpoprdi00007FFDF2F8045E 5Dpoprbp00007FFDF2F8045F C3ret它里面就调用了一个Call,也就是这句话:
callqword ptr [7FFDF2DD1030h]这个十六进制的7FFDF2DD1030h是个啥呢?继续跟进下:0x00007FFDF2DD103000007ffe50357230它里面包含了一个地址00007ffe50357230看下这个地址的汇编代码:
00007FFE50357230 C3ret它直接返回了 。
所以这得出了一个什么结论呢?也就是说在当前这个例子中,.Ctor啥都没做 。
.CCtor目的来看下静态的默认构造函数干了些啥 。先上代码:
internal class Program{static string a ="abcd";static void Main(string[] args){string i = a;Console.WriteLine(a);Console.ReadLine();}}同样反编译下:
00007FFDF01903B0 55pushrbp00007FFDF01903B1 57pushrdi00007FFDF01903B2 48 83 EC 28subrsp,28h00007FFDF01903B6 48 8D 6C 24 30learbp,[rsp+30h]00007FFDF01903BB 33 C0xoreax,eax00007FFDF01903BD 48 89 45 F0movqword ptr [rbp-10h],rax00007FFDF01903C1 48 89 4D 10movqword ptr [rbp+10h],rcx00007FFDF01903C5 83 3D C4 E9 19 00 00 cmpdword ptr [7FFDF032ED90h],000007FFDF01903CC 74 05je00007FFDF01903D300007FFDF01903CE E8 BD BF 7D 5EcallJIT_DbgIsJustMyCode (07FFE4E96C390h)00007FFDF01903D3 90nop00007FFDF01903D4 48 B9 60 EF 32 F0 FD 7F 00 00 movrcx,7FFDF032EF60h00007FFDF01903DE BA 04 00 00 00movedx,4// 可以看到这个 string 静态对象并没有调用.CCtor 。// 那是否说明上面的说法不对呢?注意看,他实际调用了// JIT_GetSharedNonGCStaticBase_SingleAppDomain,// 而这个就是关键所在00007FFDF01903E3 E8 48 7E C5 5EcallJIT_GetSharedNonGCStaticBase_SingleAppDomain (07FFE4EDE8230h)00007FFDF01903E8 8B 0D AA EB 19 00movecx,dword ptr [7FFDF032EF98h]00007FFDF01903EE FF 15 7C 94 60 00callqword ptr [7FFDF0799870h]00007FFDF01903F4 90nop00007FFDF01903F5 FF 15 9D 93 60 00callqword ptr [7FFDF0799798h]00007FFDF01903FB 48 89 45 F0movqword ptr [rbp-10h],rax00007FFDF01903FF 90nop00007FFDF0190400 90nop00007FFDF0190401 48 83 C4 28addrsp,28h00007FFDF0190405 5Fpoprdi00007FFDF0190406 5Dpoprbp00007FFDF0190407 C3ret00007FFDF0190408 19 06sbbdword ptr [rsi],eax

推荐阅读