设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间15 现在时间15 缓存数据 一个人挺好的

一个人挺好的 -- 一个

查看: 1071|回复: 5

.Net 7函数Ctor与CCtor使用及区别详解

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:223
  • 打卡月天数:0
  • 打卡总奖励:3194
  • 最近打卡:2025-04-13 11:58:00
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
426
主题
392
精华
0
金钱
4484
积分
865
注册时间
2023-1-7
最后登录
2025-4-13

发表于 2023-2-26 20:37:43 | 显示全部楼层 |阅读模式

楔子

有小伙伴被面试官问到这个问题,本篇彻底解析下这个问题。

为了彻底点,注意本篇是最底层的

  1. .Net 7 RC CLR
复制代码
运行模型(汇编)为基础进行全局剖析,局部业务分析。

如有疏漏,请斧正。

目的非手段

这两个函数比较特殊的存在,

  1. .Ctor
复制代码
是非静态默认实例化。
  1. .CCtor
复制代码
是静态默认实例化。这两个函数伴随着
  1. .Net
复制代码
任何对象的实例化都自动存在于这个对象当中。

跟踪

  1. .CCtor
复制代码
可以在全局静态对象下断点,观察它的里面运行。跟踪
  1. .Ctor
复制代码
可以通过
  1. !name2ee
复制代码
模块 模块.类名
  1. ..Ctor
复制代码
找到
  1. JITTED Code Address
复制代码
,观察它的运行。正如本段题所说,这只是手段,不是目的。所以下面看目的。

.Ctor目的

先来看下非静态默认构造函数

  1. .Ctor
复制代码
。上一段代码:

  1. internal class Program
  2. {
  3. public class ABC
  4. {
  5. }
  6. static void Main(string[] args)
  7. {
  8. ABC abc = new ABC();
  9. Console.ReadLine();
  10. }
  11. }
复制代码

直接给它反编译:

  1. 00007FFDF2FA03B0 55 push rbp
  2. 00007FFDF2FA03B1 48 83 EC 40 sub rsp,40h
  3. 00007FFDF2FA03B5 48 8D 6C 24 40 lea rbp,[rsp+40h]
  4. 00007FFDF2FA03BA C5 D8 57 E4 vxorps xmm4,xmm4,xmm4
  5. 00007FFDF2FA03BE C5 FA 7F 65 E8 vmovdqu xmmword ptr [rbp-18h],xmm4
  6. 00007FFDF2FA03C3 33 C0 xor eax,eax
  7. 00007FFDF2FA03C5 48 89 45 F8 mov qword ptr [rbp-8],rax
  8. 00007FFDF2FA03C9 48 89 4D 10 mov qword ptr [rbp+10h],rcx
  9. 00007FFDF2FA03CD 83 3D BC E9 19 00 00 cmp dword ptr [7FFDF313ED90h],0
  10. 00007FFDF2FA03D4 74 05 je 00007FFDF2FA03DB
  11. 00007FFDF2FA03D6 E8 B5 BF 79 5E call JIT_DbgIsJustMyCode (07FFE5173C390h)
  12. 00007FFDF2FA03DB 90 nop
  13. 00007FFDF2FA03DC 48 B9 30 F6 5B F3 FD 7F 00 00 mov rcx,7FFDF35BF630h
  14. 00007FFDF2FA03E6 E8 75 7C C1 5E call JIT_TrialAllocSFastMP_InlineGetThread (07FFE51BB8060h)
  15. 00007FFDF2FA03EB 48 89 45 F0 mov qword ptr [rbp-10h],rax
  16. 00007FFDF2FA03EF 48 8B 4D F0 mov rcx,qword ptr [rbp-10h]
  17. // 这个地方是调用了.Ctor
  18. 00007FFDF2FA03F3 FF 15 0F 8D 60 00 call qword ptr [7FFDF35A9108h]
  19. 00007FFDF2FA03F9 48 8B 45 F0 mov rax,qword ptr [rbp-10h]
  20. 00007FFDF2FA03FD 48 89 45 F8 mov qword ptr [rbp-8],rax
  21. 00007FFDF2FA0401 FF 15 A9 93 60 00 call qword ptr [7FFDF35A97B0h]
  22. 00007FFDF2FA0407 48 89 45 E8 mov qword ptr [rbp-18h],rax
  23. 00007FFDF2FA040B 90 nop
  24. 00007FFDF2FA040C 90 nop
  25. 00007FFDF2FA040D 48 83 C4 40 add rsp,40h
  26. 00007FFDF2FA0411 5D pop rbp
  27. 00007FFDF2FA0412 C3 ret
复制代码

调用

  1. .Ctor
复制代码
的地方注释了下,如果直接进入会调用到
  1. PrecodeFixupThunk
复制代码
。所以这里需要在
  1. PreStubWorker
