转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857574.html

续上文【翻译】MSIL 教程(一) ,本文继续讲解数组、分支、循环、使用不安全代码和如何调用Win32 API

数组

本程序分配一个int型的数组并给他的元素赋值,然后打印出元素和数组的长度。

命令:

  • newarr type— 生成一个元素类型为type 的数组。数组的大小必须在调用该命令前装入堆栈。该命令会把一个数组的引用装入堆栈。
  • stelem.i4— 给一个数组成员赋值。数组的引用、下标和值必须在调用该命令前装入堆栈。
  • ldelema type— 把数组元素的地址装入堆栈。数组的引用和下标必须在调用该命令前装入堆栈。地址用来调用非静态函数(参见后面)。
  • ldlen—把数组的长度装入堆栈。数组的引用必须在调用该命令前装入堆栈。
  • ldloca.s variable— 把变量的地址装入堆栈。
  • ldc.i4.s value— 把一个Int32的常量装入堆栈(用于大于8位的数)。
  • conv.i4— 把堆栈中值转换成Int32类型。
  • call instance function(arguments)— 调用类的非静态函数。在调用一个非静态函数之前,我们必须把某个类的实例的地址和函数的参数装入堆栈。在本例中,地址通过ldelemaldloca 命令装入。

在本例的某些代码片段中,我写了一些注释,以说明堆栈在最后一个变量后的状态。在本例中,我们看到变量由编译器生成,该变量用来调用类的非静态函数。

代码:

.assembly Array1 {}/*
// This program works as C# code:int[] x = new int[5];
x[0] = 10;
x[1] = 20;Console.WriteLine("x[0] = " + x[0].ToString());
Console.WriteLine("x[1] = " + x[1].ToString());
Console.WriteLine("Array length = " + x.Length.ToString());
*/.method static public void main() il managed
{.entrypoint.maxstack 8.locals init ([0] int32[] x,[1] int32 tmp)    // 由编译器生成// *****************************************************// x = new int[5];// *****************************************************ldc.i4.5                     // 把常量装入堆栈。// 生成数组,并把他的引用压入堆栈
    newarr     [mscorlib]System.Int32// 把数组从堆栈中取出,存入第0个局部变量中stloc.0// *****************************************************// x[0] = 10;// *****************************************************ldloc.0           // 把第0个局部变量装入堆栈(数组)ldc.i4.0          // 把常量0装入堆栈(下标)ldc.i4.s   10     // 把常量10装入堆栈(值)stelem.i4         // array[index] = value// 对数组的其余元素进行同样的操作……// ***************************************************// Console.WriteLine("x[0] = " + x[0].ToString());// ***************************************************ldstr      "x[0] = "            // 堆栈:"x[0] = "  (堆栈由局部变量表示)ldloc.0                         // 把第0个变量装入堆栈ldc.i4.0                        // 把第1个变量装入堆栈// 堆栈: "x[0] = " -> x -> 0// 把元素的地址装入堆栈
    ldelema    [mscorlib]System.Int32// 堆栈: "x[0] = " -> 指向一个Int32的指针// 10// 调用实例函数System.Int32::ToString().call       instance string [mscorlib]System.Int32::ToString()// 堆栈: "x[0] = " -> "10"// 调用静态函数System.String::Concat(string, string)call       string [mscorlib]System.String::Concat(string, string)// 堆栈: "x[0] = 10"// 调用静态函数 System.Console::WriteLine(string)call       void [mscorlib]System.Console::WriteLine(string)// 堆栈: 空//对数组的其余元素进行同样的操作……// *****************************************************// Console.WriteLine("Array length = " + x.Length.ToString());// *****************************************************ldstr      "Array length = "  // 堆栈: "Array length = "ldloc.0     // 把第0个变量装入堆栈// 堆栈: "Array length = " -> xLdlen       // 把数组的长度装入堆栈// 堆栈: "Array length = " -> 5conv.i4     // 把栈顶的值转换为Int32,并把他装入堆栈// 堆栈: "Array length = " -> 5stloc.1     // 把刚才的值存入第1个局部变量(tmp)// 堆栈: "Array length = "ldloca.s   tmp    //把变量tmp的地址装入堆栈// 堆栈: "Array length = " -> &tmpcall       instance string [mscorlib]System.Int32::ToString()// 堆栈: "Array length = " -> "5"call       string [mscorlib]System.String::Concat(string, string)// 堆栈: "Array length = 5"call       void [mscorlib]System.Console::WriteLine(string)// 堆栈: 空
    ret
}

