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

一文詳解C#中方法重載的底層玩法

 更新時(shí)間:2022年06月15日 14:37:07   作者:一線碼農(nóng)  
最近在看C++的方法重載,就在想C#中的重載底層是怎么玩的。畢竟很多朋友應(yīng)該知道C是不支持重載的。本文將來詳細(xì)講講C#中方法重載的底層玩法,感興趣的可以了解一下<BR>

最近在看 C++ 的方法重載,我就在想 C# 中的重載底層是怎么玩的,很多朋友應(yīng)該知道 C 是不支持重載的,比如下面的代碼就會(huì)報(bào)錯(cuò)。

#include <stdio.h>

int say() {
	return 1;
}
int say(int i) {
	return i;
}

int main()
{
	say(10);
	return 0;
}

從錯(cuò)誤信息看,它說 say 方法已經(jīng)存在了,尷尬。。。

一:為什么 C 不支持

要想尋找答案,需要了解一點(diǎn)點(diǎn)底層知識(shí),那就是編譯器在編譯 C 方法時(shí)會(huì)將函數(shù)名作為符號(hào)添加到符號(hào)表中,這個(gè)符號(hào)表 就是call到say方法字節(jié)碼中間的一個(gè)載體,畫個(gè)圖大概就是這樣。

簡(jiǎn)而言之,call 先跳轉(zhuǎn)到符號(hào)表, 然后再 jmp 到 say 方法,問題就出現(xiàn)在這里,符號(hào)表是一種類字典結(jié)構(gòu),是不可以出現(xiàn)符號(hào)相同的情況。對(duì)了,在 windbg 中我們可以用 x 命令去搜索這些符號(hào),

為了論證我的說法,可以在匯編層面給大家驗(yàn)證下,修改代碼如下:

#include <stdio.h>

int say(int i) {
	return i;
}

int main()
{
	say(10);
	return 0;
}

接下來再看下匯編。

--------------- say(10) -----------

00C41771  push        0Ah  
00C41773  call        _say (0C412ADh)  

--------------- 符號(hào)表 -----------

00C412AD  jmp         say (0C417B0h)  

--------------- say body -----------

00C417B0  push        ebp  
00C417B1  mov         ebp,esp  
00C417B3  sub         esp,0C0h  
00C417B9  push        ebx  
00C417BA  push        esi  
00C417BB  push        edi  
00C417BC  mov         edi,ebp  
00C417BE  xor         ecx,ecx  
00C417C0  mov         eax,0CCCCCCCCh  
00C417C5  rep stos    dword ptr es:[edi]  
00C417C7  mov         ecx,offset _2440747F_ConsoleApplication6@c (0C4C008h)  
...

知道了原理后,我們?cè)倏纯?C++ 是如何在符號(hào)表上實(shí)現(xiàn)唯一性突破。

二:C++ 符號(hào)表突破

為了方便講述,我們先上一段 C++ 方法重載的代碼。

using namespace std;

class Person
{
public:
	void sayhello(int i) {
		cout << i << endl;
	}
	void sayhello(const char* c) {
		cout << c << endl;
	}
};

int main(int argc)
{
	Person person;

	person.sayhello(10);
	person.sayhello("hello world");
}

按理說 sayhello 有多個(gè),肯定是無法突破的,帶著好奇心我們看下它的反匯編代碼。

----------     person.sayhello(10);  ----------------

003B2E5F  push        0Ah  
003B2E61  lea         ecx,[person]  
003B2E64  call        Person::sayhello (03B13A2h) 

------------  person.sayhello("hello world"); ----------------

003B2E69  push        offset string "hello world" (03B9C2Ch)  
003B2E6E  lea         ecx,[person]  
003B2E71  call        Person::sayhello (03B1302h) 

從匯編代碼看, 調(diào)的都是 Person::sayhello 這個(gè)符號(hào),奇怪的是他們屬于不同的地址: 03B13A2h03B1302h,這就太奇怪了,哈哈,字典類符號(hào)表肯定是沒有問題的,問題是 Visual Studio 20222 的反匯編窗口在調(diào)試時(shí)做了一些內(nèi)部轉(zhuǎn)換,算是蒙蔽了我們雙眼吧,

真是可氣?。?!居然運(yùn)行時(shí)匯編代碼都還不夠徹底,那現(xiàn)在我們?cè)趺蠢^續(xù)挖呢? 可以用 IDA 去看這個(gè)程序的靜態(tài)反匯編代碼,截圖如下:

從代碼上的注釋可以清楚的看到,原來:

  • Person::sayhello(int) 變成了 j_?sayhello@Person@@QAEXH@Z。
  • Person::sayhello(char const *) 變成了 j_?sayhello@Person@@QAEXPBD@Z

到這里終于搞清楚了,原來 C++ 為了支持方法重載,將方法名做了重新編碼,這樣確實(shí)可以突破符號(hào)表的唯一性限制。

三:C#如何實(shí)現(xiàn)突破

我們都知道 C# 的底層 CLR 是由 C++ 寫的,所以大概率玩法都是一樣,接下來上一段代碼:

    internal class Program
    {
        static void Main(string[] args)
        {
			//故意做一次重復(fù)
            Say(10);
            Say("hello world");

            Say(10);
            Say("hello world");
            Console.ReadLine();
        }

        static void Say(int i)
        {
            Console.WriteLine(i);
        }

        static void Say(string s)
        {
            Console.WriteLine(s);
        }
    }

