·IL代码分析方法

·IL命令解析

·.NET学习方法论

1.引言

自从『你必须知道.NET』系列开篇以来,受到大家很多的关注和支持,给予了anytao巨大的鼓励和动力。俱往昔,我发现很多的园友都把目光和焦点注意在如何理解IL代码这个问题上。对我来说,这真是个莫大的好消息,因为很明显我们的思路慢慢的从应用向底层发生着转变,技巧性的东西是一个方面的积累,底层的探索在我认为也是必不可少的修炼。如果我们选择了来关注这项修炼,那么我们就应该选择如何来着手这项修炼,首先关注anytao的『你必须知道的.NET』系列可以给你提供一个捷径,少花一些功夫;其次对大师级的作品也应有更深入的了解,如《Applied Microsoft .NET Framework Programming》、《.NET本质论》;再次,就是像我一样从博客园和MSDN的知识库中不断的成长。呵呵,除了给自己做了个广告之外,我认为不管是何种途径,了解和认识IL代码,对于我们更深刻的理解.NET和.NET应用之上的本质绝对有不一样的收获,这也就是本文研究和分享的理由。

那么,我们要了解IL代码,就要知道了解IL的好处,时间对每个程序设计师来说都是宝贵的,你必须清楚自己投资的价值再决定投入的资本。对于.NET程序员来说,IL代码意味着:

·通用的语言基础是.NET运行的基础,当我们对程序运行的结果有异议的时候,如何透过本质看表面,需要我们从本质入手来探索,这时IL是你必须知道的基础;

·元数据和IL语言是CLR的基础,了解必要的中间语言是深入认识CLR的捷径;

·大量的事例分析是以IL来揭密的,因此了解IL是读懂他人代码的必备基础,可以给自己更多收获。

很明显这些优越性足以诱惑我们花时间和精力涉猎其中。然而,了解了IL的好处,并不意味着我们应该过分的来关注IL,有人甚至可以洋洋洒洒的写一堆IL代码来实现一个简单Hello world程序,但是正如我们知道的那样,程序设计已经走过了几十年的发展,如果纯粹的陶醉在历史中,除了脑子不好,没有其他的解释。不然看见任何代码都以IL的角度来分析,又将走进另一个误区,我们的宗旨是追求但不过分。

因此,有了上述了应该了解的理由和不应该过分的基线,在摆正心态的前提下,本文开始以作者认为的方式来展开对IL代码的认识,作者期望通过本文的阐述与分析使得大家都能对IL有个概观之解,并在平时的项目实践中使用这种方法通过了解自己的代码来了解.NET。我想,这种方法应该是值得提倡和发挥的最佳实践,不知你信不信呢?呵呵。

2.使用工具

俗话说,工欲善其事,必先利其器。IL的器主要就是ILadsm.exe和reflector.exe,这两个工具都是了解IL的基础,其原理都是通过反射机制来查看IL代码。

·ILadsm.exe

打开.NET Framework SKD 命令提示行,输入ildasm回车即可打开,如图所示:

上图是我们熟悉的《第十三回:从Hello, world开始认识IL》中的示例,其中的树形符号代表的意思,可以从MSDN的一张经典帮助示例来解释,如下图所示:

图表来源:MSDN)

·

Reflector是Lutz Roeder开发的一个让人兴奋的反编译利器,目前的版本是Version 5.0.35.0,可以支持.NET3.0,其功能也相当强大,在使用上也较ILDASM更加灵活,如图所示:

可以方便的反编译为IL、C#、VB、Delphi等多种语言,是深入了解IL的最佳利器。

在本文中我们以最简单的ILadsm.exe为说明工具。

3.分析结构

分析IL结构,就参阅《第十三回:从Hello, world开始认识IL》 ,已经有了大致的介绍,在此不需要进行过多的笔墨,实际上IL的本身的结构也不是很复杂,了解了大致的体系即可。

4.解析常用命令

