MSIL实用指南-加载和保存参数
本篇讲解怎么加载和保存参数,以及参数起始序号的确定。
参数的加载
加载参数的指令是Ldarg、Ldarg_S、Ldarg_0、Ldarg_1、Ldarg_2、Ldarg_3。
Ldarg_0是加载第0个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_0);
Ldarg_1是加载第1个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_1);
Ldarg_2是加载第2个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_2);
Ldarg_3是加载第3个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_3);
Ldarg_S是加载次序为0到255的参数,例子 ilGenerator.Emit(OpCodes.Ldarg_S,5);
Ldarg加载任意次序的参数,例子 ilGenerator.Emit(OpCodes.Ldarg,6)。
我们可以根据指令的说明实现一个方便调用的方法,源码如下
public static void LoadArg(ILGenerator ilGenerator, int argIndex) { switch (argIndex) { case 0: ilGenerator.Emit(OpCodes.Ldarg_0); return; case 1: ilGenerator.Emit(OpCodes.Ldarg_1); return; case 2: ilGenerator.Emit(OpCodes.Ldarg_2); return; case 3: ilGenerator.Emit(OpCodes.Ldarg_3); return; } if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Ldarg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Ldarg, argIndex); return; } }
参数的保存
保存参数的指令是Starg、Starg_S
Ldarg_S是保存次序为0到255的参数,例子 ilGenerator.Emit(OpCodes.Starg_S,1);
Starg加载任意次序的参数,例子 ilGenerator.Emit(OpCodes.Starg,6)。
我们可以根据指令的说明实现一个方便调用的方法,源码如下
public static void StormArg(ILGenerator ilGenerator, int argIndex) { if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Starg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Starg, argIndex); return; } }
参数起始序号的确定
参数的起始序号不一定从0开始,也可能从1开始,这是由方法是否是static决定的。
如果参数所在的方法是static修饰的,序号从0开始;
如果不是static修饰,则从0开始。
完整的一个例子如下
using System; using System.Reflection; using System.Reflection.Emit; namespace LX1_ILDemo { class Demo08_Arg { static string binaryName = "Demo08_Arg.exe"; static string namespaceName = "LX1_ILDemo"; static string typeName = "ArgTest"; static AssemblyBuilder assemblyBuilder; static ModuleBuilder moduleBuilder; static TypeBuilder typeBuilder; static MethodBuilder mainMethod; static MethodBuilder printStaticMethod; static MethodBuilder printInstaceMethod; static ConstructorBuilder constructorBuilder; static void Emit_PrintInstace() { printInstaceMethod = typeBuilder.DefineMethod("PrintInstanceArg", MethodAttributes.Public, typeof(void), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(string) }); ILGenerator printILInstaceGenerator = printInstaceMethod.GetILGenerator(); ParameterBuilder ab1 = printStaticMethod.DefineParameter(1, ParameterAttributes.None, "i1"); ParameterBuilder ab2 = printStaticMethod.DefineParameter(2, ParameterAttributes.None, "i2"); ParameterBuilder ab3 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i3"); ParameterBuilder ab4 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i4"); ParameterBuilder ab5 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "s5"); MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }); MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); LoadArg(printILInstaceGenerator,1); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 2); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 3); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 4); printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod); LoadArg(printILInstaceGenerator, 5); printILInstaceGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILInstaceGenerator.Emit(OpCodes.Ldstr, "world"); StormArg(printILInstaceGenerator, 5); LoadArg(printILInstaceGenerator, 5); printILInstaceGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILInstaceGenerator.Emit(OpCodes.Ret); } public static void LoadArg(ILGenerator ilGenerator, int argIndex) { switch (argIndex) { case 0: ilGenerator.Emit(OpCodes.Ldarg_0); return; case 1: ilGenerator.Emit(OpCodes.Ldarg_1); return; case 2: ilGenerator.Emit(OpCodes.Ldarg_2); return; case 3: ilGenerator.Emit(OpCodes.Ldarg_3); return; } if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Ldarg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Ldarg, argIndex); return; } } public static void StormArg(ILGenerator ilGenerator, int argIndex) { if (argIndex > 0 && argIndex <= 255) { ilGenerator.Emit(OpCodes.Starg_S, argIndex); return; } else { ilGenerator.Emit(OpCodes.Starg, argIndex); return; } } static void Emit_PrintStatic() { printStaticMethod = typeBuilder.DefineMethod("PrintStaticArg", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(string) }); ILGenerator printILGenerator = printStaticMethod.GetILGenerator(); ParameterBuilder ab1 = printStaticMethod.DefineParameter(1, ParameterAttributes.None, "i1"); ParameterBuilder ab2 = printStaticMethod.DefineParameter(2, ParameterAttributes.None, "i2"); ParameterBuilder ab3 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i3"); ParameterBuilder ab4 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i4"); ParameterBuilder ab5 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "s5"); MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }); MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }); printILGenerator.Emit(OpCodes.Ldarg_0); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_1); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_2); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_3); printILGenerator.Emit(OpCodes.Call, writeIntLineMethod); printILGenerator.Emit(OpCodes.Ldarg_S,4); printILGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILGenerator.Emit(OpCodes.Ldstr, "world"); printILGenerator.Emit(OpCodes.Starg_S, 4); printILGenerator.Emit(OpCodes.Ldarg_S, 4); printILGenerator.Emit(OpCodes.Call, writeStringLineMethod); printILGenerator.Emit(OpCodes.Ret); } public static void Generate() { InitAssembly(); typeBuilder = moduleBuilder.DefineType( namespaceName+"."+ typeName, TypeAttributes.Public); constructorBuilder = typeBuilder.DefineDefaultConstructor( MethodAttributes.Public); Emit_PrintStatic(); Emit_PrintInstace(); EmitMain(); /* 设置assembly入口方法 */ assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication); SaveAssembly(); Console.WriteLine("生成成功"); } static void EmitMain() { mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { }); ILGenerator mainILGenerator = mainMethod.GetILGenerator(); mainILGenerator.Emit(OpCodes.Ldc_I4,(int)200); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)300); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)400); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)500); mainILGenerator.Emit(OpCodes.Ldstr,"hello static"); mainILGenerator.Emit(OpCodes.Call, printStaticMethod); LocalBuilder localBuilder = mainILGenerator.DeclareLocal(typeof(string)); mainILGenerator.Emit(OpCodes.Newobj, constructorBuilder); mainILGenerator.Emit(OpCodes.Stloc_0); mainILGenerator.Emit(OpCodes.Ldloc_0); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)200); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)300); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)400); mainILGenerator.Emit(OpCodes.Ldc_I4, (int)500); mainILGenerator.Emit(OpCodes.Ldstr, "hello instance"); mainILGenerator.Emit(OpCodes.Call, printInstaceMethod); MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { }); mainILGenerator.Emit(OpCodes.Call, readKeyMethod); mainILGenerator.Emit(OpCodes.Pop); mainILGenerator.Emit(OpCodes.Ret); } 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); } } }