MSIL实用指南-局部变量的声明、保存和加载

这一篇讲解方法内的局部变量是怎么声明、怎样保存、怎样加载的。

声明局部变量
声明用ILGenerator的DeclareLocal方法,参数是局部变量的数据类型,得到一个局部变量对应的创建类LocalBuilder。
使用格式是
LocalBuilder localBuilderx = ilGenerator.DeclareLocal(typeof(<数据类型>));
实际例子

LocalBuilder localBuilderv1 = ilGenerator.DeclareLocal(typeof(string));//声明一个string类型局部变量
LocalBuilder localBuilderv2 = ilGenerator.DeclareLocal(typeof(int));//声明一个int类型局部变量

LocalBuilder对象有两个重要的属性LocalType和LocalIndex。
属性LocalType的数据类型是System.Type,它表示的是这个局部变量的数据类型。
属性LocalIndex是int类型,它表示的是这个局部变量在这个方法体内的局部变量索引,并且是从0 开始的;假如这个局
部变量所在方法体的ilGenerator第n次调用DeclareLocal方法,那么它的LocalIndex就是(n-1)。

保存局部变量
保存局部变量的指令是Stloc、Stloc_S、Stloc_0、Stloc_1、Stloc_2、Stloc_3。
Stloc是通用指令;
当LocalBuilder的LocalIndex在0到255之间时,推荐用Stloc_S;
当LocalBuilder的LocalIndex为0时,推荐用Stloc_0;
当LocalBuilder的LocalIndex为1时,推荐用Stloc_1;
当LocalBuilder的LocalIndex为2时,推荐用Stloc_2;
当LocalBuilder的LocalIndex为3时,推荐用Stloc_3。
可以把这些指令用一个方法进行包装,源码如下

public static void StormLocal(ILGenerator ilGenerator, LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Stloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_3);
return;
}
if (localIndex > && localIndex <= )
{
ilGenerator.Emit(OpCodes.Stloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Stloc, localIndex);
return;
}
}

加载局部变量
把局部变量加载到运算栈上的指令是Ldloc、Ldloc_S、Ldloc_0、Ldloc_1、Ldloc_2、Ldloc_3。
Ldloc是通用指令;
当LocalBuilder的LocalIndex在0到255之间时,推荐用Ldloc_S;
当LocalBuilder的LocalIndex为0时,推荐用Ldloc_0;
当LocalBuilder的LocalIndex为1时,推荐用Ldloc_1;
当LocalBuilder的LocalIndex为2时,推荐用Ldloc_2;
当LocalBuilder的LocalIndex为3时,推荐用Ldloc_3。
可以把这些指令用一个方法进行包装,源码如下

        public static void LoadLocal(ILGenerator ilGenerator,LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Ldloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_3);
return;
}
if(localIndex> && localIndex<=)
{
ilGenerator.Emit(OpCodes.Ldloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Ldloc, localIndex);
return;
}
}

完整的程序如下

using System;
using System.Reflection;
using System.Reflection.Emit; namespace LX1_ILDemo
{
class Demo04_Local
{
static string binaryName = "Demo04_Local.exe";
static string namespaceName = "LX1_ILDemo";
static string typeName = "EmitLocal"; static AssemblyBuilder assemblyBuilder;
static ModuleBuilder moduleBuilder;
static TypeBuilder typeBuilder;
static MethodBuilder mainMethod;
static ILGenerator ilGenerator; static void Emit_ILCode()
{
MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) });
MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); /* string v1; */
LocalBuilder localBuilderv1 = ilGenerator.DeclareLocal(typeof(string));//声明一个string类型局部变量,第一次声明一个变量,所以它的LocalIndex是0 /* v1="hello"; */
ilGenerator.Emit(OpCodes.Ldstr,"hello");
ilGenerator.Emit(OpCodes. Stloc_0 );
/* Console.WriteLine(v1); */
ilGenerator.Emit(OpCodes.Ldloc_0);
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod); /* v1="hello"; */
ilGenerator.Emit(OpCodes.Ldstr, "world");
StormLocal(ilGenerator, localBuilderv1);
/* Console.WriteLine(v1); */
LoadLocal(ilGenerator, localBuilderv1);
ilGenerator.Emit(OpCodes.Call, writeStringLineMethod); /* int v2; */
LocalBuilder localBuilderv2 = ilGenerator.DeclareLocal(typeof(int));//声明一个int类型局部变量,第二次声明一个变量,所以它的LocalIndex是1 /* v2=int.MaxValue; */
ilGenerator.Emit(OpCodes.Ldc_I4,int.MaxValue);
ilGenerator.Emit(OpCodes.Stloc_1);
/* Console.WriteLine(v2); */
ilGenerator.Emit(OpCodes.Ldloc_1);
ilGenerator.Emit(OpCodes.Call, writeIntLineMethod); /* v1=int.MinValue; */
ilGenerator.Emit(OpCodes.Ldc_I4, int.MinValue);
StormLocal(ilGenerator, localBuilderv2);
/* Console.WriteLine(v2); */
LoadLocal(ilGenerator, localBuilderv2);
ilGenerator.Emit(OpCodes.Call, writeIntLineMethod); } public static void LoadLocal(ILGenerator ilGenerator,LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Ldloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Ldloc_3);
return;
}
if(localIndex> && localIndex<=)
{
ilGenerator.Emit(OpCodes.Ldloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Ldloc, localIndex);
return;
}
} public static void StormLocal(ILGenerator ilGenerator, LocalBuilder localBuilder)
{
int localIndex = localBuilder.LocalIndex;
switch (localIndex)
{
case :
ilGenerator.Emit(OpCodes.Stloc_0);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_1);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_2);
return;
case :
ilGenerator.Emit(OpCodes.Stloc_3);
return;
}
if (localIndex > && localIndex <= )
{
ilGenerator.Emit(OpCodes.Stloc_S, localIndex);
return;
}
else
{
ilGenerator.Emit(OpCodes.Stloc, localIndex);
return;
}
} public static void Generate()
{
InitAssembly(); /* 生成 public class LoadLFDSN */
typeBuilder = moduleBuilder.DefineType(namespaceName + "." + typeName, TypeAttributes.Public); /* 生成 public static void Main() */
GenerateMain(); Emit_ILCode(); EmitReadKey();
ilGenerator.Emit(OpCodes.Ret); /* 设置assembly入口方法 */
assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication); SaveAssembly();
Console.WriteLine("生成成功");
} static void EmitReadKey()
{
/* 生成 Console.ReadKey(); */
MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { });
ilGenerator.Emit(OpCodes.Call, readKeyMethod);
ilGenerator.Emit(OpCodes.Pop);
} static void GenerateMain()
{
mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public
| MethodAttributes.Static, typeof(void), new Type[] { });
ilGenerator = mainMethod.GetILGenerator();
} static void InitAssembly()
{
AssemblyName assemblyName = new AssemblyName(namespaceName);
assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, binaryName);
} static void SaveAssembly()
{
Type t = typeBuilder.CreateType(); //完成Type,这是必须的
assemblyBuilder.Save(binaryName);
}
}
}
上一篇:将Mac OS Lion 加入Windows 域


下一篇:JS面试题⑥