聊聊 C# 方法重載的底層玩法

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

#include?<stdio.h>int?say()?{return?1;
}
int?say(int?i)?{return?i;
}int?main()
{say(10);return?0;
}
747cc3eb43e48f49f54d3516dace9dcd.png

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

一:為什么 C 不支持

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

973bf3612131ce3f1f52aeb06d2843bb.png

簡而言之,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 這個符號,奇怪的是他們屬于不同的地址: 03B13A2h, 03B1302h,這就太奇怪了,哈哈,字典類符號表 肯定是沒有問題的,問題是 Visual Studio 20222 的反匯編窗口在調試時做了一些內部轉換,算是蒙蔽了我們雙眼吧,

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

2cb5c28bd9ca5dccc5eb7913f681afbc.png

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

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

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

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

好了本篇就聊到這里,希望對你有幫助。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/286203.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/286203.shtml
英文地址,請注明出處:http://en.pswp.cn/news/286203.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Nginx圖片剪裁模塊探究 http_image_filter_module

#yum install -y gd-devel Install add http_image_filter_module Module #./configure --prefix/usr/local/nginx_image_filter/ --with-http_image_filter_module #make && make install use: off:關閉模塊處理 test:確保圖片是jpeg gif png否則返415錯誤 size:輸出有…

Android WebView 圖片超出寬度自適應,點擊查看大圖

webView 配置 WebSettings webSettings webView.getSettings(); webSettings.setJavaScriptCanOpenWindowsAutomatically(true);webSettings.setDomStorageEnabled(true);webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//自適應屏幕 ☆…

C語言試題三十五之找出一維整型數組元素中最大的值和它所在的下標,最大的值和它所在的下標通過形參傳回。主函數中x是數組名,n 是x中的數據個數,max存放最大值,index存放最大值所在元素的下標。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 請編寫一個…

三、我的/登錄 欄制作《仿淘票票系統前后端完全制作(除支付外)》

我的頁分為登錄、注冊、我的&#xff0c;如果登錄了那么就顯示我的頁面否則顯示登錄頁。 登錄頁&#xff1a; 我的頁&#xff1a; 一、登錄頁制作 1.1 登錄頭制作 首先我們創建一個行&#xff0c;命名為登錄塊&#xff0c;設置高度為包裹&#xff1a; 之后將會在這個行中…

ASP.NET站點配置以及VS2008下C#、JavaScript聯合調試(Ajax) ----以最短路徑Dijstra最短路問題為例

實驗任務描述: 用VS2008構造ASP.NET站點開發環境;用ASP.NET完成JavaScript開發調試;用Ext3.0.0完成一個簡單的樹顯示站;WebService程序設計,Dijstra最短路Web 服務;JavaScript通過Ajax技術調用WebService;一、Windows下WEB共享設置 打開你的WINDOWS,鼠標點開“我的電腦”…

【NOIP2010】【P1317】烏龜棋

似乎很像搜索的DP&#xff08;應該也可以用搜索寫&#xff09; 原題&#xff1a; 小明過生日的時候&#xff0c;爸爸送給他一副烏龜棋當作禮物。烏龜棋的棋盤是一行N 個格子&#xff0c;每個格子上一個分數&#xff08;非負整數&#xff09;。棋盤第1格是唯一的起點&#xff0c…

mysql添加普通用戶用于管理單一數據庫

2019獨角獸企業重金招聘Python工程師標準>>> 使用phpmyadmin進行操作 創建用戶&#xff0c;輸入密碼 關鍵選擇&#xff1a;勾選 Create database with same name and grant all privileges 其他權限一律不要勾選 轉載于:https://my.oschina.net/u/2485194/blog/5491…

C# 11 新特性:接口中的靜態抽象成員

之前假設我們有一個非常復雜的數學運算方法&#xff1a;public static int Calc(int x, int y) > x y;但是&#xff0c;上述方法只能支持int類型。如果需要傳入其它數字類型&#xff0c;需要再次定義&#xff1a;public static double Calc(double x, double y) > x y;…

tomcat兩個項目沖突

