在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了一下,与大家共享,
原文http://www.codeguru.com/Csharp/.NET/net_general/il/article.php/c4635,初次翻译文章,请大家指正。

介绍

微软中间语言 (MSIL) 是一种语言,是许多编译器(C#,VB.NET等)的输出. ILDasm (中间语言反汇编器)程序和.Net Framework SDK(FrameworkSDK\Bin\ildasm.exe)打包在一起,让用户以人可阅读的格式查看MSIL代码。通过该工具,我们可以打开任何.net可执行文件(exe或dll)并查看其MSIL代码。

ILAsm 程序(中间语言编译器)从MSIL语言生成可执行文件。我们可以在WINNT \ Microsoft.NET \Framework \vn.nn.nn目录中找到这个程序。

许多Visual C++程序员开始.net开发是因为他们对.NET框架的底层发生了一些什么感兴趣。学习MSIL给了用户理解某些对C#程序员或VB.NET程序员来说是透明的东西的机会。通晓MSIL给.NET程序员更多的能力。我们从不需要直接用MSIL编写程序,但是在某些情况下是非常有用的,我们可以用ILDasm打开程序的MSIL代码,查看它到底做了一些什么。

一个Doc格式的MSIL参考对.NET开发人员来说比较有用,它也许可以在Framework SDK目录下找到:

  • FrameworkSDK\Tool Developers Guide\docs\Partition II Metadata.doc (元数据定义和术语). 在这个文件中,我发现了所有MSIL指令的说明,例如.entrypoint, .locals等.
  • FrameworkSDK\Tool Developers Guide\docs\Partition III CIL.doc (CIL命令集)包含了一个MSIL命令的完整列表。

在工作中,我也用到了一个MSDN的ILDAsm教程,一篇2001年5月由John Robbins发表在MSDN杂志的优秀的文章: "ILDASM is Your New Best Friend"。

我想学习一门语言最好的途径就是用它写一些程序,所以我决定写一些小的MSIL程序。实际上,我们有写这些代码——是C#编译器生成的,我只是做一了一些小的更改,并加了许多注释以描述MSIL是如何工作的。

通过阅读附在本文的例子可以帮助.NET程序员理解中间语言,帮助其在需要的时候更易读懂MSIL代码。


一般信息

在MSIL中,所有的操作都在栈上完成。当调用一个函数的时候,其参数和局部变量都被分配到栈上。函数的代码从该栈开始,把一些值压入栈,对这些值进行一些操作,从栈上取出值。

执行MSIL名利和函数由3个步骤完成:

1.      把命令操作数和函数参数压入栈。

2.      执行命令或者调用函数。命令或函数从栈中取出他们的操作数(参数)并把他们压入结果栈 (返回值)。

3.      从栈中读取结果值。

步骤1~3是可选的,例如,void函数不会压入一个结果值到栈。

栈包含值类型对象和引用类型对象的引用。引用类型对象本身保存在堆中。

用来把一个值压入栈中的MSIL命令是ld... (装载),用来从栈中取出值的命令是st... (存储),因为值都存在变量中。我们可以把入栈操作叫做装载,出栈操作叫做存储。


示例项目

本文附上的代码中包含了许多用MSIL写的控制台程序. 如果需要编译他们,请确定ILAsm程序可以通过PATH访问。每个项目都是一个Visual Studio解决方案,IL源文件可以用VS的文本编辑器打开,Build命令运行ILAsm 程序在项目所在目录生成exe文件,run命令执行该文件。在每个程序的末尾,我加了几行代码,他们可以用C#来写:

Console.WriteLine("Press Enter to continue");

Console.Read();

这样,当从Windows Explorer运行的时候,就可以看到程序的输出。

下面是所含项目的列表:

1.      打印字符串—打印字符传到控制台。

2.      赋值—给一个int变量赋值并把它打印到控制台。

3.      运算—从控制台读取2个数字,惊醒+,-和乘的操作,并显示结果。

4.      数组— 分配一个int类型的数组,给他的元素赋值,打印其元素和数组的长度。

5.      比较— 输入2个数字并打印出最小的那个。

6.      数组2— 用循环填充数组元素并打印某些元素。

7.      不安全代码— 使用unsafe指针访问数组元素。

8.      PInvoke— 调用Win32 API。

9.      — 和类一起工作。

10.   异常— 异常处理。

我假设你以在这所说的顺序阅读这些项目。在下面的项目描述中,我用程序来解释每一条MSIL命令,并给出一些代码片段。


打印字符串

PrintString 就是MSIL版的 Hello, World

在代码中用到的MSIL指令如下:

l          .entrypoint— 定义程序的入口点(该函数在程序启动的时候由.NET 运行库调用)

l          .maxstack— 定义函数代码所用堆栈的最大深度。C#编译器可以对每个函数设置准确的值, 在例子中,我把他设为8。

用到的MSIL命令如下:

  • ldstr string—把一个字符串常量装入堆栈。
  • call function(parameters)—调用静态函数。函数的参数必须在函数调用前装入堆栈。
  • pop— 取出栈顶的值。当我们不需要把值存入变量时使用。
  • ret— 从一个函数中返回。

调用静态函数很简单。我们把函数的参数压入堆栈,调用函数,然后从堆栈中读取函数的返回值(如果是非void函数)。Console.WriteLine 就是一个这样的函数。

下面是代码:

.assembly PrintString {}

/*

Console.WriteLine("Hello, World)"

*/

.method static public void main() il managed

{

.entrypoint             // 该函数是程序的入口

.maxstack 8

// *****************************************************

// Console.WriteLine("Hello, World)";

// *****************************************************

ldstr "Hello, World"        // 把字符串压入堆栈

// 调用静态的System.Console.Writeline函数

// (函数移除栈顶的字符串)

call   void [mscorlib]System.Console::WriteLine

(class System.String)

// *****************************************************

ldstr "Press Enter to continue"

call   void [mscorlib]System.Console::WriteLine

(class System.String)

// 调用 System.Console.Read 函数

call int32 [mscorlib]System.Console::Read()

// pop 指令移除栈顶元素

// (移除由Read()函数返回的数字

pop

// *****************************************************

ret

}


赋值

该程序给一个变量赋与int值并把它打印到控制台窗口。

命令:

  • ldc.i4.n—把一个 32位的常量(n从0到8)装入堆栈
  • stloc.n— 把一个从堆栈中返回的值存入第n(n从0到8)个局部变量

代码:

.assembly XequalN {}

// int x;

// x = 7;

// Console.WriteLine(x);

.method static public void main() il managed

{

.entrypoint

.maxstack 8

.locals init ([0] int32 x)  // 分配一个局部变量

// *****************************************************

// x = 7;

// *****************************************************

ldc.i4.7                    // 把常量装入堆栈

stloc.0                     // 把堆栈中的值存入第0个变量

// *****************************************************

// Console.WriteLine(x);

// *****************************************************

ldloc.0                     // 把第0个变量转入堆栈

call void [mscorlib]System.Console::WriteLine(int32)

ret

}


数据运算

本程序从控制台读取2个数字,对它们进行简单的运算,然后显示结果。

命令:

  • add—2个值相加。命令的参数必须在调用前装入堆栈,该函数从堆栈中移除参数并把运算后的结果压入堆栈。
  • sub— 2个值相减。
  • mul— 2个值相乘。

代码片段:

.assembly Operations {}

/*

// 程序的C#代码:

int x, y, z;

string s;

Console.WriteLine("Enter x:");

s = Console.ReadLine();

x = Int32.Parse(s);

Console.WriteLine("Enter y:");

s = Console.ReadLine();

y = Int32.Parse(s);

z = x + y;

Console.Write("x + y = ");

Console.Write(z);

Console.WriteLine("");

z = x - y;

Console.Write("x - y = ");

Console.Write(z);

Console.WriteLine("");

z = x * y;

Console.Write("x * y = ");

Console.Write(z);

Console.WriteLine("");

*/

.method static public void main() il managed

{

.entrypoint

.maxstack 8

.locals init ([0] int32 x,

[1] int32 y,

[2] int32 z,

[3] string s)

// *****************************************************

// Console.WriteLine("Enter x:");

// *****************************************************

ldstr      "Enter x:"       // 把字符装入堆栈

call       void [mscorlib]System.Console::WriteLine(string)

// *****************************************************

// s = Console.ReadLine();

// *****************************************************

call       string [mscorlib]System.Console::ReadLine()

stloc.3                     // 把值存入第3个变量

// *****************************************************

// x = Int32.Parse(s);

// *****************************************************

ldloc.3                     // 把第3个变量装入堆栈

// 调用 System.Int32::Parse(string)函数

// 把字符串从堆栈中移除并把解析的结果——int值压入堆栈

call       int32 [mscorlib]System.Int32::Parse(string)

stloc.0                     // 把值存入第0个变量

// *****************************************************

// 和变量y的一些运算

// *****************************************************

ldstr      "Enter y:"

// 装入字符串

call       void [mscorlib]System.Console::WriteLine(string)

// 调用

call       string [mscorlib]System.Console::ReadLine()

// 调用

stloc.3

//把值存入第3个变量

ldloc.3

//把第3个变量装入堆栈

call       int32 [mscorlib]System.Int32::Parse(string)

// 调用

stloc.1

//把值存入第1个变量

// *****************************************************

// z = x + y;

// *****************************************************

ldloc.0             //把第0个变量装入堆栈

ldloc.1             //把第1个变量装入堆栈

// 把这2个值从堆栈中移除,把结果压入堆栈

add

stloc.2             //把值存入第2个变量

// *****************************************************

// Console.Write("x + y = ");

// *****************************************************

ldstr      "x + y = "          // load string onto stack

call       void [mscorlib]System.Console::Write(string)

// *****************************************************

// Console.Write(z);

// *****************************************************

ldloc.2                    //把第2个变量装入堆栈

call       void [mscorlib]System.Console::Write(int32)

// *****************************************************

// Console.WriteLine("");

// *****************************************************

ldstr      ""                  //装入字符串

call       void [mscorlib]System.Console::WriteLine(string)

//相减和相乘运算过程与上面相同

ret

}

未完待续。

转载于:https://www.cnblogs.com/Yahong111/archive/2007/08/15/857140.html

【翻译】MSIL 教程(一)相关推荐

  1. MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API(转)...

    转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857574.html 续上文[翻译]MSIL 教程(一) ,本文继续讲解数组.分支.循环 ...

  2. MSIL 教程(三):类和异常处理(转)

    转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857771.html 续上文[翻译]MSIL 教程(二):数组.分支.循环.使用不安全代 ...

  3. MSIL 教程(一)

    在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了一下,与大家共享, 原文http://www.codeguru.com/Csharp/.NET/net_general/il/arti ...

  4. uc浏览器电脑版翻译设置在哪 uc浏览器翻译网页教程

    uc浏览器电脑版翻译设置在哪 uc浏览器翻译网页教程 uc浏览器电脑版翻译设置在哪?uc浏览器怎么翻译网页?现在的UC浏览器和以前的谷歌浏览器一样都带有翻译网页和反应单词的功能,如果觉得英文页面看起来 ...

  5. Hyperledger Fabric 官网翻译入门教程--之关键概念(Hyperledger Fabric 模型)

    英文地址:http://hyperledger-fabric.readthedocs.io/en/latest/fabric_model.html Hyperledger Fabric Model/ ...

  6. [翻译Pytorch教程]NLP从零开始:使用序列到序列网络和注意力机制进行翻译

    翻译自官网手册:NLP From Scratch: Translation with a Sequence to Sequence Network and Attention Author: Sean ...

  7. 知云文献翻译安装教程_阅读英文文献的好帮手

    还在为看不懂英文文献而头疼吗? 1.下载 知云文献翻译目前最新版完整版.win版本.适用于win7-win10. 大家最好直接进知云文献翻译的官网进行下载:win知云完整安装包下载 ,可直接在软件内部 ...

  8. [翻译Pytorch教程]NLP从零开始:使用字符级RNN进行名字生成

    翻译自官网手册:NLP From Scratch: Generating Names with a Character-Level RNN Author: Sean Robertson 原文githu ...

  9. 个人网络上翻译计算机教程,计算机翻译教程

    作为计算机辅助翻译入门教材,本书具有以下特点: 内容详实,图文并茂: 以实践为主,注重实际作: 紧跟计算机辅助翻译技术发展,确保科学性与时代性. 本书主要适用于翻译专业及英语专业本科生,也可以作为翻译 ...

最新文章

  1. Prim算法求权数和,POJ(1258)
  2. 坐在隔壁的00后同事,让我看到了职场“反内卷”的希望
  3. Spring(十八):Spring AOP(二):通知(前置、后置、返回、异常、环绕)
  4. 电脑达人教你怎么解决Win7系统盘渐渐变小的问题
  5. 数智化时代合格数据架构师如何养成?
  6. 在VS中创建多个项目
  7. 对于XLS碎片提取的深入研究
  8. 施一公:“中国式科研”误国误民!表面上一片繁荣,实则深藏危机
  9. 软件构造学习笔记-第四周
  10. IDEA UML图 实战
  11. python中函数包括_python中函数都有哪些简单点的例子零基础
  12. 读书笔记_打开量化投资的黑箱10
  13. set的erase()函数
  14. java垃圾回收文件分析
  15. *sql注入实战--记一次绕过WTS-WAF拦截注入**
  16. Android 10 SystemUI 如何隐藏状态栏输入法图标
  17. 前端小程序,h5,浏览器,app, doc,.docx,.ofd,.PDF,.WPS以及Office文档的在线解析预览方式
  18. 毕设经典-人事档案管理系统(layer+SSM)-AOP介绍
  19. 一定要在最好的年纪拥有学习能力
  20. Spring AOP 切面记录操作日志

热门文章

  1. 2012.02.13(rtsp)
  2. 新手学.net(习惯问题)
  3. Android开发学习之以CameraAPI方式实现相机功能(二)——相机功能配置
  4. 应用程序委托和新的单例(译)
  5. 设置c++程序的堆栈空间解决栈溢出问题
  6. Sqlserver2008日志压缩
  7. 关于左移右移的操作 学习
  8. struts2的struts.xml的详细配置1
  9. Dreamweaver 8 jquery 代码提示
  10. 马来游记(2)- 漂浮云顶间。。。