我们在了解了IL文件结构的基础上,通过学习常用的IL命令,就可以基本上对IL达到了了解不过分的标准,因此对IL常用命令的分析就是本文的重点和要点。我们通过对常用命令的解释、示例与分析,逐步了解你陌生的语言世界原来也很简单。

IL指令集包括了基础指令集和对象模型指令集大概有近200多个,对我们来说消化这么多的陌生指令显然不是明智的办法,就行高级语言的关键字一样,我们只取其一瓢独饮,抓大放小的革命传统同样是有效的学习办法,详细的指令集解释请下载[MSIL指令速查手册]。

4.1 newobj和initobj

newobj和intiobj指令就像两个兄弟,常常让我们迷惑在其然而不知其所以然,虽然认识但是不怎么清楚,这种感觉很郁闷,下面就让我们看看他们的究竟:

代码引入

指令说明

深入分析

从上面的代码中,我们可以得出哪些值得推敲的结论呢?

MSDN给出的解释是:newobj用于分配和初始化对象;而initobj用于初始化值类型。

那么newobj又是如何分配内存,完成对象初始化;而initobj又如何完成对值类型的初始化呢?

显然,关于newobj指令,在《第五回:深入浅出关键字---把new说透》中,已经有了一定的介绍,简单说来关于newobj我们有如下结论:

·从托管堆分配指定类型所需要的全部内存空间。

·在调用执行构造函数初始化之前,首先初始化对象附加成员:一个是指向该类型方法表的指针;一个是SyncBlockIndex,用于进行线程同步。所有的对象都包含这两个附加成员,用于管理对象。

·最后才是调用构造函数ctor,进行初始化操作。并返回新建对象的引用地址。

而initobj的作用又可以小结为:

·构造新的值类型,完成值类型初始化。值得关注的是,这种构造不需要调用值类型的构造函数。具体的执行过程呢?以上例来说,initobj MyStruct的执行结果是,将MyStruct中的引用类型初时化为null,而基元类型则置为0。

因此,值类型的初始化可以是:

//initobj方式初始化值类型

initobj    Anytao.net.My_Must_net.IL.MyStruct

同时,也可以直接显示调用构造函数来完成初始化,具体为

MyStruct ms = new MyStruct(123);

对应于IL则是对构造函数cto的调用。

//调用构造函数方式初始化值类型

call       instance void Anytao.net.My_Must_net.IL.MyStruct::.ctor(int32)

·Initobj还用于完成设定对指定存储单元的指针置空(null)。这一操作虽不常见,但是应该引起注意。

由此可见,newobj和initobj,都具有完成实例初始化的功能,但是针对的类型不同,执行的过程有异。其区别主要包括:

·newobj用于分配和初始化对象;而initobj用于初始化值类型。因此,可以说,newobj在堆中分配内存,并完成初始化;而initobj则是对栈上已经分配好的内存,进行初始化即可,因此值类型在编译期已经在栈上分配好了内存。

·newobj在初始化过程中会调用构造函数;而initobj不会调用构造函数,而是直接对实例置空。

·newobj有内存分配的过程;而initobj则只完成数据初始化操作。

关于对象的创建,还有其他的情况值得注意,例如:

·Newarr指令用来创建一维从零起始的数组;而多维或非从零起始的一维数组,则仍由newobj指令创建。

·String类型的创建由ldstr指令来完成,具体的讨论我们在下文来展开。

4.2 call、callvirt和calli

call、callvirt和calli指令用于完成方法调用,这些正是我们在IL中再熟悉不过的几个朋友。那么,同样是作为方法调用,这几位又有何区别呢?我们首先对其做以概括性的描述,再来通过代码与实例,进入深入分析层面。

·call使用静态调度,也就是根据引用类型的静态类型来调度方法。

·callvirt使用虚拟调度,也就是根据引用类型的动态类型来调度方法;

·calli又称间接调用,是通过函数指针来执行方法调用;对应的直接调用当然就是前面的:call和callvirt。