比较

本程序读取2个数字并打印其最小值。

命令:

  • bge.s label—跳转至label 如果value1≥value 2. Values 1和 2 必须在调用本命令前装入堆栈。
  • br.s label—跳转至label
  • box value type— 把一个值类型转成一个Object,并把该Object的引用装入堆栈。

本程序的装箱由如下C#程序引起: Console.WriteLine("{0:d}", z);
用这种形式就不会引起装箱: Console.WriteLine(z.ToString());.

代码:

.assembly Compare {}
/*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);if ( x < y )z = x;elsez = y;Console.WriteLine("{0:d}", z);
*/.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个变量装入堆栈call       int32 [mscorlib]System.Int32::Parse(string)stloc.0                             // 保存到第0个变量// 对y进行相同的操作……// *****************************************************// 分支// if ( x >= y ) goto L_GR;// *****************************************************ldloc.0                     // 把x装入堆栈(value 1)ldloc.1                     // 把y装入堆栈(value 2)bge.s  L_GR                 // 跳转到 L_GR 如果value1≥value2// *****************************************************// z = x// *****************************************************ldloc.0                     // 把第0个变量装入堆栈stloc.2                     // 保存到第2个变量
 br.s       L_CONTINUE       // 跳转至 L_CONTINUE

L_GR:// *****************************************************// z = y// *****************************************************ldloc.1             // 把第1个变量装入堆栈stloc.2             // 保存到第2个变量

L_CONTINUE:// *****************************************************// Console.WriteLine("{0:d}", z);// 注意:这一行引起装箱操作// *****************************************************ldstr      "{0:d}"  // 把字符串装入堆栈ldloc.2             // 把第2个变量装入堆栈 (z)box       [mscorlib]System.Int32   // 把Int32变为Objectcall  void [mscorlib]System.Console::WriteLine(string, object)ret
}

数组2(循环)

本程序用循环填充一个数组并打印其元素。这一次,我们增加一个静态函数ShowNumber(int), 它在main函数中调用。

命令:

  • blt.s label—跳转到label 如果value 1小于 value 2. Values 1 和 2 必须在调用本命令之前装入堆栈。
  • ldelem.i4— 把一个数组元素装入堆栈。数组引用和下标必须在调用本命令之前装入堆栈。
  • ldarga.s argument— 把函数参数的地址装入堆栈。

我们可以看到,在本程序中,for 循环在MSIL中用标签来实现。

代码:

.assembly Array2 {}
/*int[] px = new int[100];int i;for ( i = 1; i < 100; i++ ){px[i] = i + 1;}ShowNumber(px[5]);ShowNumber(px[10]);static void ShowNumber(int n){Console.WriteLine(n.ToString());}
*/.method static public void main() il managed
{.entrypoint.maxstack 8.locals init ([0] int32[] px,[1] int32 i)// *****************************************************// x = new int[100]// *****************************************************ldc.i4.s   100                      // 把常量装入堆栈newarr     [mscorlib]System.Int32   // 分配一个Int32型的数组stloc.0                             // 把它存入第0个变量// *****************************************************// i = 1// *****************************************************ldc.i4.1                    //把常量装入堆栈stloc.1                     //把它存入第1个变量
 br.s       CHECK_COUNTER    // 跳转到 CHECK_COUNTER

START_LOOP:// *****************************************************// px[i] = i + 1;// *****************************************************ldloc.0                     //  把第0个变量装入堆栈// 堆栈: pxldloc.1                     // 把第1个变量装入堆栈//堆栈; px -> ildloc.1                     //把第1个变量装入堆栈//堆栈: px -> i -> ildc.i4.1                    //把常量装入堆栈//堆栈: px -> i -> i -> 1.add                         // 2个值相加//堆栈: px -> i -> i+1//        (array,index,value)stelem.i4                   // 把值存入数组元素//堆栈[index] = value//堆栈: 空// *****************************************************// i = i + 1// *****************************************************ldloc.1                     //把第1个变量装入堆栈ldc.i4.1                    //把常量装入堆栈add                         // 相加stloc.1                     // 把值存入把第1个变量

CHECK_COUNTER:// *****************************************************// 如果 i < 100 跳转到循环开始的地方// *****************************************************ldloc.1                     // 把第1个变量装入堆栈ldc.i4.s   100              // 把常量装入堆栈blt.s      START_LOOP       // 如果value1<value2调转至START_LOOP// *****************************************************// ShowNumber(px[5]// *****************************************************ldloc.0                     // 把第0个变量装入堆栈// (array)ldc.i4.5                    // 把常量装入堆栈// (index)ldelem.i4                   // 把数组元素装入堆栈call       void ShowNumber(int32)   // 调用 ShowNumber// *****************************************************// ShowNumber(px[10]// *****************************************************ldloc.0ldc.i4.s   10ldelem.i4call       void ShowNumber(int32)ret
}.method static public void  ShowNumber(int32 n) il managed
{.maxstack  1ldarga.s   n          // 把第n个参数的地址装入堆栈call       instance string [mscorlib]System.Int32::ToString()call       void [mscorlib]System.Console::WriteLine(string)ret
}

