diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 19:50:13 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 20:34:34 -0500 |
| commit | e093c21ed880ac3eb72119be15093ee04f8ce299 (patch) | |
| tree | 9f720ebdc0ae415734b1199ed341668c69710a94 /arch/armv7/il.cpp | |
| parent | 0609276712622908254065546102381466033141 (diff) | |
Move architecture modules into the API repo
Diffstat (limited to 'arch/armv7/il.cpp')
| -rw-r--r-- | arch/armv7/il.cpp | 4966 |
1 files changed, 4966 insertions, 0 deletions
diff --git a/arch/armv7/il.cpp b/arch/armv7/il.cpp new file mode 100644 index 00000000..d946e77c --- /dev/null +++ b/arch/armv7/il.cpp @@ -0,0 +1,4966 @@ +#include <stdarg.h> +#include "il.h" +#include "lowlevelilinstruction.h" + +using namespace BinaryNinja; +using namespace armv7; + +#define ILREG(op) il.Register(get_register_size((op).reg), (op).reg) +#define ILOFFSETREG(op) il.Register(get_register_size((op).offset), (op).offset) + +//Get N set bits at offset O +#define BITMASK(N,O) (((1LL << N) - 1) << O) + +static inline ExprId DirectJump(Architecture* arch, LowLevelILFunction& il, uint64_t target, size_t addrSize) +{ + BNLowLevelILLabel* label = il.GetLabelForAddress(arch, target); + if (label) + return il.Goto(*label); + else + return il.Jump(il.ConstPointer(addrSize, target)); + + return 0; +} + + +static inline ExprId SetRegisterOrBranch(LowLevelILFunction& il, enum Register reg, ExprId expr, uint32_t flags=0) +{ + if (reg == REG_PC) + return il.Jump(expr); + else + return il.SetRegister(get_register_size(reg), reg, expr, flags); +} + + +static inline ExprId ReadRegisterOrPointer(LowLevelILFunction& il, const InstructionOperand& op, size_t addr) +{ + if (op.reg == REG_PC) + return il.ConstPointer(4, (addr+8)); + return il.Register(get_register_size(op.reg), op.reg); +} + + +ExprId GetCondition(LowLevelILFunction& il, Condition cond) +{ + switch(cond) + { + case COND_EQ: return il.FlagCondition(LLFC_E); + case COND_NE: return il.FlagCondition(LLFC_NE); + case COND_CS: return il.FlagCondition(LLFC_UGE); + case COND_CC: return il.FlagCondition(LLFC_ULT); + case COND_MI: return il.FlagCondition(LLFC_NEG); + case COND_PL: return il.FlagCondition(LLFC_POS); + case COND_VS: return il.FlagCondition(LLFC_O); + case COND_VC: return il.FlagCondition(LLFC_NO); + case COND_HI: return il.FlagCondition(LLFC_UGT); + case COND_LS: return il.FlagCondition(LLFC_ULE); + case COND_GE: return il.FlagCondition(LLFC_SGE); + case COND_LT: return il.FlagCondition(LLFC_SLT); + case COND_GT: return il.FlagCondition(LLFC_SGT); + case COND_LE: return il.FlagCondition(LLFC_SLE); + case COND_NONE: + case COND_NONE2: + return il.Const(0, 1); //Always branch + default: + return il.Const(0, 0); //Never branch + } +} + +static void ConditionalJump(Architecture* arch, LowLevelILFunction& il, Condition cond, size_t addrSize, uint64_t t, uint64_t f) +{ + BNLowLevelILLabel* trueLabel = il.GetLabelForAddress(arch, t); + BNLowLevelILLabel* falseLabel = il.GetLabelForAddress(arch, f); + + if (UNCONDITIONAL(cond)) + { + il.AddInstruction(DirectJump(arch, il, t, addrSize)); + return; + } + + if (trueLabel && falseLabel) + { + il.AddInstruction(il.If(GetCondition(il, cond), *trueLabel, *falseLabel)); + return; + } + + LowLevelILLabel trueCode, falseCode; + + if (trueLabel) + { + il.AddInstruction(il.If(GetCondition(il, cond), *trueLabel, falseCode)); + il.MarkLabel(falseCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); + return; + } + + if (falseLabel) + { + il.AddInstruction(il.If(GetCondition(il, cond), trueCode, *falseLabel)); + il.MarkLabel(trueCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, t))); + return; + } + + il.AddInstruction(il.If(GetCondition(il, cond), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, t))); + il.MarkLabel(falseCode); + il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); +} + + +static void ConditionExecute(LowLevelILFunction& il, Condition cond, ExprId trueCase) +{ + LowLevelILLabel trueCode, falseCode; + if (UNCONDITIONAL(cond)) + { + il.AddInstruction(trueCase); + return; + } + + il.AddInstruction(il.If(GetCondition(il, cond), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(trueCase); + il.MarkLabel(falseCode); +} + + +static ExprId GetShifted(LowLevelILFunction& il, Register reg, uint32_t ShiftAmount, Shift shift) +{ + if (ShiftAmount == 0) + return il.Register(get_register_size(reg), reg); + + switch (shift) + { + case SHIFT_NONE: + return il.Register(get_register_size(reg), reg); + case SHIFT_LSR: + return il.LogicalShiftRight(get_register_size(reg), + il.Register(get_register_size(reg), reg), + il.Const(1, ShiftAmount)); + case SHIFT_LSL: + return il.ShiftLeft(get_register_size(reg), + il.Register(get_register_size(reg), reg), + il.Const(1, ShiftAmount)); + case SHIFT_ASR: + return il.ArithShiftRight(get_register_size(reg), + il.Register(get_register_size(reg), reg), + il.Const(1, ShiftAmount)); + case SHIFT_ROR: + return il.RotateRight(get_register_size(reg), + il.Register(get_register_size(reg), reg), + il.Const(1, ShiftAmount)); + case SHIFT_RRX: + //RRX can only shift 1 at a time + return il.RotateRightCarry(get_register_size(reg), + il.Register(get_register_size(reg), reg), + il.Const(1, 1), il.Flag(IL_FLAG_C)); + default: + return 0; + } +} + + +static ExprId GetShiftedOffset(LowLevelILFunction& il, InstructionOperand& op) +{ + return GetShifted(il, op.offset, op.imm, op.shift); +} + + +static ExprId GetShiftedRegister(LowLevelILFunction& il, InstructionOperand& op) +{ + return GetShifted(il, op.reg, op.imm, op.shift); +} + + + +static ExprId ReadAddress(LowLevelILFunction& il, InstructionOperand& op, size_t addr) +{ + //This should only be called by with cls or MEM_* or label + // <op.imm> + // <op.reg> +/- <op.imm> + // <op.reg> +/- (<op.offset> <shift> <op.imm>) + ExprId expr; + if (op.cls == LABEL) + return il.ConstPointer(4, op.imm); + + if (op.shift == SHIFT_NONE) + { + if (op.flags.offsetRegUsed == 1) + { + expr = il.Register(get_register_size(op.offset), op.offset); + } + else + { + expr = il.Const(4, op.imm); + } + } + else + { + if (op.flags.offsetRegUsed == 1) + expr = GetShiftedOffset(il, op); + else + return GetShiftedRegister(il, op); + } + + if (op.flags.add == 1) + return il.Add(4, ReadRegisterOrPointer(il, op, addr), expr); + else + return il.Sub(4, ReadRegisterOrPointer(il, op, addr), expr); +} + + +static ExprId ReadILOperand(LowLevelILFunction& il, InstructionOperand& op, size_t addr, bool isPointer=false) +{ + switch (op.cls) + { + + case IMM64: + if (isPointer) + return il.ConstPointer(8, op.imm); + return il.Const(8, op.imm); + case IMM: + case LABEL: + if (isPointer) + return il.ConstPointer(4, op.imm); + return il.Const(4, op.imm); + case REG: + if (op.shift == SHIFT_NONE) + return ReadRegisterOrPointer(il, op, addr); + else if (op.flags.offsetRegUsed == 1) + { + return GetShiftedOffset(il, op); + } + else + { + return GetShiftedRegister(il, op); + } + break; + case MEM_IMM: + if (op.shift == SHIFT_NONE) + { + if (op.flags.offsetRegUsed == 1) + { + return op.flags.add? + il.Add(4, ReadRegisterOrPointer(il, op, addr), il.Register(get_register_size(op.reg), op.offset)): + il.Sub(4, ReadRegisterOrPointer(il, op, addr), il.Register(get_register_size(op.reg), op.offset)); + } + else + { + if (op.imm == 0) + { + return ReadRegisterOrPointer(il, op, addr); + } + return op.flags.add? + il.Add(4, ReadRegisterOrPointer(il, op, addr), il.Const(4, op.imm)): + il.Sub(4, ReadRegisterOrPointer(il, op, addr), il.Const(4, op.imm)); + } + } + else + return op.flags.add? + il.Add(4, ReadRegisterOrPointer(il, op, addr), GetShiftedOffset(il, op)): + il.Sub(4, ReadRegisterOrPointer(il, op, addr), GetShiftedOffset(il, op)); + case MEM_PRE_IDX: + case MEM_POST_IDX: + return GetShiftedRegister(il, op); + case FIMM32: + case NONE: + default: + il.AddInstruction(il.Unimplemented()); + break; + } + return 0; +} + + +static void Load( + LowLevelILFunction& il, + bool sx, + size_t size, + InstructionOperand& dst, + InstructionOperand& src, + size_t addr) +{ + ExprId value, memValue; + size_t dstSize = get_register_size(dst.reg); + value = ReadAddress(il, src, addr); + + switch (src.cls) + { + case MEM_PRE_IDX: + memValue = il.Load(size, ILREG(src)); + + if (size != dstSize) + { + if (sx) + memValue = il.SignExtend(dstSize, memValue); + else + memValue = il.ZeroExtend(dstSize, memValue); + } + + il.AddInstruction(SetRegisterOrBranch(il, src.reg, value)); + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, memValue)); + break; + case MEM_POST_IDX: + memValue = il.Load(size, ILREG(src)); + + if (size != dstSize) + { + if (sx) + memValue = il.SignExtend(dstSize, memValue); + else + memValue = il.ZeroExtend(dstSize, memValue); + } + + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, memValue)); + il.AddInstruction(SetRegisterOrBranch(il, src.reg, value)); + break; + case MEM_IMM: + case LABEL: + memValue = il.Load(size, value); + + if (size != dstSize) + { + if (sx) + memValue = il.SignExtend(dstSize, memValue); + else + memValue = il.ZeroExtend(dstSize, memValue); + } + + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, memValue)); + break; + default: + il.AddInstruction(il.Unimplemented()); + break; + } +} + + +static void LoadExclusive( + LowLevelILFunction& il, + bool sx, + size_t size, + InstructionOperand& dst, + InstructionOperand& src, + size_t addr) +{ + ExprId address = ReadAddress(il, src, addr); + size_t srcSize = get_register_size(src.reg); + + il.AddInstruction(il.Intrinsic({ }, + ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + { address, il.Const(1, srcSize) })); + Load(il, sx, size, dst, src, addr); +} + + +static void LoadPair( + Architecture* arch, + LowLevelILFunction& il, + InstructionOperand& dst1, + InstructionOperand& dst2, + InstructionOperand& src, + size_t addr) +{ + ExprId address, value; + size_t dstSize = get_register_size(dst1.reg); + + if (src.cls == MEM_PRE_IDX || src.cls == MEM_POST_IDX) + address = ILREG(src); + else + address = ReadAddress(il, src, addr); + value = il.Load(dstSize * 2, address); + + if (src.cls == MEM_PRE_IDX) + il.AddInstruction(SetRegisterOrBranch(il, src.reg, ReadAddress(il, src, addr))); + + ExprId setReg; + if (arch->GetEndianness() == LittleEndian) + setReg = il.SetRegisterSplit(dstSize, dst2.reg, dst1.reg, value); + else + setReg = il.SetRegisterSplit(dstSize, dst1.reg, dst2.reg, value); + il.AddInstruction(setReg); + + if (src.cls == MEM_POST_IDX) + il.AddInstruction(SetRegisterOrBranch(il, src.reg, ReadAddress(il, src, addr))); +} + + +static void LoadPairExclusive( + Architecture* arch, + LowLevelILFunction& il, + InstructionOperand& dst1, + InstructionOperand& dst2, + InstructionOperand& src, + size_t addr) +{ + ExprId address = ReadAddress(il, src, addr); + size_t srcSize = get_register_size(src.reg); + + il.AddInstruction(il.Intrinsic({ }, + ARMV7_INTRIN_SET_EXCLUSIVE_MONITORS, + { address, il.Const(1, srcSize) })); + LoadPair(arch, il, dst1, dst2, src, addr); +} + + +static void Store( + LowLevelILFunction& il, + uint8_t size, + InstructionOperand& src, + InstructionOperand& dst, + size_t addr) +{ + ExprId address = ReadAddress(il, dst, addr); + size_t dstSize = get_register_size(dst.reg); + + ExprId regSrc = ILREG(src); + size_t srcSize = get_register_size(src.reg); + if (size < srcSize) + regSrc = il.LowPart(size, regSrc); + + switch (dst.cls) + { + case MEM_IMM: + il.AddInstruction(il.Store(size, address, regSrc)); + break; + case MEM_PRE_IDX: + il.AddInstruction(il.SetRegister(dstSize, dst.reg, address)); + il.AddInstruction(il.Store(size, ILREG(dst), regSrc)); + break; + case MEM_POST_IDX: + il.AddInstruction(il.Store(size, ILREG(dst), regSrc)); + il.AddInstruction(il.SetRegister(dstSize, dst.reg, address)); + break; + default: + il.AddInstruction(il.Unimplemented()); + break; + } +} + + +static void StoreExclusive( + LowLevelILFunction& il, + uint8_t size, + InstructionOperand& status, + InstructionOperand& src, + InstructionOperand& dst, + size_t addr) +{ + ExprId address = ReadAddress(il, dst, addr); + size_t dstSize = get_register_size(dst.reg); + + LowLevelILLabel trueCode, falseCode; + size_t statusSize = get_register_size(status.reg); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(status.reg) }, + ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, + { address, il.Const(1, dstSize) })); + il.AddInstruction(il.If(il.CompareEqual(statusSize, il.Register(statusSize, status.reg), il.Const(statusSize, 1)), + trueCode, falseCode)); + il.MarkLabel(trueCode); + + Store(il, size, src, dst, addr); + + il.MarkLabel(falseCode); +} + + +static void StorePair( + Architecture* arch, + LowLevelILFunction& il, + InstructionOperand& src1, + InstructionOperand& src2, + InstructionOperand& dst, + size_t addr) +{ + ExprId address, value; + size_t srcSize = get_register_size(src1.reg); + LowLevelILLabel trueCode, falseCode; + + if (dst.cls == MEM_POST_IDX) + address = ILREG(dst); + else + address = ReadAddress(il, dst, addr); + + if (arch->GetEndianness() == LittleEndian) + value = il.RegisterSplit(srcSize, src2.reg, src1.reg); + else + value = il.RegisterSplit(srcSize, src1.reg, src2.reg); + + il.AddInstruction(il.Store(srcSize * 2, address, value)); + + if (dst.cls == MEM_POST_IDX || dst.cls == MEM_PRE_IDX) + il.AddInstruction(SetRegisterOrBranch(il, dst.reg, ReadAddress(il, dst, addr))); +} + + +static void StorePairExclusive( + Architecture* arch, + LowLevelILFunction& il, + InstructionOperand& status, + InstructionOperand& src1, + InstructionOperand& src2, + InstructionOperand& dst, + size_t addr) +{ + ExprId address = ReadAddress(il, dst, addr); + + LowLevelILLabel trueCode, falseCode; + size_t statusSize = get_register_size(status.reg); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(status.reg) }, + ARMV7_INTRIN_EXCLUSIVE_MONITORS_PASS, + { address, il.Const(1, 8) })); + il.AddInstruction(il.If(il.CompareEqual(statusSize, il.Register(statusSize, status.reg), il.Const(statusSize, 1)), + trueCode, falseCode)); + il.MarkLabel(trueCode); + + StorePair(arch, il, src1, src2, dst, addr); + + il.MarkLabel(falseCode); +} + + +static void Saturate(LowLevelILFunction& il, uint32_t dest, ExprId to_saturate, ExprId saturate_to, bool is_signed) +{ + + LowLevelILLabel trueCode, falseCode, endCode; + LowLevelILLabel trueCode2, falseCode2, endCode2; + + if (is_signed) + { + il.AddInstruction(il.If(il.CompareSignedLessThan(4, to_saturate, il.Neg(4, saturate_to)), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(il.SetRegister(4, dest, il.Neg(4, saturate_to))); + il.AddInstruction(il.Goto(endCode)); + il.MarkLabel(falseCode); + il.MarkLabel(endCode); + + il.AddInstruction(il.If(il.CompareSignedGreaterThan(4, to_saturate, saturate_to), trueCode2, falseCode2)); + il.MarkLabel(trueCode2); + il.AddInstruction(il.SetRegister(4, dest, saturate_to)); + il.AddInstruction(il.Goto(endCode2)); + il.MarkLabel(falseCode2); + il.AddInstruction(il.SetRegister(4, dest, to_saturate)); + il.MarkLabel(endCode2); + } + else + { + il.AddInstruction(il.If(il.CompareSignedLessThan(4, to_saturate, il.Const(4, 0)), trueCode, falseCode)); + il.MarkLabel(trueCode); + il.AddInstruction(il.SetRegister(4, dest, il.Const(4, 0))); + il.AddInstruction(il.Goto(endCode)); + il.MarkLabel(falseCode); + il.MarkLabel(endCode); + + il.AddInstruction(il.If(il.CompareSignedGreaterThan(4, to_saturate, saturate_to), trueCode2, falseCode2)); + il.MarkLabel(trueCode2); + il.AddInstruction(il.SetRegister(4, dest, saturate_to)); + il.AddInstruction(il.Goto(endCode2)); + il.MarkLabel(falseCode2); + il.AddInstruction(il.SetRegister(4, dest, to_saturate)); + il.MarkLabel(endCode2); + } +} + + +uint32_t GetNumberOfRegs(uint16_t regList) +{ + uint32_t nregs = 0; + for (uint32_t i = 0; i < 16; i++) + { + if (((regList >> i) & 1) == 1) + nregs++; + } + return nregs; +} + + +void ConditionExecute(size_t addrSize, Condition cond, Instruction& instr, LowLevelILFunction& il, + std::function<void (size_t addrSize, Instruction& instr, LowLevelILFunction& il)> conditionalCode) +{ + if (UNCONDITIONAL(cond)) + { + conditionalCode(addrSize, instr, il); + return; + } + + LowLevelILLabel trueLabel, falseLabel; + il.AddInstruction(il.If(GetCondition(il, cond), trueLabel, falseLabel)); + il.MarkLabel(trueLabel); + conditionalCode(addrSize, instr, il); + il.AddInstruction(il.Goto(falseLabel)); + il.MarkLabel(falseLabel); +} + +void LoadOrStoreWithAdjustment(InstructionOperand& src, + InstructionOperand& dst, + LowLevelILFunction& il, + bool load, + bool increment, + bool before) +{ + if (before) + { + if (increment) + { + il.AddInstruction(il.SetRegister(get_register_size(src.reg), src.reg, + il.Add(get_register_size(src.reg), ILREG(src), il.Const(1, get_register_size(src.reg))))); + } + else + { + il.AddInstruction(il.SetRegister(get_register_size(src.reg), src.reg, + il.Sub(get_register_size(src.reg), ILREG(src), il.Const(1, get_register_size(src.reg))))); + } + } + + if (load) + { + il.AddInstruction(il.SetRegister(get_register_size(dst.reg), dst.reg, + il.Load(get_register_size(dst.reg), ILREG(src)))); + } + else + { + il.AddInstruction(il.Store(get_register_size(dst.reg), ILREG(dst), ILREG(src))); + } + + if (!before) + { + if (increment) + { + il.AddInstruction(il.SetRegister(get_register_size(src.reg), src.reg, + il.Add(get_register_size(src.reg), ILREG(src), il.Const(1, get_register_size(src.reg))))); + } + else + { + il.AddInstruction(il.SetRegister(get_register_size(src.reg), src.reg, + il.Sub(get_register_size(src.reg), ILREG(src), il.Const(1, get_register_size(src.reg))))); + } + } +} + + +bool GetLowLevelILForArmInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize) +{ + (void)arch; + (void)addr; + (void)addrSize; + InstructionOperand& op1 = instr.operands[0]; + InstructionOperand& op2 = instr.operands[1]; + InstructionOperand& op3 = instr.operands[2]; + InstructionOperand& op4 = instr.operands[3]; + InstructionOperand& op5 = instr.operands[4]; + InstructionOperand& op6 = instr.operands[5]; + LowLevelILLabel trueLabel, falseLabel, endLabel, loopBody, loopStart, loopExit; + uint32_t flagOperation[2] = {IL_FLAGWRITE_NONE, IL_FLAGWRITE_ALL}; + LowLevelILLabel trueCode, falseCode, endCode; + switch (instr.operation) + { + case ARMV7_ADD: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Add(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_ADDW: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Add(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), IL_FLAGWRITE_NONE))); + break; + case ARMV7_ADC: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.AddCarry(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), il.Flag(IL_FLAG_C), flagOperation[instr.setsFlags]))); + break; + case ARMV7_ADR: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.ConstPointer(get_register_size(op1.reg), op2.imm))); + break; + case ARMV7_AND: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_ASR: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.ArithShiftRight(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_B: + ConditionalJump(arch, il, instr.cond, addrSize, op1.imm, addr + 4); + return false; + case ARMV7_BFC: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op1.reg), ReadRegisterOrPointer(il, op1, addr), + il.Const(get_register_size(op1.reg), ~(((1<<op3.imm) - 1) << op2.imm))))); + break; + case ARMV7_BFI: + { + uint32_t lsb = op3.imm; + uint32_t width_mask = (1<<op4.imm) - 1; + uint32_t mask = width_mask << lsb; + + //bit field insert: op1 = (op1 & (~(<width_mask> << lsb))) | ((op2 & <width_mask>) << lsb) + //width_mask = (1<<width)-1 + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Or(get_register_size(op1.reg), + il.And(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, ~mask) + ), + il.ShiftLeft(4, + il.And(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + il.Const(get_register_size(op1.reg), width_mask) + ), + il.Const(4, lsb))))); + break; + } + case ARMV7_BKPT: + il.AddInstruction(il.Breakpoint()); + break; + case ARMV7_BL: + ConditionExecute(il, instr.cond, il.Call(il.ConstPointer(4, op1.imm))); + break; + case ARMV7_BXJ: + case ARMV7_BX: + ConditionExecute(il, instr.cond, il.Jump(ReadILOperand(il, op1, addr, true))); + break; + case ARMV7_BLX: + ConditionExecute(il, instr.cond, il.Call(ReadILOperand(il, op1, addr, true))); + break; + case ARMV7_BIC: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + il.Not(get_register_size(op2.reg), + ReadILOperand(il, op3, addr)), flagOperation[instr.setsFlags] + ))); + break; + case ARMV7_CLZ: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + //Count leading zeros + // + // TEMP0 = 0 + // TEMP1 = op2.reg + // while (TEMP1 != 0) + // TEMP1 = TEMP1 >> 1 + // TEMP0 = TEMP0 + 1 + // op1.reg = 32 - TEMP0 + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Const(4, 0))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), ReadRegisterOrPointer(il, op2, addr))); + il.AddInstruction(il.Goto(loopStart)); + il.MarkLabel(loopStart); + il.AddInstruction(il.If(il.CompareNotEqual(4, il.Register(4, LLIL_TEMP(1)), il.Const(4, 0)), loopBody, loopExit)); + il.MarkLabel(loopBody); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(4,1)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Add(4, il.Register(4, LLIL_TEMP(0)), il.Const(4,1)))); + il.AddInstruction(il.Goto(loopStart)); + il.MarkLabel(loopExit); + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, il.Sub(4, il.Const(4, 32), il.Register(4, LLIL_TEMP(0))))); + }); + break; + case ARMV7_CMN: + ConditionExecute(il, instr.cond, il.Add(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadILOperand(il, op2, addr), IL_FLAGWRITE_ALL)); + break; + case ARMV7_CMP: + ConditionExecute(il, instr.cond, il.Sub(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadILOperand(il, op2, addr), IL_FLAGWRITE_ALL)); + break; + case ARMV7_EOR: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Xor(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_LDM: + case ARMV7_LDMIA: + case ARMV7_LDMIB: + case ARMV7_LDMDA: + case ARMV7_LDMDB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + //Cache src address register in case it's mutated by loads + ExprId base = 0; + switch (instr.operation) + { + case ARMV7_LDM: + case ARMV7_LDMIA: + base = ILREG(op1); + break; + case ARMV7_LDMIB: + base = il.Add(4, ILREG(op1), il.Const(1, 4)); + break; + case ARMV7_LDMDB: + base = il.Sub(4, ILREG(op1), il.Const(1, 4 * GetNumberOfRegs(op2.reg))); + break; + case ARMV7_LDMDA: + base = il.Sub(4, ILREG(op1), il.Const(1, 4 * GetNumberOfRegs(op2.reg) - 4)); + break; + default: + break; + } + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), base)); + + for (int reg = 0, slot = 0; reg < 16; reg++) + { + if (op2.reg & 1 << reg) + { + il.AddInstruction( + il.SetRegister(4, + // writes to PC are deferred to a final Jump + (reg != REG_PC) ? reg : LLIL_TEMP(1), + il.Load(4, + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 4 * slot++) + ) + ) + ) + ); + } + } + if (op1.flags.wb) + { + ExprId wb; + switch (instr.operation) + { + case ARMV7_LDM: + case ARMV7_LDMIA: + wb = il.Const(1, 4 * GetNumberOfRegs(op2.reg)); + wb = il.Add(4, il.Register(4, LLIL_TEMP(0)), wb); + break; + case ARMV7_LDMIB: + wb = il.Const(1, 4 * GetNumberOfRegs(op2.reg) - 4); + wb = il.Add(4, il.Register(4, LLIL_TEMP(0)), wb); + break; + case ARMV7_LDMDB: + wb = il.Register(4, LLIL_TEMP(0)); + break; + case ARMV7_LDMDA: + wb = il.Const(1, 4); + wb = il.Sub(4, il.Register(4, LLIL_TEMP(0)), wb); + break; + default: + break; + } + //if (1 << op1.reg & op2.reg) [[unlikely]] { + if (1 << op1.reg & op2.reg) { + wb = il.Undefined(); + } + il.AddInstruction(il.SetRegister(4, op1.reg, wb)); + } + if (op2.reg & REG_LIST_PC) + { + il.AddInstruction(il.Jump(il.Register(4, LLIL_TEMP(1)))); + } + }); + break; + case ARMV7_LDREX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + LoadExclusive(il, false, 4, op1, op2, addr); + }); + break; + case ARMV7_LDR: + case ARMV7_LDRT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Load(il, false, 4, op1, op2, addr); + }); + break; + case ARMV7_LDREXH: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + LoadExclusive(il, false, 2, op1, op2, addr); + }); + break; + case ARMV7_LDRH: + case ARMV7_LDRHT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Load(il, false, 2, op1, op2, addr); + }); + break; + case ARMV7_LDREXB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + LoadExclusive(il, false, 1, op1, op2, addr); + }); + break; + case ARMV7_LDRB: + case ARMV7_LDRBT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Load(il, false, 1, op1, op2, addr); + }); + break; + case ARMV7_LDRSH: + case ARMV7_LDRSHT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Load(il, true, 2, op1, op2, addr); + }); + break; + case ARMV7_LDRSB: + case ARMV7_LDRSBT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Load(il, true, 1, op1, op2, addr); + }); + break; + case ARMV7_LDREXD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + LoadPairExclusive(arch, il, op1, op2, op3, addr); + }); + break; + case ARMV7_LDRD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + LoadPair(arch, il, op1, op2, op3, addr); + }); + break; + case ARMV7_LSL: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.ShiftLeft(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_LSR: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.LogicalShiftRight(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_MCR: + case ARMV7_MCR2: + ConditionExecute(il, instr.cond, + il.Intrinsic({ }, ARMV7_INTRIN_COPROC_SENDONEWORD, + { + il.Register(4, op3.reg), + il.Const(1, op1.reg), + il.Const(1, op2.imm), + il.Const(1, op4.reg), + il.Const(1, op5.reg), + il.Const(1, op6.imm), + } + ) + ); + break; + case ARMV7_MCRR: + case ARMV7_MCRR2: + ConditionExecute(il, instr.cond, + il.Intrinsic({ }, ARMV7_INTRIN_COPROC_SENDTWOWORDS, + { + il.Register(4, op4.reg), + il.Register(4, op3.reg), + il.Const(1, op1.reg), + il.Const(1, op2.imm), + il.Const(1, op5.reg), + } + ) + ); + break; + case ARMV7_MLA: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Add(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op4, addr), + il.Mult(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + (op3.cls == NONE) ? ReadRegisterOrPointer(il, op1, addr) : ReadRegisterOrPointer(il, op3, addr)), + instr.setsFlags ? IL_FLAGWRITE_NZ : IL_FLAGWRITE_NONE))); + break; + case ARMV7_MLS: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Sub(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op4, addr), + il.Mult(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + (op3.cls == NONE) ? ReadRegisterOrPointer(il, op1, addr) : ReadRegisterOrPointer(il, op3, addr)), + flagOperation[instr.setsFlags]))); + break; + case ARMV7_MOV: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + ReadILOperand(il, op2, addr), + instr.setsFlags ? IL_FLAGWRITE_NZ : IL_FLAGWRITE_NONE)); + break; + case ARMV7_MOVT: + // op1.reg = (op2.imm << 16) | (op1 & 0x0000ffff) + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.Const(2, op2.imm), il.Const(1,16)), + il.And(4, il.Const(4, 0x0000ffff), ReadRegisterOrPointer(il, op1, addr))))); + break; + case ARMV7_MOVW: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, il.Const(4, op2.imm))); + break; + case ARMV7_MRC: + case ARMV7_MRC2: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void)addrSize; + (void)instr; + auto params = { + il.Const(1, op1.reg), + il.Const(1, op2.imm), + il.Const(1, op4.reg), + il.Const(1, op5.reg), + il.Const(1, op6.imm), + }; + switch (op3.cls) { + case REG: + il.AddInstruction( + il.Intrinsic( + { RegisterOrFlag::Register(op3.reg) }, + ARMV7_INTRIN_COPROC_GETONEWORD, + params + ) + ); + break; + case REG_SPEC: + il.AddInstruction( + il.Intrinsic( + { RegisterOrFlag::Register(LLIL_TEMP(0)) }, + ARMV7_INTRIN_COPROC_GETONEWORD, + params + ) + ); + il.AddInstruction(il.SetFlag(IL_FLAG_N, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 31)))); + il.AddInstruction(il.SetFlag(IL_FLAG_Z, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 30)))); + il.AddInstruction(il.SetFlag(IL_FLAG_C, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 29)))); + il.AddInstruction(il.SetFlag(IL_FLAG_V, il.TestBit(4, il.Register(4, LLIL_TEMP(0)), il.Const(1, 28)))); + break; + default: + break; + } + }); + break; + case ARMV7_MRRC: + case ARMV7_MRRC2: + ConditionExecute(il, instr.cond, + il.Intrinsic( + { RegisterOrFlag::Register(op4.reg), RegisterOrFlag::Register(op3.reg) }, + ARMV7_INTRIN_COPROC_GETTWOWORDS, + { + il.Const(1, op1.reg), + il.Const(1, op2.imm), + il.Const(1, op5.reg), + } + ) + ); + break; + case ARMV7_MUL: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Mult(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + (op3.cls == NONE) ? ReadRegisterOrPointer(il, op1, addr) : ReadRegisterOrPointer(il, op3, addr), + instr.setsFlags ? IL_FLAGWRITE_NZ : IL_FLAGWRITE_NONE))); + break; + case ARMV7_MVN: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Not(get_register_size(op2.reg), + ReadILOperand(il, op2, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_NOP: + case ARMV7_DSB: + case ARMV7_DMB: + case ARMV7_ISB: + ConditionExecute(il, instr.cond, il.Nop()); + break; + case ARMV7_ORR: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Or(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_PKHBT: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Or(4, + il.And(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(4, 0xffff0000)), + il.And(2, + ReadRegisterOrPointer(il, op3, addr), + il.Const(2, 0xffff)) + ) + )); + break; + case ARMV7_PKHTB: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Or(4, + il.And(2, + ReadRegisterOrPointer(il, op3, addr), + il.Const(4, 0xffff0000)), + il.And(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(2, 0xffff)) + ) + )); + break; + case ARMV7_POP: + if (CONDITIONAL(instr.cond)) + { + il.AddInstruction(il.If(GetCondition(il, instr.cond), trueCode, falseCode)); + il.MarkLabel(trueCode); + } + for (int32_t j = 0; j <= 15; j++) + { + if (((op1.reg >> j) & 1) == 1) + { + if (1 << j == REG_LIST_PC) + { + il.AddInstruction( + il.SetRegister(4, LLIL_TEMP(0), + il.Pop(get_register_size((enum Register)j)))); + } + else + { + il.AddInstruction(SetRegisterOrBranch(il, (Register)j, + il.Pop(get_register_size((enum Register)j)))); + } + + } + } + if ((op1.reg & REG_LIST_PC) == REG_LIST_PC) + il.AddInstruction(il.Jump(il.Register(4, LLIL_TEMP(0)))); + + if (CONDITIONAL(instr.cond)) + il.MarkLabel(falseCode); + break; + case ARMV7_PUSH: + + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + for (int32_t j = 15; j >= 0; j--) + { + if (((op1.reg >> j) & 1) == 1) + { + il.AddInstruction(il.Push(get_register_size((enum Register)j), + il.Register(get_register_size((enum Register)j), j))); + } + } + }); + break; + case ARMV7_QADD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.Add(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadRegisterOrPointer(il, op3, addr) + ))); + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.Or(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + il.Neg(get_register_size(op1.reg), + il.CompareSignedLessThan(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadRegisterOrPointer(il, op2, addr) + ))))); + }); + break; + case ARMV7_QADD16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Add(2, + il.LowPart(2, + ReadRegisterOrPointer(il, op2, addr)), + il.LowPart(2, + ReadRegisterOrPointer(il, op3, addr)) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Or(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, + il.Neg(2, + il.CompareSignedLessThan(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) + )); + + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.Add(2, + il.LowPart(2, il.ArithShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))), + il.LowPart(2, il.ArithShiftRight(2, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 16))) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.Or(2, + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.Neg(2, + il.CompareSignedLessThan(get_register_size(op2.reg), + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.ArithShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))))) + )))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), + il.Register(2, LLIL_TEMP(0)) + ))); + }); + break; + case ARMV7_UQADD16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Add(2, + il.LowPart(2, + ReadRegisterOrPointer(il, op2, addr)), + il.LowPart(2, + ReadRegisterOrPointer(il, op3, addr)) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Or(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, + il.Neg(2, + il.CompareUnsignedLessThan(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) + )); + + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.Add(2, + il.LowPart(2, il.LogicalShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))), + il.LowPart(2, il.LogicalShiftRight(2, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 16))) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.Or(2, + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.Neg(2, + il.CompareUnsignedLessThan(get_register_size(op2.reg), + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.LogicalShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))))) + )))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), + il.Register(2, LLIL_TEMP(0)) + ))); + }); + break; + case ARMV7_QADD8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.Add(1, + il.LowPart(1, + il.ArithShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i))), + il.LowPart(1, + il.ArithShiftRight(4, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 8*i)))))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.Or(1, + il.Register(1, LLIL_TEMP(i)), + il.Neg(1, + il.CompareSignedLessThan(1, + il.Register(1, LLIL_TEMP(i)), + il.LowPart(1, + il.ArithShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i)))))))); + } + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1,24)), + il.ShiftLeft(3, + il.Register(1, LLIL_TEMP(2)), + il.Const(1,16))), + il.Or(2, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(1)), + il.Const(1,8)), + il.Register(1, LLIL_TEMP(0)))))); + }); + break; + case ARMV7_UQADD8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.Add(1, + il.LowPart(1, + il.LogicalShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i))), + il.LowPart(1, + il.LogicalShiftRight(4, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 8*i)))))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.Or(1, + il.Register(1, LLIL_TEMP(i)), + il.Neg(1, + il.CompareUnsignedLessThan(1, + il.Register(1, LLIL_TEMP(i)), + il.LowPart(1, + il.LogicalShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i)))))))); + } + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1,24)), + il.ShiftLeft(3, + il.Register(1, LLIL_TEMP(2)), + il.Const(1,16))), + il.Or(2, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(1)), + il.Const(1,8)), + il.Register(1, LLIL_TEMP(0)))))); + }); + break; + case ARMV7_QDADD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.Add(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + il.Mult(4, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 2)) + ))); + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.Or(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + il.Neg(get_register_size(op1.reg), + il.CompareSignedLessThan(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadRegisterOrPointer(il, op2, addr) + ))))); + }); + break; + case ARMV7_QASX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.ArithShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.ArithShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + + Saturate(il, LLIL_TEMP(2), il.Register(4, LLIL_TEMP(0)), il.Const(2, 0x7fff), true); + Saturate(il, LLIL_TEMP(3), il.Register(4, LLIL_TEMP(1)), il.Const(2, 0x7fff), true); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(3)), + il.Const(1, 16) + ), + il.Register(2, LLIL_TEMP(2)) + ) + )); + }); + break; + case ARMV7_QSAX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.ArithShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.ArithShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + + Saturate(il, LLIL_TEMP(2), il.Register(4, LLIL_TEMP(0)), il.Const(2, 0x7fff), true); + Saturate(il, LLIL_TEMP(3), il.Register(4, LLIL_TEMP(1)), il.Const(2, 0x7fff), true); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(3)), + il.Const(1, 16) + ), + il.Register(2, LLIL_TEMP(2)) + ) + )); + }); + break; + case ARMV7_QDSUB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.Sub(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + il.Mult(4, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 2)) + ))); + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.And(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + il.Neg(get_register_size(op1.reg), + il.CompareSignedLessEqual(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadRegisterOrPointer(il, op2, addr) + ))))); + }); + break; + case ARMV7_QSUB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.Sub(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadRegisterOrPointer(il, op3, addr) + ))); + il.AddInstruction(il.SetRegister(get_register_size(op1.reg), op1.reg, + il.And(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + il.Neg(get_register_size(op1.reg), + il.CompareSignedLessEqual(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadRegisterOrPointer(il, op2, addr) + ))))); + }); + break; + case ARMV7_QSUB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Sub(2, + il.LowPart(2, + ReadRegisterOrPointer(il, op2, addr)), + il.LowPart(2, + ReadRegisterOrPointer(il, op3, addr)) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.And(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, + il.Neg(2, + il.CompareSignedLessEqual(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) + )); + + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.Sub(2, + il.LowPart(2, il.ArithShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))), + il.LowPart(2, il.ArithShiftRight(2, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 16))) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.And(2, + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.Neg(2, + il.CompareSignedLessEqual(get_register_size(op2.reg), + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.ArithShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))))) + )))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), + il.Register(2, LLIL_TEMP(0)) + ))); + }); + break; + case ARMV7_UQSUB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Sub(2, + il.LowPart(2, + ReadRegisterOrPointer(il, op2, addr)), + il.LowPart(2, + ReadRegisterOrPointer(il, op3, addr)) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.And(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, + il.Neg(2, + il.CompareUnsignedLessEqual(2, + il.Register(2, LLIL_TEMP(0)), + il.LowPart(2, ReadRegisterOrPointer(il, op2, addr)))))) + )); + + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.Sub(2, + il.LowPart(2, il.LogicalShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))), + il.LowPart(2, il.LogicalShiftRight(2, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 16))) + ))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), + il.And(2, + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.Neg(2, + il.CompareUnsignedLessEqual(get_register_size(op2.reg), + il.Register(2, LLIL_TEMP(1)), + il.LowPart(2, + il.LogicalShiftRight(2, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 16))))) + )))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 0x10)), + il.Register(2, LLIL_TEMP(0)) + ))); + }); + break; + case ARMV7_QSUB8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.Sub(1, + il.LowPart(1, + il.ArithShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i))), + il.LowPart(1, + il.ArithShiftRight(4, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 8*i)))))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.And(1, + il.Register(1, LLIL_TEMP(i)), + il.Neg(1, + il.CompareSignedLessEqual(1, + il.Register(1, LLIL_TEMP(i)), + il.LowPart(1, + il.ArithShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i)))))))); + } + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1,24)), + il.ShiftLeft(3, + il.Register(1, LLIL_TEMP(2)), + il.Const(1,16))), + il.Or(2, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(1)), + il.Const(1,8)), + il.Register(1, LLIL_TEMP(0)))))); + }); + break; + case ARMV7_UQSUB8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.Sub(1, + il.LowPart(1, + il.LogicalShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i))), + il.LowPart(1, + il.LogicalShiftRight(4, + ReadRegisterOrPointer(il, op3, addr), + il.Const(1, 8*i)))))); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(i), + il.And(1, + il.Register(1, LLIL_TEMP(i)), + il.Neg(1, + il.CompareSignedLessEqual(1, + il.Register(1, LLIL_TEMP(i)), + il.LowPart(1, + il.LogicalShiftRight(4, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 8*i)))))))); + } + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1,24)), + il.ShiftLeft(3, + il.Register(1, LLIL_TEMP(2)), + il.Const(1,16))), + il.Or(2, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(1)), + il.Const(1,8)), + il.Register(1, LLIL_TEMP(0)))))); + }); + break; + case ARMV7_RBIT: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + //Reverse bits + // + // TEMP0 = 0 + // TEMP1 = op2.reg + // TEMP2 = 0 + // while (TEMP0 != 31) + // TEMP2 = TEMP2 | (TEMP1 & 1) + // TEMP2 = TEMP2 << 1 + // TEMP1 = TEMP1 >> 1 + // TEMP0 = TEMP0 + 1 + // op1.reg = 32 - TEMP0 + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Const(4, 0))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), ReadRegisterOrPointer(il, op2, addr))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), il.Const(4, 0))); + il.AddInstruction(il.Goto(loopStart)); + il.MarkLabel(loopStart); + il.AddInstruction(il.If(il.CompareNotEqual(4, il.Register(4, LLIL_TEMP(0)), il.Const(4, 31)), loopBody, loopExit)); + il.MarkLabel(loopBody); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), il.Or(4, il.Register(4, LLIL_TEMP(2)), il.And(4, il.Register(4, LLIL_TEMP(1)), il.Const(4,1))))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), il.ShiftLeft(4, il.Register(4, LLIL_TEMP(2)), il.Const(4,1)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(4,1)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.Add(4, il.Register(4, LLIL_TEMP(0)), il.Const(4,1)))); + il.AddInstruction(il.Goto(loopStart)); + il.MarkLabel(loopExit); + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, il.Register(4, LLIL_TEMP(2)))); + }); + break; + case ARMV7_REV: + ConditionExecute(il, instr.cond, il.SetRegister(4, op1.reg, + il.Or(4, + il.LogicalShiftRight(4, il.Register(4, op2.reg), il.Const(1, 24)), + il.Or(4, + il.ShiftLeft(4, il.And(4, il.LogicalShiftRight(4, il.Register(4, op2.reg), il.Const(1, 16)), il.Const(4, 0xff)), il.Const(1, 8)), + il.Or(4, + il.ShiftLeft(4, il.And(4, il.LogicalShiftRight(4, il.Register(4, op2.reg), il.Const(1, 8)), il.Const(4, 0xff)), il.Const(1, 16)), + il.ShiftLeft(4, il.And(4, il.Register(4, op2.reg), il.Const(4, 0xff)), il.Const(1, 24)) + ) + ) + ), + flagOperation[instr.setsFlags])); + break; + case ARMV7_REV16: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), il.RotateRight(2, il.LowPart(2, ReadILOperand(il, op2, addr)), il.Const(1, 16)))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), il.RotateRight(2, il.LogicalShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1, 16)), il.Const(1, 16)))); + il.AddInstruction(il.SetRegister(4, op1.reg, il.Or(4, il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 16)), il.Register(2, LLIL_TEMP(0))))); + }); + break; + case ARMV7_REVSH: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), il.RotateRight(2, il.LowPart(2, ReadILOperand(il, op2, addr)), il.Const(1, 16)))); + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(1), il.RotateRight(2, il.LogicalShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1, 16)), il.Const(1, 16)))); + il.AddInstruction(il.SetRegister(4, op1.reg, il.SignExtend(4, il.Or(4, il.ShiftLeft(4, il.Register(2, LLIL_TEMP(1)), il.Const(1, 16)), il.Register(2, LLIL_TEMP(0)))))); + }); + break; + + case ARMV7_RSB: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Sub(get_register_size(op2.reg), + ReadILOperand(il, op3, addr), + ReadRegisterOrPointer(il, op2, addr), + flagOperation[instr.setsFlags]))); + break; + case ARMV7_RSC: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.SubBorrow(get_register_size(op2.reg), + ReadILOperand(il, op3, addr), + ReadRegisterOrPointer(il, op2, addr), + il.Not(1,il.Flag(IL_FLAG_C))), + flagOperation[instr.setsFlags])); + break; + case ARMV7_ROR: + case ARMV7_RORS: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.RotateRight(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op2, addr), + il.And(1, + ReadILOperand(il, op3, addr), + il.Const(1, 0xff) + ), + flagOperation[instr.setsFlags] + ) + ) + ); + break; + case ARMV7_RRX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.Flag(IL_FLAG_C), il.Const(1,31)), + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1,1)) + ) + )); + }); + break; + case ARMV7_SADD16: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(2, + il.Add(2, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, LLIL_TEMP(1), + il.And(2, + il.Add(2, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.And(2, + il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff) + ), + il.Const(1, 16) + ), + il.And(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(2, 0xffff) + ) + ) + )); + }); + break; + case ARMV7_UADD16: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(2, + il.Add(2, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, LLIL_TEMP(1), + il.And(2, + il.Add(2, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.And(2, + il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff) + ), + il.Const(1, 16) + ), + il.And(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(2, 0xffff) + ) + ) + )); + }); + break; + case ARMV7_SADD8: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(1, + il.Add(1, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(1), + il.And(1, + il.Add(1, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(2), + il.And(1, + il.Add(1, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(3), + il.And(1, + il.Add(1, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1, 24) + ), + il.ShiftLeft(3, + il.Register(1, LLIL_TEMP(2)), + il.Const(1, 16) + ) + ), + il.Or(4, + il.ShiftLeft(2, + il.Register(1, LLIL_TEMP(1)), + il.Const(1, 8) + ), + il.Register(1, LLIL_TEMP(0)) + ) + ) + )); + }); + break; + case ARMV7_UADD8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(1, + il.Add(1, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(1), + il.And(1, + il.Add(1, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(2), + il.And(1, + il.Add(1, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(3), + il.And(1, + il.Add(1, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1, 24) + ), + il.ShiftLeft(3, + il.Register(1, LLIL_TEMP(2)), + il.Const(1, 16) + ) + ), + il.Or(4, + il.ShiftLeft(2, + il.Register(1, LLIL_TEMP(1)), + il.Const(1, 8) + ), + il.Register(1, LLIL_TEMP(0)) + ) + ) + )); + }); + break; + case ARMV7_SASX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.ArithShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.ArithShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(1)), + il.Const(1, 16) + ), + il.Register(2, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_UASX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.LogicalShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LogicalShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(1)), + il.Const(1, 16) + ), + il.Register(2, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_SHASX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.ArithShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.ArithShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.LowPart(2, + il.ArithShiftRight(2, + il.Register(4, LLIL_TEMP(1)), + il.Const(1,1) + ) + ), + il.Const(1, 16) + ), + il.LowPart(2, + il.ArithShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 1) + ) + ) + ) + )); + }); + break; + case ARMV7_UHASX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.LogicalShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LogicalShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.LowPart(2, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(1)), + il.Const(1,1) + ) + ), + il.Const(1, 16) + ), + il.LowPart(2, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 1) + ) + ) + ) + )); + }); + break; + case ARMV7_SHSAX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.ArithShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.ArithShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.LowPart(2, + il.ArithShiftRight(2, + il.Register(4, LLIL_TEMP(1)), + il.Const(1,1) + ) + ), + il.Const(1, 16) + ), + il.LowPart(2, + il.ArithShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 1) + ) + ) + ) + )); + }); + break; + case ARMV7_UHSAX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.LogicalShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.LogicalShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.LowPart(2, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(1)), + il.Const(1,1) + ) + ), + il.Const(1, 16) + ), + il.LowPart(2, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 1) + ) + ) + ) + )); + }); + break; + case ARMV7_SSAX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.ArithShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.ArithShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(1)), + il.Const(1, 16) + ), + il.Register(2, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_UMAAL: + /* op2:op1 = op4 * op3 + op2 + op1 */ + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction( + il.SetRegisterSplit(4, + op2.reg, /* hi result */ + op1.reg, /* lo result */ + il.Add(8, + il.MultDoublePrecUnsigned(4, + il.Register(4, op4.reg), + il.Register(4, op3.reg) + ), + il.Add(8, + il.Register(4, op2.reg), + il.Register(4, op1.reg) + ) + ) + ) + ); + }); + break; + case ARMV7_UMLAL: + /* op2:op1 = op4 * op3 + op2:op1 */ + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction( + il.SetRegisterSplit(4, + op2.reg, /* hi result */ + op1.reg, /* lo result */ + il.Add(8, + il.MultDoublePrecUnsigned(4, + il.Register(4, op4.reg), + il.Register(4, op3.reg) + ), + il.RegisterSplit( + 4, + op2.reg, + op1.reg + ) + ), + instr.setsFlags ? IL_FLAGWRITE_NZ : IL_FLAGWRITE_NONE + ) + ); + }); + break; + case ARMV7_SSUB16: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(2, + il.Sub(2, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, LLIL_TEMP(1), + il.And(2, + il.Sub(2, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.And(2, + il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff) + ), + il.Const(1, 16) + ), + il.And(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(2, 0xffff) + ) + ) + )); + }); + break; + case ARMV7_USUB16: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(2, + il.Sub(2, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, LLIL_TEMP(1), + il.And(2, + il.Sub(2, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(2, 0xffff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.And(2, + il.Register(4, LLIL_TEMP(1)), il.Const(2, 0xffff) + ), + il.Const(1, 16) + ), + il.And(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(2, 0xffff) + ) + ) + )); + }); + break; + case ARMV7_SSUB8: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(1, + il.Sub(1, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(1), + il.And(1, + il.Sub(1, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(2), + il.And(1, + il.Sub(1, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(3), + il.And(1, + il.Sub(1, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1, 24) + ), + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(2)), + il.Const(1, 16) + ) + ), + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(1)), + il.Const(1, 8) + ), + il.Register(1, LLIL_TEMP(0)) + ) + ) + )); + }); + break; + case ARMV7_USUB8: //TODO: APSR + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.And(1, + il.Sub(1, + ReadILOperand(il, op2, addr), + ReadILOperand(il, op3, addr) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(1), + il.And(1, + il.Sub(1, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(2), + il.And(1, + il.Sub(1, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(1, LLIL_TEMP(3), + il.And(1, + il.Sub(1, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ), + il.Const(1, 0xff) + ))); + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(3)), + il.Const(1, 24) + ), + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(2)), + il.Const(1, 16) + ) + ), + il.Or(4, + il.ShiftLeft(4, + il.Register(1, LLIL_TEMP(1)), + il.Const(1, 8) + ), + il.Register(1, LLIL_TEMP(0)) + ) + ) + )); + }); + break; + case ARMV7_SBC: + case ARMV7_SBCS: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.SubBorrow(get_register_size(op2.reg), + ReadILOperand(il, op2, addr), + ReadRegisterOrPointer(il, op3, addr), + il.Not(1,il.Flag(IL_FLAG_C))), + flagOperation[instr.setsFlags])); + break; + case ARMV7_SBFX: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.ArithShiftRight(get_register_size(op1.reg), + il.ShiftLeft(get_register_size(op2.reg), + ReadILOperand(il, op2, addr), + il.Const(1, (get_register_size(op2.reg) * 8) - op3.imm - op4.imm)), + il.Const(1, (get_register_size(op2.reg) * 8) - op4.imm)))); + break; + case ARMV7_SDIV: + if (op3.cls == NONE) + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.DivSigned(get_register_size(op1.reg), ReadRegisterOrPointer(il, op1, addr), ReadRegisterOrPointer(il, op2, addr)))); + else + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.DivSigned(get_register_size(op2.reg), ReadRegisterOrPointer(il, op2, addr), ReadRegisterOrPointer(il, op3, addr)))); + break; + case ARMV7_SHADD16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), + il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) + ) + )); + }); + break; + case ARMV7_UHADD16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), + il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) + ) + )); + }); + break; + case ARMV7_SHADD8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), + il.Add(4, + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), + il.Add(4, + il.LowPart(1, ReadILOperand(il, op2, addr)), + il.LowPart(1, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) + ), + il.Or(4, + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), + il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) + ) + ) + )); + }); + break; + case ARMV7_UHADD8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Add(4, + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), + il.Add(4, + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), + il.Add(4, + il.LowPart(1, ReadILOperand(il, op2, addr)), + il.LowPart(1, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) + ), + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), + il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) + ) + ) + )); + }); + break; + case ARMV7_SHSUB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), + il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) + ) + )); + }); + break; + case ARMV7_UHSUB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,16)), + il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)) + ) + )); + }); + break; + case ARMV7_SHSUB8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), + il.Sub(4, + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), + il.LowPart(1, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), + il.Sub(4, + il.LowPart(1, ReadILOperand(il, op2, addr)), + il.LowPart(1, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) + ), + il.Or(4, + il.ShiftLeft(4, il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), + il.ArithShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) + ) + ) + )); + }); + break; + case ARMV7_UHSUB8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 24)), + il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 24)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(2), + il.Sub(4, + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 8))), + il.LowPart(1, il.LogicalShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 8))) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(3), + il.Sub(4, + il.LowPart(1, ReadILOperand(il, op2, addr)), + il.LowPart(1, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(0)), il.Const(1,1)), il.Const(1,24)), + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(1)), il.Const(1,1)), il.Const(1,16)) + ), + il.Or(4, + il.ShiftLeft(4, il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(2)), il.Const(1,1)), il.Const(1,8)), + il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(3)), il.Const(1,1)) + ) + ) + )); + }); + break; + case ARMV7_SMLABB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLABT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLATB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Mult(4, + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLATT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Mult(4, + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLAD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1,16)), + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadILOperand(il, op4, addr), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ) + ) + )); + }); + break; + case ARMV7_SMLADX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1,16)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadILOperand(il, op4, addr), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ) + ) + )); + }); + break; + case ARMV7_SMLAL: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op3, addr), ReadILOperand(il, op4, addr)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), + il.Add(8, + il.Or(8, + il.ShiftLeft(8, + ReadILOperand(il, op2, addr), + il.Const(1, 32) + ), + ReadILOperand(il, op1, addr) + ), + il.Register(8, LLIL_TEMP(0)) + ) + )); + il.AddInstruction(il.SetRegister(4, op2.reg, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(1)), + il.Const(1, 32) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Register(8, LLIL_TEMP(1)) + ), + flagOperation[instr.setsFlags]) + ); + }); + break; + case ARMV7_SMLALBB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.SignExtend(8, + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLALBT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.SignExtend(8, + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLALTB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.SignExtend(8, + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLALTT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.SignExtend(8, + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLALD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op3, addr)), + il.LowPart(2, ReadILOperand(il, op4, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)), + il.ArithShiftRight(2, ReadILOperand(il, op4, addr), il.Const(1,16)) + ) + )); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(2), + il.Add(8, + il.Or(8, + il.ShiftLeft(8, + ReadILOperand(il, op2, addr), + il.Const(1, 32) + ), + ReadILOperand(il, op1, addr) + ), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Register(8, LLIL_TEMP(2)) + ) + )); + il.AddInstruction(il.SetRegister(4, op2.reg, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(2)), + il.Const(1, 32) + ) + )); + }); + break; + case ARMV7_SMLALDX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op3, addr)), + il.ArithShiftRight(2, ReadILOperand(il, op4, addr), il.Const(1,16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)), + il.LowPart(2, ReadILOperand(il, op4, addr)) + ) + )); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(2), + il.Add(8, + il.Or(8, + il.ShiftLeft(8, + ReadILOperand(il, op2, addr), + il.Const(1, 32) + ), + ReadILOperand(il, op1, addr) + ), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Register(8, LLIL_TEMP(2)) + ) + )); + il.AddInstruction(il.SetRegister(4, op2.reg, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(2)), + il.Const(1, 32) + ) + )); + }); + break; + case ARMV7_SMLAWB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.Mult(8, + ReadILOperand(il, op2, addr), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ), + il.ShiftLeft(8, + ReadILOperand(il, op4, addr), + il.Const(1, 16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.And(4, + il.ArithShiftRight(8, + il.Register(8, LLIL_TEMP(0)), + il.Const(1, 16) + ), + il.Const(4, 0xffffffff) + ) + )); + }); + break; + case ARMV7_SMLAWT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Add(8, + il.Mult(8, + ReadILOperand(il, op2, addr), + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ), + il.ShiftLeft(8, + ReadILOperand(il, op4, addr), + il.Const(1, 16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.And(4, + il.ArithShiftRight(8, + il.Register(8, LLIL_TEMP(0)), + il.Const(1, 16) + ), + il.Const(4, 0xffffffff) + ) + )); + }); + break; + case ARMV7_SMLSD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Sub(4, + il.Register(4, LLIL_TEMP(1)), + il.Register(4, LLIL_TEMP(0)) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLSDX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Sub(4, + il.Register(4, LLIL_TEMP(1)), + il.Register(4, LLIL_TEMP(0)) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMLSLD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op3, addr)), + il.LowPart(2, ReadILOperand(il, op4, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)), + il.ArithShiftRight(2, ReadILOperand(il, op4, addr), il.Const(1,16)) + ) + )); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(2), + il.Add(8, + il.Or(8, + il.ShiftLeft(8, + ReadILOperand(il, op2, addr), + il.Const(1, 32) + ), + ReadILOperand(il, op1, addr) + ), + il.Sub(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Register(8, LLIL_TEMP(2)) + ) + )); + il.AddInstruction(il.SetRegister(4, op2.reg, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(2)), + il.Const(1, 32) + ) + )); + }); + break; + case ARMV7_SMLSLDX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op3, addr)), + il.ArithShiftRight(2, ReadILOperand(il, op4, addr), il.Const(1,16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)), + il.LowPart(2, ReadILOperand(il, op4, addr)) + ) + )); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(2), + il.Add(8, + il.Or(8, + il.ShiftLeft(8, + ReadILOperand(il, op2, addr), + il.Const(1, 32) + ), + ReadILOperand(il, op1, addr) + ), + il.Sub(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Register(8, LLIL_TEMP(2)) + ) + )); + il.AddInstruction(il.SetRegister(4, op2.reg, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(2)), + il.Const(1, 32) + ) + )); + }); + break; + case ARMV7_SMMLA: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), il.ArithShiftRight(8, il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), il.Const(1, 32)))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMMLAR: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Add(8, il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), il.Const(8, 0x80000000)))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.ArithShiftRight(4, + il.Register(8, LLIL_TEMP(0)), + il.Const(1, 32) + ), + ReadILOperand(il, op4, addr) + ) + )); + }); + break; + case ARMV7_SMMLS: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), il.ShiftLeft(8, ReadILOperand(il, op4, addr), il.Const(1, 32)))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.ArithShiftRight(4, + il.Sub(8, + il.Register(8, LLIL_TEMP(1)), + il.Register(8, LLIL_TEMP(0)) + ), + il.Const(1, 32) + ) + )); + }); + break; + case ARMV7_SMMLSR: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), il.ShiftLeft(8, ReadILOperand(il, op4, addr), il.Const(1, 32)))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.ArithShiftRight(4, + il.Add(8, + il.Sub(8, + il.Register(8, LLIL_TEMP(1)), + il.Register(8, LLIL_TEMP(0)) + ), + il.Const(8, 0x80000000) + ), + il.Const(1, 32) + ) + )); + }); + break; + case ARMV7_SMUAD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Register(4, LLIL_TEMP(1)), + il.Register(4, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_SMUADX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + il.Register(4, LLIL_TEMP(1)), + il.Register(4, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_SMMUL: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)))); + il.AddInstruction(il.SetRegister(4, op1.reg, il.ArithShiftRight(4, il.Register(8, LLIL_TEMP(0)), il.Const(1, 32)))); + }); + break; + case ARMV7_SMMULR: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Add(8, il.Mult(8, ReadILOperand(il, op2, addr), ReadILOperand(il, op3, addr)), il.Const(4, 0x80000000)))); + il.AddInstruction(il.SetRegister(4, op1.reg, il.ArithShiftRight(4, il.Register(8, LLIL_TEMP(0)), il.Const(1, 32)))); + }); + break; + case ARMV7_UMULL: + case ARMV7_SMULL: + /* op2:op1 = op3 * op4 */ + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + ExprId product; + if (instr.operation == ARMV7_UMULL) + product = il.MultDoublePrecUnsigned(get_register_size(op3.reg), ReadILOperand(il, op3, addr), ReadILOperand(il, op4, addr)); + else + product = il.MultDoublePrecSigned(get_register_size(op3.reg), ReadILOperand(il, op3, addr), ReadILOperand(il, op4, addr)); + + il.AddInstruction( + il.SetRegisterSplit(get_register_size(op1.reg), + op2.reg, + op1.reg, + product + ) + ); + }); + break; + case ARMV7_SMULBB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + ) + ); + }); + break; + case ARMV7_SMULBT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ) + ) + ); + }); + break; + case ARMV7_SMULTB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Mult(4, + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + ) + ); + }); + break; + case ARMV7_SMULTT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Mult(4, + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16))), + il.LowPart(2, il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16))) + ) + ) + ); + }); + break; + case ARMV7_SMULWB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Mult(4, + ReadILOperand(il, op2, addr), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + }); + break; + case ARMV7_SMULWT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Mult(4, + ReadILOperand(il, op2, addr), + il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1,16)) + ) + )); + }); + break; + case ARMV7_SMUSD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Sub(4, + il.Register(4, LLIL_TEMP(1)), + il.Register(4, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_SMUSDX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Mult(4, + il.ArithShiftRight(4, ReadILOperand(il, op2, addr), il.Const(1, 16)), + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Mult(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.ArithShiftRight(4, ReadILOperand(il, op3, addr), il.Const(1, 16)) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Sub(4, + il.Register(4, LLIL_TEMP(1)), + il.Register(4, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_SSAT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.ShiftLeft(4, + il.Const(1, 2), + ReadILOperand(il, op2, addr) + ), + il.Const(1,1) + ) + )); + + Saturate(il, op1.reg, ReadILOperand(il, op3, addr), il.Register(4, LLIL_TEMP(0)), true); + }); + break; + case ARMV7_SSAT16: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Sub(2, + il.ShiftLeft(2, + il.Const(1, 2), + ReadILOperand(il, op2, addr) + ), + il.Const(1, 1) + ) + )); + + Saturate(il, LLIL_TEMP(1), il.LowPart(2, ReadILOperand(il, op3, addr)), il.Register(4, LLIL_TEMP(0)), true); + Saturate(il, LLIL_TEMP(2), il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)), il.Register(4, LLIL_TEMP(0)), true); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ZeroExtend(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(2)), + il.Const(1, 16) + ) + ), + il.ZeroExtend(2, il.Register(2, LLIL_TEMP(1))) + ) + )); + }); + break; + case ARMV7_STMDA: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + uint32_t lowestSetBit = 1337; + uint32_t numToLoad = 0; + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + numToLoad++; + if (j < lowestSetBit) + lowestSetBit = j; + } + } + //Set base address + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, (4*numToLoad) - 4) + ) + )); + //Check only the first 15 bits, 16th bit is PC which is handled at the bottom + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Unimplemented() + ) + ); + } + else + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); + } + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 4) + ) + )); + } + } + // Check if PC is stored + if (((op2.reg >> 15) & 1) == 1) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, REG_PC) + ) + ); + } + // Check for writeback + if (op1.flags.wb == 1) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Sub(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, 4*numToLoad) + ) + )); + } + }); + break; + case ARMV7_STMDB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + uint32_t lowestSetBit = 1337; + uint32_t numToLoad = 0; + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + numToLoad++; + if (j < lowestSetBit) + lowestSetBit = j; + } + } + //Set base address + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, 4*numToLoad) + ) + )); + //Check only the first 15 bits, 16th bit is PC which is handled at the bottom + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Unimplemented() + ) + ); + } + else + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); + } + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 4) + ) + )); + } + } + // Check if PC is stored + if (((op2.reg >> 15) & 1) == 1) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, REG_PC) + ) + ); + } + // Check for writeback + if (op1.flags.wb == 1) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Sub(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, 4*numToLoad) + ) + )); + } + }); + break; + case ARMV7_STMIB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + uint32_t lowestSetBit = 1337; + uint32_t numToLoad = 0; + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + numToLoad++; + if (j < lowestSetBit) + lowestSetBit = j; + } + } + //Set base address + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(1, 4) + ) + )); + //Check only the first 15 bits, 16th bit is PC which is handled at the bottom + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Unimplemented() + ) + ); + } + else + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); + } + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 4) + ) + )); + } + } + // Check if PC is stored + if (((op2.reg >> 15) & 1) == 1) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, REG_PC) + ) + ); + } + // Check for writeback + if (op1.flags.wb == 1) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, 4*numToLoad) + ) + )); + } + }); + break; + case ARMV7_STM: + case ARMV7_STMIA: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + uint32_t lowestSetBit = 1337; + uint32_t numToLoad = 0; + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + numToLoad++; + if (j < lowestSetBit) + lowestSetBit = j; + } + } + //Set base address + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + ReadRegisterOrPointer(il, op1, addr) + )); + //Check only the first 15 bits, 16th bit is PC which is handled at the bottom + for (uint32_t j = 0; j < 15; j++) + { + if (((op2.reg >> j) & 1) == 1) + { + if (j == op1.reg && op1.flags.wb == 1 && j != lowestSetBit) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Unimplemented() + ) + ); + } + else + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(get_register_size((enum Register)j), j) + ) + ); + } + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 4) + ) + )); + } + } + // Check if PC is stored + if (((op2.reg >> 15) & 1) == 1) + { + il.AddInstruction( + il.Store(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, REG_PC) + ) + ); + } + // Check for writeback + if (op1.flags.wb == 1) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadRegisterOrPointer(il, op1, addr), + il.Const(4, 4*numToLoad) + ) + )); + } + }); + break; + case ARMV7_STREX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + StoreExclusive(il, 4, op1, op2, op3, addr); + }); + break; + case ARMV7_STREXH: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + StoreExclusive(il, 2, op1, op2, op3, addr); + }); + break; + case ARMV7_STREXB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + StoreExclusive(il, 1, op1, op2, op3, addr); + }); + break; + case ARMV7_STR: + case ARMV7_STRT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Store(il, 4, op1, op2, addr); + }); + break; + case ARMV7_STRH: + case ARMV7_STRHT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Store(il, 2, op1, op2, addr); + }); + break; + case ARMV7_STRB: + case ARMV7_STRBT: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Store(il, 1, op1, op2, addr); + }); + break; + case ARMV7_STREXD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + StorePairExclusive(arch, il, op1, op2, op3, op4, addr); + }); + break; + case ARMV7_STRD: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + StorePair(arch, il, op1, op2, op3, addr); + }); + break; + case ARMV7_SUB: + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Sub(get_register_size(op2.reg), + ReadRegisterOrPointer(il, op2, addr), + ReadILOperand(il, op3, addr), flagOperation[instr.setsFlags]))); + break; + case ARMV7_SVC: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, FAKEREG_SYSCALL_INFO, il.Const(4, op1.imm))); + il.AddInstruction(il.SystemCall()); + }); + break; + case ARMV7_SWP: + if (op1.reg == op2.reg) + { + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Load(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op3, addr) + ) + )); + il.AddInstruction(il.Store(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op3, addr), + ReadRegisterOrPointer(il, op2, addr) + )); + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, + il.Register(4, LLIL_TEMP(0)) + )); + }); + } + else + { + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, + il.Load(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op3, addr) + ) + )); + il.AddInstruction(il.Store(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op3, addr), + ReadRegisterOrPointer(il, op2, addr) + )); + }); + } + break; + case ARMV7_SWPB: + if (op1.reg == op2.reg) + { + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), + il.Load(1, + ReadRegisterOrPointer(il, op3, addr) + ) + )); + il.AddInstruction(il.Store(1, + ReadRegisterOrPointer(il, op3, addr), + il.And(1, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 0xff) + ) + )); + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, + il.ZeroExtend(4, il.Register(1, LLIL_TEMP(0))) + )); + }); + } + else + { + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(SetRegisterOrBranch(il, op1.reg, + il.ZeroExtend(4, + il.Load(1, + ReadRegisterOrPointer(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.Store(1, + ReadRegisterOrPointer(il, op3, addr), + il.And(1, + ReadRegisterOrPointer(il, op2, addr), + il.Const(1, 0xff) + ) + )); + }); + } + break; + case ARMV7_SXTAB: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + ReadILOperand(il, op3, addr) + )); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadILOperand(il, op2, addr), + il.SignExtend(4, + il.Register(1, LLIL_TEMP(0)) + ) + ) + )); + }); + break; + case ARMV7_SXTAB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + ReadILOperand(il, op3, addr) + )); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Add(2, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.SignExtend(2, + il.LowPart(1, + il.ArithShiftRight(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 16) + ) + ) + ) + ), + il.Const(1, 16) + ), + il.Add(2, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.SignExtend(2, + il.Register(1, LLIL_TEMP(0)) + ) + ) + ) + )); + }); + break; + case ARMV7_SXTAH: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadILOperand(il, op2, addr), + il.SignExtend(4, + il.LowPart(2, ReadILOperand(il, op3, addr)) + ) + ) + )); + }); + break; + case ARMV7_SXTB: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.ArithShiftRight(get_register_size(op1.reg), + il.ShiftLeft(get_register_size(op1.reg), ReadRegisterOrPointer(il, op2, addr), il.Const(get_register_size(op1.reg), get_register_size(op1.reg)-8)), + il.Const(get_register_size(op1.reg), (get_register_size(op1.reg)*8)-8)))); + break; + case ARMV7_SXTB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + ReadILOperand(il, op2, addr) + )); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.SignExtend(2, + il.LowPart(1, + il.ArithShiftRight(4, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 16) + ) + ) + ), + il.Const(1, 16) + ), + il.SignExtend(2, + il.Register(1, LLIL_TEMP(0)) + ) + ) + )); + }); + break; + case ARMV7_SXTH: + { + ExprId source = il.Register(4, op2.reg); + + if (op2.shift == SHIFT_ROR && op2.imm) + source = il.RotateRight(4, source, il.Const(1, op2.imm)); + + ConditionExecute(il, instr.cond, + il.SetRegister(4, + op1.reg, + il.SignExtend(4, + il.LowPart(2, + source + ) + ) + ) + ); + + break; + } + + /*case ARMV7_SXTW: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.ArithShiftRight(get_register_size(op1.reg), + il.ShiftLeft(get_register_size(op1.reg), ReadRegisterOrPointer(il, op2, addr), il.Const(get_register_size(op1.reg), get_register_size(op1.reg)-16)), + il.Const(get_register_size(op1.reg), (get_register_size(op1.reg)*8)-16)))); + break; + */ + case ARMV7_TEQ: + ConditionExecute(il, instr.cond, il.Xor(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadILOperand(il, op2, addr), IL_FLAGWRITE_CNZ)); + break; + case ARMV7_TST: + ConditionExecute(il, instr.cond, il.And(get_register_size(op1.reg), + ReadRegisterOrPointer(il, op1, addr), + ReadILOperand(il, op2, addr), IL_FLAGWRITE_ALL)); + break; + case ARMV7_UBFX: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op1.reg), + il.LogicalShiftRight(get_register_size(op2.reg), ReadILOperand(il, op2, addr), il.Const(1, op3.imm)), + il.Const(get_register_size(op2.reg), BITMASK(op4.imm, 0))))); + break; + case ARMV7_USAD8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.Sub(4, + il.LowPart(1, + il.ArithShiftRight(4, + ReadILOperand(il, op2, addr), + il.Const(1, i*8) + ) + ), + il.LowPart(1, + il.ArithShiftRight(4, + ReadILOperand(il, op3, addr), + il.Const(1, i*8) + ) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.Sub(4, + il.Xor(4, + il.Register(4, LLIL_TEMP(i)), + il.ArithShiftRight(4, + il.Register(4, LLIL_TEMP(i)), + il.Const(1, 31) + ) + ), + il.ArithShiftRight(4, + il.Register(4, LLIL_TEMP(i)), + il.Const(1, 31) + ) + ) + )); + } + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Add(4, + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ), + il.Add(4, + il.Register(4, LLIL_TEMP(2)), + il.Register(4, LLIL_TEMP(3)) + ) + ) + ) + )); + }); + break; + case ARMV7_USADA8: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.Sub(4, + il.LowPart(1, + il.ArithShiftRight(4, + ReadILOperand(il, op2, addr), + il.Const(1, i*8) + ) + ), + il.LowPart(1, + il.ArithShiftRight(4, + ReadILOperand(il, op3, addr), + il.Const(1, i*8) + ) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.Sub(4, + il.Xor(4, + il.Register(4, LLIL_TEMP(i)), + il.ArithShiftRight(4, + il.Register(4, LLIL_TEMP(i)), + il.Const(1, 31) + ) + ), + il.ArithShiftRight(4, + il.Register(4, LLIL_TEMP(i)), + il.Const(1, 31) + ) + ) + )); + } + il.AddInstruction(il.SetRegister(4, op1.reg, + il.LowPart(4, + il.Add(4, + ReadILOperand(il, op4, addr), + il.Add(4, + il.Add(4, + il.Register(4, LLIL_TEMP(0)), + il.Register(4, LLIL_TEMP(1)) + ), + il.Add(4, + il.Register(4, LLIL_TEMP(2)), + il.Register(4, LLIL_TEMP(3)) + ) + ) + ) + ) + )); + }); + break; + case ARMV7_USAT: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Sub(4, + il.ShiftLeft(4, + il.Const(1, 1), + ReadILOperand(il, op2, addr) + ), + il.Const(1, 1) + ) + )); + + Saturate(il, op1.reg, ReadILOperand(il, op3, addr), il.Register(4, LLIL_TEMP(0)), false); + + }); + break; + case ARMV7_USAT16: + ConditionExecute(addr, instr.cond, instr, il, [&](size_t, Instruction&, LowLevelILFunction& il){ + il.AddInstruction(il.SetRegister(2, LLIL_TEMP(0), + il.Sub(2, + il.ShiftLeft(2, + il.Const(1, 1), + ReadILOperand(il, op2, addr) + ), + il.Const(1, 1) + ) + )); + + Saturate(il, LLIL_TEMP(1), il.LowPart(2, ReadILOperand(il, op3, addr)), il.Register(4, LLIL_TEMP(0)), false); + Saturate(il, LLIL_TEMP(2), il.ArithShiftRight(2, ReadILOperand(il, op3, addr), il.Const(1, 16)), il.Register(4, LLIL_TEMP(0)), false); + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ZeroExtend(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(2)), + il.Const(1, 16) + ) + ), + il.ZeroExtend(2, il.Register(2, LLIL_TEMP(1))) + ) + )); + }); + break; + case ARMV7_USAX: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), + il.Add(4, + il.LowPart(2, + ReadILOperand(il, op2, addr) + ), + il.LogicalShiftRight(2, + ReadILOperand(il, op3, addr), + il.Const(1,16) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(1), + il.Sub(4, + il.LogicalShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1,16) + ), + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + )); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Register(2, LLIL_TEMP(1)), + il.Const(1, 16) + ), + il.Register(2, LLIL_TEMP(0)) + ) + )); + }); + break; + case ARMV7_UXTAB: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.Add(get_register_size(op2.reg), ReadRegisterOrPointer(il, op2, addr), + il.And(get_register_size(op3.reg), + GetShiftedRegister(il, op3), il.Const(get_register_size(op3.reg), 0xff))))); + break; + case ARMV7_UXTAB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), ReadILOperand(il, op3, addr))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.Add(4, + il.LowPart(2, ReadILOperand(il, op2, addr)), + il.ZeroExtend(2, il.Register(1, LLIL_TEMP(0))) + ), + il.Const(1, 32) + ), + il.Add(4, + il.LogicalShiftRight(2, + ReadILOperand(il, op2, addr), + il.Const(1, 16) + ), + il.ZeroExtend(2, + il.LowPart(1, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 16) + ) + ) + ) + ) + ) + )); + }); + break; + case ARMV7_UXTAH: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadILOperand(il, op2, addr), + il.ZeroExtend(4, + il.LowPart(2, + ReadILOperand(il, op3, addr) + ) + ) + ) + )); + }); + break; + case ARMV7_UXTB: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op2.reg), GetShiftedRegister(il, op2), il.Const(get_register_size(op2.reg), 0xff)))); + break; + case ARMV7_UXTB16: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(0), ReadILOperand(il, op2, addr))); + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Or(4, + il.ShiftLeft(4, + il.ZeroExtend(2, + il.LowPart(1, + il.LogicalShiftRight(2, + il.Register(4, LLIL_TEMP(0)), + il.Const(1, 16) + ) + ) + ), + il.Const(1, 16) + ), + il.ZeroExtend(2, il.Register(1, LLIL_TEMP(0))) + ) + )); + }); + break; + case ARMV7_UXTH: + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.And(get_register_size(op2.reg), GetShiftedRegister(il, op2), il.Const(get_register_size(op2.reg), 0xffff)))); + break; + case ARMV7_UDF: + il.AddInstruction(il.Trap(op1.imm)); + break; + case ARMV7_UDIV: + if (op3.cls == NONE) + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.DivUnsigned(get_register_size(op1.reg), ReadRegisterOrPointer(il, op1, addr), ReadRegisterOrPointer(il, op2, addr)))); + else + ConditionExecute(il, instr.cond, SetRegisterOrBranch(il, op1.reg, + il.DivUnsigned(get_register_size(op2.reg), ReadRegisterOrPointer(il, op2, addr), ReadRegisterOrPointer(il, op3, addr)))); + break; + case ARMV7_VADD: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatAdd(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) + ) + ); + break; + case ARMV7_VDIV: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatDiv(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) + ) + ); + break; + case ARMV7_VLDR: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Load(il, false, get_register_size(op1.reg), op1, op2, addr); + }); + break; + case ARMV7_VMOV: + /* VMOV(register) */ + if (op1.cls == REG && op2.cls == REG && op3.cls == NONE) + { + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + ReadILOperand(il, op2, addr), flagOperation[instr.setsFlags])); + } else if (op1.cls == REG && (op2.cls == IMM || op2.cls == IMM64) && op3.cls == NONE) { + /* VMOV(immediate) */ + if (get_register_size(op1.reg) == 16) + { + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Or(16, il.Const(8, op2.imm64), il.ShiftLeft(16, il.Const(8, op2.imm64), il.Const(8, 64))), + flagOperation[instr.setsFlags])); + } else + { + ConditionExecute(il, instr.cond, + SetRegisterOrBranch(il, op1.reg, + il.Const(get_register_size(op1.reg), op2.imm64), flagOperation[instr.setsFlags])); + } + } else + { + ConditionExecute(il, instr.cond, il.Unimplemented()); + } + break; + case ARMV7_VMUL: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatMult(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) + ) + ); + break; + case ARMV7_VSTR: + ConditionExecute(addrSize, instr.cond, instr, il, + [&](size_t addrSize, Instruction& instr, LowLevelILFunction& il) + { + (void) addrSize; + (void) instr; + Store(il, get_register_size(op1.reg), op1, op2, addr); + }); + break; + case ARMV7_VSUB: + if((instr.dataType != DT_F32) && (instr.dataType != DT_F32) && (instr.dataType != DT_F64)) + break; + + ConditionExecute(il, instr.cond, + il.SetRegister(get_register_size(op1.reg), op1.reg, + il.FloatSub(get_register_size(op1.reg), + il.Register(get_register_size(op2.reg), op2.reg), + il.Register(get_register_size(op3.reg), op3.reg) + ) + ) + ); + break; + default: + //printf("Instruction: %s\n", get_operation(instr.operation)); + ConditionExecute(il, instr.cond, il.Unimplemented()); + break; + } + return true; +} |
