聊聊 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.mzph.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…