然而,虽然有以上的通用性结论,但是对于call和callvirt不可一概而论。call在某种情况下可以调用虚方法,而callvirt也可以调用非虚方法。具体的分析我们在以后的文章中来展开,暂不做过多分析。   

5.结论

本文从几个重点的IL指令开始,力求通过对比性的分析和深入来逐步揭开IL的神秘与迷惑,正如我们在开始强调的那样,本文只是个开始也许也是个阶段,对IL的探求正如我自己的脚步一样,也在继续着,为的是在.NET的技术世界能够有更多的领悟。作者期望通过不断的努力逐渐和大家一起从IL世界探求.NET世界,在以后的讨论中我们间或的继续这个主题的不断成长。

认识IL代码---从开始到现在 <第二篇>的更多相关文章

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

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

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

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

  3. iOS开发:代码通用性以及其规范 第二篇(猜想iOS中实现TableView内部设计思路(附代码),以类似的思想实现一个通用的进度条)

    在iOS开发中,经常是要用到UITableView的,我曾经思考过这样一个问题,为什么任何种类的model放到TableView和所需的cell里面,都可以正常显示?而我自己写的很多view却只是能放 ...

  4. 读懂IL代码(二)

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

  5. IL代码完结篇

    读懂IL代码就这么简单(三)完结篇   一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在 ...

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

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

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

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

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

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

  9. 读懂IL代码(四)

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

随机推荐

  1. ANSIC程序到KeilC51的移植心得

    摘要:本文讲述了将ANSIC程序移植到KeilC51上应该注意的事项.文章讲述了存储类型.指针类型.重入函数.根据目标系统RAM的分布的段定位和仿真栈设置.函数指针.NULL指针问题.字节顺序.交叉汇 ...

  2. rsync实现文件备份同步(比如服务器镜像)

    [rsync实现网站的备份,文件的同步,不同系统的文件的同步,如果是windows的话,需要windows版本cwrsync] 一.什么是rsync rsync,remote synchronize顾 ...

  3. DELL配置信息

    CPU详情CPU厂商 英特尔CPU (英特尔)Intel(R) Core(TM) i3 CPU M 370 @ 2.40GHzCPU核心数 2CPU默认频率 2400 MhzCPU外频 533 MHz ...

  4. OpenWRT 编译 error GNU libiconv not in use but included iconv.h is from...

    OpenWRT 编译 error GNU libiconv not in use but included iconv.h is from... 编译的时候碰到一个常见的错误,但是却在一个陌生的地方爆 ...

  5. MicrosoftSQLServer中的锁模式

    在SQL Server数据库中加锁时,除了可以对不同的资源加锁,还可以使用不同程度的加锁方式,即锁有多种模式,SQL Server中锁模式包括: 1.共享锁 SQL Server中,共享锁用于所有的只 ...

  6. ubuntu14.04 安装 StudioZend12

    到官网下载:http://www.zend.com/en/products/studio/downloadsLinux-64位:http://downloads.zend.com/studio-ecl ...

  7. Eclipse上改动Jython代码的Comment颜色

    1.问题起因 依据上一篇文章<MonkeyRunner在Windows下的Eclipse开发环境搭建步骤(兼解决网上Jython配置出错的问题)>搭配好Eclipse上面的MonkeyRu ...

  8. SQL中的delete和TRUNCATE的用法

    TRUNCATE TABLE 表名 删除表中的所有行,而不记录单个行删除操作. 语法 TRUNCATE TABLE name 参数 name 是要截断的表的名称或要删除其全部行的表的名称. 注释 TR ...

  9. 自定义UIView动画效果

    最普通动画: //开始动画 [UIView beginAnimations:nil context:nil]; //设定动画持续时间 [UIView setAnimationDuration:]; / ...

  10. codeforces 339C Xenia and Weights(dp或暴搜)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Xenia and Weights Xenia has a set of weig ...