浅析.NET IL代码

 

一、前言

IL是什么?

Intermediate Language (IL)微软中间语言

C#代码编译过程?

C#源代码通过LC转为IL代码,IL主要包含一些元数据和中间语言指令;

JIT编译器把IL代码转为机器识别的机器代码。如下图

语言编译器:无论是VB code还是C# code都会被Language Compiler转换为MSIL

MSIL的作用:MSIL包含一些元数据和中间语言指令

JIT编译器的作用:根据系统环境将MSIL中间语言指令转换为机器码

为什么ASP.NET网站第一次运行时会较慢,而后面的执行速度则会相对快很多?

当你第一次运行.NET开发的站点时,CLR会将MSIL通过JIT进行编译,最终转换为执行速度非常快的Native Code。这可以解释。

为什么要了解IL代码?

如果想学好.NET,IL是必须的基础,IL代码是.NET运行的基础,当我们对运行结果有异议的时候,可以通过IL代码透过表面看本质;

IL也是更好理解、认识CLR的基础;

大量的实例分析是以IL为基础的,所以了解IL,是读懂他人代码的必备基础,同时自己也可以获得潜移默化的提高;

二、如何把ILDasm导入到VS中

想要看IL代码需要使用ILDasm工具,工具一般在电脑的

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe

把ILDasm导入到VS工具中,使用方便,具体如下:工具 - > 外部工具

  

导入之后,vs工具里面就有ILDasm工具了。以后想看IL代码方便多了。

IL代码通过ILDasm反编译后(左图),ILDasm图标意义(右图)

  

三、分析IL代码

在分析IL代码之前,要先理解几个概念:

Managed Heap(托管堆):这就是NET中的托管堆,用来存放引用类型,它是由GC(垃圾回收器自动进行回收)管理;

Call Stack(调用堆栈):调用堆栈:调用堆栈是一个方法列表,按调用顺序保存所有在运行期被调用的方法。

Evaluation Stack(计算堆栈):每个线程都有自己的线程栈,IL 里面的任何计算,都发生在 Evaluation Stack 上,其实就是一个 Stack 结构。可以 Push,也可以 Pop。

可以对照IL指令:指令列表,一步一步来分析IL代码

1、用C#写一个简单控制台应用程序

  1. using System;
  2.  
  3. namespace ILDemo
  4. {
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. int i = 1;
  10. int j = 2;
  11. int k = 3;
  12. int answer = i + j + k;
  13. Console.WriteLine("i+j+k=" + answer);
  14. Console.ReadKey();
  15. }
  16. }
  17. }

2、 用ILDasm打开bin下的.exe文件查看代码,具体IL代码如下:

  1. .method private hidebysig static void Main(string[] args) cil managed
  2. {
  3. .entrypoint
  4. // 代码大小 42 (0x2a)
  5. .maxstack 2
  6. .locals init ([0] int32 i,
  7. [1] int32 j,
  8. [2] int32 k,
  9. [3] int32 answer)
  10. IL_0000: nop
  11. IL_0001: ldc.i4.1
  12. IL_0002: stloc.0
  13. IL_0003: ldc.i4.2
  14. IL_0004: stloc.1
  15. IL_0005: ldc.i4.3
  16. IL_0006: stloc.2
  17. IL_0007: ldloc.0
  18. IL_0008: ldloc.1
  19. IL_0009: add
  20. IL_000a: ldloc.2
  21. IL_000b: add
  22. IL_000c: stloc.3
  23. IL_000d: ldstr "i+j+k="
  24. IL_0012: ldloc.3
  25. IL_0013: box [mscorlib]System.Int32
  26. IL_0018: call string [mscorlib]System.String::Concat(object,
  27. object)
  28. IL_001d: call void [mscorlib]System.Console::WriteLine(string)
  29. IL_0022: nop
  30. IL_0023: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  31. IL_0028: pop
  32. IL_0029: ret
  33. } // end of method Program::Main

3、会用到的IL指令:

nop:无操作

ret:从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。

call:调用由传递的方法说明符指示的方法。

box:将值类转换为对象引用,就是装箱,同理可以知道拆箱unbox

ldc.i4.X:把int32的值推送到计算堆栈

stloc.X:把计算堆栈顶部的值放到调用堆栈索引为X处

ldloc.X:把调用堆栈X处的值复制到计算堆栈

4、理解注释后的代码

  1. .method private hidebysig static void Main(string[] args) cil managed
  2. {
  3. .entrypoint //程序入口
  4. // 代码大小 42 (0x2a)
  5. .maxstack 2 // 计算出计算堆栈的能存几个值
  6.  
  7. .locals init ([0] int32 i,
  8. [1] int32 j,
  9. [2] int32 k,
  10. [3] int32 answer) //定义int32类型的i,j,k,answer
  11.  
  12. IL_0000: nop //无操作
  13.  
  14. IL_0001: ldc.i4.1 //把i的值放到计算堆栈上
  15. IL_0002: stloc.0 //把计算堆栈顶部的值(i的值)放到调用堆栈索引0处
  16. IL_0003: ldc.i4.2 //把j的值放到计算堆栈上
  17. IL_0004: stloc.1 //把计算堆栈顶部的值(j的值)放到调用堆栈索引1处
  18. IL_0005: ldc.i4.3 //把k的值放到计算堆栈上
  19. IL_0006: stloc.2 //把计算堆栈顶部的值(k的值)放到调用堆栈索引2处
  20.  
  21. IL_0007: ldloc.0 //把调用堆栈索引为0处的值复制到计算堆栈
  22. IL_0008: ldloc.1 //把调用堆栈索引为1处的值复制到计算堆栈
  23. IL_0009: add //相加
  24. IL_000a: ldloc.2 //把调用堆栈索引为2处的值复制到计算堆栈
  25. IL_000b: add //相加
  26. IL_000c: stloc.3 //把计算堆栈顶部的值(add的值)放到调用堆栈索引3处
  27. IL_000d: ldstr "i+j+k=" //推送对元数据中存储的字符串的新对象引用。
  28. IL_0012: ldloc.3 //把调用堆栈索引为3处的值复制到计算堆栈
  29.  
  30. IL_0013: box [mscorlib]System.Int32 //装箱
  31. IL_0018: call string [mscorlib]System.String::Concat(object,object) //调用内部方法
  32. IL_001d: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine
  33. IL_0022: nop //无操作
  34. IL_0023: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() //调用ConsoleKey
  35. IL_0028: pop //无操作
  36. IL_0029: ret //return
  37. } // end of method Program::Main

