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

看这段代码上面的注释,这段代码里面并没有.CCtor被调用的痕迹 。而它的奥秘在JIT_GetSharedNonGCStaticBase_SingleAppDomain函数里面 。
JIT_GetSharedNonGCStaticBase_SingleAppDomain又调用了JIT_GetSharedNonGCStaticBase_Helper
看下堆栈
> coreclr.dll!MethodTable::RunClassInitEx 行 3591 C++coreclr.dll!MethodTable::DoRunClassInitThrowing 行 3792 C++coreclr.dll!MethodTable::CheckRunClassInitThrowing 行 3929 C++coreclr.dll!JIT_GetSharedNonGCStaticBase_Helper 行 1401 C++函数 RunClassInitEx代码如下:
BOOL MethodTable::RunClassInitEx(OBJECTREF *pThrowable){//为了方便观看 此处省略部分代码PCODE pCctorCode = pCanonMT->GetSlot(pCanonMT->GetClassConstructorSlot());//为了方便观看 此处省略部分代码PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCctorCode);DECLARE_ARGHOLDER_ARRAY(args, 0);CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;CALL_MANAGED_METHOD_NORET(args);//为了方便观看 此处省略部分代码变量pCctorCode就是.CCtor的函数头地址 。而后面的一堆的宏定义实际上是调用了函数 DispatchCallSimple,而DispatchCallSimple又调用了CallDescrWorkerWithHandler然后又调用了PrecodeFixupThunk下面调用了PreStubWorker
PreStubWorker通过 call rax命令跳转到调用的函数的函数头地址 , 比如本例的 .CCtor函数头的地址 。
00007FFE8BB289C0 E8 DB FE 8F FFcallPreStubWorker (07FFE8B4288A0h)00007FFE8BB289C5 66 0F 6F 44 24 20movdqaxmm0,xmmword ptr [rsp+20h]00007FFE8BB289CB 66 0F 6F 4C 24 30movdqaxmm1,xmmword ptr [rsp+30h]00007FFE8BB289D1 66 0F 6F 54 24 40movdqaxmm2,xmmword ptr [rsp+40h]00007FFE8BB289D7 66 0F 6F 5C 24 50movdqaxmm3,xmmword ptr [rsp+50h]00007FFE8BB289DD 48 8B 8C 24 B0 00 00 00 movrcx,qword ptr [rsp+0B0h]00007FFE8BB289E5 48 8B 94 24 B8 00 00 00 movrdx,qword ptr [rsp+0B8h]00007FFE8BB289ED 4C 8B 84 24 C0 00 00 00 movr8,qword ptr [rsp+0C0h]00007FFE8BB289F5 4C 8B 8C 24 C8 00 00 00 movr9,qword ptr [rsp+0C8h]00007FFE8BB289FD 48 83 C4 68addrsp,68h00007FFE8BB28A01 5Fpoprdi00007FFE8BB28A02 5Epoprsi00007FFE8BB28A03 5Bpoprbx00007FFE8BB28A04 5Dpoprbp00007FFE8BB28A05 41 5Cpopr1200007FFE8BB28A07 41 5Dpopr1300007FFE8BB28A09 41 5Epopr1400007FFE8BB28A0B 41 5Fpopr15// 这个rax 就是 .CCtor的函数头的地址00007FFE8BB28A0D 48 FF E0jmpraxjmprax跳转到了如下:00007FFE2CFE8888 FF 25 FA 0F 00 00jmpqword ptr [7FFE2CFE9888h]
7FFE2CFE9888h地址的值是00007FFE8A50C7A0
注意这句代码
static string a ="abcd";它实际上被编译成了一个函数,当运行到.CCtor的时候,会调用它,然后对它进行赋值 abcd
>>> 00007ffe`06ac29e0 55pushrbp00007ffe`06ac29e1 4883ec20subrsp,20h00007ffe`06ac29e5 488d6c2420learbp,[rsp+20h]00007ffe`06ac29ea 833d9f410c0000cmpdword ptr [00007ffe`06b86b90],000007ffe`06ac29f1 7405jeConsoleApp3!ConsoleApp3.Program..cctor+0x18 (00007ffe`06ac29f8)00007ffe`06ac29f3 e8e8a4cd5fcallcoreclr!JIT_DbgIsJustMyCode (00007ffe`6679cee0)00007ffe`06ac29f8 48bad83000186c020000 mov rdx,26C180030D8h00007ffe`06ac2a02 488b12movrdx,qword ptr [rdx]00007ffe`06ac2a05 48b9902e00186c020000 mov rcx,26C18002E90h00007ffe`06ac2a0f e8fc85bb5fcallcoreclr!JIT_CheckedWriteBarrier (00007ffe`6667b010)00007ffe`06ac2a14 90nop00007ffe`06ac2a15 4883c420addrsp,20h00007ffe`06ac2a19 5dpoprbp00007ffe`06ac2a1a c3retJIT_CheckedWriteBarrier的原型如下:
extern "C" HCIMPL2_RAW(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref)很明显 , 他这就是把ref指向的object完整的传递给dst 。也就是赋值给静态字符串a 。寄存器rcx表示dstrdx表示ref 。此处可以通过 !dumpobj rdx来查被看对象 。
那么总结下,.CCtor的作用就是把静态的全局变量对象进行一个初始化 , 这个结果也说明,静态全局变量不是在CLR初始化的时候初始化,而是在当前类的.CCtor里面初始化的 。
作者:江湖评谈原文:https://www.cnblogs.com/tangyanzhi1111/p/16868020.html版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可 。

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

文章插图
【.Net 7里的函数.Ctor和.CCtor是干啥用的呢?你知道吗】

推荐阅读