如何解读IL代码
如何解读IL代码
关于IL代码,我有将从三个方面去揭开它神秘的面纱。IL代码是什么?我们为什么要去读懂IL代码?我们如何去读懂IL代码?这三个问题的解答,将是我解读IL代码的整体思路。
IL代码是什么?IL(Intermediate Language),它也称为CIL或者MSIL,翻译成中文就是“中间语言”。C#的JIT编译器可以将C#源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的二进制代码,而是传说中的IL代码。因此,.exe或者.dll文件都可以被VS安装自带的ILDASM打开,查看IL代码。
我们为什么要去读懂IL代码?无论精通哪一门技术,我们都应该从其本质出发,探明最核心的运作机理,最终有效地理解和掌握它。对于C#语言来说,掌握IL语言就如同抓住了C#语言的本质,它可以有效地帮助我们去理解编译器的运作机理。对于一些C#高手而言,深入地研究IL语言后,能对IL语言直接进行修改后编译。但就我目前的水准,读懂IL代码是为了更深入地理解C#各种特性,比如C#中最重要的一些基本特性,委托、事件。
我们又将如何去读懂IL代码?在读懂IL代码之前,我必须先给大家介绍一下,C#代码编译环境下的内存结构。就我目前已知分为5大块内存区。分别为,托管堆,线程堆栈,计算栈,调用栈,代码区。
托管堆(Managed Heap):存放引用类型的数据,引用类型的数据由GC(Garbage Collection)负责管理。
线程堆栈(Thread Heap Stack):存放值类型的数据和引用类型地址,值类型的数据由操作系统直接负责管理。
计算栈(Evaluation Stack):临时存放值类型的数据和引用类型的地址的堆栈。符合先进后出(FILO)基本栈规则。
调用栈(Call Stack):其中的Record Frame用于存放.locals init(int32 V_0)指令的参数值,是一个局部变量表,不符合先进后出(FILO)基本栈规则。
代码区(Code):存放各种程序指令集。
数据内存区有4个,按等级可以划分成3个级别。托管区为最高级,只有存放引用类型数据;线程堆栈为第二级,存放值类型数据与引用类型地址;计算栈和调用栈为第三级,在线程中调用方法时,主要在这两个栈中操作数据。要看懂IL代码第一步便是需要清晰地了解计算栈与调用栈互相操作数据的关系。下面我将引入一个IL代码实例来说明几个内存区是如何互相操作数据的。
C#源代码
using System;
namespace ILDemo
{
class Program
{
static void Main(string[] args)
{
int i = 1;
int j = 2;
int k = 3;
int answer = i + j + k;
Console.WriteLine("i+j+k=" + answer);
Console.ReadKey();
}
}
}
IL代码
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint //程序入口
// 代码大小 42 (0x2a)
.maxstack 2 // 计算出计算堆栈的能存几个值
.locals init ([0] int32 i,
[1] int32 j,
[2] int32 k,
[3] int32 answer) //定义int32类型的i,j,k,answer放入调用栈
IL_0000: nop //无操作
IL_0001: ldc.i4.1 //把i的值从线程堆栈放到计算堆栈上
IL_0002: stloc.0 //把计算堆栈顶部的值(i的值)放到调用堆栈索引0处
IL_0003: ldc.i4.2 //把j的值从线程堆栈放到计算堆栈上
IL_0004: stloc.1 //把计算堆栈顶部的值(j的值)放到调用堆栈索引1处
IL_0005: ldc.i4.3 //把k的值从线程堆栈放到计算堆栈上
IL_0006: stloc.2 //把计算堆栈顶部的值(k的值)放到调用堆栈索引2处
IL_0007: ldloc.0 //把调用堆栈索引为0处的值复制到计算堆栈
IL_0008: ldloc.1 //把调用堆栈索引为1处的值复制到计算堆栈
IL_0009: add //相加
IL_000a: ldloc.2 //把调用堆栈索引为2处的值复制到计算堆栈
IL_000b: add //相加
IL_000c: stloc.3 //把计算堆栈顶部的值(add的值)放到调用堆栈索引3处
IL_000d: ldstr "i+j+k=" //推送对元数据中存储的字符串的新对象引用。
IL_0012: ldloc.3 //把调用堆栈索引为3处的值复制到计算堆栈
IL_0013: box [mscorlib]System.Int32 //装箱
IL_0018: call string [mscorlib]System.String::Concat(object,object) //调用内部方法
IL_001d: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine
IL_0022: nop //无操作
IL_0023: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() //调用ConsoleKey
IL_0028: pop //无操作
IL_0029: ret //return
} // end of method Program::Main
总结:1.ldloc.0前缀ld,load含义载入,即压入计算栈;loc,locals含义调用栈,即取值于调用栈第0位参数。
2.其他的ld前缀都是取值于线程堆栈。比如ldc.i4.0,ldstr,ldfld,ldfld。
3.st前缀,store含义存储,即弹出计算栈。弹出的值存放于调用栈。
基于以上3条结论,大家基本可以看懂大部分IL代码的方法内部计算栈和调用栈的数据交互。在随后的博文中,我会叙述一下如何通过IL代码去深入理解委托、事件。希望大家能够支持一下。
如何解读IL代码的更多相关文章
- 【小白学C#】浅谈.NET中的IL代码
一.前言 前几天群里有位水友提问:”C#中,当一个方法所传入的参数是一个静态字段的时候,程序是直接到静态字段拿数据还是从复制的函数栈中拿数据“.其实很明显,这和方法参数的传递方式有关,如果是引用传递的 ...
- 深入理解xLua基于IL代码注入的热更新原理
目前大部分手游都会采用热更新来解决应用商店审核周期长,无法满足快节奏迭代的问题.另外热更新能够有效降低版本升级所需的资源大小,节省玩家的时间和流量,这也使其成为移动游戏的主流更新方式之一. 热更新可以 ...
- 读懂IL代码就这么简单(三)完结篇
一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认 ...
- 读懂IL代码就这么简单(二)
一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...
- 读懂IL代码就这么简单 (一)
一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...
- 详解.NET IL代码
一.前言 IL是什么? Intermediate Language (IL)微软中间语言 C#代码编译过程? C#源代码通过LC转为IL代码,IL主要包含一些元数据和中间语言指令: JIT编译器把IL ...
- 如何通过ildasm/ilasm修改assembly的IL代码
原文地址:http://kb.cnblogs.com/page/101162/ 这段时间为跟踪一个Bug而焦头烂额,最后发现是Framework的问题,这让人多少有些绝望.所以到微软论坛提了个帖子,希 ...
- 用ildasm/ilasm修改IL代码
原文地址:http://www.cnblogs.com/dudu/archive/2011/05/17/ildasm_ilasm_il.html 在开发中遇到这样一个场景,需要修改一个dll文件(.N ...
- 时空上下文视觉跟踪(STC)算法的解读与代码复现(转)
时空上下文视觉跟踪(STC)算法的解读与代码复现 zouxy09@qq.com http://blog.csdn.net/zouxy09 本博文主要是关注一篇视觉跟踪的论文.这篇论文是Kaihua Z ...
随机推荐
- 利用python传送文件
转:微信公众号李云景(侵删) 很多人传送文件都是使用QQ,微信,百度云,或者其他网盘. 不过都有微信的传输文件有大小的限制,百度云就不说了,想要正常的下载速度反而要充VIP. 我一直推崇大家都学习Py ...
- UWP_开源小程序 水印添加器
前几天写了一个确定水印位置的小博客.决定要写一个添加水印的UWP程序. 目前程序技术方面已经差不多了.所以提上日程
- Python3中装饰器的使用
较为复杂的装饰器使用: user,passwd = 'hjc',111111 def auth(type): print('auth type:',type) def outwrapper(func) ...
- Python3的简单的函数调用
python3的几种传参方法(初学者): 例1: def func(x,*argv): print(x) print(argv) func('alex','wt','hjc','lao liu') 输 ...
- html之表单和简单CSS
一.==表单== 1. form表单本身 <form name="myform" action="#" method="get"> ...
- Reincarnation HDU - 4622
\(\color{#0066ff}{ 题目描述 }\) 给定一个字符串,多次询问某一字串的f值 f(s)代表s的不同字串数量 \(\color{#0066ff}{输入格式}\) 第一行T,代表数据组数 ...
- error : Could not load UI satellite dll 'TrackerUI.dll'. Make sure it exists in an LCID subdirectory of 'C:\Program Files (x86)\MSBuild\12.0\bin\'.
原因 VS2013 + QT环境部署好后, 又安装了VS2015\ 解决方案: 在另一台电脑里重装VS2013, 并将 C:\Program Files (x86)\MSBuild\12.0\B ...
- for循环删除list中多个元素出现的误区
错误的做法是: for(int i= 0;i<list.size();i++) 因为在你删除元素的同时list.size()也在变小,这样就会照成越界. 正确做法:因为要删除list里面的多个的 ...
- 【转】eclipse上的.properties文件中文编辑显示问题
首先,解决.properties文件中的中文编辑问题,我们发现,在.properties文件中输入的中文变成了这个样子: 这是eclipse的.properties文件,默认的编码方式是iso-885 ...
- PhpStrom 和 wamp 配置 xdebug
本地服务器: 1.php.ini 添加内容: ;设置xdebug的端口为9000 xdebug.remote_handler = dbgp xdebug.remote_host= localhost ...