<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
有小夥伴被面試官問到這個問題,本篇徹底解析下這個問題。
為了徹底點,注意本篇是最底層的.Net 7 RC CLR
執行模型(組合)為基礎進行全域性剖析,區域性業務分析。
如有疏漏,請斧正。
這兩個函數比較特殊的存在,.Ctor
是非靜態預設範例化。.CCtor
是靜態預設範例化。這兩個函數伴隨著.Net
任何物件的範例化都自動存在於這個物件當中。
跟蹤.CCtor
可以在全域性靜態物件下斷點,觀察它的裡面執行。跟蹤.Ctor
可以通過!name2ee
模組 模組.類名..Ctor
找到JITTED Code Address
,觀察它的執行。正如本段題所說,這只是手段,不是目的。所以下面看目的。
先來看下非靜態預設建構函式.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
呼叫.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 行 1938 coreclr.dll!ThePreStub(
到JitCompileCodeLocked
裡面呼叫了UnsafeJitFunction
為止,因為後面都是RyuJit的
複雜編譯過程,此處不述。
我們來看下UnsafeJitFunction
返回的pCode
地址處的組合程式碼:
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
,也就是這句話:
call qword ptr [7FFDF2DD1030h]
這個十六進位制的7FFDF2DD1030h
是個啥呢?繼續跟進下:0x00007FFDF2DD1030 00007ffe50357230
它裡面包含了一個地址00007ffe50357230
看下這個地址的組合程式碼:
00007FFE50357230 C3 ret
它直接返回了。
所以這得出了一個什麼結論呢?也就是說在當前這個例子中,.Ctor啥都沒做。
來看下靜態的預設建構函式幹了些啥。先上程式碼:
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
看這段程式碼上面的註釋,這段程式碼裡面並沒有.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 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
jmp rax
跳轉到了如下:
00007FFE2CFE8888 FF 25 FA 0F 00 00 jmp qword ptr [7FFE2CFE9888h]
7FFE2CFE9888h
地址的值是00007FFE8A50C7A0
注意這句程式碼
static string a ="abcd";
它實際上被編譯成了一個函數,當執行到.CCtor
的時候,會呼叫它,然後對它進行賦值abcd
>>> 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
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
裡面初始化的。
以上就是.Net 7函數Ctor與CCtor使用及區別詳解的詳細內容,更多關於.Net 7函數Ctor CCtor的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45