• 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 0:
                        ilGenerator.Emit(OpCodes.Stloc_0);
                        return;
                    case 1:
                        ilGenerator.Emit(OpCodes.Stloc_1);
                        return;
                    case 2:
                        ilGenerator.Emit(OpCodes.Stloc_2);
                        return;
                    case 3:
                        ilGenerator.Emit(OpCodes.Stloc_3);
                        return;
                }
                if (localIndex > 0 && localIndex <= 255)
                {
                    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 0:
                        ilGenerator.Emit(OpCodes.Ldloc_0);
                        return;
                    case 1:
                        ilGenerator.Emit(OpCodes.Ldloc_1);
                        return;
                    case 2:
                        ilGenerator.Emit(OpCodes.Ldloc_2);
                        return;
                    case 3:
                        ilGenerator.Emit(OpCodes.Ldloc_3);
                        return;
                }
                if(localIndex>0 && localIndex<=255)
                {
                    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 0:
                        ilGenerator.Emit(OpCodes.Ldloc_0);
                        return;
                    case 1:
                        ilGenerator.Emit(OpCodes.Ldloc_1);
                        return;
                    case 2:
                        ilGenerator.Emit(OpCodes.Ldloc_2);
                        return;
                    case 3:
                        ilGenerator.Emit(OpCodes.Ldloc_3);
                        return;
                }
                if(localIndex>0 && localIndex<=255)
                {
                    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 0:
                        ilGenerator.Emit(OpCodes.Stloc_0);
                        return;
                    case 1:
                        ilGenerator.Emit(OpCodes.Stloc_1);
                        return;
                    case 2:
                        ilGenerator.Emit(OpCodes.Stloc_2);
                        return;
                    case 3:
                        ilGenerator.Emit(OpCodes.Stloc_3);
                        return;
                }
                if (localIndex > 0 && localIndex <= 255)
                {
                    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);
            }
        }
    }
    View Code
  • 相关阅读:
    mybatis设置添加新对象数据的时候id使用uuid类型自动写入数据库
    mysql大小写敏感配置
    linux中iproute2工具介绍
    openwrt中补丁命名规则
    Java: ThreadLocal 用法详解和原理(转)
    Git: tag 标签操作
    android: 详解 Android 中的 HandlerThread(转)
    android: drawable中同时设置state_enabled和和state_pressed不起作用的问题
    C语言:记录32bit数据的一些常用位操作
    android: 分享一个带多行选择功能的RadioGroup
  • 原文地址:https://www.cnblogs.com/tkt2016/p/8602508.html
Copyright © 2020-2023  润新知