看这段代码上面的注释,这段代码里面并没有.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 E0jmprax
jmprax
跳转到了如下: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 c3ret
JIT_CheckedWriteBarrier
的原型如下:
extern "C" HCIMPL2_RAW(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref)
很明显 , 他这就是把ref
指向的object
完整的传递给dst
。也就是赋值给静态字符串a
。寄存器rcx
表示dst
,rdx
表示ref
。此处可以通过 !dumpobj rdx
来查被看对象 。
那么总结下,.CCtor
的作用就是把静态的全局变量对象进行一个初始化 , 这个结果也说明,静态全局变量不是在CLR
初始化的时候初始化,而是在当前类的.CCtor
里面初始化的 。
作者:江湖评谈原文:https://www.cnblogs.com/tangyanzhi1111/p/16868020.html版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可 。
文章插图
【.Net 7里的函数.Ctor和.CCtor是干啥用的呢?你知道吗】
推荐阅读
- PGL Paddle Graph Learning 关于图计算&图学习的基础知识概览:前置知识点学习
- 部落冲突哥布林之王的贡品雕像获取方法
- 45岁适合眼霜排行榜,45岁最好用的眼霜推荐
- BODYCOMBAT认证之路
- 如何破解压缩包的密码从网盘里面下载了一个压缩包,解压的时候需要输入密码,不知道密码是什么,该怎么
- 怎么破解解压包的密码(解压密码一般是多少)
- 打字真的可以赚钱吗(键盘打字挣钱)
- 网上打字赚钱是真的吗(在线文字录入赚钱)
- 有一个打字赚钱的app叫什么(手机上练习打字的app)
- 为什么还有人相信网络上的“打字赚钱”骗局