diff --git a/de4dot.blocks/cflow/ConstantsFolder.cs b/de4dot.blocks/cflow/ConstantsFolder.cs index a740fa45..b5227acf 100644 --- a/de4dot.blocks/cflow/ConstantsFolder.cs +++ b/de4dot.blocks/cflow/ConstantsFolder.cs @@ -70,6 +70,96 @@ namespace de4dot.blocks.cflow { case Code.Ldloca_S: instructionEmulator.MakeLocalUnknown((Local)instr.Operand); break; + + case Code.Add: + case Code.Add_Ovf: + case Code.Add_Ovf_Un: + case Code.And: + case Code.Ceq: + case Code.Cgt: + case Code.Cgt_Un: + case Code.Clt: + case Code.Clt_Un: + case Code.Conv_I: + case Code.Conv_I1: + case Code.Conv_I2: + case Code.Conv_I4: + case Code.Conv_I8: + case Code.Conv_Ovf_I: + case Code.Conv_Ovf_I_Un: + case Code.Conv_Ovf_I1: + case Code.Conv_Ovf_I1_Un: + case Code.Conv_Ovf_I2: + case Code.Conv_Ovf_I2_Un: + case Code.Conv_Ovf_I4: + case Code.Conv_Ovf_I4_Un: + case Code.Conv_Ovf_I8: + case Code.Conv_Ovf_I8_Un: + case Code.Conv_Ovf_U: + case Code.Conv_Ovf_U_Un: + case Code.Conv_Ovf_U1: + case Code.Conv_Ovf_U1_Un: + case Code.Conv_Ovf_U2: + case Code.Conv_Ovf_U2_Un: + case Code.Conv_Ovf_U4: + case Code.Conv_Ovf_U4_Un: + case Code.Conv_Ovf_U8: + case Code.Conv_Ovf_U8_Un: + case Code.Conv_R_Un: + case Code.Conv_R4: + case Code.Conv_R8: + case Code.Conv_U: + case Code.Conv_U1: + case Code.Conv_U2: + case Code.Conv_U4: + case Code.Conv_U8: + case Code.Div: + case Code.Div_Un: + case Code.Dup: + case Code.Mul: + case Code.Mul_Ovf: + case Code.Mul_Ovf_Un: + case Code.Neg: + case Code.Not: + case Code.Or: + case Code.Rem: + case Code.Rem_Un: + case Code.Shl: + case Code.Shr: + case Code.Shr_Un: + case Code.Sub: + case Code.Sub_Ovf: + case Code.Sub_Ovf_Un: + case Code.Xor: + if (i + 1 < instrs.Count && instrs[i + 1].OpCode.Code == Code.Pop) + break; + if (!VerifyValidArgs(instr.Instruction)) + break; + instructionEmulator.Emulate(instr.Instruction); + var tos = instructionEmulator.Peek(); + Instruction newInstr = null; + if (tos.IsInt32()) { + var val = (Int32Value)tos; + if (val.AllBitsValid()) + newInstr = Instruction.CreateLdcI4(val.Value); + } + else if (tos.IsInt64()) { + var val = (Int64Value)tos; + if (val.AllBitsValid()) + newInstr = OpCodes.Ldc_I8.ToInstruction(val.Value); + } + else if (tos.IsReal8()) { + var val = (Real8Value)tos; + if (val.IsValid) + newInstr = GetLoadRealInstruction(val.Value); + } + if (newInstr != null) { + block.Insert(i + 1, Instruction.Create(OpCodes.Pop)); + block.Insert(i + 2, newInstr); + i += 2; + modified = true; + } + continue; } try { @@ -84,6 +174,53 @@ namespace de4dot.blocks.cflow { return modified; } + bool VerifyValidArgs(Instruction instr) { + int pushes, pops; + instr.CalculateStackUsage(out pushes, out pops); + if (pops < 0) + return false; + + bool retVal; + Value val2, val1; + switch (pops) { + case 0: + return true; + + case 1: + val1 = instructionEmulator.Pop(); + retVal = VerifyValidArg(val1); + instructionEmulator.Push(val1); + return retVal; + + case 2: + val2 = instructionEmulator.Pop(); + val1 = instructionEmulator.Pop(); + retVal = VerifyValidArg(val2) && VerifyValidArg(val1); + instructionEmulator.Push(val1); + instructionEmulator.Push(val2); + return retVal; + } + + return false; + } + + static bool VerifyValidArg(Value value) { + if (value.IsInt32()) + return ((Int32Value)value).AllBitsValid(); + if (value.IsInt64()) + return ((Int64Value)value).AllBitsValid(); + if (value.IsReal8()) + return ((Real8Value)value).IsValid; + return false; + } + + static Instruction GetLoadRealInstruction(double value) { + var floatVal = (float)value; + if (floatVal == value || double.IsNaN(value)) + return OpCodes.Ldc_R4.ToInstruction(floatVal); + return OpCodes.Ldc_R8.ToInstruction(value); + } + bool FixLoadInstruction(Block block, int index, Value value) { if (value.IsInt32()) { var intValue = (Int32Value)value;