四、最后

IL是跟我高级架构经理的分享和博客园相关的博客学习总结的,最后留2个题目,也是我的高级架构经理分享中提到的两个好玩的问题,也能看出对IL的掌握的程度

答案后续公布。

最后、加关注

如果本文对你有帮助,请点击右下角【好文要顶】和【关注我】;也可以加QQ群:528743692 一起交流学习

 
分类: MSIL

IL代码的更多相关文章

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

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

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

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

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

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

  4. 详解.NET IL代码

    一.前言 IL是什么? Intermediate Language (IL)微软中间语言 C#代码编译过程? C#源代码通过LC转为IL代码,IL主要包含一些元数据和中间语言指令: JIT编译器把IL ...

  5. 如何通过ildasm/ilasm修改assembly的IL代码

    原文地址:http://kb.cnblogs.com/page/101162/ 这段时间为跟踪一个Bug而焦头烂额,最后发现是Framework的问题,这让人多少有些绝望.所以到微软论坛提了个帖子,希 ...

  6. 用ildasm/ilasm修改IL代码

    原文地址:http://www.cnblogs.com/dudu/archive/2011/05/17/ildasm_ilasm_il.html 在开发中遇到这样一个场景,需要修改一个dll文件(.N ...

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

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

  8. 读懂IL代码(四)

    这一篇是IL系列的最后一篇的,主要是要说一下IL中的流程控制.我相信,经过前面三篇的介绍,看IL代码应该不是什么大问题了吧.好吧,闲话不多说了,就来简单的说一下吧. 还是跟前几篇一样,以例子来解释说明 ...

  9. 读懂IL代码(三)

    由于要写毕业论文的缘故,最近比较没有时间写,总是要抽出时间抽出时间.诶,这样的生活比较烦躁. 这一篇主要写委托.类.方法的IL代码,一一来说明. 委托:搞过C#的都应该清楚,委托实际上是一个类.编译器 ...

  10. 读懂IL代码(二)

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

随机推荐

  1. BZOJ 3359: [Usaco2004 Jan]矩形( dp )

    数据范围这么小..怎么乱搞都可以吧... 先排序一遍然后O(n²) dp --------------------------------------------------------------- ...

  2. Jsp分页实例---假分页

    今天总结一个JSP假分页的实例,由基本功能由js实现. 相较前一篇真分页中程序的功能,丰富了一些.具备首页尾页,和页面跳转功能. 首先还是来总结一下真假分页的优缺点和特性吧. 假分页:从数据库中取出所 ...

  3. 11-UIKit(Storyboard、View的基本概念、绘制图形、UIBezierPath)

    目录: 1. Storyboard 2. Views 3. View的基本概念介绍 4. 绘制图形 5. UIBezierPath 回到顶部 1. Storyboard 1.1 静态表视图 1)Sec ...

  4. mysql字符串连接,重复等字符串函数总结

    mysql concat()函数 MySQL的concat函数可以连接一个或者多个字符串,如 select concat('10'); 输出 10 select concat('11','22','3 ...

  5. VMware Player 使用错误集锦

    1.执行VMware Player 弹出"开机时出错:内部错误"的提示.虚拟机执行不了,例如以下图: 解决的方法: 以管理员身份执行.         可能如今登录windows的 ...

  6. 【floyd】HDU 1874 畅通project续

    之后的题解偏重有用/总结性质,尽量理解算法本身而不是题,时间复杂度什么的也能够放放. 非常久之前做过这个题,当时使用dijkstra做的,关于几个最短路算法,分类的话能够分为下面几种. 1.单源最短路 ...

  7. android ADT 设置编辑字体

    新配置的android ADT 设置编辑字体的时候  可能里面没有我们想要的Courier new 这种舒服的字体 那么就在 字体选项窗口的  做下端 有个显示更多字体的链接  然后就显示微软的所有字 ...

  8. 阿里云CentOS配置iptables防火墙[转]

    虽说阿里云推出了云盾服务,但是自己再加一层防火墙总归是更安全些,下面是我在阿里云vps上配置防火墙的过程,目前只配置INPUT.OUTPUT和FORWORD都是ACCEPT的规则 一.检查iptabl ...

  9. javascript笔记整理(函数)

    javascript函数的声明和调用将完成某一特定功能的代码集合起来,可以重复使用的代码块. 一.函数的声明方式(创建) A.基本语法(function  关键字)function 函数名([参数1] ...

  10. <转载>div+css布局教程之div+css常见布局结构定义

    在使用div+css布局时,首先应该根据网页内容进行结构设计,仔细分析和规划你的页面结构,你可能得到类似这样的几块: 页面层容器.页面头部.标志和站点名称.站点导航(主菜单).主页面内容.子菜单.搜索 ...