不安全代码

本程序通过unsafe指针填充和打印一个int型数组。

在本程序中,我们将看到新的类型:int32* 和 int32&。使用关键字pinned 可以阻止GC移动由局部指针变量指向的对象。

命令:

  • dup—在堆栈上复制一个值。
  • stind.i4—存储值的地址。地址和值必须在调用本命令之前装入堆栈。

Code:

.assembly Unsafe {}
/*
int[] nArray = new int[5];
int i;
int* pCurrent;fixed ( int* pArray = nArray )
{pCurrent = pArray;for ( i = 0; i < 5; i++ ){*pCurrent++ = i + 1;}
}for ( i = 0; i < 5; i++ )
{Console.WriteLine(nArray[i].ToString());
}*/.method static public void main() il managed
{.entrypoint.maxstack 8.locals ([0] int32[] nArray,[1] int32 i,[2] int32* pCurrent,[3] int32& pinned pArray)  // GC不会移动该指针指向的对象// *****************************************************// nArray = new int[5];// *****************************************************ldc.i4.5                            // 把常量5装入堆栈                                       newarr     [mscorlib]System.Int32   // 生成数组 Int32[5]stloc.0                             // 存入第0个变量// *****************************************************// pArray = nArray    (pArray = &nArray[0])// *****************************************************ldloc.0//把第0个变量装入堆栈(array)ldc.i4.0//把常量0装入堆栈(index)
    ldelema    [mscorlib]System.Int32// 把array[index]装入堆栈stloc.3//存入第3个局部变量// *****************************************************// pCurrent = pArray;// *****************************************************ldloc.3                     //把第3个变量装入堆栈conv.i                      // 转变为intstloc.2                     //存入第2个变量// *****************************************************// i = 0// *****************************************************ldc.i4.0                    //把常量0装入堆栈stloc.1                     //存入第1个变量// *****************************************************// 跳转到 CHECK_COUNTER// *****************************************************
    br.s       CHECK_COUNTERSTART_LOOP:// *****************************************************// *pCurrent++ = i + 1                             // *****************************************************// 1) 保存pCurrent到堆栈,然后累加pCurrentldloc.2//把第2个变量装入堆栈            [pCurrent]
    dup// 复制栈顶的值//                                [pCurrent pCurrent]ldc.i4.4// 把常量4装入堆栈               [pCurrent pCurrent 4]
    add// 相加                           [pCurrent pCurrent + 4]stloc.2// 存入第2个变量                 [pCurrent]// 译注:因为int型指针是4位的,所以加pCurrent+4==*pCurrent++// 2) 把 (i+1) 保存到pCurrentldloc.1// 把第1个变量装入堆栈           [pCurrent i]ldc.i4.1//把常量1装入堆栈                [pCurrent i 1]add   // 相加                           [pCurrent i+1]//                                 地址     值
    stind.i4// 把i+1的值的地址存入pCurrent   [empty]// *****************************************************// i = i + 1// *****************************************************ldloc.1             // 把第1个变量装入堆栈ldc.i4.1            // 把常量1装入堆栈add                 // 相加stloc.1             // 存入第1个变量

CHECK_COUNTER:// *****************************************************// 如果i < 5 跳转至 START_LOOP;// *****************************************************ldloc.1                     // 把第1个变量装入堆栈ldc.i4.5                    // 把常量5装入堆栈blt.s      START_LOOP       // 如果i<5跳转至START_LOOP// *****************************************************// pArray = 0               fixed 块结束// *****************************************************ldc.i4.0                    // 把常量0装入堆栈conv.u                      // 转变为unsigned int,并压入堆栈stloc.3                     // 存入第3个变量// 打印数组元素……
 ret
}

