欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.Net 7函數(shù)Ctor與CCtor使用及區(qū)別詳解

 更新時(shí)間:2022年11月09日 10:33:19   作者:江湖評(píng)談  
這篇文章主要為大家介紹了.Net 7函數(shù)Ctor與CCtor使用及區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

楔子

有小伙伴被面試官問(wèn)到這個(gè)問(wèn)題,本篇徹底解析下這個(gè)問(wèn)題。

為了徹底點(diǎn),注意本篇是最底層的.Net 7 RC CLR運(yùn)行模型(匯編)為基礎(chǔ)進(jìn)行全局剖析,局部業(yè)務(wù)分析。

如有疏漏,請(qǐng)斧正。

目的非手段

這兩個(gè)函數(shù)比較特殊的存在,.Ctor是非靜態(tài)默認(rèn)實(shí)例化。.CCtor是靜態(tài)默認(rèn)實(shí)例化。這兩個(gè)函數(shù)伴隨著.Net任何對(duì)象的實(shí)例化都自動(dòng)存在于這個(gè)對(duì)象當(dāng)中。

跟蹤.CCtor可以在全局靜態(tài)對(duì)象下斷點(diǎn),觀察它的里面運(yùn)行。跟蹤.Ctor可以通過(guò)!name2ee模塊 模塊.類名..Ctor找到JITTED Code Address,觀察它的運(yùn)行。正如本段題所說(shuō),這只是手段,不是目的。所以下面看目的。

.Ctor目的

先來(lái)看下非靜態(tài)默認(rèn)構(gòu)造函數(shù).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]  
// 這個(gè)地方是調(diào)用了.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  

調(diào)用.Ctor的地方注釋了下,如果直接進(jìn)入會(huì)調(diào)用到PrecodeFixupThunk。所以這里需要在PreStubWorker下斷點(diǎn)。一路跟蹤下去發(fā)現(xiàn)這個(gè).Ctor是利用預(yù)備的IL代碼,讓RyuJIt對(duì)它進(jìn)行一個(gè)編譯

.Ctor調(diào)用堆棧:

    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里面調(diào)用了UnsafeJitFunction為止,因?yàn)楹竺娑际?code>RyuJit的復(fù)雜編譯過(guò)程,此處不述。

我們來(lái)看下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  

它里面就調(diào)用了一個(gè)Call,也就是這句話:

call  qword ptr [7FFDF2DD1030h]  

這個(gè)十六進(jìn)制的7FFDF2DD1030h是個(gè)啥呢?繼續(xù)跟進(jìn)下:0x00007FFDF2DD1030 00007ffe50357230它里面包含了一個(gè)地址00007ffe50357230看下這個(gè)地址的匯編代碼:

00007FFE50357230 C3   ret 

它直接返回了。

所以這得出了一個(gè)什么結(jié)論呢?也就是說(shuō)在當(dāng)前這個(gè)例子中,.Ctor啥都沒(méi)做。

.CCtor目的

來(lái)看下靜態(tài)的默認(rèn)構(gòu)造函數(shù)干了些啥。先上代碼:

    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  
// 可以看到這個(gè) string 靜態(tài)對(duì)象并沒(méi)有調(diào)用.CCtor。
// 那是否說(shuō)明上面的說(shuō)法不對(duì)呢?注意看,他實(shí)際調(diào)用了
// JIT_GetSharedNonGCStaticBase_SingleAppDomain,
// 而這個(gè)就是關(guān)鍵所在
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  

看這段代碼上面的注釋,這段代碼里面并沒(méi)有.CCtor被調(diào)用的痕跡。而它的奧秘在JIT_GetSharedNonGCStaticBase_SingleAppDomain函數(shù)里面。

JIT_GetSharedNonGCStaticBase_SingleAppDomain又調(diào)用了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++

函數(shù)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的函數(shù)頭地址。而后面的一堆的宏定義實(shí)際上是調(diào)用了函數(shù)DispatchCallSimple,而DispatchCallSimple又調(diào)用了CallDescrWorkerWithHandler然后又調(diào)用了PrecodeFixupThunk下面調(diào)用了PreStubWorker

PreStubWorker通過(guò)call rax命令跳轉(zhuǎn)到調(diào)用的函數(shù)的函數(shù)頭地址,比如本例的.CCtor函數(shù)頭的地址。

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  
// 這個(gè)rax 就是 .CCtor的函數(shù)頭的地址
00007FFE8BB28A0D 48 FF E0             jmp  rax  

jmp rax跳轉(zhuǎn)到了如下:

00007FFE2CFE8888 FF 25 FA 0F 00 00 jmp qword ptr [7FFE2CFE9888h]

7FFE2CFE9888h地址的值是00007FFE8A50C7A0

注意這句代碼

static string a ="abcd";

它實(shí)際上被編譯成了一個(gè)函數(shù),當(dāng)運(yùn)行到.CCtor的時(shí)候,會(huì)調(diào)用它,然后對(duì)它進(jìn)行賦值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。也就是賦值給靜態(tài)字符串a。寄存器rcx表示dstrdx表示ref。此處可以通過(guò)!dumpobj rdx來(lái)查被看對(duì)象。

那么總結(jié)下,.CCtor的作用就是把靜態(tài)的全局變量對(duì)象進(jìn)行一個(gè)初始化,這個(gè)結(jié)果也說(shuō)明,靜態(tài)全局變量不是在CLR初始化的時(shí)候初始化,而是在當(dāng)前類的.CCtor里面初始化的。

以上就是.Net 7函數(shù)Ctor與CCtor使用及區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于.Net 7函數(shù)Ctor CCtor的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論