MSIL 教程(二):数组、分支、循环、使用不安全代码和如何调用Win32 API(转)...
转自: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)— 调用类的非静态函数。在调用一个非静态函数之前,我们必须把某个类的实例的地址和函数的参数装入堆栈。在本例中,地址通过ldelema和ldloca 命令装入。
在本例的某些代码片段中,我写了一些注释,以说明堆栈在最后一个变量后的状态。在本例中,我们看到变量由编译器生成,该变量用来调用类的非静态函数。
代码:
.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(转)...相关推荐
- Java(二)分支循环、数组、字符串、方法
文章目录 一.分支循环 1.1 分支结构 1.2 循环结构 1.3 跳转语句 1.4 分支循环相关问题 1.4.1 switch是否能作用在byte上,是否能作用在long上,是否能作用在String ...
- html title 不显示_SEO入门教程二:学习最基础的html代码知识
其实,做SEO并不一定要很懂代码,只要基础能看懂就行.当然如果你很懂代码,那是加分项,下面这些基础能看就行. 首先,我们需要了解网页的基本结构,分为head和body两部分,中文解释头部和内容部分,如 ...
- MSIL 教程(三):类和异常处理(转)
转自:http://www.cnblogs.com/Yahong111/archive/2007/08/16/857771.html 续上文[翻译]MSIL 教程(二):数组.分支.循环.使用不安全代 ...
- 【翻译】MSIL 教程(一)
在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了一下,与大家共享, 原文http://www.codeguru.com/Csharp/.NET/net_general/il/arti ...
- 分支循环语句练习和友尽模拟器的综合应用
目录 一.循环语句练习 1.计算 n的阶乘 2. 计算 1!+ 2!+ 3!+ -- + 10! 二.分支循环综合练习 3. 在一个有序数组中查找具体的某个数字n. 4. 编写代码,演示多个字符从两端 ...
- MSIL 教程(一)
在网上发现了一个非常好的MSIL教程,可惜是英文版的,于是就翻译了一下,与大家共享, 原文http://www.codeguru.com/Csharp/.NET/net_general/il/arti ...
- 《零基础看得懂的C++入门教程 》——(8)搞定二维数组与循环嵌套
一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<软件介绍> 想了解编译原理和学习方法点这 ...
- 取得数组下标_《零基础C++入门教程》——(8)搞定二维数组与循环嵌套
一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 预备第一篇,使用软件介绍在这一篇,C++与C使用的软件是一样的,查看这篇即可:<零基础看得懂的C语言入门教程>--(二) ...
- 《零基础看得懂的C语言入门教程 》——(九)C语言二维数组与循环嵌套
一.学习目标 了解二维数组的使用方法 了解循环嵌套的使用方法 目录 C语言真的很难吗?那是你没看这张图,化整为零轻松学习C语言. 第一篇:(一)脱离学习误区 第二篇:(二)C语言没那么难简单开发带你了 ...
最新文章
- Linux13-计划任务crontab
- Locality Sensitive Hashing(局部敏感哈希)
- 网络安全系列之五十 对Web主目录进行备份
- SQL-16 统计出当前各个title类型对应的员工当前薪水对应的平均工资。结果给出title以及平均工资avg。...
- JFreeChart插件使用
- 【UVALive - 3126】Taxi Cab Scheme (二分图,最小路径覆盖)
- 依赖注入[5]: 创建一个简易版的DI框架[下篇]
- 你该怎么去学软件测试,过来人告诉你
- 1 Oracle数据库环境搭建
- 吾之工作要求:死板,教条,僵化
- 国外一些DICOM资源下载网址
- 投资20亿元,又一个云手机基地诞生
- 专题方案 | 项目里程碑管理系统
- 产品生命周期和项目生命周期
- iphone开源汇总
- Map集合、Collections类
- 解决关于引入的网络图片,浏览器无法正常打开的问题
- 北航计算机学院硕士培养方案,北航硕士研究生培养方案.doc
- OpenDDS有问必答
- Standardized QCI characteristics
热门文章
- 最近发现了好多好资源,赶紧收藏一下!【粒子特效】
- 运行个Hello Word也能出Bug?Python、Java、C++等16种语言中枪,最严重可导致文件丢失...
- MIT科学家首次发现只对歌唱有反应的神经元,对,只能人声带伴奏的那种歌
- 云原生首超Linux成最热,92%公司表示开源人才留不住|Linux基金会最新报告
- C罗还会是史上第一个上链的得分王吗?
- 2840页的计算机毕业论文,德州奥斯汀华人博士究竟写了啥
- 无人出租要遍地,Waymo百度这种报告就得常走起
- 丘成桐教授,不必动怒
- 只需2小时,成本不到7块,你我皆可制作的3D机器人
- vue--axios请求头设置传输编码格式+