中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#中方法重載實例分析

發布時間:2022-06-15 16:16:04 來源:億速云 閱讀:150 作者:iii 欄目:開發技術

這篇文章主要介紹了C#中方法重載實例分析的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C#中方法重載實例分析文章都會有所收獲,下面我們一起來看看吧。

最近在看 C++ 的方法重載,我就在想 C# 中的重載底層是怎么玩的,很多朋友應該知道 C 是不支持重載的,比如下面的代碼就會報錯。

#include <stdio.h>

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

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

C#中方法重載實例分析

從錯誤信息看,它說 say 方法已經存在了,尷尬。。。

一:為什么 C 不支持

要想尋找答案,需要了解一點點底層知識,那就是編譯器在編譯 C 方法時會將函數名作為符號添加到符號表中,這個符號表 就是call到say方法字節碼中間的一個載體,畫個圖大概就是這樣。

C#中方法重載實例分析

簡而言之,call 先跳轉到符號表, 然后再 jmp 到 say 方法,問題就出現在這里,符號表是一種類字典結構,是不可以出現符號相同的情況。對了,在 windbg 中我們可以用 x 命令去搜索這些符號,

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

#include <stdio.h>

int say(int i) {
	return i;
}

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

接下來再看下匯編。

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

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

--------------- 符號表 -----------

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++ 符號表突破

為了方便講述,我們先上一段 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 有多個,肯定是無法突破的,帶著好奇心我們看下它的反匯編代碼。

----------     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)

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

真是可氣!!!居然運行時匯編代碼都還不夠徹底,那現在我們怎么繼續挖呢? 可以用 IDA 去看這個程序的靜態反匯編代碼,截圖如下:

C#中方法重載實例分析

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

  • Person::sayhello(int) 變成了 j_?sayhello@Person@@QAEXH@Z

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

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

三:C#如何實現突破

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

    internal class Program
    {
        static void Main(string[] args)
        {
			//故意做一次重復
            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 在運行時動態編譯的,并且首次編譯方法會先跳轉到 JIT 的樁地址,所以斷點必須下在第二次調用 Say(10) 處才能看到方法的符號地址,匯編代碼如下:

 -----------	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

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

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

-----------	符號表	-----------
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

關于“C#中方法重載實例分析”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“C#中方法重載實例分析”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁晋县| 九台市| 和平县| 锡林郭勒盟| 改则县| 察哈| 抚顺县| 贵溪市| 龙川县| 淮南市| 曲阳县| 沐川县| 周口市| 秀山| 长沙市| 宁城县| 潮安县| 轮台县| 灌南县| 申扎县| 涞水县| 张家口市| 馆陶县| 建瓯市| 西安市| 米脂县| 和顺县| 五寨县| 吐鲁番市| 新平| 饶阳县| 班戈县| 明溪县| 涞水县| 当雄县| 四会市| 丹江口市| 正定县| 兴宁市| 新沂市| 独山县|