Add code to emulate switch and ldelem

This commit is contained in:
de4dot 2011-10-18 08:17:21 +02:00
parent de8e63d140
commit 98936364f7
4 changed files with 40 additions and 8 deletions

View File

@ -173,6 +173,12 @@ namespace de4dot.blocks {
replaceLastInstrsWithBranch(1, target);
}
public void replaceSwitchWithBranch(Block target) {
if (LastInstr.OpCode.Code != Code.Switch)
throw new ApplicationException("Last instruction is not a switch");
replaceLastInstrsWithBranch(1, target);
}
public void removeDeadBlock() {
if (sources.Count != 0)
throw new ApplicationException("Trying to remove a non-dead block");

View File

@ -65,6 +65,7 @@ namespace de4dot.blocks.cflow {
case Code.Brfalse_S:return emulate_Brfalse();
case Code.Brtrue:
case Code.Brtrue_S: return emulate_Brtrue();
case Code.Switch: return emulate_Switch();
default:
return false;
@ -78,13 +79,16 @@ namespace de4dot.blocks.cflow {
}
bool emulateBranch(int stackArgs, bool isTaken) {
popPushedArgs(stackArgs);
block.replaceBccWithBranch(isTaken);
return true;
}
void popPushedArgs(int stackArgs) {
// Pop the arguments to the bcc instruction. The dead code remover will get rid of the
// pop and any pushed arguments. Insert the pops just before the bcc instr.
for (int i = 0; i < stackArgs; i++)
block.insert(block.Instructions.Count - 1, Instruction.Create(OpCodes.Pop));
block.replaceBccWithBranch(isTaken);
return true;
}
bool emulate_Beq() {
@ -236,5 +240,27 @@ namespace de4dot.blocks.cflow {
else
return false;
}
bool emulate_Switch() {
var val1 = instructionEmulator.pop();
if (val1.valueType != ValueType.Int32)
return false;
var int1 = (Int32Value)val1;
if (!int1.allBitsValid())
return false;
int index = int1.value;
var targets = block.Targets;
Block newTarget;
if (targets == null || index < 0 || index >= targets.Count)
newTarget = block.FallThrough;
else
newTarget = targets[index];
popPushedArgs(1);
block.replaceSwitchWithBranch(newTarget);
return true;
}
}
}

View File

@ -230,11 +230,11 @@ namespace de4dot.blocks.cflow {
case Code.Castclass: emulate_Castclass(instr); break;
case Code.Isinst: emulate_Isinst(instr); break;
case Code.Add_Ovf: emulateIntOps2(); break;
case Code.Add_Ovf: emulateIntOps2(); break;
case Code.Add_Ovf_Un: emulateIntOps2(); break;
case Code.Sub_Ovf: emulateIntOps2(); break;
case Code.Sub_Ovf: emulateIntOps2(); break;
case Code.Sub_Ovf_Un: emulateIntOps2(); break;
case Code.Mul_Ovf: emulateIntOps2(); break;
case Code.Mul_Ovf: emulateIntOps2(); break;
case Code.Mul_Ovf_Un: emulateIntOps2(); break;
case Code.Conv_Ovf_I1:
@ -261,6 +261,7 @@ namespace de4dot.blocks.cflow {
case Code.Ldelem_U1: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt8()); break;
case Code.Ldelem_U2: valueStack.pop(2); valueStack.push(Int32Value.createUnknownUInt16()); break;
case Code.Ldelem_U4: valueStack.pop(2); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldelem_Any:valueStack.pop(2); valueStack.push(getUnknownValue(instr.Operand as TypeReference)); break;
case Code.Ldind_I1: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
case Code.Ldind_I2: valueStack.pop(); valueStack.push(Int32Value.createUnknown()); break;
@ -327,7 +328,6 @@ namespace de4dot.blocks.cflow {
case Code.Initobj:
case Code.Jmp:
case Code.Ldelema:
case Code.Ldelem_Any:
case Code.Ldelem_I:
case Code.Ldelem_R4:
case Code.Ldelem_R8:

View File

@ -41,7 +41,7 @@ namespace de4dot.blocks.cflow {
return validMask != NO_UNKNOWN_BITS;
}
bool allBitsValid() {
public bool allBitsValid() {
return !hasUnknownBits();
}