复制代码
下断点。一路跟踪下去发现这个
  1. .Ctor
复制代码
是利用预备的IL代码,让
  1. RyuJIt
复制代码
对它进行一个编译

  1. .Ctor
复制代码
调用堆栈:

  1. coreclr.dll!MethodDesc::JitCompileCodeLocked 行 952 C++
  2. coreclr.dll!MethodDesc::JitCompileCodeLockedEventWrapper 行 823 C++
  3. coreclr.dll!MethodDesc::JitCompileCode 行 763 C++
  4. coreclr.dll!MethodDesc::PrepareILBasedCode 行 426 C++
  5. coreclr.dll!MethodDesc::PrepareCode 行 323 C++
  6. coreclr.dll!CodeVersionManager::PublishVersionableCodeIfNecessary 行 1698 C++
  7. coreclr.dll!MethodDesc::DoPrestub 行 2109 C++
  8. coreclr.dll!PreStubWorker 行 1938
  9. coreclr.dll!ThePreStub(
复制代码

  1. JitCompileCodeLocked
复制代码
里面调用了
  1. UnsafeJitFunction
复制代码
为止,因为后面都是
  1. RyuJit的
复制代码
复杂编译过程,此处不述。

我们来看下

  1. UnsafeJitFunction
复制代码
返回的
  1. pCode
复制代码
地址处的汇编代码:

  1. 00007FFDF2F80430 55 push rbp
  2. 00007FFDF2F80431 57 push rdi
  3. 00007FFDF2F80432 48 83 EC 28 sub rsp,28h
  4. 00007FFDF2F80436 48 8D 6C 24 30 lea rbp,[rsp+30h]
  5. 00007FFDF2F8043B 48 89 4D 10 mov qword ptr [rbp+10h],rcx
  6. 00007FFDF2F8043F 83 3D 4A E9 19 00 00 cmp dword ptr [7FFDF311ED90h],0
  7. 00007FFDF2F80446 74 05 je 00007FFDF2F8044D
  8. 00007FFDF2F80448 E8 43 BF 7B 5E call JIT_DbgIsJustMyCode (07FFE5173C390h)
  9. 00007FFDF2F8044D 48 8B 4D 10 mov rcx,qword ptr [rbp+10h]
  10. 00007FFDF2F80451 FF 15 D9 0B E5 FF call qword ptr [7FFDF2DD1030h]
  11. 00007FFDF2F80457 90 nop
  12. 00007FFDF2F80458 90 nop
  13. 00007FFDF2F80459 48 83 C4 28 add rsp,28h
  14. 00007FFDF2F8045D 5F pop rdi
  15. 00007FFDF2F8045E 5D pop rbp
  16. 00007FFDF2F8045F C3 ret
复制代码

它里面就调用了一个

  1. Call
复制代码
,也就是这句话:

  1. call qword ptr [7FFDF2DD1030h]
复制代码

这个十六进制的

  1. 7FFDF2DD1030h
复制代码
是个啥呢?继续跟进下:
  1. 0x00007FFDF2DD1030 00007ffe50357230
复制代码
它里面包含了一个地址
  1. 00007ffe50357230
复制代码
看下这个地址的汇编代码:

  1. 00007FFE50357230 C3 ret
复制代码

它直接返回了。

所以这得出了一个什么结论呢?也就是说在当前这个例子中,.Ctor啥都没做。

.CCtor目的

来看下静态的默认构造函数干了些啥。先上代码:

  1. internal class Program
  2. {
  3. static string a ="abcd"; static void Main(string[] args)
  4. {
  5. string i = a;
  6. Console.WriteLine(a);
  7. Console.ReadLine();
  8. }
  9. }
复制代码

同样反编译下:

  1. 00007FFDF01903B0 55 push rbp
  2. 00007FFDF01903B1 57 push rdi
  3. 00007FFDF01903B2 48 83 EC 28 sub rsp,28h
  4. 00007FFDF01903B6 48 8D 6C 24 30 lea rbp,[rsp+30h]
  5. 00007FFDF01903BB 33 C0 xor eax,eax
  6. 00007FFDF01903BD 48 89 45 F0 mov qword ptr [rbp-10h],rax
  7. 00007FFDF01903C1 48 89 4D 10 mov qword ptr [rbp+10h],rcx
  8. 00007FFDF01903C5 83 3D C4 E9 19 00 00 cmp dword ptr [7FFDF032ED90h],0
  9. 00007FFDF01903CC 74 05 je 00007FFDF01903D3
  10. 00007FFDF01903CE E8 BD BF 7D 5E call JIT_DbgIsJustMyCode (07FFE4E96C390h)
  11. 00007FFDF01903D3 90 nop
  12. 00007FFDF01903D4 48 B9 60 EF 32 F0 FD 7F 00 00 mov rcx,7FFDF032EF60h
  13. 00007FFDF01903DE BA 04 00 00 00 mov edx,4
  14. // 可以看到这个 string 静态对象并没有调用.CCtor。
  15. // 那是否说明上面的说法不对呢?注意看,他实际调用了
  16. // JIT_GetSharedNonGCStaticBase_SingleAppDomain,
  17. // 而这个就是关键所在
  18. 00007FFDF01903E3 E8 48 7E C5 5E call JIT_GetSharedNonGCStaticBase_SingleAppDomain (07FFE4EDE8230h)
  19. 00007FFDF01903E8 8B 0D AA EB 19 00 mov ecx,dword ptr [7FFDF032EF98h]
  20. 00007FFDF01903EE FF 15 7C 94 60 00 call qword ptr [7FFDF0799870h]
  21. 00007FFDF01903F4 90 nop
  22. 00007FFDF01903F5 FF 15 9D 93 60 00 call qword ptr [7FFDF0799798h]
  23. 00007FFDF01903FB 48 89 45 F0 mov qword ptr [rbp-10h],rax
  24. 00007FFDF01903FF 90 nop
  25. 00007FFDF0190400 90 nop
  26. 00007FFDF0190401 48 83 C4 28 add rsp,28h
  27. 00007FFDF0190405 5F pop rdi
  28. 00007FFDF0190406 5D pop rbp
  29. 00007FFDF0190407 C3 ret
  30. 00007FFDF0190408 19 06 sbb dword ptr [rsi],eax
复制代码

看这段代码上面的注释,这段代码里面并没有

  1. .CCtor
复制代码
被调用的痕迹。而它的奥秘在
  1. JIT_GetSharedNonGCStaticBase_SingleAppDomain
复制代码
函数里面。

  1. JIT_GetSharedNonGCStaticBase_SingleAppDomain
复制代码
又调用了
  1. JIT_GetSharedNonGCStaticBase_Helper
复制代码

看下堆栈

  1. > coreclr.dll!MethodTable::RunClassInitEx 行 3591 C++
  2. coreclr.dll!MethodTable::DoRunClassInitThrowing 行 3792 C++
  3. coreclr.dll!MethodTable::CheckRunClassInitThrowing 行 3929 C++
  4. coreclr.dll!JIT_GetSharedNonGCStaticBase_Helper 行 1401 C++
复制代码

函数

  1. RunClassInitEx
复制代码
代码如下:

  1. BOOL MethodTable::RunClassInitEx(OBJECTREF *pThrowable)
  2. {
  3. //为了方便观看 此处省略部分代码
  4. PCODE pCctorCode = pCanonMT->GetSlot(pCanonMT->GetClassConstructorSlot());
  5. //为了方便观看 此处省略部分代码
  6. PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCctorCode);
  7. DECLARE_ARGHOLDER_ARRAY(args, 0);
  8. CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
  9. CALL_MANAGED_METHOD_NORET(args);
  10. //为了方便观看 此处省略部分代码
复制代码

变量

  1. pCctorCode
复制代码
就是
  1. .CCtor
复制代码
的函数头地址。而后面的一堆的宏定义实际上是调用了函数
  1. DispatchCallSimple
复制代码
,而
  1. DispatchCallSimple
复制代码
又调用了
  1. CallDescrWorkerWithHandler
复制代码
然后又调用了
  1. PrecodeFixupThunk
复制代码
下面调用了
  1. PreStubWorker
复制代码

  1. PreStubWorker
复制代码
通过
  1. call rax
复制代码
命令跳转到调用的函数的函数头地址,比如本例的
  1. .CCtor
复制代码
函数头的地址。

  1. 00007FFE8BB289C0 E8 DB FE 8F FF call PreStubWorker (07FFE8B4288A0h)
  2. 00007FFE8BB289C5 66 0F 6F 44 24 20 movdqa xmm0,xmmword ptr [rsp+20h]
  3. 00007FFE8BB289CB 66 0F 6F 4C 24 30 movdqa xmm1,xmmword ptr [rsp+30h]
  4. 00007FFE8BB289D1 66 0F 6F 54 24 40 movdqa xmm2,xmmword ptr [rsp+40h]
  5. 00007FFE8BB289D7 66 0F 6F 5C 24 50 movdqa xmm3,xmmword ptr [rsp+50h]
  6. 00007FFE8BB289DD 48 8B 8C 24 B0 00 00 00 mov rcx,qword ptr [rsp+0B0h]
  7. 00007FFE8BB289E5 48 8B 94 24 B8 00 00 00 mov rdx,qword ptr [rsp+0B8h]
  8. 00007FFE8BB289ED 4C 8B 84 24 C0 00 00 00 mov r8,qword ptr [rsp+0C0h]
  9. 00007FFE8BB289F5 4C 8B 8C 24 C8 00 00 00 mov r9,qword ptr [rsp+0C8h]
  10. 00007FFE8BB289FD 48 83 C4 68 add rsp,68h
  11. 00007FFE8BB28A01 5F pop rdi
  12. 00007FFE8BB28A02 5E pop rsi
  13. 00007FFE8BB28A03 5B pop rbx
  14. 00007FFE8BB28A04 5D pop rbp
  15. 00007FFE8BB28A05 41 5C pop r12
  16. 00007FFE8BB28A07 41 5D pop r13
  17. 00007FFE8BB28A09 41 5E pop r14
  18. 00007FFE8BB28A0B 41 5F pop r15
  19. // 这个rax 就是 .CCtor的函数头的地址
  20. 00007FFE8BB28A0D 48 FF E0 jmp rax
复制代码

  1. jmp rax
复制代码
跳转到了如下:

  1. 00007FFE2CFE8888 FF 25 FA 0F 00 00 jmp qword ptr [7FFE2CFE9888h]
复制代码

  1. 7FFE2CFE9888h
复制代码
地址的值是
  1. 00007FFE8A50C7A0
复制代码

注意这句代码

  1. static string a ="abcd";
复制代码

它实际上被编译成了一个函数,当运行到

  1. .CCtor
复制代码
的时候,会调用它,然后对它进行赋值
  1. abcd
复制代码

  1. >>> 00007ffe`06ac29e0 55 push rbp
  2. 00007ffe`06ac29e1 4883ec20 sub rsp,20h
  3. 00007ffe`06ac29e5 488d6c2420 lea rbp,[rsp+20h]
  4. 00007ffe`06ac29ea 833d9f410c0000 cmp dword ptr [00007ffe`06b86b90],0
  5. 00007ffe`06ac29f1 7405 je ConsoleApp3!ConsoleApp3.Program..cctor+0x18 (00007ffe`06ac29f8)
  6. 00007ffe`06ac29f3 e8e8a4cd5f call coreclr!JIT_DbgIsJustMyCode (00007ffe`6679cee0)
  7. 00007ffe`06ac29f8 48bad83000186c020000 mov rdx,26C180030D8h
  8. 00007ffe`06ac2a02 488b12 mov rdx,qword ptr [rdx]
  9. 00007ffe`06ac2a05 48b9902e00186c020000 mov rcx,26C18002E90h
  10. 00007ffe`06ac2a0f e8fc85bb5f call coreclr!JIT_CheckedWriteBarrier (00007ffe`6667b010)
  11. 00007ffe`06ac2a14 90 nop
  12. 00007ffe`06ac2a15 4883c420 add rsp,20h
  13. 00007ffe`06ac2a19 5d pop rbp
  14. 00007ffe`06ac2a1a c3 ret
复制代码

  1. JIT_CheckedWriteBarrier
复制代码
的原型如下:

  1. extern "C" HCIMPL2_RAW(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref)
复制代码

很明显,他这就是把

  1. ref
复制代码
指向的
  1. object
复制代码
完整的传递给
  1. dst
复制代码
。也就是赋值给静态字符串
  1. a
复制代码
。寄存器
  1. rcx
复制代码
表示
  1. dst
复制代码
  1. rdx
复制代码
表示
  1. ref
复制代码
。此处可以通过
  1. !dumpobj rdx
复制代码
来查被看对象。

那么总结下,

  1. .CCtor
复制代码
的作用就是把静态的全局变量对象进行一个初始化,这个结果也说明,静态全局变量不是在
  1. CLR
复制代码
初始化的时候初始化,而是在当前类的
  1. .CCtor
复制代码
里面初始化的。

以上就是.Net 7函数Ctor与CCtor使用及区别详解的详细内容,更多关于.Net 7函数Ctor CCtor的资料请关注晓枫资讯其它相关文章!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
16
积分
12
注册时间
2022-12-24
最后登录
2022-12-24

发表于 2023-3-17 12:07:56 | 显示全部楼层
免费分享的大佬,反手就是一个赞~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:22
  • 打卡月天数:0
  • 打卡总奖励:308
  • 最近打卡:2025-04-10 20:44:21
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
353
积分
50
注册时间
2023-1-1
最后登录
2025-4-10

发表于 2023-4-10 02:53:50 | 显示全部楼层
感谢分享~~~~感谢分享~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:19
  • 打卡月天数:0
  • 打卡总奖励:250
  • 最近打卡:2025-04-19 06:33:57
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
287
积分
42
注册时间
2022-12-31
最后登录
2025-4-19

发表于 2023-7-20 23:26:51 | 显示全部楼层
感谢大大分享~~~~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
16
注册时间
2022-12-29
最后登录
2022-12-29

发表于 2024-11-2 07:10:57 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
14
积分
8
注册时间
2022-12-28
最后登录
2022-12-28

发表于 2024-11-19 00:55:19 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼
5楼
6楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表