java.lang.IllegalStateException: Web app root system property already set to different value 最近在搭建項目環境的時候出現了下面的錯誤 java.lang.IllegalStateException: Web app root system property already set to different value: webapp.root [D:/tomcat-5.0.…

四、一般頁面制作《仿淘票票系統前后端完全制作(除支付外)》

一、播放影片影院頁制作 上一節已經做完了首頁所有欄目內容&#xff0c;那么點擊購票后應該出現對應有購票的影院&#xff0c;選擇影院后進入購買票務頁。 首先新建一個頁面命名為播放該影片的影院&#xff1a; 接著復制首頁中的標題欄到播放影片的影院頁中&#xff0c;此時…

SuppressLint黃色警告的原因以及解決辦法

最近在做項目的時候&#xff0c;碰到方法的前面和類的前面有時會出現SuppressLint或者SuppressWarnings這樣的黃色警告&#xff0c;看起來很不舒服&#xff0c;于是上網搜集了一些相關資料。發現這些警告的出現其實是由于我們編寫代碼時的一些不規范的寫法導致&#xff0c;解決…

重磅!win10無法安裝.NET Framework 3.5服務解決辦法(附離線安裝包下載)

安裝CASS測圖軟件之前需要安裝CAD,Win10操作系統安裝CAD時經常會需要.net framework 3.5,win10中默認是沒有安裝該環境的,需要單獨安裝。本文講解Win10系統中在線和離線安裝.net framework 3.5。 CAD 2006+CASS 7.1安裝參考:《Win 10操作系統CAD 2006+CASS 7.1安裝圖文經典…

C語言試題三十六之將s所指字符串中所有下標為奇數位置上的字母轉換為大寫(若該位置上不是字母,則不轉換)。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 請編寫一個…

數據結構實驗之鏈表二:逆序建立鏈表

數據結構實驗之鏈表二&#xff1a;逆序建立鏈表 Time Limit: 1000MS Memory Limit: 65536KBSubmit StatisticProblem Description 輸入整數個數N&#xff0c;再輸入N個整數&#xff0c;按照這些整數輸入的相反順序建立單鏈表&#xff0c;并依次遍歷輸出單鏈表的數據。Input 第一…

執行yum:Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again...

安裝eple源&#xff0c;在yum clean all&#xff1b;yum makecache 后出現報錯Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again解決辦法&#xff1a;sed -i s/mirrorlist/\#mirrorlist/g epel.repo epel-testing.reposed -i s/\#…

700行無用 純 CSS 祝考生 金榜高粽《1_bit 的無用 CSS 代碼 》

今天才想起來這回事&#xff0c;沒辦法就急急忙忙的趕工一下&#xff0c;接下來我就畫一下這個海報試試手了&#xff1a; 一、背景制作 1.1 準備工作 先給整個網頁制作一個布局吧&#xff0c;直接 flex 搞定&#xff0c;并且使其居中 justify-content、align-items 都要賦值為…

【CASS精品教程】win10安裝CAD+CASS過程中出現的錯誤問題及解決辦法集錦

文章目錄 1. 無法安裝2. 提示DWF Viewer、AutoCAD2008未安裝3. 安裝完成后一直出現如下窗口4. Win10 64位 cass9.1+cad2008打開后出現Frame主框架程序沒有加載。5. 注冊程序無法運行,提示由于無法安裝此service pack。1. 無法安裝 解決辦法:開啟Administrator,以管理員身份…

(01).NET MAUI實戰 建項目

1.概要本系列文章將會針對.NET MAUI實戰開發的一些內容&#xff0c;會長期不間斷更新我了解學習到的內容。當學習新的軟件開發技術時&#xff0c;都會從基礎建項目開始MAUI也不例外。ref&#xff1a;https://docs.microsoft.com/zh-cn/dotnet/maui/get-started/first-app?pivo…

Android Studio 引用aar包 更新后找不到新增的方法問題(踩坑)

明明已經更新了aar文件&#xff0c;但死活找不到新增的方法&#xff0c;代碼提示里也找不到新增的方法名&#xff0c;但編譯能編譯&#xff0c;運行也一切正常&#xff0c;只是IDE一直提示錯誤&#xff0c;有強迫癥的小猿好幾天都想不明白。 其間有高手指教說&#xff1a;“那…

VMware Workstation與VMware vSphere的區別

在學完vSphere后&#xff0c;想起了VMware Workstation。這兩個都是虛擬化的東西&#xff0c;這兩者到底有什么本質的不同呢&#xff1f;順著我的思路我開始將所學過的進行檢索期望從中尋到一絲半點的線索。很快大腦中建立了兩個對他們明顯的標簽 VMware Workstation&#xff1…