由于 C# 的方法是由 JIT 在運(yùn)行時(shí)動(dòng)態(tài)編譯的,并且首次編譯方法會(huì)先跳轉(zhuǎn)到 JIT 的樁地址,所以斷點(diǎn)必須下在第二次調(diào)用 Say(10) 處才能看到方法的符號(hào)地址,匯編代碼如下:

 -----------	Say(10);	-----------

00007FFB82134DFC  mov         ecx,0Ah  
00007FFB82134E01  call        Method stub for: ConsoleApp1.Program.Say(Int32) (07FFB81F6F118h)  
00007FFB82134E06  nop  

-----------	Say("hello world");		-----------

00007FFB82134E07  mov         rcx,qword ptr [1A8C65E8h]  
00007FFB82134E0F  call        Method stub for: ConsoleApp1.Program.Say(System.String) (07FFB81F6F120h)  
00007FFB82134E14  nop  

從輸出信息看,同樣也是兩個(gè)符號(hào)表地址,然后由符號(hào)表地址 jmp 到最后的方法體。

-----------	Say(10);	-----------
00007FFB82134E01  call        Method stub for: ConsoleApp1.Program.Say(Int32) (07FFB81F6F118h)  

-----------	符號(hào)表	-----------
00007FFB81F6F118  jmp         ConsoleApp1.Program.Say(Int32) (07FFB82134F10h)  

-----------	Say body -----------

00007FFB82134F10  push        rbp  
00007FFB82134F11  push        rdi  
00007FFB82134F12  push        rsi  
00007FFB82134F13  sub         rsp,20h  
00007FFB82134F17  mov         rbp,rsp  
00007FFB82134F1A  mov         dword ptr [rbp+40h],ecx  
00007FFB82134F1D  cmp         dword ptr [7FFB82036B80h],0  
00007FFB82134F24  je          ConsoleApp1.Program.Say(Int32)+01Bh (07FFB82134F2Bh)  
00007FFB82134F26  call        00007FFBE1C2CC40  

暫時(shí)還不知道怎么看 JIT 改名后方法名,有知道的朋友可以留言一下哈,但總的來說還是 C++ 這一套。

以上就是一文詳解C#中方法重載的底層玩法 的詳細(xì)內(nèi)容,更多關(guān)于C#方法重載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#程序連接數(shù)據(jù)庫及讀取數(shù)據(jù)庫中字段的簡(jiǎn)單方法總結(jié)

    C#程序連接數(shù)據(jù)庫及讀取數(shù)據(jù)庫中字段的簡(jiǎn)單方法總結(jié)

    包括C#連接Access、Oracle或者SQL Server,這里整理了一些C#連接數(shù)據(jù)庫及從讀取數(shù)據(jù)庫中字段的簡(jiǎn)單方法總結(jié),需要的朋友可以參考下
    2016-05-05
  • WPF字體或內(nèi)容模糊的解決方法

    WPF字體或內(nèi)容模糊的解決方法

    WPF下開發(fā)的程序字體模糊,這個(gè)問題或許大家都有遇到過,為了解決WPF字體模糊,查閱了各種資料,結(jié)果偶然發(fā)現(xiàn)是自己疏忽了一些細(xì)節(jié)造成的,具體是什么細(xì)節(jié)呢,通過下面的這篇文章來一起看看吧,有需要的朋友們可以參考借鑒。
    2016-12-12
  • C# Websocket連接實(shí)現(xiàn)wss協(xié)議

    C# Websocket連接實(shí)現(xiàn)wss協(xié)議

    本文主要介紹了C# Websocket連接實(shí)現(xiàn)wss協(xié)議,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C#規(guī)則引擎RulesEngine的具體使用

    C#規(guī)則引擎RulesEngine的具體使用

    這篇文章主要介紹了C#規(guī)則引擎RulesEngine的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(4)

    C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(4)

    這篇文章主要介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì),學(xué)習(xí)內(nèi)容是總結(jié)銷售信息的保存以及加載銷售信息,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-11-11
  • C#實(shí)現(xiàn)給圖片加水印的方法

    C#實(shí)現(xiàn)給圖片加水印的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)給圖片加水印的方法,結(jié)合完整實(shí)例形式分析了C#常見的圖片水印操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2016-02-02
  • C#使用for循環(huán)移除HTML標(biāo)記

    C#使用for循環(huán)移除HTML標(biāo)記

    大家在項(xiàng)目開發(fā)階段移除文字中的html標(biāo)記最常用的方法就是使用正則表達(dá)式,但是正則表達(dá)式不能處理所有的html文檔,所以采用迭代方式會(huì)更好,下面小編給大家解答下
    2016-08-08
  • 如何在Unity中檢測(cè)死循環(huán)和卡死

    如何在Unity中檢測(cè)死循環(huán)和卡死

    這篇文章主要介紹了在Unity中檢測(cè)死循環(huán)和卡死的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • C#用Parallel.Invoke方法盡可能并行執(zhí)行提供的每個(gè)線程

    C#用Parallel.Invoke方法盡可能并行執(zhí)行提供的每個(gè)線程

    本文主要介紹了C#用Parallel.Invoke方法盡可能并行執(zhí)行提供的每個(gè)線程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • C#中ListView用法實(shí)例

    C#中ListView用法實(shí)例

    我們經(jīng)常會(huì)在應(yīng)用程序中使用列表的形式來展現(xiàn)一些內(nèi)容,所以學(xué)好ListView是非常必需的,下面這篇文章主要給大家介紹了關(guān)于C#中ListView用法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06

最新評(píng)論