示例#1
0
        Instruction ReplaceCalli(ILProcessor ilProcessor, Instruction instruction, MethodReference calledMethod)
        {
            //public static unsafe void Calli(
            //System.Runtime.InteropServices.CallingConvention callingConvention, Type returnType, Type arg0, ...)
            var stack = Analysis[instruction.Previous];
            Tuple <Instruction, StackAnalyser.StackEntry> entry;

            var module = ilProcessor.Body.Method.Module;

            var args = new List <Tuple <Instruction, StackAnalyser.StackEntry> >();

            for (int i = 0; i < calledMethod.Parameters.Count - 2; ++i)
            {
                entry = stack.Head;
                stack = stack.Tail;
                args.Add(entry);
            }
            args.Reverse();

            entry = stack.Head;
            stack = stack.Tail;
            var returnType = entry;

            entry = stack.Head;
            stack = stack.Tail;
            var callingConvention = entry.Item2;

            Mono.Cecil.MethodCallingConvention methodCallingConvention;
            if (callingConvention.IsConstant)
            {
                switch ((System.Runtime.InteropServices.CallingConvention)callingConvention.Value)
                {
                case System.Runtime.InteropServices.CallingConvention.Cdecl:
                    methodCallingConvention = MethodCallingConvention.C;
                    break;

                case System.Runtime.InteropServices.CallingConvention.FastCall:
                    methodCallingConvention = MethodCallingConvention.FastCall;
                    break;

                case System.Runtime.InteropServices.CallingConvention.StdCall:
                    methodCallingConvention = MethodCallingConvention.StdCall;
                    break;

                case System.Runtime.InteropServices.CallingConvention.ThisCall:
                    methodCallingConvention = MethodCallingConvention.ThisCall;
                    break;

                case System.Runtime.InteropServices.CallingConvention.Winapi:
                    methodCallingConvention = MethodCallingConvention.StdCall;
                    break;

                default:
                    methodCallingConvention = MethodCallingConvention.Default;
                    break;
                }
            }
            else
            {
                Console.WriteLine("Calling convention passed to Calli is not a constant expression.");
                var next = instruction.Next;
                StackAnalyser.RemoveInstructionChain(ilProcessor.Body.Method, instruction, Analysis);
                return(next);
            }

            TypeReference returnTypeReference = null;

            if (returnType.Item2.IsConstant)
            {
                Type retTy = returnType.Item2.Value;
                returnTypeReference = module.Import(retTy);
            }
            else if (returnType.Item1.OpCode == OpCodes.Call && returnType.Item1.Operand is MethodReference && (returnType.Item1.Operand as MethodReference).Name == "GetTypeFromHandle")
            {
                var ldtoken_stack = Analysis[returnType.Item1.Previous];
                var ldtoken       = ldtoken_stack.Head;

                returnTypeReference = ldtoken.Item1.Operand as TypeReference;
            }

            if (returnTypeReference == null)
            {
                Console.WriteLine("Return type passed to Calli is not a constant expression.");
                var next = instruction.Next;
                StackAnalyser.RemoveInstructionChain(ilProcessor.Body.Method, instruction, Analysis);
                return(next);
            }

            TypeReference[] parameterTypesArray = new TypeReference[args.Count];
            for (int i = 0; i < args.Count; ++i)
            {
                var arg = args[i];

                if (arg.Item2.IsConstant)
                {
                    parameterTypesArray[i] = module.Import((Type)arg.Item2.Value);
                }
                else if (arg.Item1.OpCode == OpCodes.Call && arg.Item1.Operand is MethodReference && (arg.Item1.Operand as MethodReference).Name == "GetTypeFromHandle")
                {
                    var ldtoken_stack = Analysis[arg.Item1.Previous];
                    var ldtoken       = ldtoken_stack.Head;

                    parameterTypesArray[i] = ldtoken.Item1.Operand as TypeReference;
                }
            }

            if (parameterTypesArray.Any(ty => ty == null))
            {
                Console.WriteLine("Type passed to Calli is not a constant expression.");
                var next = instruction.Next;
                StackAnalyser.RemoveInstructionChain(ilProcessor.Body.Method, instruction, Analysis);
                return(next);
            }

            var callSite = new CallSite(returnTypeReference);

            callSite.CallingConvention = methodCallingConvention;
            foreach (var parameterType in parameterTypesArray)
            {
                callSite.Parameters.Add(new ParameterDefinition(parameterType));
            }

            {
                var calli = Instruction.Create(OpCodes.Calli, callSite);
                ilProcessor.InsertAfter(instruction, calli);
                StackAnalyser.RemoveInstructionChain(ilProcessor.Body.Method, instruction, Analysis);
                return(calli.Next);
            }
        }