PInvoke 

本程序使用Win32 API GetComputerName 和 MessageBox 显示计算机的名字。API的MSIL声明形式如下:

.method public hidebysig static pinvokeimpl("kernel32.dll"autochar winapi)int32  GetComputerName(class [mscorlib]System.Text.StringBuildermarshal( lptstr) buffer,int32& size) cil managed preservesig
{
}.method public hidebysig static pinvokeimpl("User32.dll"autochar winapi)int32  MessageBox(native int hWnd,string  marshal( lptstr) lpText,string  marshal( lptstr) lpCaption,int32 uType) cil managed preservesig
{
}

其调用规则与其他函数一致。

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

  1. Java(二)分支循环、数组、字符串、方法

    文章目录 一.分支循环 1.1 分支结构 1.2 循环结构 1.3 跳转语句 1.4 分支循环相关问题 1.4.1 switch是否能作用在byte上,是否能作用在long上,是否能作用在String ...

  2. html title 不显示_SEO入门教程二:学习最基础的html代码知识

    其实,做SEO并不一定要很懂代码,只要基础能看懂就行.当然如果你很懂代码,那是加分项,下面这些基础能看就行. 首先,我们需要了解网页的基本结构,分为head和body两部分,中文解释头部和内容部分,如 ...

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

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

  4. 【翻译】MSIL 教程(一)

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

  5. 分支循环语句练习和友尽模拟器的综合应用

    目录 一.循环语句练习 1.计算 n的阶乘 2. 计算 1!+ 2!+ 3!+ -- + 10! 二.分支循环综合练习 3. 在一个有序数组中查找具体的某个数字n. 4. 编写代码,演示多个字符从两端 ...

  6. MSIL 教程(一)

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

  7. 《零基础看得懂的C++入门教程 》——(8)搞定二维数组与循环嵌套

    一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<软件介绍> 想了解编译原理和学习方法点这 ...

  8. 取得数组下标_《零基础C++入门教程》——(8)搞定二维数组与循环嵌套

    一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<零基础看得懂的C语言入门教程>--(二) ...

  9. 《零基础看得懂的C语言入门教程 》——(九)C语言二维数组与循环嵌套

    一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言. 第一篇:(一)脱离学习误区 第二篇:(二)C语言没那么难简单开发带你了 ...

最新文章

  1. Linux13-计划任务crontab
  2. Locality Sensitive Hashing(局部敏感哈希)
  3. 网络安全系列之五十 对Web主目录进行备份
  4. SQL-16 统计出当前各个title类型对应的员工当前薪水对应的平均工资。结果给出title以及平均工资avg。...
  5. JFreeChart插件使用
  6. 【UVALive - 3126】Taxi Cab Scheme (二分图,最小路径覆盖)
  7. 依赖注入[5]: 创建一个简易版的DI框架[下篇]
  8. 你该怎么去学软件测试,过来人告诉你
  9. 1 Oracle数据库环境搭建
  10. 吾之工作要求:死板,教条,僵化
  11. 国外一些DICOM资源下载网址
  12. 投资20亿元,又一个云手机基地诞生
  13. 专题方案 | 项目里程碑管理系统
  14. 产品生命周期和项目生命周期
  15. iphone开源汇总
  16. Map集合、Collections类
  17. 解决关于引入的网络图片,浏览器无法正常打开的问题
  18. 北航计算机学院硕士培养方案,北航硕士研究生培养方案.doc
  19. OpenDDS有问必答
  20. Standardized QCI characteristics

热门文章

  1. 最近发现了好多好资源,赶紧收藏一下!【粒子特效】
  2. 运行个Hello Word也能出Bug?Python、Java、C++等16种语言中枪,最严重可导致文件丢失...
  3. MIT科学家首次发现只对歌唱有反应的神经元,对,只能人声带伴奏的那种歌
  4. 云原生首超Linux成最热,92%公司表示开源人才留不住|Linux基金会最新报告
  5. C罗还会是史上第一个上链的得分王吗?
  6. 2840页的计算机毕业论文,德州奥斯汀华人博士究竟写了啥
  7. 无人出租要遍地,Waymo百度这种报告就得常走起
  8. 丘成桐教授,不必动怒
  9. 只需2小时,成本不到7块,你我皆可制作的3D机器人
  10. vue--axios请求头设置传输编码格式+