以前刚开始学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. 14.5.4 Phantom Rows 幻影行

    14.5.4 Phantom Rows 幻影行 所谓的幻读问题发生在一个事务 当相同的查询产生不同的结果集在不同的时间. 例如,如果一个SELECT 是执行2次,但是第2次返回的时间不第一次返回不同, ...

  2. quartz 两次执行问题

    最近发现网站(xiayule.net)越写越大,有些东西已经难以维护了,想要添加个功能,都得斟酌半天 项目中有很多可重构的地方,小重构一直进行,大的不敢动,毕竟没有很多时间做测试. 最后,决定精简代码 ...

  3. 利用纯java捕获和播放音频

    参考: 1.http://www.cjsdn.net/doc/jdk60/javax/sound/sampled/package-summary.html 2.http://www.cjsdn.net ...

  4. Delhi 安装ocx的方法

    Delhi 安装ocx的方法 1.通过cmd注册 2.通过delphi 注册 然后 可以修改 classnames  改成__tlb.pas单元中的控件的名称,就可以了 例如下图:

  5. TMS320VC5509A DSP学习路线(持续更新)

    step 1:芯片的数据手册(data sheet) 参考资料:sprs205k_TMS320VC5509A Fixed-Point Digital Signal Processor Data Man ...

  6. eclipse配置j2ee项目

    1.下载jdk (1.5,1.6) 安装 从sun的官方网站下载,我下的是jdk-1_5_0_19-nb-6_5_1-windows-ml.exe,集成netbean的版本,下载后一路默认安装. 配置 ...

  7. mysql中group_concat函数用法

    该函数返回带有来自一个组的连接的非NULL值的字符串结果.该函数是一个增强的Sybase SQL Anywhere支持的基本LIST()函数. 语法结构: GROUP_CONCAT([DISTINCT ...

  8. ODBC 中遇到的错误

    直接贴解决办法的链接: http://zhidao.baidu.com/link?url=pyd2AiazzsZr4IlMpiCdXlLC6nnao908xmqmY9QI0yj8vIGCbRPRrqh ...

  9. IAP内购 返回的产品数量为0

    上个月搞IAP,提交到appstore审核被拒,根据附件截图 可以知道是请求产品信息的时候,产品数量返回0了. 返回产品数量为0 要么是Itunes Connect 里面的Contracts Tax ...

  10. 关于Win8对getElementsByTagName等dom方法兼容性的替代方法

    在对Twebbrowser进行dom编程时,引用MSHTML并使用其中的HTMLDocument; IHTMLElementCollection;IHTMLElement;能获得较好的代码提示 其中封 ...