如何看懂IL代码--转载

1//示例一:输出整数的立方值。
  2private void PrintCube( int i )
  3{
  4    int cube = i * i * i;
  5    Console.WriteLine( cube );
  6}
  7//方法签名。
  8/// hidebysig:MethodAttributes 枚举值之一,指示此方法按名称和签名隐藏,否则只
  9/// 按名称隐藏。
 10/// cil managed:未查到具体资料,应是“受中间语言管理”之意。
 11
 12.method private hidebysig instance void 
 13          PrintCube(int32 i) cil managed
 14  {
 15    // 代码大小       15 (0xf)
 16    .maxstack  2
 17    /**//// 在 .locals 部分声明所有的局部变量。
 18    .locals init ([0] int32 cube)    /**//// 第一个名局部变量,int 型,名为 cube。索
 19                                    /// 引从 0 开始。
 20    IL_0000:  nop    /**//// no operation.
 21    IL_0001:  ldarg.1    /**//// load argument 第一个方法参数入栈,比如“3”。索引号
 22                        /// 从 1 开始,而不是从 0 开始。
 23    IL_0002:  ldarg.1    /**//// 再次向堆栈压入第一个方法参数,又一个“3”。
 24    IL_0003:  mul    /**//// multiply 计算堆栈最顶上两个数的乘积 3×3,并把结果入栈,
 25                    /// 即堆栈最顶部是 9 了。
 26    IL_0004:  ldarg.1    /**//// 再次压入第一个方法参数“3”。
 27    IL_0005:  mul    /**//// 堆栈最顶上是“3”,第二是“9”,计算 3×9,此时 27 入栈。
 28    IL_0006:  stloc.0    /**//// pop value from stack to local variable 堆栈最顶上的
 29                        /// 值“27”出栈,并被赋给索引位置“0”处的局部变量 cube,
 30                        /// 即内存中变量 cube 的值为“27”。
 31    IL_0007:  ldloc.0    /**//// 局部变量 cube 的值“27”入栈。
 32    IL_0008:  call       void [mscorlib]System.Console::WriteLine(int32)
 33                        /**//// 控制台输出堆栈最顶上的 32 位整数“27”。
 34    IL_000d:  nop    /**//// no operation. 35    IL_000e:  ret    /**//// return from method. 36  } // end of method Program::PrintCube 37//示例二:把字符串拆分成字符,并按顺序每行输出一个字符 38public void SeparateString( string source ) 39{ 40    if( source == null ) 41        return; 42 43    int count = source.Length; 44 45    char c; 46    for( int i = 0; i < count; i++ ) 47    { 48        c = source[ i ]; 49        Console.WriteLine( c ); 50    } 51} 52 53.method public hidebysig instance void  54          SeparateString(string source) cil managed 55  { 56    // 代码大小       55 (0x37) 57    .maxstack  2 58    .locals init ([0] int32 count, 59             [1] char c, 60             [2] int32 i, 61             [3] bool CS$4$0000)    /**//// 索引为“3”的这个布尔型局部变量在 C# 代 62                                    /// 码中并未显式声明,是编译器编译时添加的, 63                                    /// 用于保存执行过程中布尔运算的结果,比如比 64                                    /// 较 source 是否为空时,以及比较 i<count 时。 65    IL_0000:  nop 66    IL_0001:  ldarg.1    /**//// 方法参数 source 的值入栈。 67    IL_0002:  ldnull    /**//// “空引用”null入栈。 68    IL_0003:  ceq    /**//// compare equal 比较栈顶的 null 和第二项的 source 是否相等,并 69                    /// 把结果 0(false,source 不为空)或 1(true,source 为空)入栈。 70    IL_0005:  ldc.i4.0    /**//// 32 位整型数“0”入栈。 71    IL_0006:  ceq    /**//// 比较栈顶的“0”和堆栈的第二项,第二项可能是“0”,也可能 72                    /// 是“1”。比较的结果“1”或“0”入栈。 73    IL_0008:  stloc.3    /**//// 栈顶的“1”或“0”出栈,被保存到索引为“3”的局部变量中。 74    IL_0009:  ldloc.3    /**//// 执行后,栈顶为“1”(source 不为空)或“0”(source 为空)。 75    IL_000a:  brtrue.s   IL_000e    /**//// branch on non-false or non-null 判断栈顶是否 76                                    /// 为“1”,如果是,跳转到第“IL_000e”行;否则 77                                    /// 继续往下执行。 78 79    IL_000c:  br.s       IL_0036    /**//// unconditional branch 当栈顶为“0”时,才会 80                                    /// 执行到这一行,这一行的执行结果是程序无条件 81                                    /// 跳转到第“IL_0036”行。 82 83    IL_000e:  ldarg.1 84    IL_000f:  callvirt   instance int32 [mscorlib]System.String::get_Length()     85                        /**//// 对堆栈最顶上的字符串调用其获取长度的实例方法,长度值被入栈。 86                        /// “get_Length()”实际是字符串 Length 属性的“get”部分。 87    IL_0014:  stloc.0    /**//// 局部变量 count 被赋值为字符串长度。 88    IL_0015:  ldc.i4.0 89    IL_0016:  stloc.2    /**//// 局部变量 i 被赋值为 0。 90    IL_0017:  br.s       IL_002e    /**//// 无条件跳转到第“IL_002e”行。 91 92    IL_0019:  nop 93    IL_001a:  ldarg.1 94    IL_001b:  ldloc.2 95    IL_001c:  callvirt   instance char [mscorlib]System.String::get_Chars(int32)     96                        /**//// source 中索引为 i 处的 char 值入栈。 97    IL_0021:  stloc.1 98    IL_0022:  ldloc.1 99    IL_0023:  call       void [mscorlib]System.Console::WriteLine(char)    /**//// char 值被输100                                                                        /// 出到控制台。101    IL_0028:  nop102    IL_0029:  nop103    IL_002a:  ldloc.2    /**//// i 值入栈。104    IL_002b:  ldc.i4.1    /**//// 32 位整数 1 入栈。105    IL_002c:  add    /**//// i+1 的结果入栈。106    IL_002d:  stloc.2    /**//// i=i+1。107    IL_002e:  ldloc.2    /**//// i 值入栈。108    IL_002f:  ldloc.0    /**//// count 值入栈。109    IL_0030:  clt    /**//// compare less than 比较 i<count 是否为真,比较结果入栈。110    IL_0032:  stloc.3111    IL_0033:  ldloc.3112    IL_0034:  brtrue.s   IL_0019    /**//// 如果 i<count 则跳转到第“IL_0019”行。113114    IL_0036:  ret115  } // end of method Program::SeparateString116117

时间: 2024-12-06 23:47:35

如何看懂IL代码--转载的相关文章

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

一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉厉. 然后开始接触IL,了解了一段时后才发现原来读懂IL代码并不难.进入正题   1.1  什么是IL IL是.NET框架中中间语言(Intermediate Language)的缩写.使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直

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

一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 .感谢 @冰麟轻武 的指点 你没有看第一篇?  点这里看第一篇 读懂IL代码就这么简单(一) IL指令大全 :IL指令详解 IL反编译工具: ILDasm 知识点回顾: Managed Heap(托管堆):用于存放引用类型的值 Evaluation Statck(计算栈):临时存放值类型数据,引用

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

原文:读懂IL代码就这么简单(三)完结篇 一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认为,重要的地方都差不多 写到了, 最后一篇决定把之前的内容全部整合起做一个综合的例子,然后简单的解释下IL指令的含义,及在内存中的变化 如果你没有看前两篇请狂点这里 读懂IL代码就这么简单 (一) 读懂IL代码就这么简单(二) IL指令大全 :IL指令详解

读懂IL代码(二)

上一篇提到了最基本的IL代码,应该是比较通俗易懂的,所以有了上一篇的基础之后,这篇便要深入一点点的来讲述了. 首先我必须再来说一些重要的概念: Evaluation Stack(评估栈):这是由.NET CLR在执行时候自动管理的记忆体,每一个线程都有自己的评估栈,也就是说,它是用来存储临时变量的线程栈(应该可以这么理解).值类型存储数据,引用类型存储地址. Call Stack(调用栈):这也是由.NET CLR在执行时候自动管理的记忆体,每一个线程都有自己的调用栈,每一次调用method,就

一篇文章看懂iOS代码块Block

iOS代码块Block 概述 代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量.作为参数.作为返回值,特殊地,Block还可以保存一段代码,在需要的时候调用,目前Block已经广泛应用于iOS开发中,常用于GCD.动画.排序及各类回调 注: Block的声明与赋值只是保存了一段代码段,必须调用才能执行内部代码 Block变量的声明.赋值与调用 Block变量的声明 Block变量的声明格式为: 返回值类型(^Bl

一个例子看懂异步代码执行效率

异步代码采用线程池,提供代码执行的并行性,不阻塞当前线程,实例代码,模拟三个耗时操作,分别耗时为1000.1500.1800ms,提供同步与异步的实现方式,Main中以同步异步的方式执行,对比执行时间,同步执行方式为各个方法的执行时间总和,而异步执行方式为最长的那个时间.ps:实际执行情况可能有其他的一些微不足道开销,但大体能反应异步的执行效率. class OutHelper { public DateTime Method1() { Thread.Sleep(1000); return Da

一份只有巨佬才能看懂的代码

你能一眼看出这份代码在干啥么?? 1 #include <cstdio> 2 #include <cstring> 3 #define _______ for 4 #define ________ int 5 const ________ ______ = 1000050; 6 const ________ _________ = 0x20afbf^04503406^3287225; 7 const ________ __________ = 0x205db7^020352146^

教你看懂网上流传的60行JavaScript代码俄罗斯方块游戏

早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用C写一个功能基本齐全的俄罗斯方块的话,大约需要1000行代码的样子.所以60行乍一看还是很让人吃惊的. 但是读懂了代码之后发现其实整个程序并没有使用什么神秘的技术,只不过是利用一些工具或者JavaScript本身的技巧大大简化了代码. 总结起来主要是以下三点 1.使用eval来产生JavaScript代码,减小了代码体积 2.以字符串作为

写在最前面 - 《看懂每一行代码 - kubernetes》

我要写什么 <看懂每一行代码 - kubernetes>会包含k8s整个项目的源码解析,考虑到门槛问题,在开始分析k8s之前我会通过一些更低难度的golang开源项目讲解来帮助大家提升golang编码技能:然后通过与k8s相关的一些项目的讲解,打通阻碍k8s学习的一些大障碍:最后集中火力,将kubernetes项目的整个源码吃透. 总体来说,本系列计划分三步走完成源码层面掌握k8s的目标: golang技能提升 k8s依赖技术 k8s核心组件 目前关于k8s应用的教程已经很多了,其中不乏相当优