读懂IL代码(一)

摘要:
当我第一次阅读IL代码时,我感到非常困难。我不太明白。后来,我慢慢地读了一遍,终于明白了一点。没有太多流言蜚语,我将开始谈论IL代码1,什么是IL代码IL,也称为CIL、MSIL,它是中中间语言的缩写。NET框架。学习IL代码也是如此。它有200多条指令。我们可以通过学习20%的常用问题来解决80%的问题。上图右侧是传说中的IL代码。看起来复杂吗?上述IL代码是一段相对简单的代码,因为没有诸如条件判断之类的过程控制。

以前刚开始学C#的时候,总有高手跟我说,去了解一下IL代码吧,看懂了你能更加清楚的知道你写出来的代码是如何运行互相调用的,可是那时候没去看,后来补的,其实感觉也不晚。刚开始看IL代码的时候,感觉非常吃力,一大堆不懂,后来,慢慢看,最后也能看得懂一丁点啦。

闲话不多说了,下面就开始讲讲IL代码

1、什么是IL代码

IL,也称为CIL,MSIL,是.NET框架中中间语言(Intermediate Language)的缩写。上一篇文章已经说过了,Visual Studio继承的C#编译器可以直接把C#写的源程序编译成.exe或.dll格式的文件,这些文件里面保存的就是IL代码,这些代码CPU是认不得的,只能再经过JIT编译后,CPU才会执行。

2、How to Study IL

IL的代码形式比较特殊,看起来会比较吃力,理解全部肯定更困难。但在这个世上有一个定律叫做“二八原则”,20%的人掌握着世上80%的财富。这在编程上也是一样的,80%的功能其实只需要用20%的技术就可以完成了,但另外的20%,就有可能需要80%的技术了。学习IL代码也是一样,它有200多个指令(可以查看这里:IL指令),我们只要学习常用的20%就可以解决80%的问题了。不管怎么说,就是要多看,看多了自然就会懂了。

3、怎么查看源代码

(1)先写正常程序,通过编译

读懂IL代码(一)第1张

(2)找Bin文件夹中找到exe后缀的文件

(3)拖入Reflector(我习惯用这个来看反编译代码),也可以使用别的反编译软件,比如ILDasm,ILSpy等。初学者我是建议使用ILDasm,因为这是微软自带的。

我在网上找了两张图,是使用ILDasm的,大家可以参考借鉴一下。

读懂IL代码(一)第2张读懂IL代码(一)第3张

上面两张图是用ILDasm的。而我还是习惯用Reflector。

读懂IL代码(一)第4张

上图的右边就是传说中的IL代码了,看起来复杂吗?应该不复杂吧,来,再多看几眼......下面我就一句一句来解释。

//Call Stack是调用栈,一个局部变量列表,用于存储.locals init([0] int32 num,[1] int32 num2,[2] int32 num3)初始化变量。

//Evaluation Stack也是一个评估栈,用来存储值,比如ldc.i4.1这种指令会把1压入栈中等待操作。

//栈是一种先进后出的数据结构。

//hidebysig指令表示如果当前类为父类,用该指令标记的方法将不会被子类继承
//cil managed表明方法体中的代码是IL代码,且是托管代码,即运行在CLR运行库上的代码

