
离线 TA的专栏
- 打卡等级:热心大叔
- 打卡总天数:223
- 打卡月天数:0
- 打卡总奖励:3194
- 最近打卡:2025-04-13 11:58:00
|
楔子
有小伙伴被面试官问到这个问题,本篇彻底解析下这个问题。
为了彻底点,注意本篇是最底层的 运行模型(汇编)为基础进行全局剖析,局部业务分析。
如有疏漏,请斧正。
目的非手段
这两个函数比较特殊的存在, 是非静态默认实例化。 是静态默认实例化。这两个函数伴随着 任何对象的实例化都自动存在于这个对象当中。
跟踪 可以在全局静态对象下断点,观察它的里面运行。跟踪 可以通过 模块 模块.类名 找到 ,观察它的运行。正如本段题所说,这只是手段,不是目的。所以下面看目的。
.Ctor目的
先来看下非静态默认构造函数 。上一段代码:
- internal class Program
- {
- public class ABC
- {
- }
- static void Main(string[] args)
- {
- ABC abc = new ABC();
- Console.ReadLine();
- }
- }
复制代码
直接给它反编译:
- 00007FFDF2FA03B0 55 push rbp
- 00007FFDF2FA03B1 48 83 EC 40 sub rsp,40h
- 00007FFDF2FA03B5 48 8D 6C 24 40 lea rbp,[rsp+40h]
- 00007FFDF2FA03BA C5 D8 57 E4 vxorps xmm4,xmm4,xmm4
- 00007FFDF2FA03BE C5 FA 7F 65 E8 vmovdqu xmmword ptr [rbp-18h],xmm4
- 00007FFDF2FA03C3 33 C0 xor eax,eax
- 00007FFDF2FA03C5 48 89 45 F8 mov qword ptr [rbp-8],rax
- 00007FFDF2FA03C9 48 89 4D 10 mov qword ptr [rbp+10h],rcx
- 00007FFDF2FA03CD 83 3D BC E9 19 00 00 cmp dword ptr [7FFDF313ED90h],0
- 00007FFDF2FA03D4 74 05 je 00007FFDF2FA03DB
- 00007FFDF2FA03D6 E8 B5 BF 79 5E call JIT_DbgIsJustMyCode (07FFE5173C390h)
- 00007FFDF2FA03DB 90 nop
- 00007FFDF2FA03DC 48 B9 30 F6 5B F3 FD 7F 00 00 mov rcx,7FFDF35BF630h
- 00007FFDF2FA03E6 E8 75 7C C1 5E call JIT_TrialAllocSFastMP_InlineGetThread (07FFE51BB8060h)
- 00007FFDF2FA03EB 48 89 45 F0 mov qword ptr [rbp-10h],rax
- 00007FFDF2FA03EF 48 8B 4D F0 mov rcx,qword ptr [rbp-10h]
- // 这个地方是调用了.Ctor
- 00007FFDF2FA03F3 FF 15 0F 8D 60 00 call qword ptr [7FFDF35A9108h]
- 00007FFDF2FA03F9 48 8B 45 F0 mov rax,qword ptr [rbp-10h]
- 00007FFDF2FA03FD 48 89 45 F8 mov qword ptr [rbp-8],rax
- 00007FFDF2FA0401 FF 15 A9 93 60 00 call qword ptr [7FFDF35A97B0h]
- 00007FFDF2FA0407 48 89 45 E8 mov qword ptr [rbp-18h],rax
- 00007FFDF2FA040B 90 nop
- 00007FFDF2FA040C 90 nop
- 00007FFDF2FA040D 48 83 C4 40 add rsp,40h
- 00007FFDF2FA0411 5D pop rbp
- 00007FFDF2FA0412 C3 ret
复制代码
调用 的地方注释了下,如果直接进入会调用到 。所以这里需要在 下断点。一路跟踪下去发现这个 是利用预备的IL代码,让 对它进行一个编译
调用堆栈:
- 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 行 1938
- coreclr.dll!ThePreStub(
复制代码
到 里面调用了 为止,因为后面都是 复杂编译过程,此处不述。
我们来看下 返回的 地址处的汇编代码:
- 00007FFDF2F80430 55 push rbp
- 00007FFDF2F80431 57 push rdi
- 00007FFDF2F80432 48 83 EC 28 sub rsp,28h
- 00007FFDF2F80436 48 8D 6C 24 30 lea rbp,[rsp+30h]
- 00007FFDF2F8043B 48 89 4D 10 mov qword ptr [rbp+10h],rcx
- 00007FFDF2F8043F 83 3D 4A E9 19 00 00 cmp dword ptr [7FFDF311ED90h],0
- 00007FFDF2F80446 74 05 je 00007FFDF2F8044D
- 00007FFDF2F80448 E8 43 BF 7B 5E call JIT_DbgIsJustMyCode (07FFE5173C390h)
- 00007FFDF2F8044D 48 8B 4D 10 mov rcx,qword ptr [rbp+10h]
- 00007FFDF2F80451 FF 15 D9 0B E5 FF call qword ptr [7FFDF2DD1030h]
- 00007FFDF2F80457 90 nop
- 00007FFDF2F80458 90 nop
- 00007FFDF2F80459 48 83 C4 28 add rsp,28h
- 00007FFDF2F8045D 5F pop rdi
- 00007FFDF2F8045E 5D pop rbp
- 00007FFDF2F8045F C3 ret
复制代码
它里面就调用了一个 ,也就是这句话:
- call qword ptr [7FFDF2DD1030h]
复制代码
这个十六进制的 是个啥呢?继续跟进下: - 0x00007FFDF2DD1030 00007ffe50357230
复制代码它里面包含了一个地址 看下这个地址的汇编代码:
它直接返回了。
所以这得出了一个什么结论呢?也就是说在当前这个例子中,.Ctor啥都没做。
.CCtor目的
来看下静态的默认构造函数干了些啥。先上代码:
- internal class Program
- {
- static string a ="abcd"; static void Main(string[] args)
- {
- string i = a;
- Console.WriteLine(a);
- Console.ReadLine();
- }
- }
复制代码
同样反编译下:
- 00007FFDF01903B0 55 push rbp
- 00007FFDF01903B1 57 push rdi
- 00007FFDF01903B2 48 83 EC 28 sub rsp,28h
- 00007FFDF01903B6 48 8D 6C 24 30 lea rbp,[rsp+30h]
- 00007FFDF01903BB 33 C0 xor eax,eax
- 00007FFDF01903BD 48 89 45 F0 mov qword ptr [rbp-10h],rax
- 00007FFDF01903C1 48 89 4D 10 mov qword ptr [rbp+10h],rcx
- 00007FFDF01903C5 83 3D C4 E9 19 00 00 cmp dword ptr [7FFDF032ED90h],0
- 00007FFDF01903CC 74 05 je 00007FFDF01903D3
- 00007FFDF01903CE E8 BD BF 7D 5E call JIT_DbgIsJustMyCode (07FFE4E96C390h)
- 00007FFDF01903D3 90 nop
- 00007FFDF01903D4 48 B9 60 EF 32 F0 FD 7F 00 00 mov rcx,7FFDF032EF60h
- 00007FFDF01903DE BA 04 00 00 00 mov edx,4
- // 可以看到这个 string 静态对象并没有调用.CCtor。
- // 那是否说明上面的说法不对呢?注意看,他实际调用了
- // JIT_GetSharedNonGCStaticBase_SingleAppDomain,
- // 而这个就是关键所在
- 00007FFDF01903E3 E8 48 7E C5 5E call JIT_GetSharedNonGCStaticBase_SingleAppDomain (07FFE4EDE8230h)
- 00007FFDF01903E8 8B 0D AA EB 19 00 mov ecx,dword ptr [7FFDF032EF98h]
- 00007FFDF01903EE FF 15 7C 94 60 00 call qword ptr [7FFDF0799870h]
- 00007FFDF01903F4 90 nop
- 00007FFDF01903F5 FF 15 9D 93 60 00 call qword ptr [7FFDF0799798h]
- 00007FFDF01903FB 48 89 45 F0 mov qword ptr [rbp-10h],rax
- 00007FFDF01903FF 90 nop
- 00007FFDF0190400 90 nop
- 00007FFDF0190401 48 83 C4 28 add rsp,28h
- 00007FFDF0190405 5F pop rdi
- 00007FFDF0190406 5D pop rbp
- 00007FFDF0190407 C3 ret
- 00007FFDF0190408 19 06 sbb dword ptr [rsi],eax
复制代码
看这段代码上面的注释,这段代码里面并没有 被调用的痕迹。而它的奥秘在 - 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++
复制代码
函数 代码如下:
- 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);
- //为了方便观看 此处省略部分代码
复制代码
变量 就是 的函数头地址。而后面的一堆的宏定义实际上是调用了函数 ,而 又调用了 - CallDescrWorkerWithHandler
复制代码然后又调用了 下面调用了
通过 命令跳转到调用的函数的函数头地址,比如本例的 函数头的地址。
- 00007FFE8BB289C0 E8 DB FE 8F FF call PreStubWorker (07FFE8B4288A0h)
- 00007FFE8BB289C5 66 0F 6F 44 24 20 movdqa xmm0,xmmword ptr [rsp+20h]
- 00007FFE8BB289CB 66 0F 6F 4C 24 30 movdqa xmm1,xmmword ptr [rsp+30h]
- 00007FFE8BB289D1 66 0F 6F 54 24 40 movdqa xmm2,xmmword ptr [rsp+40h]
- 00007FFE8BB289D7 66 0F 6F 5C 24 50 movdqa xmm3,xmmword ptr [rsp+50h]
- 00007FFE8BB289DD 48 8B 8C 24 B0 00 00 00 mov rcx,qword ptr [rsp+0B0h]
- 00007FFE8BB289E5 48 8B 94 24 B8 00 00 00 mov rdx,qword ptr [rsp+0B8h]
- 00007FFE8BB289ED 4C 8B 84 24 C0 00 00 00 mov r8,qword ptr [rsp+0C0h]
- 00007FFE8BB289F5 4C 8B 8C 24 C8 00 00 00 mov r9,qword ptr [rsp+0C8h]
- 00007FFE8BB289FD 48 83 C4 68 add rsp,68h
- 00007FFE8BB28A01 5F pop rdi
- 00007FFE8BB28A02 5E pop rsi
- 00007FFE8BB28A03 5B pop rbx
- 00007FFE8BB28A04 5D pop rbp
- 00007FFE8BB28A05 41 5C pop r12
- 00007FFE8BB28A07 41 5D pop r13
- 00007FFE8BB28A09 41 5E pop r14
- 00007FFE8BB28A0B 41 5F pop r15
- // 这个rax 就是 .CCtor的函数头的地址
- 00007FFE8BB28A0D 48 FF E0 jmp rax
复制代码
跳转到了如下:
- 00007FFE2CFE8888 FF 25 FA 0F 00 00 jmp qword ptr [7FFE2CFE9888h]
复制代码
地址的值是
注意这句代码
它实际上被编译成了一个函数,当运行到 的时候,会调用它,然后对它进行赋值
- >>> 00007ffe`06ac29e0 55 push rbp
- 00007ffe`06ac29e1 4883ec20 sub rsp,20h
- 00007ffe`06ac29e5 488d6c2420 lea rbp,[rsp+20h]
- 00007ffe`06ac29ea 833d9f410c0000 cmp dword ptr [00007ffe`06b86b90],0
- 00007ffe`06ac29f1 7405 je ConsoleApp3!ConsoleApp3.Program..cctor+0x18 (00007ffe`06ac29f8)
- 00007ffe`06ac29f3 e8e8a4cd5f call coreclr!JIT_DbgIsJustMyCode (00007ffe`6679cee0)
- 00007ffe`06ac29f8 48bad83000186c020000 mov rdx,26C180030D8h
- 00007ffe`06ac2a02 488b12 mov rdx,qword ptr [rdx]
- 00007ffe`06ac2a05 48b9902e00186c020000 mov rcx,26C18002E90h
- 00007ffe`06ac2a0f e8fc85bb5f call coreclr!JIT_CheckedWriteBarrier (00007ffe`6667b010)
- 00007ffe`06ac2a14 90 nop
- 00007ffe`06ac2a15 4883c420 add rsp,20h
- 00007ffe`06ac2a19 5d pop rbp
- 00007ffe`06ac2a1a c3 ret
复制代码
的原型如下:
- extern "C" HCIMPL2_RAW(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref)
复制代码
很明显,他这就是把 指向的 完整的传递给 。也就是赋值给静态字符串 。寄存器 表示 , 表示 。此处可以通过 来查被看对象。
那么总结下, 的作用就是把静态的全局变量对象进行一个初始化,这个结果也说明,静态全局变量不是在 初始化的时候初始化,而是在当前类的 里面初始化的。
以上就是.Net 7函数Ctor与CCtor使用及区别详解的详细内容,更多关于.Net 7函数Ctor CCtor的资料请关注晓枫资讯其它相关文章! 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:  进行删除处理。
4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
|