From c60bdc9e395102cf1953d97ae08a0e4cbed89514 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Wed, 1 Jul 2026 17:00:51 -0400 Subject: [PATCH] Improve x86 flag lifting semantics Expand x86 LLIL flag modeling for arithmetic, test, rotate, shift, double-shift, and signed multiply instructions. Add popcnt-based parity calculation, auxiliary-carry formulas, SBB/ADC carry and overflow handling, IMUL truncation checks, and count-sensitive CF/OF behavior for shifts and rotates. Use LLIL unknown for architecturally undefined flags. Fix several flag correctness issues, including PTEST/VPTEST flag polarity and cleared flags, CCMP/CTEST signed-not-less conditions, EVEX default flag values, and SHLD/SHRD count/result flag behavior. Keep variable-count register shift and rotate value lifts clean by moving count-zero/count-one flag handling into flag callbacks, while preserving count-zero no-op behavior for memory destinations. Also improve ENTER lifting for nonzero nesting levels. --- arch/x86/arch_x86.cpp | 619 +++++++++++++++++++++++++++++++++++++++++- arch/x86/il.cpp | 567 ++++++++++++++++++++++++++++++-------- arch/x86/il.h | 5 + 3 files changed, 1082 insertions(+), 109 deletions(-) diff --git a/arch/x86/arch_x86.cpp b/arch/x86/arch_x86.cpp index 0ae9ecc58..35d58a008 100644 --- a/arch/x86/arch_x86.cpp +++ b/arch/x86/arch_x86.cpp @@ -5,6 +5,7 @@ #include #include "binaryninjaapi.h" #include "il.h" +#include "lowlevelilinstruction.h" extern "C" { #include "xed-interface.h" } @@ -2105,6 +2106,69 @@ bool X86CommonArchitecture::GetInstructionLowLevelIL(const uint8_t* data, uint64 size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, LowLevelILFunction& il) { + auto undefinedFlag = [&il]() { + return il.Unknown(); + }; + auto boolChoice = [&il](ExprId condition, ExprId inverseCondition, ExprId trueValue, ExprId falseValue) { + return il.Or(0, + il.And(0, condition, trueValue), + il.And(0, inverseCondition, falseValue)); + }; + auto rotateCarryCount = [](size_t operandSize, uint64_t maskedCount) { + switch (operandSize) + { + case 1: + return maskedCount % 9; + case 2: + return maskedCount % 17; + default: + return maskedCount; + } + }; + + if ((flag == IL_FLAG_O) && (flagWriteType == IL_FLAGWRITE_SHRD1)) + { + size_t bitWidth = size * 8; + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + return il.CompareNotEqual(size, + il.And(size, + il.Xor(size, + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 1)), + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 2))), + il.Const(size, 1)), + il.Const(size, 0)); + } + + if (flagWriteType == IL_FLAGWRITE_PTEST) + { + switch (flag) + { + case IL_FLAG_Z: + if (operandCount < 2) + return undefinedFlag(); + return il.CompareEqual(size, + il.And(size, + il.GetExprForRegisterOrConstant(operands[0], size), + il.GetExprForRegisterOrConstant(operands[1], size)), + il.Const(size, 0)); + case IL_FLAG_C: + if (operandCount < 2) + return undefinedFlag(); + return il.CompareEqual(size, + il.And(size, + il.GetExprForRegisterOrConstant(operands[1], size), + il.Not(size, il.GetExprForRegisterOrConstant(operands[0], size))), + il.Const(size, 0)); + case IL_FLAG_O: + case IL_FLAG_S: + case IL_FLAG_A: + case IL_FLAG_P: + return il.Const(0, 0); + default: + break; + } + } + switch (op) { case LLIL_NEG: @@ -2124,7 +2188,478 @@ size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, s case IL_FLAG_O: return il.Const(0, 0); case IL_FLAG_A: - return il.Unimplemented(); + return undefinedFlag(); + } + break; + case LLIL_ROL: + if ((flagWriteType == IL_FLAGWRITE_CO) && ((flag == IL_FLAG_C) || (flag == IL_FLAG_O))) + { + if (operandCount < 2) + return undefinedFlag(); + + size_t bitWidth = size * 8; + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + if (operands[1].constant) + { + uint64_t maskedCount = operands[1].value & countMask; + uint64_t effectiveCount = maskedCount % bitWidth; + if (maskedCount == 0) + return il.Flag(flag); + + BNRegisterOrConstant effectiveOperands[2] = {operands[0], operands[1]}; + effectiveOperands[1].value = effectiveCount; + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, effectiveOperands, 2); + ExprId carry = il.CompareNotEqual(size, + il.And(size, result, il.Const(size, 1)), il.Const(size, 0)); + if (flag == IL_FLAG_C) + return carry; + + if (maskedCount == 1) + { + ExprId sign = il.CompareNotEqual(size, + il.And(size, result, il.Const(size, 1ULL << (bitWidth - 1))), il.Const(size, 0)); + return il.Xor(0, sign, carry); + } + + return undefinedFlag(); + } + + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + ExprId carry = il.CompareNotEqual(size, + il.And(size, result, il.Const(size, 1)), il.Const(size, 0)); + ExprId count = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId countIsZero = il.CompareEqual(size, count, il.Const(size, 0)); + ExprId countNotZero = il.CompareNotEqual(size, count, il.Const(size, 0)); + if (flag == IL_FLAG_C) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), carry); + + ExprId countIsOne = il.CompareEqual(size, count, il.Const(size, 1)); + ExprId countGreaterThanOne = il.And(0, countNotZero, il.Not(0, countIsOne)); + ExprId sign = il.CompareNotEqual(size, + il.And(size, result, il.Const(size, 1ULL << (bitWidth - 1))), il.Const(size, 0)); + return il.Or(0, + il.And(0, countIsZero, il.Flag(flag)), + il.Or(0, + il.And(0, countIsOne, il.Xor(0, sign, carry)), + il.And(0, countGreaterThanOne, undefinedFlag()))); + } + break; + case LLIL_ROR: + if ((flagWriteType == IL_FLAGWRITE_CO) && ((flag == IL_FLAG_C) || (flag == IL_FLAG_O))) + { + if (operandCount < 2) + return undefinedFlag(); + + size_t bitWidth = size * 8; + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + if (operands[1].constant) + { + uint64_t maskedCount = operands[1].value & countMask; + uint64_t effectiveCount = maskedCount % bitWidth; + if (maskedCount == 0) + return il.Flag(flag); + + BNRegisterOrConstant effectiveOperands[2] = {operands[0], operands[1]}; + effectiveOperands[1].value = effectiveCount; + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, effectiveOperands, 2); + if (flag == IL_FLAG_C) + return il.AddExpr(LLIL_CMP_SLT, size, 0, result, il.Const(size, 0)); + + if (maskedCount == 1) + return il.CompareNotEqual(size, + il.And(size, + il.Xor(size, + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 1)), + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 2))), + il.Const(size, 1)), + il.Const(size, 0)); + + return undefinedFlag(); + } + + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + ExprId carry = il.AddExpr(LLIL_CMP_SLT, size, 0, result, il.Const(size, 0)); + ExprId count = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId countIsZero = il.CompareEqual(size, count, il.Const(size, 0)); + ExprId countNotZero = il.CompareNotEqual(size, count, il.Const(size, 0)); + if (flag == IL_FLAG_C) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), carry); + + ExprId countIsOne = il.CompareEqual(size, count, il.Const(size, 1)); + ExprId countGreaterThanOne = il.And(0, countNotZero, il.Not(0, countIsOne)); + ExprId overflow = il.CompareNotEqual(size, + il.And(size, + il.Xor(size, + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 1)), + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 2))), + il.Const(size, 1)), + il.Const(size, 0)); + return il.Or(0, + il.And(0, countIsZero, il.Flag(flag)), + il.Or(0, + il.And(0, countIsOne, overflow), + il.And(0, countGreaterThanOne, undefinedFlag()))); + } + break; + case LLIL_RLC: + if (((flagWriteType == IL_FLAGWRITE_CO) || (flagWriteType == IL_FLAGWRITE_CUO)) && + ((flag == IL_FLAG_C) || (flag == IL_FLAG_O))) + { + if (operandCount < 3) + return undefinedFlag(); + + size_t bitWidth = size * 8; + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + ExprId count = il.GetExprForRegisterOrConstant(operands[1], size); + uint64_t maskedCount = 0; + if (operands[1].constant) + { + maskedCount = operands[1].value & countMask; + uint64_t effectiveCount = rotateCarryCount(size, maskedCount); + if (effectiveCount == 0) + return il.Flag(flag); + count = il.Const(size, effectiveCount); + } + + if ((flag == IL_FLAG_O) && (flagWriteType == IL_FLAGWRITE_CUO)) + return undefinedFlag(); + + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + ExprId carry = il.CompareNotEqual(size, + il.And(size, + il.LogicalShiftRight(size, left, il.Sub(size, il.Const(size, bitWidth), count)), + il.Const(size, 1)), + il.Const(size, 0)); + if (flag == IL_FLAG_C) + return carry; + + if (!operands[1].constant) + return undefinedFlag(); + + uint64_t effectiveCount = rotateCarryCount(size, maskedCount); + if (maskedCount != 1) + return undefinedFlag(); + + BNRegisterOrConstant effectiveOperands[3] = {operands[0], operands[1], operands[2]}; + effectiveOperands[1].value = effectiveCount; + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, effectiveOperands, 3); + ExprId sign = il.CompareNotEqual(size, + il.And(size, result, il.Const(size, 1ULL << (bitWidth - 1))), + il.Const(size, 0)); + return il.Xor(0, sign, carry); + } + break; + case LLIL_RRC: + if (((flagWriteType == IL_FLAGWRITE_CO) || (flagWriteType == IL_FLAGWRITE_CUO)) && + ((flag == IL_FLAG_C) || (flag == IL_FLAG_O))) + { + if (operandCount < 3) + return undefinedFlag(); + + size_t bitWidth = size * 8; + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + ExprId count = il.GetExprForRegisterOrConstant(operands[1], size); + uint64_t maskedCount = 0; + if (operands[1].constant) + { + maskedCount = operands[1].value & countMask; + uint64_t effectiveCount = rotateCarryCount(size, maskedCount); + if (effectiveCount == 0) + return il.Flag(flag); + count = il.Const(size, effectiveCount); + } + + if ((flag == IL_FLAG_O) && (flagWriteType == IL_FLAGWRITE_CUO)) + return undefinedFlag(); + + if (flag == IL_FLAG_C) + { + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + return il.CompareNotEqual(size, + il.And(size, + il.LogicalShiftRight(size, left, il.Sub(size, count, il.Const(size, 1))), + il.Const(size, 1)), + il.Const(size, 0)); + } + + if (!operands[1].constant) + return undefinedFlag(); + + uint64_t effectiveCount = rotateCarryCount(size, maskedCount); + if (maskedCount != 1) + return undefinedFlag(); + + BNRegisterOrConstant effectiveOperands[3] = {operands[0], operands[1], operands[2]}; + effectiveOperands[1].value = effectiveCount; + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, effectiveOperands, operandCount); + return il.CompareNotEqual(size, + il.And(size, + il.Xor(size, + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 1)), + il.LogicalShiftRight(size, result, il.Const(size, bitWidth - 2))), + il.Const(size, 1)), + il.Const(size, 0)); + } + break; + case LLIL_ADC: + if ((flag == IL_FLAG_O) && (flagWriteType == IL_FLAGWRITE_ALL) && (operandCount >= 3)) + { + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + ExprId right = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + return il.CompareNotEqual(size, + il.And(size, + il.And(size, il.Xor(size, left, result), il.Xor(size, right, result)), + il.Const(size, 1ULL << ((size * 8) - 1))), + il.Const(size, 0)); + } + break; + case LLIL_SBB: + if ((flagWriteType == IL_FLAGWRITE_ALL) && (operandCount >= 3)) + { + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + ExprId right = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId carry = il.GetExprForFlagOrConstant(operands[2]); + switch (flag) + { + case IL_FLAG_C: + return il.Or(0, + il.CompareUnsignedLessThan(size, left, right), + il.And(0, carry, il.CompareEqual(size, left, right))); + case IL_FLAG_O: + { + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + return il.CompareNotEqual(size, + il.And(size, + il.And(size, il.Xor(size, left, right), il.Xor(size, left, result)), + il.Const(size, 1ULL << ((size * 8) - 1))), + il.Const(size, 0)); + } + default: + break; + } + } + break; + case LLIL_MUL: + if ((flagWriteType == IL_FLAGWRITE_CO) && ((flag == IL_FLAG_C) || (flag == IL_FLAG_O)) && (operandCount >= 2)) + { + if ((operands[0].constant && (operands[0].value == 0)) || + (operands[1].constant && (operands[1].value == 0))) + return il.Const(0, 0); + + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + ExprId right = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + size_t fullSize = size * 2; + ExprId fullResult = il.Mult(fullSize, il.SignExtend(fullSize, left), il.SignExtend(fullSize, right)); + return il.CompareNotEqual(fullSize, fullResult, il.SignExtend(fullSize, result)); + } + break; + case LLIL_LSL: + if (((flagWriteType == IL_FLAGWRITE_ALL) || (flagWriteType == IL_FLAGWRITE_NOCARRY) || + (flagWriteType == IL_FLAGWRITE_CO) || (flagWriteType == IL_FLAGWRITE_C)) && (operandCount >= 2)) + { + size_t bitWidth = size * 8; + uint64_t resultMask = (size == 8) ? UINT64_MAX : ((1ULL << bitWidth) - 1); + uint64_t signBit = 1ULL << (bitWidth - 1); + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + ExprId maskedResult = il.And(size, result, il.Const(size, resultMask)); + ExprId count = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId countIsZero = il.CompareEqual(size, count, il.Const(size, 0)); + ExprId countNotZero = il.CompareNotEqual(size, count, il.Const(size, 0)); + + switch (flag) + { + case IL_FLAG_C: + { + if (!operands[1].constant) + { + ExprId carry = il.CompareNotEqual(size, + il.And(size, + il.LogicalShiftRight(size, left, il.Sub(size, il.Const(size, bitWidth), count)), + il.Const(size, 1)), + il.Const(size, 0)); + return boolChoice(countIsZero, countNotZero, il.Flag(flag), carry); + } + + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + uint64_t maskedCount = operands[1].value & countMask; + if (maskedCount == 0) + return il.Flag(flag); + if (maskedCount >= bitWidth) + return undefinedFlag(); + if (maskedCount == 1) + return il.CompareNotEqual(size, il.And(size, left, il.Const(size, signBit)), il.Const(size, 0)); + return il.CompareNotEqual(size, + il.And(size, + il.LogicalShiftRight(size, left, il.Const(size, bitWidth - maskedCount)), + il.Const(size, 1)), + il.Const(size, 0)); + } + case IL_FLAG_P: + { + ExprId lowByte = il.LowPart(1, maskedResult); + ExprId parity = il.And(1, il.PopulationCount(1, lowByte), il.Const(1, 1)); + ExprId computed = il.CompareEqual(1, parity, il.Const(1, 0)); + if (!operands[1].constant) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), computed); + return computed; + } + case IL_FLAG_Z: + { + ExprId computed = il.CompareEqual(size, maskedResult, il.Const(size, 0)); + if (!operands[1].constant) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), computed); + return computed; + } + case IL_FLAG_S: + { + ExprId computed = il.CompareNotEqual(size, il.And(size, maskedResult, il.Const(size, signBit)), il.Const(size, 0)); + if (!operands[1].constant) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), computed); + return computed; + } + case IL_FLAG_O: + { + if (!operands[1].constant) + { + ExprId countIsOne = il.CompareEqual(size, count, il.Const(size, 1)); + ExprId countGreaterThanOne = il.And(0, countNotZero, il.Not(0, countIsOne)); + ExprId computed = il.CompareNotEqual(size, + il.And(size, il.Xor(size, left, maskedResult), il.Const(size, signBit)), + il.Const(size, 0)); + return il.Or(0, + il.And(0, countIsZero, il.Flag(flag)), + il.Or(0, + il.And(0, countIsOne, computed), + il.And(0, countGreaterThanOne, undefinedFlag()))); + } + + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + uint64_t maskedCount = operands[1].value & countMask; + if (maskedCount == 0) + return il.Flag(flag); + if (maskedCount != 1) + return undefinedFlag(); + + return il.CompareNotEqual(size, + il.And(size, il.Xor(size, left, maskedResult), il.Const(size, signBit)), + il.Const(size, 0)); + } + case IL_FLAG_A: + if (!operands[1].constant) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), undefinedFlag()); + break; + default: + break; + } + } + break; + case LLIL_LSR: + case LLIL_ASR: + if (((flag == IL_FLAG_C) || (flag == IL_FLAG_O) || (flag == IL_FLAG_P) || (flag == IL_FLAG_A) || + (flag == IL_FLAG_Z) || (flag == IL_FLAG_S)) && + ((flagWriteType == IL_FLAGWRITE_ALL) || (flagWriteType == IL_FLAGWRITE_NOCARRY) || + (flagWriteType == IL_FLAGWRITE_CO) || (flagWriteType == IL_FLAGWRITE_C))) + { + if (operandCount < 2) + return undefinedFlag(); + + uint64_t countMask = (size == 8) ? 0x3f : 0x1f; + ExprId left = il.GetExprForRegisterOrConstant(operands[0], size); + ExprId count = il.GetExprForRegisterOrConstant(operands[1], size); + ExprId countIsZero = il.CompareEqual(size, count, il.Const(size, 0)); + ExprId countNotZero = il.CompareNotEqual(size, count, il.Const(size, 0)); + ExprId result = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + ExprId sign = il.And(size, left, il.Const(size, 1ULL << ((size * 8) - 1))); + if (operands[1].constant) + { + uint64_t effectiveCount = operands[1].value & countMask; + if (effectiveCount == 0) + return il.Flag(flag); + count = il.Const(size, effectiveCount); + if ((flag == IL_FLAG_O) && (effectiveCount != 1)) + return undefinedFlag(); + } + + if (flag == IL_FLAG_C) + { + ExprId carry = il.CompareNotEqual(size, + il.And(size, + il.LogicalShiftRight(size, left, il.Sub(size, count, il.Const(size, 1))), + il.Const(size, 1)), + il.Const(size, 0)); + if (!operands[1].constant) + return boolChoice(countIsZero, countNotZero, il.Flag(flag), carry); + return carry; + } + + switch (op) + { + case LLIL_LSR: + if (flag == IL_FLAG_O) + { + ExprId overflow = il.CompareNotEqual(size, sign, il.Const(size, 0)); + if (!operands[1].constant) + { + ExprId countIsOne = il.CompareEqual(size, count, il.Const(size, 1)); + ExprId countGreaterThanOne = il.And(0, countNotZero, il.Not(0, countIsOne)); + return il.Or(0, + il.And(0, countIsZero, il.Flag(flag)), + il.Or(0, + il.And(0, countIsOne, overflow), + il.And(0, countGreaterThanOne, undefinedFlag()))); + } + return overflow; + } + break; + case LLIL_ASR: + if (flag == IL_FLAG_O) + { + ExprId overflow = il.Const(0, 0); + if (!operands[1].constant) + { + ExprId countIsOne = il.CompareEqual(size, count, il.Const(size, 1)); + ExprId countGreaterThanOne = il.And(0, countNotZero, il.Not(0, countIsOne)); + return il.Or(0, + il.And(0, countIsZero, il.Flag(flag)), + il.Or(0, + il.And(0, countIsOne, overflow), + il.And(0, countGreaterThanOne, undefinedFlag()))); + } + return overflow; + } + break; + default: + break; + } + + if (!operands[1].constant) + { + switch (flag) + { + case IL_FLAG_P: + { + ExprId lowByte = il.LowPart(1, result); + ExprId parity = il.And(1, il.PopulationCount(1, lowByte), il.Const(1, 1)); + return boolChoice(countIsZero, countNotZero, il.Flag(flag), + il.CompareEqual(1, parity, il.Const(1, 0))); + } + case IL_FLAG_Z: + return boolChoice(countIsZero, countNotZero, il.Flag(flag), + il.CompareEqual(size, result, il.Const(size, 0))); + case IL_FLAG_S: + return boolChoice(countIsZero, countNotZero, il.Flag(flag), + il.CompareNotEqual(size, + il.And(size, result, il.Const(size, 1ULL << ((size * 8) - 1))), + il.Const(size, 0))); + case IL_FLAG_A: + return boolChoice(countIsZero, countNotZero, il.Flag(flag), undefinedFlag()); + default: + break; + } + } } break; case LLIL_MULU_DP: @@ -2136,6 +2671,19 @@ size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, s il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount), il.AddExpr(LLIL_CONST, 1, 0, size * 8)), il.AddExpr(LLIL_CONST, size * 2, 0, 0)); } + break; + case LLIL_MULS_DP: + switch (flag) + { + case IL_FLAG_C: + case IL_FLAG_O: + { + size_t fullSize = size * 2; + ExprId fullResult = il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount); + return il.CompareNotEqual(fullSize, fullResult, + il.SignExtend(fullSize, il.LowPart(size, fullResult))); + } + } default: break; } @@ -2153,6 +2701,52 @@ size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, s } } + if ((flag == IL_FLAG_A) && ((flagWriteType == IL_FLAGWRITE_ALL) || (flagWriteType == IL_FLAGWRITE_NOCARRY))) + { + switch (op) + { + case LLIL_ADD: + case LLIL_ADC: + case LLIL_SUB: + case LLIL_SBB: + if (operandCount < 2) + break; + return il.AddExpr(LLIL_CMP_NE, size, 0, + il.And(size, + il.Xor(size, + il.Xor(size, il.GetExprForRegisterOrConstant(operands[0], size), + il.GetExprForRegisterOrConstant(operands[1], size)), + il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount)), + il.Const(size, 0x10)), + il.Const(size, 0)); + case LLIL_NEG: + if (operandCount < 1) + break; + return il.AddExpr(LLIL_CMP_NE, size, 0, + il.And(size, + il.Xor(size, il.GetExprForRegisterOrConstant(operands[0], size), + il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount)), + il.Const(size, 0x10)), + il.Const(size, 0)); + default: + break; + } + + return undefinedFlag(); + } + if ((flag == IL_FLAG_A) && (flagWriteType == IL_FLAGWRITE_PAZS)) + return undefinedFlag(); + if ((flag == IL_FLAG_A) && (flagWriteType == IL_FLAGWRITE_SHRD1)) + return undefinedFlag(); + + if ((flag == IL_FLAG_P) && ((flagWriteType == IL_FLAGWRITE_ALL) || (flagWriteType == IL_FLAGWRITE_NOCARRY) || + (flagWriteType == IL_FLAGWRITE_PAZS) || (flagWriteType == IL_FLAGWRITE_SHRD1))) + { + ExprId lowByte = il.LowPart(1, il.GetExprForRegisterOrConstantOperation(op, size, operands, operandCount)); + ExprId parity = il.And(1, il.PopulationCount(1, lowByte), il.Const(1, 1)); + return il.AddExpr(LLIL_CMP_E, 1, 0, parity, il.Const(1, 0)); + } + // POPCNT sets ZF from the result and clears every other flag. ZF falls through to the default // (result == 0) handling below. if (flagWriteType == IL_FLAGWRITE_POPCNT && flag != IL_FLAG_Z) @@ -2333,6 +2927,16 @@ string X86CommonArchitecture::GetFlagWriteTypeName(uint32_t flags) return "popcnt"; case IL_FLAGWRITE_LZTZCNT: return "lztzcnt"; + case IL_FLAGWRITE_PAZS: + return "pazs"; + case IL_FLAGWRITE_C: + return "c"; + case IL_FLAGWRITE_SHRD1: + return "shrd1"; + case IL_FLAGWRITE_CUO: + return "cuo"; + case IL_FLAGWRITE_PTEST: + return "ptest"; default: return ""; } @@ -2359,7 +2963,8 @@ vector X86CommonArchitecture::GetAllFlagWriteTypes() { return vector {IL_FLAGWRITE_ALL, IL_FLAGWRITE_NOCARRY, IL_FLAGWRITE_CO, IL_FLAGWRITE_X87COM, IL_FLAGWRITE_X87COMI, IL_FLAGWRITE_X87C1Z, IL_FLAGWRITE_X87RND, - IL_FLAGWRITE_VCOMI, IL_FLAGWRITE_POPCNT, IL_FLAGWRITE_LZTZCNT}; + IL_FLAGWRITE_VCOMI, IL_FLAGWRITE_POPCNT, IL_FLAGWRITE_LZTZCNT, IL_FLAGWRITE_PAZS, + IL_FLAGWRITE_C, IL_FLAGWRITE_SHRD1, IL_FLAGWRITE_CUO, IL_FLAGWRITE_PTEST}; } BNFlagRole X86CommonArchitecture::GetFlagRole(uint32_t flag, uint32_t semClass) @@ -2577,6 +3182,16 @@ vector X86CommonArchitecture::GetFlagsWrittenByFlagWriteType(uint32_t return vector{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; case IL_FLAGWRITE_LZTZCNT: return vector{ IL_FLAG_C, IL_FLAG_Z }; + case IL_FLAGWRITE_PAZS: + return vector{ IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S }; + case IL_FLAGWRITE_C: + return vector{ IL_FLAG_C }; + case IL_FLAGWRITE_SHRD1: + return vector{ IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; + case IL_FLAGWRITE_CUO: + return vector{ IL_FLAG_C, IL_FLAG_O }; + case IL_FLAGWRITE_PTEST: + return vector{ IL_FLAG_C, IL_FLAG_P, IL_FLAG_A, IL_FLAG_Z, IL_FLAG_S, IL_FLAG_O }; default: return vector(); } diff --git a/arch/x86/il.cpp b/arch/x86/il.cpp index fbc8a6b59..f4a28e868 100644 --- a/arch/x86/il.cpp +++ b/arch/x86/il.cpp @@ -48,6 +48,34 @@ static xed_reg_enum_t GetCountRegister(const size_t addrSize) } } + +static uint64_t GetRotateCarryEffectiveCount(size_t opSize, uint64_t maskedCount) +{ + switch (opSize) + { + case 1: + return maskedCount % 9; + case 2: + return maskedCount % 17; + default: + return maskedCount; + } +} + + +static ExprId GetRotateCarryEffectiveCount(LowLevelILFunction& il, size_t opSize, size_t countSize, ExprId maskedCount) +{ + switch (opSize) + { + case 1: + return il.ModUnsigned(countSize, maskedCount, il.Const(countSize, 9)); + case 2: + return il.ModUnsigned(countSize, maskedCount, il.Const(countSize, 17)); + default: + return maskedCount; + } +} + //TODO handle imms for MPX args // For most instructions, instruction_index == operand_index, but some instructions (floating point, some others) have an implicit first operand (st0), so we have to remap things a bit // Instruction index represents the 'nth' argument/opcode in the instruction, whereas the operand index is index that XED holds that operand in the instruction @@ -595,7 +623,7 @@ static void AssignEvexDfv(const xed_decoded_inst_t* xedd, LowLevelILFunction& il il.Const(1, defaultFlagValues.s.cf))); il.AddInstruction( il.SetFlag(IL_FLAG_P, - il.Const(1, defaultFlagValues.s.cf))); + il.Const(1, 0))); il.AddInstruction( il.SetFlag(IL_FLAG_A, il.Const(1, 0))); @@ -1633,7 +1661,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev break; case XED_ICLASS_CCMPNL: - ConditionalCmp(addr, xedd, il, opOneLen, il.FlagCondition(LLFC_SLT)); + ConditionalCmp(addr, xedd, il, opOneLen, il.FlagCondition(LLFC_SGE)); break; case XED_ICLASS_CCMPLE: @@ -1929,20 +1957,25 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev case XED_ICLASS_ENTER: { - uint32_t baseReg = addrSize == 4 ? XED_REG_EBP : XED_REG_RBP; - uint32_t stackReg = addrSize == 4 ? XED_REG_ESP : XED_REG_RSP; - if (xed_decoded_inst_get_second_immediate(xedd) != 0) + uint32_t baseReg = GetFramePointer(addrSize); + uint32_t stackReg = GetStackPointer(addrSize); + uint64_t nestingLevel = xed_decoded_inst_get_second_immediate(xedd) & 0x1f; + il.AddInstruction(il.Push(addrSize, il.Register(addrSize, baseReg))); + il.AddInstruction(il.SetRegister(addrSize, LLIL_TEMP(0), il.Register(addrSize, stackReg))); + for (uint64_t i = 1; i < nestingLevel; i++) { - il.AddInstruction(il.Unimplemented()); - break; + il.AddInstruction(il.SetRegister(addrSize, baseReg, + il.Sub(addrSize, il.Register(addrSize, baseReg), il.Const(addrSize, addrSize)))); + il.AddInstruction(il.Push(addrSize, il.Load(addrSize, il.Register(addrSize, baseReg)))); } - il.AddInstruction(il.Push(addrSize, il.Register(addrSize, baseReg))); - il.AddInstruction(il.SetRegister(addrSize, baseReg, il.Register(addrSize, stackReg))); + if (nestingLevel != 0) + il.AddInstruction(il.Push(addrSize, il.Register(addrSize, LLIL_TEMP(0)))); + il.AddInstruction(il.SetRegister(addrSize, baseReg, il.Register(addrSize, LLIL_TEMP(0)))); if (immediateOne) il.AddInstruction(il.SetRegister(addrSize, stackReg, il.Sub(addrSize, il.Register(addrSize, stackReg), - il.Const(2, immediateOne)))); + il.Const(addrSize, immediateOne)))); break; } @@ -3305,6 +3338,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3317,18 +3351,71 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.RotateLeftCarry(opSize, left, right, - il.Flag(IL_FLAG_C), IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t maskedImmediateCount = immediateOne & countMask; + uint64_t effectiveImmediateCount = GetRotateCarryEffectiveCount(opSize, maskedImmediateCount); + ExprId maskedCount = immediateCount ? + il.Const(countSize, maskedImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + ExprId effectiveCount = immediateCount ? maskedCount : + GetRotateCarryEffectiveCount(il, opSize, countSize, maskedCount); + if (immediateCount) + effectiveCount = il.Const(countSize, effectiveImmediateCount); + if (immediateCount && effectiveImmediateCount == 0) + { + il.AddInstruction(il.Nop()); + break; + } + + il.AddInstruction(il.SetRegister(opSize, LLIL_TEMP(0), left)); + if (noFlags) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeftCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + il.Flag(IL_FLAG_C)))); + } + else if (immediateCount) + { + uint32_t flagWriteType = (maskedImmediateCount == 1) ? IL_FLAGWRITE_CO : IL_FLAGWRITE_CUO; + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeftCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + il.Flag(IL_FLAG_C), flagWriteType))); + } + else + { + LowLevelILLabel nonZeroCount, singleBitCount, multiBitCount, done; + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, effectiveCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(1), il.BoolToInt(1, il.Flag(IL_FLAG_C)))); + ExprId oldCarry = il.CompareNotEqual(1, il.Register(1, LLIL_TEMP(1)), il.Const(1, 0)); + il.AddInstruction(il.If( + il.CompareEqual(countSize, maskedCount, il.Const(countSize, 1)), singleBitCount, multiBitCount)); + il.MarkLabel(singleBitCount); + il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeftCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), il.Const(countSize, 1), + oldCarry, IL_FLAGWRITE_CO))); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(multiBitCount); + il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeftCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + oldCarry, IL_FLAGWRITE_CUO))); + il.MarkLabel(done); + } break; } case XED_ICLASS_RCR: { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3341,12 +3428,63 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.RotateRightCarry(opSize, left, right, - il.Flag(IL_FLAG_C), IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t maskedImmediateCount = immediateOne & countMask; + uint64_t effectiveImmediateCount = GetRotateCarryEffectiveCount(opSize, maskedImmediateCount); + ExprId maskedCount = immediateCount ? + il.Const(countSize, maskedImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + ExprId effectiveCount = immediateCount ? + il.Const(countSize, effectiveImmediateCount) : + GetRotateCarryEffectiveCount(il, opSize, countSize, maskedCount); + if (immediateCount && effectiveImmediateCount == 0) + { + il.AddInstruction(il.Nop()); + break; + } + il.AddInstruction(il.SetRegister(opSize, LLIL_TEMP(0), left)); + if (noFlags) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRightCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + il.Flag(IL_FLAG_C)))); + } + else + { + if (immediateCount) + { + uint32_t flagWriteType = (maskedImmediateCount == 1) ? IL_FLAGWRITE_CO : IL_FLAGWRITE_CUO; + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRightCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + il.Flag(IL_FLAG_C), flagWriteType))); + } + else + { + LowLevelILLabel nonZeroCount, singleBitCount, multiBitCount, done; + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, effectiveCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction(il.If( + il.CompareEqual(countSize, maskedCount, il.Const(countSize, 1)), singleBitCount, multiBitCount)); + il.MarkLabel(singleBitCount); + il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRightCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), il.Const(countSize, 1), + il.Flag(IL_FLAG_C), IL_FLAGWRITE_CO))); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(multiBitCount); + il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRightCarry(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + il.Flag(IL_FLAG_C), IL_FLAGWRITE_CUO))); + il.MarkLabel(done); + } + } break; } @@ -3371,6 +3509,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3383,18 +3522,52 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.RotateLeft(opSize, left, right, - noFlags ? 0 : IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t maskedImmediateCount = immediateOne & countMask; + ExprId maskedCount = immediateCount ? + il.Const(countSize, maskedImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + if (immediateCount && (maskedImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; + } + + if (immediateCount || (noFlags && + (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name)))) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeft(opSize, left, maskedCount, noFlags ? 0 : IL_FLAGWRITE_CO))); + } + else if (!noFlags && (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name))) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeft(opSize, left, maskedCount, IL_FLAGWRITE_CO))); + } + else + { + LowLevelILLabel nonZeroCount, done; + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, maskedCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, + il.RotateLeft(opSize, left, maskedCount, noFlags ? 0 : IL_FLAGWRITE_CO))); + il.MarkLabel(done); + } break; } case XED_ICLASS_ROR: { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3407,12 +3580,45 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.RotateRight(opSize, left, right, - noFlags ? 0 : IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t maskedImmediateCount = immediateOne & countMask; + ExprId maskedCount = immediateCount ? + il.Const(countSize, maskedImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + if (immediateCount && (maskedImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; + } + + if (immediateCount || (noFlags && + (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name)))) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRight(opSize, left, maskedCount, noFlags ? 0 : IL_FLAGWRITE_CO))); + } + else if (!noFlags && (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name))) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRight(opSize, left, maskedCount, IL_FLAGWRITE_CO))); + } + else + { + LowLevelILLabel nonZeroCount, done; + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, maskedCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, + il.RotateRight(opSize, left, maskedCount, noFlags ? 0 : IL_FLAGWRITE_CO))); + il.MarkLabel(done); + } break; } // there is no ROLX instruciton @@ -3429,6 +3635,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3441,12 +3648,53 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.ArithShiftRight(opSize, left, right, - noFlags ? 0 : IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t effectiveImmediateCount = immediateOne & countMask; + ExprId effectiveCount = immediateCount ? + il.Const(countSize, effectiveImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + if (immediateCount && (effectiveImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; + } + + if (noFlags) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ArithShiftRight(opSize, left, effectiveCount))); + } + else if (immediateCount) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ArithShiftRight(opSize, left, effectiveCount, IL_FLAGWRITE_ALL))); + } + else if (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name)) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ArithShiftRight(opSize, left, effectiveCount, IL_FLAGWRITE_ALL))); + } + else + { + LowLevelILLabel nonZeroCount, done; + il.AddInstruction(il.SetRegister(opSize, LLIL_TEMP(0), left)); + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, effectiveCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ArithShiftRight(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, + IL_FLAGWRITE_ALL))); + il.MarkLabel(done); + } break; } @@ -3649,6 +3897,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3661,21 +3910,62 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.ShiftLeft(opSize, left, right, - noFlags ? 0 : IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t effectiveImmediateCount = immediateOne & countMask; + ExprId effectiveCount = immediateCount ? + il.Const(countSize, effectiveImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + if (immediateCount && (effectiveImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; + } + + if (noFlags) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ShiftLeft(opSize, left, effectiveCount))); + } + else if (immediateCount) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ShiftLeft(opSize, left, effectiveCount, IL_FLAGWRITE_ALL))); + } + else if (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name)) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ShiftLeft(opSize, left, effectiveCount, IL_FLAGWRITE_ALL))); + } + else + { + LowLevelILLabel nonZeroCount, done; + il.AddInstruction(il.SetRegister(opSize, LLIL_TEMP(0), left)); + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, effectiveCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.ShiftLeft(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, IL_FLAGWRITE_ALL))); + il.MarkLabel(done); + } break; } // This is imprecise since it does NOT move the last shifted bit into CF - // the same problem also happens on SHL, SAR + // the same problem also happens on SAR case XED_ICLASS_SHR: { ExprId left, right; size_t opSize = opOneLen; + size_t countSize = opTwoLen; if (!newDataDestination) { // nothing special @@ -3688,12 +3978,52 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); opSize = opTwoLen; + countSize = opTreLen; } - il.AddInstruction( - WriteILOperand(il, xedd, addr, 0, 0, - il.LogicalShiftRight(opSize, left, right, - noFlags ? 0 : IL_FLAGWRITE_ALL))); + uint64_t countMask = (opSize == 8) ? 0x3f : 0x1f; + xed_operand_enum_t countOperand = newDataDestination ? opTre_name : opTwo_name; + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t effectiveImmediateCount = immediateOne & countMask; + ExprId effectiveCount = immediateCount ? + il.Const(countSize, effectiveImmediateCount) : + il.And(countSize, right, il.Const(countSize, countMask)); + if (immediateCount && (effectiveImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; + } + + if (noFlags) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.LogicalShiftRight(opSize, left, effectiveCount))); + } + else if (immediateCount) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.LogicalShiftRight(opSize, left, effectiveCount, IL_FLAGWRITE_ALL))); + } + else if (xed_operand_is_register(opOne_name) || xed_operand_is_memory_addressing_register(opOne_name)) + { + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.LogicalShiftRight(opSize, left, effectiveCount, IL_FLAGWRITE_ALL))); + } + else + { + LowLevelILLabel nonZeroCount, done; + il.AddInstruction(il.SetRegister(opSize, LLIL_TEMP(0), left)); + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, effectiveCount, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction( + WriteILOperand(il, xedd, addr, 0, 0, + il.LogicalShiftRight(opSize, il.Register(opSize, LLIL_TEMP(0)), effectiveCount, IL_FLAGWRITE_ALL))); + il.MarkLabel(done); + } break; } @@ -3719,84 +4049,136 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev { // TODO: Might need to swap for new data? size_t opSize = opOneLen; - size_t mask = opSize == 4 ? 31 : 63; + size_t countSize = opTreLen; + size_t mask = opSize == 8 ? 0x3f : 0x1f; // Shift left double: operand[0] = operand[0]:operand[1] << operand[3] // this since we can't easily operation on a combined register we do it like this // operand[0] = (operand[0] << operand[3]) | (operand[1] >> (63|32 - operand[3])) // One final caveat operand[3] must be masked with 63|32 - ExprId left, right, count; + ExprId left, right, rawCount; if (!newDataDestination) { // nothing special left = ReadILOperand(il, xedd, addr, 0, 0); right = ReadILOperand(il, xedd, addr, 1, 1); - - count = il.And(opSize, - il.Const(1, mask), - ReadILOperand(il, xedd, addr, 2, 2)); + rawCount = ReadILOperand(il, xedd, addr, 2, 2); } else { // new data destination left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); + countSize = xed_decoded_inst_operand_length_bits(xedd, 3) / 8; + rawCount = ReadILOperand(il, xedd, addr, 3, 3); + } - count = il.And(opSize, - il.Const(1, mask), - ReadILOperand(il, xedd, addr, 3, 3)); + xed_operand_enum_t countOperand = xed_operand_name(xed_inst_operand(xi, newDataDestination ? 3 : 2)); + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t effectiveImmediateCount = immediateOne & mask; + ExprId count = immediateCount ? + il.Const(countSize, effectiveImmediateCount) : + il.And(countSize, rawCount, il.Const(countSize, mask)); + if (immediateCount && (effectiveImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; } - il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, - il.Or(opSize, - il.ShiftLeft(opSize, left, count, - noFlags ? 0 : IL_FLAGWRITE_ALL), - il.LogicalShiftRight(opSize, - right, - il.Sub(opSize, count, il.Const(1, opSize * 8)))))); + auto liftShld = [&]() { + return WriteILOperand(il, xedd, addr, 0, 0, + il.Or(opSize, + il.ShiftLeft(opSize, left, count, noFlags ? 0 : IL_FLAGWRITE_CO), + il.LogicalShiftRight(opSize, + right, + il.Sub(countSize, il.Const(countSize, opSize * 8), count)), + noFlags ? 0 : IL_FLAGWRITE_PAZS)); + }; + + if (immediateCount) + il.AddInstruction(liftShld()); + else + { + LowLevelILLabel nonZeroCount, done; + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, count, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction(liftShld()); + il.MarkLabel(done); + } break; } case XED_ICLASS_SHRD: { // TODO: Might need to swap for new data? size_t opSize = opOneLen; - size_t mask = opSize == 4 ? 31 : 63; + size_t countSize = opTreLen; + size_t mask = opSize == 8 ? 0x3f : 0x1f; // Shift right double: operand[0] = operand[0]:operand[1] >> operand[3] // this since we can't easily operation on a combined register we do it like this // operand[0] = (operand[0] >> operand[3]) | (operand[1] << (63|31 - operand[3])) // One final caveat operand[3] must be masked with 63|31 - ExprId left, right, count; + ExprId left, right, rawCount; if (!newDataDestination) { // nothing special left = ReadILOperand(il, xedd, addr, 0, 0); right = ReadILOperand(il, xedd, addr, 1, 1); - - count = il.And(opSize, - il.Const(1, mask), - ReadILOperand(il, xedd, addr, 2, 2)); + rawCount = ReadILOperand(il, xedd, addr, 2, 2); } else { // new data destination left = ReadILOperand(il, xedd, addr, 1, 1); right = ReadILOperand(il, xedd, addr, 2, 2); + countSize = xed_decoded_inst_operand_length_bits(xedd, 3) / 8; + rawCount = ReadILOperand(il, xedd, addr, 3, 3); + } - count = il.And(opSize, - il.Const(1, mask), - ReadILOperand(il, xedd, addr, 3, 3)); + xed_operand_enum_t countOperand = xed_operand_name(xed_inst_operand(xi, newDataDestination ? 3 : 2)); + bool immediateCount = countOperand == XED_OPERAND_IMM0; + uint64_t effectiveImmediateCount = immediateOne & mask; + ExprId count = immediateCount ? + il.Const(countSize, effectiveImmediateCount) : + il.And(countSize, rawCount, il.Const(countSize, mask)); + if (immediateCount && (effectiveImmediateCount == 0)) + { + il.AddInstruction(il.Nop()); + break; } - il.AddInstruction(WriteILOperand(il, xedd, addr, 0, 0, - il.Or(opSize, - il.LogicalShiftRight(opSize, - left, - count, - noFlags ? 0 : IL_FLAGWRITE_ALL), - il.ShiftLeft(opSize, - right, - il.Sub(opSize, il.Const(1, opSize * 8), count))))); + auto liftShrd = [&](ExprId dest, ExprId shiftCount, uint32_t shiftFlagWrite, uint32_t resultFlagWrite) { + return WriteILOperand(il, xedd, addr, 0, 0, + il.Or(opSize, + il.LogicalShiftRight(opSize, dest, shiftCount, shiftFlagWrite), + il.ShiftLeft(opSize, right, il.Sub(countSize, il.Const(countSize, opSize * 8), shiftCount)), + resultFlagWrite)); + }; + + if (noFlags) + il.AddInstruction(liftShrd(left, count, 0, 0)); + else if (immediateCount) + { + uint32_t shiftFlagWrite = (effectiveImmediateCount == 1) ? IL_FLAGWRITE_C : IL_FLAGWRITE_CO; + uint32_t resultFlagWrite = (effectiveImmediateCount == 1) ? IL_FLAGWRITE_SHRD1 : IL_FLAGWRITE_PAZS; + il.AddInstruction(liftShrd(left, count, shiftFlagWrite, resultFlagWrite)); + } + else + { + LowLevelILLabel nonZeroCount, singleBitCount, multiBitCount, done; + il.AddInstruction(il.If( + il.CompareNotEqual(countSize, count, il.Const(countSize, 0)), nonZeroCount, done)); + il.MarkLabel(nonZeroCount); + il.AddInstruction(il.If( + il.CompareEqual(countSize, count, il.Const(countSize, 1)), singleBitCount, multiBitCount)); + il.MarkLabel(singleBitCount); + il.AddInstruction(liftShrd(left, il.Const(countSize, 1), IL_FLAGWRITE_C, IL_FLAGWRITE_SHRD1)); + il.AddInstruction(il.Goto(done)); + il.MarkLabel(multiBitCount); + il.AddInstruction(liftShrd(left, count, IL_FLAGWRITE_CO, IL_FLAGWRITE_PAZS)); + il.MarkLabel(done); + } break; } case XED_ICLASS_STOSB: @@ -3954,39 +4336,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev case XED_ICLASS_PTEST: case XED_ICLASS_VPTEST: il.AddInstruction( - il.SetFlag(IL_FLAG_Z, - il.BoolToInt( - 1, - il.CompareEqual( - opOneLen, - il.And( - opOneLen, - ReadILOperand(il, xedd, addr, 0, 0), - ReadILOperand(il, xedd, addr, 1, 1) - ), - il.Const(opOneLen, 0) - ) - ) - ) - ); - il.AddInstruction( - il.SetFlag(IL_FLAG_C, - il.BoolToInt( - 1, - il.CompareEqual( - opOneLen, - il.And( - opOneLen, - ReadILOperand(il, xedd, addr, 0, 0), - il.Not(opTwoLen, - ReadILOperand(il, xedd, addr, 1, 1) - ) - ), - il.Const(opOneLen, 0) - ) - ) - ) - ); + il.And(opOneLen, + ReadILOperand(il, xedd, addr, 0, 0), + ReadILOperand(il, xedd, addr, 1, 1), + IL_FLAGWRITE_PTEST)); break; case XED_ICLASS_CTESTO: @@ -4034,7 +4387,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, const uint64_t addr, LowLev break; case XED_ICLASS_CTESTNL: - ConditionalTest(addr, xedd, il, opOneLen, il.FlagCondition(LLFC_SLT)); + ConditionalTest(addr, xedd, il, opOneLen, il.FlagCondition(LLFC_SGE)); break; case XED_ICLASS_CTESTLE: diff --git a/arch/x86/il.h b/arch/x86/il.h index 3bdd07995..9b743692f 100644 --- a/arch/x86/il.h +++ b/arch/x86/il.h @@ -52,6 +52,11 @@ struct DISASSEMBLY_OPTIONS #define IL_FLAGWRITE_VCOMI 8 #define IL_FLAGWRITE_POPCNT 9 #define IL_FLAGWRITE_LZTZCNT 10 +#define IL_FLAGWRITE_PAZS 11 +#define IL_FLAGWRITE_C 12 +#define IL_FLAGWRITE_SHRD1 13 +#define IL_FLAGWRITE_CUO 14 +#define IL_FLAGWRITE_PTEST 15 #define IL_FLAG_CLASS_INT 0 // Default #define IL_FLAG_CLASS_X87COM 1