.method
private hidebysig static void Main(string[] args)cil managed { .entrypoint //该指令代表该函数程序的入口函数。每一个托管应用程序都有且只有一个入口函数,CLR加载程序时,首先从.entrypoint函数开始执行。 .maxstack 2 //执行构造函数时,评估堆栈可容纳数据项的最大个数。评估堆栈是保存方法中所需要变量的值的一个内存区域,该区域在方法执行结束时会被清空,或者存储一个返回值。 .locals init ( [0] int32 num, [1] int32 num2, [2] int32 num3) //表示定义int类型的变量,变量名分别为num,num2,num3。存储在调用栈。 L_0000: nop //No operation的意思,即没有任何操作。 L_0001: ldc.i4.1 //将“1”压入评估栈,此时“1”处于评估栈的栈顶。 L_0002: stloc.0 //此指令表示把值从评估栈中弹出,并赋值给调用栈的第0个变量num。 L_0003: ldc.i4.2 L_0004: stloc.1 L_0005: ldc.i4.3 L_0006: stloc.2 //从.locals init到L_0006,相当于C#代码的为i,j,k赋值。 L_0007: ldloc.0 //取调用栈中位置为0的元素压入评估栈(取i的值)。 L_0008: ldloc.1 //取调用栈中位置为1的元素压入评估栈(取j的值)。 L_0009: add //做加法操作 L_000a: ldloc.2 //取调用栈中位置为2的元素压入评估栈(取k的值)。 L_000b: add //做加法操作 L_000c: call void [mscorlib]System.Console::WriteLine(int32) //调用输出方法 L_0011: nop //No Operation L_0012: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() //调用ReadKey方法 L_0017: pop //把评估栈的内容清空 L_0018: ret //return 标记返回值 } //Main方法结束
 
通过上面的代码,我们可以总结一下:
.maxstack:代码中变量需要在调用栈(Call Stack)中占用几个位置;
.locals int(......):定义变量初始化并放入调用栈中(Call Stack);
nop:No Operation,没有任何操作;
ldstr:Load String,把字符串压入评估栈(Evaluation Stack)中;
ldc.i4.1:把数值2以4字节长度整数的形式压入评估栈;
stloc:把评估栈(Evaluation)中的值弹出赋值到调用栈中(Call Stack);
ldloc:把调用栈(Call Stack)中指定位置的值取出(Copy)压入评估栈(Evaluation Stack)中;
call:调用指定的方法,这个指令一般用于调用静态方法;而callvir则一般用于调用实例方法;
ret:return ,标记返回。
 

 以上的IL代码算是比较简单的一段代码,因为没有条件判断等流程控制。但只要记住每一条IL指令固定的操作,我觉得也不难。接下来会写第二部分,主要写引用类型的IL代码,更深入理解IL代码。

免责声明:文章转载自《读懂IL代码(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇快到极致的Android模拟器——Genymotionpyinstaller打包python源程序访问hive下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

关于mysql installer 的安装和环境变量配置

MySQL针对不同的用户提供了2中不同的版本: MySQL Community Server:社区版。由MySQL开源社区开发者和爱好者提供技术支持,对开发者开放源代码并提供免费下载。 MySQL Enterprise Server:企业版。包括最全面的高级功能和管理工具,不过对用户收费。 下面讲到的MySQL安装都是以免费开源的社区版为基础。打开My...

chapter11:认识与学习bash之(1)认识shell与shell的变量功能

  使用终端的命令行就是通过bash 环境变量来处理的,bash还包括变量的设置与使用,bash操作环境的构建,数据流的重定向和管道等。 一,认识bash这个shell 1.什么是shell   我们一般通过shell来和内核进行通信,因为内核是要保护的。也就是说通过shell将我们的命令与内核通信,好让崔可以控制硬件来完成工作。   其实shell只是提...

Delphi管理多线程之线程局部存储:threadvar

尽管多线程能够解决许多问题,但是同时它又给我们带来了很多的问题。其中主要的问题就是:对全局变量或句柄这样的全局资源如何访问?另外,当必须确保一个线程中的某些事件要在另一个线程中的其他时间之前(或之后)发生时,该怎么办?这里将讲解通过使用由 Delphi提供的线程局部存储和 A P I为线程提供同步的方法。 这里先讲线程局部存储,下一篇再讲线程同步 线程局部...

C#命名惯例和规范

C#命名惯例和规范 注记 : Pascal 大小写形式-所有单词第一个字母大写,其他字母小写。 Camel   大小写形式-除了第一个单词,所有单词第一个字母大写,其他字母小写。 类名使用Pascal 大小写形式 public class HelloWorld{ ...} 方法使用Pascal 大小写形式 public class HelloW...

开源BI分析工具Metabase配置与完全使用手册

文章目录 简介 安装 初始配置 数据分析 简单查询 创建场景 创建集合和仪表盘 自定义查询 原生查询 sql变量 动态sql片段 管理员操作 添加数据库连接oracle 成员管理邀请新成员 权限配置 数据权限 文件夹权限 邮箱配置 定时任务 简介 Metabase是一个免费的BI分析工具,可以帮助你把数据库...

JMeter之BeanShell常用内置对象

 一、什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k。...