MSIL教程.docx
《MSIL教程.docx》由会员分享,可在线阅读,更多相关《MSIL教程.docx(36页珍藏版)》请在冰豆网上搜索。
![MSIL教程.docx](https://file1.bdocx.com/fileroot1/2022-12/16/fc16670d-1c45-436a-8817-5d8fe0921010/fc16670d-1c45-436a-8817-5d8fe09210101.gif)
MSIL教程
基本概念
微软中间语言(MSIL)是一种语言,是许多编译器(C#,VB.NET等)的输出
中间语言反汇编器(ILDasm)让用户以人可阅读的格式查看MSIL代码。
中间语言编译器(ILAsm)从MSIL语言生成可执行文件
存放路径:
WINNT\Microsoft.NET\Framework\vn.nn.nn
语言参考
所有MSIL指令的说明
FrameworkSDK\ToolDevelopersGuide\docs\PartitionIIMetadata.doc
MSIL命令的完整列表
FrameworkSDK\ToolDevelopersGuide\docs\PartitionIIICIL.doc
一般信息
在MSIL中,所有的操作都在栈上完成。
当调用一个函数的时候,其参数和局部变量都被分配到栈上。
函数的代码从该栈开始,把一些值压入栈,对这些值进行一些操作,从栈上取出值。
执行MSIL命令和函数由3个步骤完成
Step1把命令操作数和函数参数压入栈(ld命令)。
Step2执行命令或者调用函数。
命令或函数从栈中取出他们的操作数(参数)并把他们压入结果栈(返回值)。
Step3从栈中读取结果值(st命令)。
注意:
上面的步骤是可选的,例如void函数不会压入一个结果值到栈。
栈包含值类型对象和引用类型对象
引用类型对象本身保存在堆中
示例项目
打印字符串
用到的MSIL指令
.entrypoint定义程序的入口点,该函数在程序启动的时候由.NET运行库调用
.maxstack定义函数代码所用堆栈的最大深度。
用到的MSIL命令
ldstrstring把一个字符串常量装入堆栈。
callfunction(parameters)调用静态函数,函数的参数必须在函数调用前装入堆栈。
pop取出栈顶的值,当我们不需要把值存入变量时使用。
ret从一个函数中返回。
.assemblyPrintString{}
/*
Console.WriteLine("Hello,World)"
*/
.methodstaticpublicvoidmain()ilmanaged
{
.entrypoint //该函数是程序的入口
.maxstack8
//*****************************************************
//Console.WriteLine("Hello,World)";
//*****************************************************
ldstr"Hello,World" //把字符串压入堆栈
//调用静态的System.Console.Writeline函数
//(函数移除栈顶的字符串)
call void[mscorlib]System.Console:
:
WriteLine
(classSystem.String)
//*****************************************************
ldstr"PressEntertocontinue"
call void[mscorlib]System.Console:
:
WriteLine
(classSystem.String)
//调用System.Console.Read函数
callint32[mscorlib]System.Console:
:
Read()
//pop指令移除栈顶元素
//(移除由Read()函数返回的数字
pop
//*****************************************************
ret
}
赋值
该程序给一个变量赋与int值并把它打印到控制台窗口
用到的MSIL命令
ldc.i4.n把一个32位的常量(n从0到8)装入堆栈
stloc.n把一个从堆栈中返回的值存入第n(n从0到8)个局部变量
.assemblyXequalN{}
//intx;
//x=7;
//Console.WriteLine(x);
.methodstaticpublicvoidmain()ilmanaged
{
.entrypoint
.maxstack8
.localsinit([0]int32x) //分配一个局部变量
//*****************************************************
//x=7;
//*****************************************************
ldc.i4.7 //把常量装入堆栈
stloc.0 //把堆栈中的值存入第0个变量
//*****************************************************
//Console.WriteLine(x);
//*****************************************************
ldloc.0 //把第0个变量转入堆栈
callvoid[mscorlib]System.Console:
:
WriteLine(int32)
ret
}
数据运算
本程序从控制台读取2个数字,对它们进行简单的运算,然后显示结果。
要用到的MSIL命令
add2个值相加。
命令的参数必须在调用前装入堆栈,该函数从堆栈中移除参数并把运算后的结果压入堆栈。
sub2个值相减。
mul2个值相乘。
.assemblyOperations{}
/*
//程序的C#代码:
intx,y,z;
strings;
Console.WriteLine("Enterx:
");
s=Console.ReadLine();
x=Int32.Parse(s);
Console.WriteLine("Entery:
");
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("");
*/
.methodstaticpublicvoidmain()ilmanaged
{
.entrypoint
.maxstack8
.localsinit([0]int32x,
[1]int32y,
[2]int32z,
[3]strings)
//*****************************************************
//Console.WriteLine("Enterx:
");
//*****************************************************
ldstr "Enterx:
" //把字符装入堆栈
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 "Entery:
"
//装入字符串
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=" //loadstringontostack
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
}
数组
本程序分配一个int型的数组并给他的元素赋值,然后打印出元素和数组的长度。
要用到的MSIL命令
newarrtype生成一个元素类型为type的数组。
数组的大小必须在调用该命令前装入堆栈。
该命令会把一个数组的引用装入堆栈。
stelem.i4给一个数组成员赋值。
数组的引用、下标和值必须在调用该命令前装入堆栈。
ldelematype把数组元素的地址装入堆栈。
数组的引用和下标必须在调用该命令前装入堆栈。
地址用来调用非静态函数(参见后面)。
ldlen把数组的长度装入堆栈。
数组的引用必须在调用该命令前装入堆栈。
ldloca.svariable—把变量的地址装入堆栈。
ldc.i4.svalue把一个Int32的常量装入堆栈(用于大于8位的数)。
conv.i4把堆栈中值转换成Int32类型。
callinstancefunction(arguments)调用类的非静态函数。
在调用一个非静态函数之前,我们必须把某个类的实例的地址和函数的参数装入堆栈。
在本例中,地址通过ldelema和ldloca命令装入。
.assemblyArray1{}
/*
//ThisprogramworksasC#code:
int[]x=newint[5];
x[0]=10;
x[1]=20;
Console.WriteLine("x[0]="+x[0].ToString());
Console.WriteLine("x[1]="+x[1].ToString());
Console.WriteLine("Arraylength="+x.Length.ToString());
*/
.methodstaticpublicvoidmain()ilmanaged
{
.entrypoint
.maxstack8
.localsinit([0]int32[]x,
[1]int32tmp) //由编译器生成
//*****************************************************
//x=newint[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 instancestring[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("Arraylength="+x.Length.ToString());
//*****************************************************
ldstr "Arraylength="
//堆栈:
"Arraylength="
ldloc.0 //把第0个变量装入堆栈
//堆栈:
"Arraylength="->x
Ldlen //把数组的长度装入堆栈
//堆栈:
"Arraylength="->5
conv.i4 //把栈顶的值转换为Int32,并把他装入堆栈
//堆栈:
"Arraylength="->5
stloc.1 //把刚才的值存入第1个局部变量(tmp)
//堆栈:
"Arraylength="
ldloca.s tmp //把变量tmp的地址装入堆栈
//堆栈:
"Arraylength="->&tmp
call instancestring[mscorlib]System.Int32:
:
ToString()
//堆栈:
"Arraylength="->"5"
call string[mscorlib]System.String:
:
Concat
(string,string)
//堆栈:
"Arraylength=5"
call void[msco