zoukankan      html  css  js  c++  java
  • IL代码

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

     

    一前言

      对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉厉

    然后开始接触IL,了解了一段时后才发现原来读懂IL代码并不难。进入正题

       1.1  什么是IL

      IL是.NET框架中中间语言(Intermediate Language)的缩写。使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermediate Language)的代码(来源百度)

       1.2 为什么要了解IL

        在很多时候不明白代码是如何操作时就可以通过IL指令来解释,比如,装箱,拆箱是否只是听别人说或者书上讲是怎么怎么实现的,自己是否证实过呢?了解IL指令你可清楚看到是每一步是如何处理的

       1.3  怎么学IL

       世上有个定律叫“二八定律” ,80%的功能,只要用20%的技术就可以完成,但要完成另外20%可能就需要80%技术了,对于IL代码也是如此,有200多个指令,我们只需要用到其20%的指令就可以解决我们80%的问题了,所以我不会写太多,只是让大家能看懂普通的程序代码编译成IL代码后就行了,还有就是要多看,IL代码的每一条指令都是特定的意思,看得多了自然就懂了,当对自己代码有疑问时尝试看看它对应的IL代码,也许你会了解得更多。

     IL指令大全  点这里

     IL代码编译器 ILDasm   点这里

    二 如何查看IL代码

      2.1 步骤

       1 编写代码并编译通过

       2  找到源文件的obj文件下的 .exe文件

         3 导入到ILDasm中反编译成IL代码

    上图

    1 -2步                                                     3  导入到ILDasm中                      

               

      ILDasm中图标含义

     

    三  如何读IL(大致了解)

      以上步骤完成后我们就可以看到代码被编译后的IL代码,以下部份将会对每一条IL指令做详细的解释

    C#代码 

    复制代码
    1         static void Main(string[] args)
    2         {
    3             int i = 1;
    4             int j = 2;
    5             int k = 3;
    6             Console.WriteLine(i+j+k);
    7         }
    复制代码

    IL代码

    复制代码
     1  .method private hidebysig static void  Main(string[] args) cil managed
     2 {
     3   .entrypoint  //程序入口
     4   // Code size       19 (0x13)
     5   .maxstack  2  //定义函数代码所用堆栈的最大深度,也可理解为占用栈的变量个数
     6   //以下我们把它看做是完成代码中的初始化
     7   .locals init (int32 V_0,int32 V_1,int32 V_2) //定义 int 类型参数 V_0,V_2,V_3 
     8   IL_0000:  nop //即No Operation 没有任何操作,我们也不用管它
     9   IL_0001:  ldc.i4.1    //加载第一个变量i  
    10   IL_0002:  stloc.0     //把i 压入栈中第0个位置
    11   IL_0003:  ldc.i4.2    //加载第二个变量 j 
    12   IL_0004:  stloc.1     //把j 压入栈中第1个位置
    13   IL_0005:  ldc.i4.3    //加载第三个变量k
    14   IL_0006:  stloc.2     //把 k 压入栈中第2个位置
    15 
    16    //上面代码初始化完成后要开始输出了,所要把数据从栈中取出
    17 
    18   IL_0007:  ldloc.0     //取出栈中位置为0的元素 (i)
    19   IL_0008:  ldloc.1     //取出栈中位置为1的元素 (j)
    20   IL_0009:  add         // 做加法操作
    21   IL_000a:  ldloc.2     // 取出栈中位置为2的元素(k)
    22   IL_000b:  add         // 做加法操作
    23   IL_000c:  call       void [mscorlib]System.Console::WriteLine(int32) //调用输出方法
    24   IL_0011:  nop
    25   IL_0012:  ret         //即为  return  标记 返回值
    26 } // end of method Program::Main
    复制代码

     指令详解

    .maxstack:代码中变量需要在栈中占用几个位置

    .locals init (string V_0,string V_1):定义变量

    nop:即No Operation 没有任何操作,我们也不用管它,

    ldstr.:即Load String 把字符串加载到Evaluation Stack中 

    stloc.:把Evaluation Stack中的值压入到Call Stack中

    ldloc.:把Call Stack中的值弹出存入 Evaluation Stack中   以上两条指令为相互的操作stloc压入,ldloc弹出

    call:  调用指定的方法

    ret: 即return  标记返回

      每一句IL代码都加了注释后,是不是觉得IL代码其实并不难呢,因为它的每一条指令都是固定的,你只要记住了,看IL代码就比较轻松了。

    四 如何读IL(深入了解)

    4.1 提出问题

      有了上面的一点IL基础后,现在我们来深入一点点,

      有如下几个问题:

      1  当 ldc.i4.1 这一指定加载 “i” 这个变量后并没有马上存入栈中,而是要执行 stloc.0 后才被存入栈中,那没存入栈前是存在哪里的呢?

      2 ldloc.0  把元素取出来后,存在哪里的?

      3 add    操作是在哪里进行的?

    4.2 概念引入

      Managed Heap:這是動態配置(Dynamic Allocation)的記憶體,由 Garbage Collector(GC)在執行時自動管理,整個 Process 共用一個

      Managed Heap(我理解为托管堆,存储引用类型的值)。

      Evaluation Stack:這是由 .NET CLR 在執行時自動管理的記憶體,每個 Thread 都有自己專屬的 Evaluation Stack(我理解为类似一个临时存放值类型数据的线程栈)

      Call Stack:這是由 .NET CLR 在執行時自動管理的記憶體,每個 Thread 都有自己專屬的 Call Stack。每呼叫一次 method,就會使得 Call Stack 上多了一個 Record     Frame;呼叫完畢之後,此 Record Frame 會被丟棄(我理解为线程栈,用于存放值类型数据)

    4.3  IL指令详解

     对三个名词做解释后现在我们再来仔细看看执行IL指令时,对应的变量是如何存放的

    IL_0001:  ldc.i4.1    //加载第一个变量i  
    首先对 ldc.i4.1 做下细解:变量的值为1 时IL指令就是ldc.i4.1 ,变量值为2 时IL指令就是ldc.i4.2,依此类推一直到ldc.i4.8
    当为-1 时IL指令为ldc.i4.M1,当超过8时就是一个统一指令 ldc.i4.S

    IL_0001: ldc.i4.1 //加载第一个变量i

    当执行这一条指令时会把变量i 的值存入Evaluation Stack中做临时存储



    IL_0002:  stloc.0     //把i 压入栈中第0个位置
    当执行这一条指信时会把Evaluation Stack 中的 i 取出存入Call Stack中的第0个位置



    IL_0007:  ldloc.0     //取出栈中位置为0的元素 (i)
    当执行这条指令时会将 Call Stack中的位置为0的元素取出存入Evaluation Stack 等待做加法的指令 Add

      IL_000b:  add         // 做加法操作
      add 这一指令是在Evaluation Stack中完成的(会把需要的值从CallStack中取到Evaluation Stack中计算)
    4.4 问题回答
      以上内容看完开始的问题相应也解决了
      1 ldc.i4.1 把值取出来后先存在 Evaluation Stack中 执行了stloc.0 后才会存入Call Stack中
      2 ldloc.0 把取出来后也是先存在 Evaluation Stack 等持指令
      3 add 操作是在 Evaluation Stack中处理的


    以上把IL指令是如何操作内存中的值做了一点很基本的介绍,让大家在了解IL指令时,知道是如何操作内存中的值的。我想对于理解IL指令或许更透彻一点。



    五 总结



      这一篇只写了IL中最基本的几个指令,然后讲解了IL指令是如何操作内存中数据的。古人云:水得一口一口喝,路得一步一步走,步子迈得大了容易扯着蛋,慢慢来内容虽然少了点,但是还会有下篇的。下一篇还是会写IL的一些基本指令,我会结合我自己的理解,尽量把文字写得通俗一点,让大家更容易理解。

    另外本人水平有限,难免会有理解错误的地方,如有发现,请指出!我会马上修改,以免误导他人。

    如果您觉得本文能给您带来一点收获不妨点下 推荐 让更多的人了解IL,您的推荐是我源源不断的写作力
    如果觉得我的博客还不错,那就关个注吧~

    成长在于积累

     参考资料:《你必须知道的.net》,MSDN

     

    C#基础知识

     
    摘要: 一前言 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉厉。然后开始接触IL,了解了一段时后才发现原来读懂IL代码并不难。进入正题 1.1 什么是IL IL是.NET框架中中间语言(Intermediate Language)的缩写。使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermediate Language)的代码(来源百度) 1.2 为什么要了解IL 在很多时候不明白代...阅读全文
    posted @ 2013-10-15 08:56 Zery-zhang 阅读(1704) | 评论 (29) 编辑
     
    摘要: 先来了解下操作XML所涉及到的几个类及之间的关系 如果大家发现少写了一些常用的方法,麻烦在评论中指出,我一定会补上的!谢谢大家 * 1 XMLElement 主要是针对节点的一些属性进行操作 * 2 XMLDocument 主要是针对节点的CUID操作 * 3 XMLNode 为抽象类,做为以上两类的基类,提供一些操作节点的方法阅读全文
    posted @ 2013-10-12 09:04 Zery-zhang 阅读(1186) | 评论 (26) 编辑
     
    摘要: 对于文件夹,文件档的操作一直处于一知半解状态,有时间闲下来了,好好练习了一把,对文档,文件的操作有了一个基本的认知, 若要深入了解,还是得通过实际的项目才行了,好了废话不多说,上酸菜!阅读全文
    posted @ 2013-09-13 09:05 Zery-zhang 阅读(1400) | 评论 (9) 编辑
     
    摘要: 让你彻底理解 “==”与 Equals阅读全文
    posted @ 2013-09-05 09:06 Zery-zhang 阅读(158) | 评论 (1) 编辑
     
    摘要: 理解 new阅读全文
    posted @ 2013-08-18 23:54 Zery-zhang 阅读(105) | 评论 (1) 编辑
     
    摘要: 对于在.Net 开发中常用到的关键字,做一个简单的总结,结合书本与自己的理解,也算是自己的总结吧1 BaseBase 关键字,常用的方法有以下几种1 访问基类中的成员 1 Class SomeClass 2 { 3 public void Print() 4 { 5 Console.Write("Hello World"); 6 } 7 } 8 9 Class OtherClass:SomeClass10 {11 public void PrintStr()12 {13 Console.Wri...阅读全文
    posted @ 2013-03-06 21:54 Zery-zhang 阅读(29) | 评论 (0) 编辑
     
    标签: ILIL代码
  • 相关阅读:
    二十八、线程安全
    一、JAVA内存区域与内存溢出异常
    一、SQLite学习
    排列问题
    2016年秋季个人阅读计划
    有向图强连通分量求解【转】
    《梦断代码》阅读笔记之五
    《梦断代码》阅读笔记之四
    软件工程个人总结
    《梦断代码》阅读笔记之三
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3370028.html
Copyright © 2011-2022 走看看