以前刚开始学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)先写正常程序,通过编译

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

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

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

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

上图的右边就是传说中的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 (
[] int32 num,
[] int32 num2,
[] 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代码(一)的更多相关文章

  1. 读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认 ...

  2. 读懂IL代码就这么简单(二)

    一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...

  3. 读懂IL代码就这么简单 (一)

    一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...

  4. 读懂IL代码就这么简单

    原文地址:http://www.cnblogs.com/zery/p/3366175.html 一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不 ...

  5. 读懂IL代码就这么简单 ---- IL系列文章

    读懂IL代码就这么简单 (一) 读懂IL代码就这么简单(二) 读懂IL代码就这么简单(三)完结篇 出处:http://www.cnblogs.com/zery/tag/IL%20%E7%B3%BB%E ...

  6. 【转载】读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认为 ...

  7. 【转载】读懂IL代码就这么简单(二)

    一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...

  8. 【转载】读懂IL代码就这么简单 (一)

    一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...

  9. 读懂IL代码(二)

    上一篇提到了最基本的IL代码,应该是比较通俗易懂的,所以有了上一篇的基础之后,这篇便要深入一点点的来讲述了. 首先我必须再来说一些重要的概念: Evaluation Stack(评估栈):这是由.NE ...

随机推荐

  1. struts1 工作原理

    struts1的原理和工作流程 struts1的工作原理或者说工作流程: 1.在web应用程序启动就会加载ActionServlet,ActionServlet从配置文件struts-config.x ...

  2. bzoj2653

    CLJ神牛的可持久化论文的题目,果然厉害其实第一步能想到后面就还是很简单的首先是二分答案,转化为判定性问题然后对于区间内的数,比他大的标为1,小的标为-1显然,如果存在一个左右端点符合的区间使得这个区 ...

  3. Linux学习笔记21——线程同步的两种方式

    一  用信号量同步 1 信号量函数的名字都以sem_开头,线程中使用的基本信号量函数有4个 2 创建信号量 #include<semaphore.h> int sem_init(sem_t ...

  4. 2013.08.23.diary

    Today, my baby called me.She said, she want to go abroad . And she wants me to go abroad too. I thin ...

  5. MHz 和 Mbps的区别

    Hz是频率单位,例如10Hz就是表示每秒运算10次 Mbps是Million bit per secend (表示每秒传输的兆位数)=Mb/s MHz 和 Mbps 并不是同一个单位,关键是看bus的 ...

  6. jQuery各种效果举例

    jQuery 所有jQuery详细使用说明请见:http://www.php100.com/manual/jquery/ jQuery的作用是操作浏览器html,从而达到用户的可视化效果,按照功能可分 ...

  7. java 实现 DES加密 解密算法

    DES算法的入口参数有三个:Key.Data.Mode.其中Key为8个字节共64位,是DES算法的工作密钥:Data也为8个字节64位,是要被加密或被解密的数据:Mode为DES的工作方式,有两种: ...

  8. winform 窗体关闭按钮禁用、不显示最大化、最小化、关闭按钮 分类: WinForm 2014-12-22 16:09 82人阅读 评论(0) 收藏

    关闭按钮禁用: (1) FormClosing事件 private void Main_FormClosing(object sender, FormClosingEventArgs e) {     ...

  9. jstree 节点拖拽保存数据库

    需要jstree具有拖拽功能需要在加载jstree时添加dnd插件,具体看代码: $('**').jstree({ //plugins-各种jstree的插件引入,展示树的多样性 'plugins' ...

  10. Bluetooth 4.0之Android 解说

     Android平台包括了对蓝牙网络协议栈的支持,它同意一个蓝牙设备跟其它的蓝牙设备进行无线的数据交换.应用程序通过Android蓝牙API提供訪问蓝牙的功能. 这些API会把应用程序无线连接到其 ...