Beispiel #1
0
 public static void Emit(ILGenerator ilg, ILInstruction il)
 {
     if (il.Operand == null) {
         ilg.Emit(il.Code);
         return;
     }
     var typeName = il.Operand.GetType().Name;
     switch (typeName) {
         case OperandTypeNames.Byte:
             ilg.Emit(il.Code, (byte)il.Operand);
             break;
         case OperandTypeNames.Float:
             ilg.Emit(il.Code, (float)il.Operand);
             break;
         case OperandTypeNames.Double:
             ilg.Emit(il.Code, (double)il.Operand);
             break;
         case OperandTypeNames.Short:
             ilg.Emit(il.Code, (short)il.Operand);
             break;
         case OperandTypeNames.Int:
             ilg.Emit(il.Code, (int)il.Operand);
             break;
         case OperandTypeNames.Long:
             ilg.Emit(il.Code, (long)il.Operand);
             break;
         case OperandTypeNames.String:
             ilg.Emit(il.Code, (string)il.Operand);
             break;
         case OperandTypeNames.Method:
             ilg.Emit(il.Code, (MethodInfo)il.Operand);
             break;
         case OperandTypeNames.Constructor:
             ilg.Emit(il.Code, (ConstructorInfo)il.Operand);
             break;
         case OperandTypeNames.Field:
             ilg.Emit(il.Code, (FieldInfo)il.Operand);
             break;
         case OperandTypeNames.Label:
             ilg.Emit(il.Code, (Label)il.Operand);
             break;
         default:
             throw new NotSupportedException(string.Format("OperandType: {0}", typeName));
     }
 }
Beispiel #2
0
        /// <summary>
        /// Constructs the array of ILInstructions according to the IL byte code.
        /// </summary>
        /// <param name="module"></param>
        private void ConstructInstructions(Module module)
        {
            byte[] il = this.il;
            int position = 0;
            instructions = new List<ILInstruction>();
            while (position < il.Length)
            {
                ILInstruction instruction = new ILInstruction();

                // get the operation code of the current instruction
                OpCode code = OpCodes.Nop;
                ushort value = il[position++];
                if (value != 0xfe)
                {
                    code = Globals.singleByteOpCodes[(int)value];
                }
                else
                {
                    value = il[position++];
                    code = Globals.multiByteOpCodes[(int)value];
                    value = (ushort)(value | 0xfe00);
                }
                instruction.Code = code;
                instruction.Offset = position - 1;
                int metadataToken = 0;
                // get the operand of the current operation
                switch (code.OperandType)
                {
                    case OperandType.InlineBrTarget:
                        metadataToken = ReadInt32(il, ref position);
                        metadataToken += position;
                        instruction.Operand = metadataToken;
                        break;
                    case OperandType.InlineField:
                        metadataToken = ReadInt32(il, ref position);
                        instruction.Operand = module.ResolveField(metadataToken);
                        break;
                    case OperandType.InlineMethod:
                        metadataToken = ReadInt32(il, ref position);
                        try
                        {
                            instruction.Operand = module.ResolveMethod(metadataToken);
                        }
                        catch
                        {
                            instruction.Operand = module.ResolveMember(metadataToken);
                        }
                        break;
                    case OperandType.InlineSig:
                        metadataToken = ReadInt32(il, ref position);
                        instruction.Operand = module.ResolveSignature(metadataToken);
                        break;
                    case OperandType.InlineTok:
                        metadataToken = ReadInt32(il, ref position);
                        // SSS : see what to do here
                        break;
                    case OperandType.InlineType:
                        metadataToken = ReadInt32(il, ref position);
                        instruction.Operand = module.ResolveType(metadataToken);
                        break;
                    case OperandType.InlineI:
                        {
                            instruction.Operand = ReadInt32(il, ref position);
                            break;
                        }
                    case OperandType.InlineI8:
                        {
                            instruction.Operand = ReadInt64(il, ref position);
                            break;
                        }
                    case OperandType.InlineNone:
                        {
                            instruction.Operand = null;
                            break;
                        }
                    case OperandType.InlineR:
                        {
                            instruction.Operand = ReadDouble(il, ref position);
                            break;
                        }
                    case OperandType.InlineString:
                        {
                            metadataToken = ReadInt32(il, ref position);
                            instruction.Operand = module.ResolveString(metadataToken);
                            break;
                        }
                    case OperandType.InlineSwitch:
                        {
                            int count = ReadInt32(il, ref position);
                            int[] casesAddresses = new int[count];
                            for (int i = 0; i < count; i++)
                            {
                                casesAddresses[i] = ReadInt32(il, ref position);
                            }
                            int[] cases = new int[count];
                            for (int i = 0; i < count; i++)
                            {
                                cases[i] = position + casesAddresses[i];
                            }
                            break;
                        }
                    case OperandType.InlineVar:
                        {
                            instruction.Operand = ReadUInt16(il, ref position);
                            break;
                        }
                    case OperandType.ShortInlineBrTarget:
                        {
                            instruction.Operand = ReadSByte(il, ref position) + position;
                            break;
                        }
                    case OperandType.ShortInlineI:
                        {
                            instruction.Operand = ReadSByte(il, ref position);
                            break;
                        }
                    case OperandType.ShortInlineR:
                        {
                            instruction.Operand = ReadSingle(il, ref position);
                            break;
                        }
                    case OperandType.ShortInlineVar:
                        {
                            instruction.Operand = ReadByte(il, ref position);
                            break;
                        }
                    default:
                        {
                            throw new Exception("Unknown operand type.");
                        }
                }
                instructions.Add(instruction);
            }
        }
Beispiel #3
0
        static void RedirectMethodInfo(ILInstruction il)
        {
            Type targetType = typeof(Console);
            var targetMethod = targetType.GetMethod("WriteLine", new Type[] { typeof(string) });

            var redirect = typeof(Program).GetMethod("WriteLine");

            var method = (MethodInfo)il.Operand;
            if (il.Operand.Equals(targetMethod)) {
                il.Operand = redirect;
            }
        }
Beispiel #4
0
 public StringToInt(ILInstruction argument, string[] map)
     : base(OpCode.StringToInt)
 {
     this.Argument = argument;
     this.Map      = map;
 }
 public CodeThisReferenceExpression(ILInstruction inline) : base(inline)
 {
 }
 /// <summary>
 /// if (logic.not(ldloc V_1)) Block IL_0149 {
 ///     dynamic.setmember.compound B(target, dynamic.binary.operator AddAssign(ldloc V_2,  value))
 /// } else Block IL_0151 {
 ///     dynamic.invokemember.invokespecial.discard add_B(target, value)
 /// }
 /// </summary>
 static bool MatchIsEventAssignmentIfInstruction(ILInstruction ifInst, DynamicIsEventInstruction isEvent, ILVariable flagVar, ILVariable getMemberVar,
                                                 out DynamicSetMemberInstruction setMemberInst, out ILInstruction getMemberVarUse, out ILInstruction isEventConditionUse)
 {
     setMemberInst       = null;
     getMemberVarUse     = null;
     isEventConditionUse = null;
     if (!ifInst.MatchIfInstruction(out var condition, out var trueInst, out var falseInst))
     {
         return(false);
     }
     if (MatchFlagEqualsZero(condition, flagVar))
     {
         if (!condition.MatchCompEquals(out var left, out _))
         {
             return(false);
         }
         isEventConditionUse = left;
     }
     else if (condition.MatchLdLoc(flagVar))
     {
         var tmp = trueInst;
         trueInst            = falseInst;
         falseInst           = tmp;
         isEventConditionUse = condition;
     }
     else
     {
         return(false);
     }
     setMemberInst = Block.Unwrap(trueInst) as DynamicSetMemberInstruction;
     if (!(setMemberInst != null))
     {
         return(false);
     }
     if (!isEvent.Argument.Match(setMemberInst.Target).Success)
     {
         return(false);
     }
     if (!(Block.Unwrap(falseInst) is DynamicInvokeMemberInstruction invokeMemberInst && invokeMemberInst.Arguments.Count == 2))
     {
         return(false);
     }
     if (!isEvent.Argument.Match(invokeMemberInst.Arguments[0]).Success)
     {
         return(false);
     }
     if (!(setMemberInst.Value is DynamicBinaryOperatorInstruction binOp && binOp.Left.MatchLdLoc(getMemberVar)))
     {
         return(false);
     }
     getMemberVarUse = binOp.Left;
     return(true);
 }
 static bool MatchFlagEqualsZero(ILInstruction condition, ILVariable flagVar)
 {
     return(condition.MatchCompEquals(out var left, out var right) &&
            left.MatchLdLoc(flagVar) &&
            right.MatchLdcI4(0));
 }
        public void EmulateInstruction(ILInstruction instruction)
        {
            // TODO: Perhaps include flag register updates?

            Registers[VMRegisters.IP] = new VMSlot()
            {
                U8 = (ulong)(instruction.Offset + instruction.Size)
            };
            Registers[VMRegisters.SP] = new VMSlot()
            {
                U4 = (uint)instruction.ProgramState.Stack.Count
            };

            switch (instruction.OpCode.Code)
            {
            case ILCode.PUSHR_OBJECT:
            {
                // TODO: This is definitely not accurate, but works for the purpose of this mini emulator (pushr_object sp).
                Stack.Push(new VMSlot
                    {
                        U8 = Registers[(VMRegisters)instruction.Operand].U8
                    });
                break;
            }

            case ILCode.PUSHR_BYTE:
                Stack.Push(new VMSlot
                {
                    U1 = Registers[(VMRegisters)instruction.Operand].U1
                });
                break;

            case ILCode.PUSHR_WORD:
                Stack.Push(new VMSlot
                {
                    U2 = Registers[(VMRegisters)instruction.Operand].U2
                });
                break;

            case ILCode.PUSHR_DWORD:
                Stack.Push(new VMSlot
                {
                    U4 = Registers[(VMRegisters)instruction.Operand].U4
                });
                break;

            case ILCode.PUSHR_QWORD:
                Stack.Push(new VMSlot
                {
                    U8 = Registers[(VMRegisters)instruction.Operand].U8
                });
                break;

            case ILCode.PUSHI_DWORD:
                uint  imm = Convert.ToUInt32(instruction.Operand);
                ulong sx  = (imm & 0x80000000) != 0 ? 0xffffffffUL << 32 : 0;
                Stack.Push(new VMSlot
                {
                    U8 = sx | imm
                });
                break;

            case ILCode.PUSHI_QWORD:
                Stack.Push(new VMSlot
                {
                    U8 = Convert.ToUInt64(instruction.Operand)
                });
                break;

            case ILCode.ADD_DWORD:
            {
                var op2 = Stack.Pop();
                var op1 = Stack.Pop();
                Stack.Push(new VMSlot
                    {
                        U4 = op1.U4 + op2.U4
                    });
                break;
            }

            case ILCode.ADD_QWORD:
            {
                var op2 = Stack.Pop();
                var op1 = Stack.Pop();
                Stack.Push(new VMSlot
                    {
                        U8 = op1.U8 + op2.U8
                    });
                break;
            }

            case ILCode.POP:
            {
                Registers[(VMRegisters)instruction.Operand] = Stack.Pop();
                break;
            }

            case ILCode.NOP:
                break;

            default:
                throw new EmulationException($"Failed to emulate the instruction {instruction}.",
                                             new NotSupportedException($"OpCode {instruction.OpCode.Code} not supported yet!"));
            }
        }
        public void Run(ILFunction function, ILTransformContext context)
        {
            if (!context.Settings.Dynamic)
            {
                return;
            }

            this.context = context;

            Dictionary <IField, CallSiteInfo> callsites          = new Dictionary <IField, CallSiteInfo>();
            HashSet <BlockContainer>          modifiedContainers = new HashSet <BlockContainer>();

            foreach (var block in function.Descendants.OfType <Block>())
            {
                if (block.Instructions.Count < 2)
                {
                    continue;
                }
                // Check if, we deal with a callsite cache field null check:
                // if (comp(ldsfld <>p__3 == ldnull)) br IL_000c
                // br IL_002b
                if (!(block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst))
                {
                    continue;
                }
                if (!(block.Instructions.LastOrDefault() is Branch branchAfterInit))
                {
                    continue;
                }
                if (!MatchCallSiteCacheNullCheck(ifInst.Condition, out var callSiteCacheField, out var callSiteDelegate, out bool invertBranches))
                {
                    continue;
                }
                if (!ifInst.TrueInst.MatchBranch(out var trueBlock))
                {
                    continue;
                }
                Block callSiteInitBlock, targetBlockAfterInit;
                if (invertBranches)
                {
                    callSiteInitBlock    = branchAfterInit.TargetBlock;
                    targetBlockAfterInit = trueBlock;
                }
                else
                {
                    callSiteInitBlock    = trueBlock;
                    targetBlockAfterInit = branchAfterInit.TargetBlock;
                }
                if (!ScanCallSiteInitBlock(callSiteInitBlock, callSiteCacheField, callSiteDelegate, out var callSiteInfo, out var blockAfterInit))
                {
                    continue;
                }
                if (targetBlockAfterInit != blockAfterInit)
                {
                    continue;
                }
                callSiteInfo.DelegateType          = callSiteDelegate;
                callSiteInfo.ConditionalJumpToInit = ifInst;
                callSiteInfo.Inverted        = invertBranches;
                callSiteInfo.BranchAfterInit = branchAfterInit;
                callsites.Add(callSiteCacheField, callSiteInfo);
            }

            var storesToRemove = new List <StLoc>();

            foreach (var invokeCall in function.Descendants.OfType <CallVirt>())
            {
                if (invokeCall.Method.DeclaringType.Kind != TypeKind.Delegate || invokeCall.Method.Name != "Invoke" || invokeCall.Arguments.Count == 0)
                {
                    continue;
                }
                var firstArgument = invokeCall.Arguments[0];
                if (firstArgument.MatchLdLoc(out var stackSlot) && stackSlot.Kind == VariableKind.StackSlot && stackSlot.IsSingleDefinition)
                {
                    firstArgument = ((StLoc)stackSlot.StoreInstructions[0]).Value;
                }
                if (!firstArgument.MatchLdFld(out var cacheFieldLoad, out var targetField))
                {
                    continue;
                }
                if (!cacheFieldLoad.MatchLdsFld(out var cacheField))
                {
                    continue;
                }
                if (!callsites.TryGetValue(cacheField, out var callsite))
                {
                    continue;
                }
                context.Stepper.Step("Transform callsite for " + callsite.MemberName);
                var           deadArguments = new List <ILInstruction>();
                ILInstruction replacement   = MakeDynamicInstruction(callsite, invokeCall, deadArguments);
                if (replacement == null)
                {
                    continue;
                }
                invokeCall.ReplaceWith(replacement);
                Debug.Assert(callsite.ConditionalJumpToInit?.Parent is Block);
                var block = ((Block)callsite.ConditionalJumpToInit.Parent);
                if (callsite.Inverted)
                {
                    block.Instructions.Remove(callsite.ConditionalJumpToInit);
                    callsite.BranchAfterInit.ReplaceWith(callsite.ConditionalJumpToInit.TrueInst);
                }
                else
                {
                    block.Instructions.Remove(callsite.ConditionalJumpToInit);
                }
                foreach (var arg in deadArguments)
                {
                    if (arg.MatchLdLoc(out var temporary) && temporary.Kind == VariableKind.StackSlot && temporary.IsSingleDefinition && temporary.LoadCount == 0)
                    {
                        StLoc stLoc = (StLoc)temporary.StoreInstructions[0];
                        if (stLoc.Parent is Block storeParentBlock)
                        {
                            var value = stLoc.Value;
                            if (value.MatchLdsFld(out var cacheFieldCopy) && cacheFieldCopy.Equals(cacheField))
                            {
                                storesToRemove.Add(stLoc);
                            }
                            if (value.MatchLdFld(out cacheFieldLoad, out var targetFieldCopy) && cacheFieldLoad.MatchLdsFld(out cacheFieldCopy) && cacheField.Equals(cacheFieldCopy) && targetField.Equals(targetFieldCopy))
                            {
                                storesToRemove.Add(stLoc);
                            }
                        }
                    }
                }
                modifiedContainers.Add((BlockContainer)block.Parent);
            }

            foreach (var inst in storesToRemove)
            {
                Block parentBlock = (Block)inst.Parent;
                parentBlock.Instructions.RemoveAt(inst.ChildIndex);
            }

            foreach (var container in modifiedContainers)
            {
                container.SortBlocks(deleteUnreachableBlocks: true);
            }
        }
        private bool PatternMatchRefTypes(Block block, BlockContainer container, ILTransformContext context, ref ControlFlowGraph?cfg)
        {
            if (!block.MatchIfAtEndOfBlock(out var condition, out var trueInst, out var falseInst))
            {
                return(false);
            }
            int pos = block.Instructions.Count - 3;

            if (condition.MatchLdLoc(out var conditionVar))
            {
                // stloc conditionVar(comp.o(ldloc s == ldnull))
                // if (logic.not(ldloc conditionVar)) br trueBlock
                if (pos < 0)
                {
                    return(false);
                }
                if (!(conditionVar.IsSingleDefinition && conditionVar.LoadCount == 1 &&
                      conditionVar.Kind == VariableKind.StackSlot))
                {
                    return(false);
                }
                if (!block.Instructions[pos].MatchStLoc(conditionVar, out condition))
                {
                    return(false);
                }
                pos--;
            }
            if (condition.MatchCompEqualsNull(out var loadInNullCheck))
            {
                ExtensionMethods.Swap(ref trueInst, ref falseInst);
            }
            else if (condition.MatchCompNotEqualsNull(out loadInNullCheck))
            {
                // do nothing
            }
            else
            {
                return(false);
            }
            if (!loadInNullCheck.MatchLdLoc(out var s))
            {
                return(false);
            }
            if (!s.IsSingleDefinition)
            {
                return(false);
            }
            if (s.Kind is not(VariableKind.Local or VariableKind.StackSlot))
            {
                return(false);
            }
            if (pos < 0)
            {
                return(false);
            }
            // stloc V(isinst T(testedOperand))
            ILInstruction storeToV = block.Instructions[pos];

            if (!storeToV.MatchStLoc(out var v, out var value))
            {
                return(false);
            }
            if (value.MatchLdLoc(s))
            {
                // stloc v(ldloc s)
                pos--;
                if (!block.Instructions[pos].MatchStLoc(s, out value))
                {
                    return(false);
                }
                if (v.Kind is not(VariableKind.Local or VariableKind.StackSlot))
                {
                    return(false);
                }
                if (s.LoadCount != 2)
                {
                    return(false);
                }
            }
            else
            {
                if (v != s)
                {
                    return(false);
                }
            }
            IType?unboxType;

            if (value is UnboxAny unboxAny)
            {
                // stloc S(unbox.any T(isinst T(testedOperand)))
                unboxType = unboxAny.Type;
                value     = unboxAny.Argument;
            }
            else
            {
                unboxType = null;
            }
            if (value is not IsInst {
                Argument : var testedOperand, Type : var type
            })