mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-23 17:13:13 -05:00
66 E8, 66 E9 and 66 0F 80-8F without REX.W take a 16-bit displacement on AMD processors, the console included. Every near relative branch with that prefix truncates its target to 16 bits, so the decoder reports no branch target for it and stubs refuse to move it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016TFMtUC4L4wMS4eeEqaNSR
600 lines
25 KiB
C++
600 lines
25 KiB
C++
#include <codegen/x86/X64InstructionDecoder.hpp>
|
|
#include <codegen/x86/X64OpcodeConstants.hpp>
|
|
#include <codegen/CodegenException.hpp>
|
|
#include <cstring>
|
|
|
|
namespace Codegen {
|
|
|
|
using namespace X64OpcodeConstants;
|
|
|
|
std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t available) const {
|
|
constexpr std::size_t maxInstructionLength = 15;
|
|
std::size_t pos = 0;
|
|
bool rexPresent = false;
|
|
std::uint8_t rex = 0;
|
|
bool operandSizeOverride = false;
|
|
bool addressSizeOverride = false;
|
|
bool repnePrefix = false;
|
|
|
|
while (pos < available) {
|
|
if (pos == maxInstructionLength) throw CodegenException("Instruction exceeds 15 bytes");
|
|
const std::uint8_t b = data[pos];
|
|
|
|
if (b >= RexMin && b <= RexMax) {
|
|
rexPresent = true;
|
|
rex = b;
|
|
pos += 1;
|
|
continue;
|
|
}
|
|
|
|
if (b == PrefixRepne) {
|
|
repnePrefix = true;
|
|
} else if (b == PrefixOperandSize) {
|
|
operandSizeOverride = true;
|
|
} else if (b == PrefixAddressSize) {
|
|
addressSizeOverride = true;
|
|
} else if (b != PrefixLock && b != PrefixRep &&
|
|
b != PrefixSegCs && b != PrefixSegSs && b != PrefixSegDs &&
|
|
b != PrefixSegEs && b != PrefixSegFs && b != PrefixSegGs) {
|
|
break;
|
|
}
|
|
|
|
rexPresent = false;
|
|
rex = 0;
|
|
pos += 1;
|
|
}
|
|
|
|
const bool rexW = rexPresent && (rex & RexWBit) != 0;
|
|
const std::size_t operandImmediateSize = operandSizeOverride && !rexW ? ImmSize16 : ImmSize32;
|
|
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after prefixes");
|
|
}
|
|
|
|
std::uint8_t opcode = data[pos];
|
|
pos += 1;
|
|
bool twoByteOpcode = false;
|
|
bool vexPresent = false;
|
|
bool evexPresent = false;
|
|
std::uint8_t vexMap = 0;
|
|
std::uint8_t xopMap = 0;
|
|
std::uint8_t threeByteMap = 0;
|
|
bool threeByteEscape = false;
|
|
|
|
if (opcode == OneByteVex2) {
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after VEX2 prefix");
|
|
}
|
|
vexPresent = true;
|
|
vexMap = 1;
|
|
pos += 1;
|
|
} else if (opcode == OneByteVex3) {
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after VEX3 prefix");
|
|
}
|
|
vexPresent = true;
|
|
vexMap = static_cast<std::uint8_t>(data[pos] & Vex3MapMask);
|
|
pos += 1;
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after VEX3 prefix");
|
|
}
|
|
pos += 1;
|
|
} else if (opcode == XopPrefix && pos < available && (data[pos] & Vex3MapMask) >= XopMapMin) {
|
|
if (pos + 1 >= available) {
|
|
throw CodegenException("Instruction truncated after XOP prefix");
|
|
}
|
|
xopMap = static_cast<std::uint8_t>(data[pos] & Vex3MapMask);
|
|
pos += 2;
|
|
} else if (opcode == EvexPrefix) {
|
|
if (pos + 2 >= available) {
|
|
throw CodegenException("Instruction truncated after EVEX prefix");
|
|
}
|
|
evexPresent = true;
|
|
vexMap = static_cast<std::uint8_t>(data[pos] & EvexMapMask);
|
|
pos += 3;
|
|
} else if (opcode == TwoByteOpcodeEscape) {
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after two-byte opcode escape");
|
|
}
|
|
twoByteOpcode = true;
|
|
opcode = data[pos];
|
|
pos += 1;
|
|
if (opcode == ThreeByteEscape38 || opcode == ThreeByteEscape3A) {
|
|
threeByteEscape = true;
|
|
threeByteMap = opcode;
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after three-byte opcode escape");
|
|
}
|
|
opcode = data[pos];
|
|
pos += 1;
|
|
}
|
|
}
|
|
|
|
if (vexPresent || evexPresent || xopMap != 0) {
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated after VEX prefix");
|
|
}
|
|
opcode = data[pos];
|
|
pos += 1;
|
|
}
|
|
|
|
bool hasModRm = false;
|
|
std::size_t immediateSize = ImmSizeNone;
|
|
|
|
const bool vectorImmediate = vexMap == 1 && ((opcode >= 0x70 && opcode <= 0x73) || opcode == 0xC2 || opcode == 0xC4 || opcode == 0xC5 || opcode == 0xC6);
|
|
|
|
if (xopMap != 0) {
|
|
hasModRm = true;
|
|
if (xopMap == XopMap8) {
|
|
immediateSize = ImmSize8;
|
|
} else if (xopMap == XopMapA) {
|
|
immediateSize = ImmSize32;
|
|
}
|
|
} else if (vexPresent) {
|
|
if (vexMap == 1 && opcode >= VexNoModRmMin && opcode <= VexNoModRmMax) {
|
|
hasModRm = false;
|
|
} else {
|
|
hasModRm = true;
|
|
if (vexMap == Vex3Map0F3A || vectorImmediate) {
|
|
immediateSize = ImmSize8;
|
|
}
|
|
}
|
|
} else if (evexPresent) {
|
|
hasModRm = true;
|
|
if (vexMap == EvexMap0F3A || vectorImmediate) {
|
|
immediateSize = ImmSize8;
|
|
}
|
|
} else if (threeByteEscape) {
|
|
hasModRm = true;
|
|
if (threeByteMap == ThreeByteEscape3A) {
|
|
immediateSize = ImmSize8;
|
|
}
|
|
} else if (!twoByteOpcode) {
|
|
if ((opcode >= OneByteModRmRangeAMin && opcode <= OneByteModRmRangeAMax) ||
|
|
(opcode >= OneByteModRmRangeBMin && opcode <= OneByteModRmRangeBMax) ||
|
|
(opcode >= OneByteModRmRangeCMin && opcode <= OneByteModRmRangeCMax) ||
|
|
(opcode >= OneByteModRmRangeDMin && opcode <= OneByteModRmRangeDMax) ||
|
|
(opcode >= OneByteModRmRangeEMin && opcode <= OneByteModRmRangeEMax) ||
|
|
(opcode >= OneByteModRmRangeFMin && opcode <= OneByteModRmRangeFMax) ||
|
|
(opcode >= OneByteModRmRangeGMin && opcode <= OneByteModRmRangeGMax) ||
|
|
(opcode >= OneByteModRmRangeHMin && opcode <= OneByteModRmRangeHMax) ||
|
|
opcode == OneByteArpl || opcode == OneByteMovsxd ||
|
|
(opcode >= OneByteModRmRangeIMin && opcode <= OneByteModRmRangeIMax) ||
|
|
opcode == OneByteGrp2Rm8Imm8 || opcode == OneByteGrp2RmImm8 ||
|
|
opcode == OneByteMovImm8 || opcode == OneByteMovImm32 ||
|
|
opcode == OneByteImm32AluCmp || opcode == OneByteImm8Grp1 ||
|
|
opcode == OneByteImm8AluCmp ||
|
|
opcode == OneByteImulRm32Imm32 || opcode == OneByteImulRm32Imm8 ||
|
|
opcode == OneByteShiftRm8By1 || opcode == OneByteShiftRmBy1 ||
|
|
opcode == OneByteShiftRm8ByCl || opcode == OneByteShiftRmByCl ||
|
|
opcode == OneByteTestGrp3Rm8 || opcode == OneByteTestGrp3Rm ||
|
|
opcode == OneByteIncDecRm8 || opcode == OneByteGrp5Rm ||
|
|
(opcode >= OneByteModRmRangeJMin && opcode <= OneByteModRmRangeJMax) ||
|
|
(opcode >= OneByteX87Min && opcode <= OneByteX87Max)) {
|
|
hasModRm = true;
|
|
}
|
|
|
|
if (opcode == OneByteImm8AluOrGrp3 || opcode == OneByteImm8AluCmp ||
|
|
opcode == OneByteImm8AddAl || opcode == OneByteImm8OrAl ||
|
|
opcode == OneByteImm8AdcAl || opcode == OneByteImm8SbbAl ||
|
|
opcode == OneByteImm8AndAl || opcode == OneByteImm8SubAl ||
|
|
opcode == OneByteImm8XorAl || opcode == OneByteImm8CmpAl ||
|
|
opcode == OneByteGrp2Rm8Imm8 || opcode == OneByteGrp2RmImm8 ||
|
|
(opcode >= OneByteMovImm8RegMin && opcode <= OneByteMovImm8RegMax) ||
|
|
opcode == OneBytePushImm8 ||
|
|
opcode == OneByteTestAlImm8) {
|
|
immediateSize = ImmSize8;
|
|
} else if (opcode == OneByteImm32AluCmp || opcode == OneByteMovImm32 ||
|
|
opcode == OneByteImulRm32Imm32 ||
|
|
opcode == OneByteImm32AddEax || opcode == OneByteImm32OrEax ||
|
|
opcode == OneByteImm32AdcEax || opcode == OneByteImm32SbbEax ||
|
|
opcode == OneByteImm32AndEax || opcode == OneByteImm32SubEax ||
|
|
opcode == OneByteImm32XorEax || opcode == OneByteImm32CmpEax ||
|
|
opcode == OneBytePushImm32 ||
|
|
opcode == OneByteTestEaxImm32 ||
|
|
(opcode >= OneByteMovImm32RegMin && opcode <= OneByteMovImm32RegMax)) {
|
|
if (opcode >= OneByteMovImm32RegMin && opcode <= OneByteMovImm32RegMax) {
|
|
immediateSize = rexW ? ImmSize64 : operandImmediateSize;
|
|
} else {
|
|
immediateSize = operandImmediateSize;
|
|
}
|
|
} else if (opcode == OneByteImm8Grp1 || opcode == OneByteImulRm32Imm8) {
|
|
immediateSize = ImmSize8;
|
|
}
|
|
|
|
if (opcode >= OneByteJccRel8Min && opcode <= OneByteJccRel8Max) {
|
|
immediateSize = ImmSize8;
|
|
}
|
|
|
|
if (opcode == OneByteCallRel32 || opcode == OneByteJmpRel32) {
|
|
immediateSize = operandImmediateSize;
|
|
}
|
|
|
|
if (opcode == OneByteJmpRel8 || opcode == OneByteJrcxz ||
|
|
(opcode >= OneByteLoop && opcode <= OneByteLoopMax) ||
|
|
(opcode >= OneByteInOutImm8Min && opcode <= OneByteInOutImm8Max) ||
|
|
opcode == OneByteInt) {
|
|
immediateSize = ImmSize8;
|
|
}
|
|
|
|
if (opcode == OneByteRetImm16 || opcode == OneByteRetFarImm16) {
|
|
immediateSize = ImmSize16;
|
|
}
|
|
|
|
if (opcode == OneByteEnter) {
|
|
immediateSize = ImmSizeEnter;
|
|
}
|
|
|
|
if (opcode >= OneByteMovMoffsMin && opcode <= OneByteMovMoffsMax) {
|
|
immediateSize = addressSizeOverride ? ImmSize32 : ImmSize64;
|
|
}
|
|
} else {
|
|
if (opcode == TwoByteExtrqInsertqImm8Imm8) {
|
|
if (!operandSizeOverride && !repnePrefix) {
|
|
throw CodegenException("Unsupported 0F 78 opcode without SSE4A prefix");
|
|
}
|
|
hasModRm = true;
|
|
immediateSize = ImmSize16;
|
|
} else if (opcode == TwoByteExtrqInsertqModRm) {
|
|
if (!operandSizeOverride && !repnePrefix) {
|
|
throw CodegenException("Unsupported 0F 79 opcode without SSE4A prefix");
|
|
}
|
|
hasModRm = true;
|
|
} else if (opcode >= TwoByteJccRel32Min && opcode <= TwoByteJccRel32Max) {
|
|
immediateSize = operandImmediateSize;
|
|
} else if (opcode == TwoByteMovImm8ModRm || opcode == TwoByte3DNow) {
|
|
hasModRm = true;
|
|
immediateSize = ImmSize8;
|
|
} else if (opcode >= TwoByteShiftImm8Min && opcode <= TwoByteShiftImm8Max) {
|
|
hasModRm = true;
|
|
immediateSize = ImmSize8;
|
|
} else if (opcode == TwoByteShldImm8 || opcode == TwoByteShrdImm8 ||
|
|
opcode == TwoByteShufpsImm8 || opcode == TwoByteShufpdImm8 ||
|
|
opcode == TwoBytePextrw || opcode == TwoBytePinsrw) {
|
|
hasModRm = true;
|
|
immediateSize = ImmSize8;
|
|
} else if (opcode == TwoByteShldCl || opcode == TwoByteShrdCl ||
|
|
opcode == TwoBytePopcnt || opcode == TwoByteUd1 || opcode == TwoByteBtc ||
|
|
opcode == TwoBytePrefetchw || opcode == TwoByteXaddRm8 ||
|
|
opcode == TwoByteMovnti || opcode == TwoByteGrp6 ||
|
|
opcode == TwoByteLar || opcode == TwoByteLsl ||
|
|
(opcode >= TwoByteMovCrDrMin && opcode <= TwoByteMovCrDrMax)) {
|
|
hasModRm = true;
|
|
} else if ((opcode >= TwoByteCmovRangeMin && opcode <= TwoByteCmovRangeMax) ||
|
|
(opcode >= TwoByteModRmRangeAMin && opcode <= TwoByteModRmRangeAMax) ||
|
|
opcode == TwoByteBts ||
|
|
(opcode >= TwoByteModRmRangeBMin && opcode <= TwoByteModRmRangeBMax) ||
|
|
(opcode >= TwoByteModRmRangeCMin && opcode <= TwoByteModRmRangeCMax) ||
|
|
(opcode >= TwoByteModRmRangeDMin && opcode <= TwoByteModRmRangeDMax) ||
|
|
(opcode >= TwoByteModRmRangeEMin && opcode <= TwoByteModRmRangeEMax) ||
|
|
(opcode >= TwoByteModRmRangeGMin && opcode <= TwoByteModRmRangeGMax && opcode != TwoByteEmms) ||
|
|
(opcode >= TwoByteModRmRangeHMin && opcode <= TwoByteModRmRangeHMax) ||
|
|
(opcode >= TwoByteModRmRangeIMin && opcode <= TwoByteModRmRangeIMax) ||
|
|
(opcode >= TwoBytePrefetchGrpMin && opcode <= TwoBytePrefetchGrpMax) ||
|
|
(opcode >= TwoByteSetccMin && opcode <= TwoByteSetccMax) ||
|
|
opcode == TwoByteImulRmModRm ||
|
|
opcode == TwoByteGrp7 ||
|
|
opcode == TwoByteGrp15 ||
|
|
opcode == TwoByteXadd ||
|
|
opcode == TwoByteGrp9 ||
|
|
opcode == TwoByteNopModRm || opcode == TwoByteEndbr) {
|
|
hasModRm = true;
|
|
}
|
|
}
|
|
|
|
if (!hasModRm) {
|
|
if (pos + immediateSize > maxInstructionLength) throw CodegenException("Instruction exceeds 15 bytes");
|
|
if (pos + immediateSize > available) {
|
|
throw CodegenException("Instruction truncated in immediate operand");
|
|
}
|
|
return pos + immediateSize;
|
|
}
|
|
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated before ModRM byte");
|
|
}
|
|
|
|
const std::uint8_t modrm = data[pos];
|
|
pos += 1;
|
|
|
|
const bool registerOnlyModRm = twoByteOpcode && !threeByteEscape && opcode >= TwoByteMovCrDrMin && opcode <= TwoByteMovCrDrMax;
|
|
const auto mod = registerOnlyModRm ? ModRmModRegister : static_cast<std::uint8_t>((modrm >> ModRmModShift) & ModRmModMask);
|
|
const auto reg = static_cast<std::uint8_t>((modrm >> ModRmRegShift) & ModRmRegMask);
|
|
const auto rm = static_cast<std::uint8_t>(modrm & ModRmRmMask);
|
|
|
|
if (!vexPresent && !evexPresent && !twoByteOpcode &&
|
|
(opcode == OneByteTestGrp3Rm8 || opcode == OneByteTestGrp3Rm) &&
|
|
reg <= Grp3RegTestMax) {
|
|
immediateSize = (opcode == OneByteTestGrp3Rm8)
|
|
? ImmSize8
|
|
: operandImmediateSize;
|
|
}
|
|
|
|
if (mod != ModRmModRegister && rm == ModRmRmSibPresent) {
|
|
if (pos >= available) {
|
|
throw CodegenException("Instruction truncated before SIB byte");
|
|
}
|
|
const std::uint8_t sib = data[pos];
|
|
const auto base = static_cast<std::uint8_t>(sib & SibBaseMask);
|
|
pos += 1;
|
|
|
|
if (mod == ModRmModIndirect && base == SibBaseDisp32) {
|
|
pos += Disp32Size;
|
|
}
|
|
}
|
|
|
|
if (mod == ModRmModDisp8) {
|
|
pos += Disp8Size;
|
|
} else if (mod == ModRmModDisp32) {
|
|
pos += Disp32Size;
|
|
} else if (mod == ModRmModIndirect && rm == ModRmRmRipRelative) {
|
|
pos += Disp32Size;
|
|
}
|
|
|
|
pos += immediateSize;
|
|
|
|
if (pos > maxInstructionLength) throw CodegenException("Instruction exceeds 15 bytes");
|
|
if (pos > available) {
|
|
throw CodegenException("Instruction truncated in displacement or immediate operand");
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
}
|
|
|
|
namespace Codegen {
|
|
|
|
DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction(
|
|
const std::uint8_t* data,
|
|
std::size_t available
|
|
) const {
|
|
using namespace X64OpcodeConstants;
|
|
|
|
DecodedInstructionInfo info{};
|
|
info.Length = Decode(data, available);
|
|
|
|
std::size_t pos = 0;
|
|
bool operandSizeOverride = false;
|
|
|
|
while (pos < info.Length) {
|
|
std::uint8_t b = data[pos];
|
|
if (b >= RexMin && b <= RexMax) {
|
|
info.RexPrefix = b;
|
|
++pos;
|
|
continue;
|
|
}
|
|
if (b == PrefixLock || b == PrefixRepne || b == PrefixRep ||
|
|
b == PrefixSegCs || b == PrefixSegSs || b == PrefixSegDs ||
|
|
b == PrefixSegEs || b == PrefixSegFs || b == PrefixSegGs ||
|
|
b == PrefixOperandSize || b == PrefixAddressSize) {
|
|
if (b >= PrefixSegFs && b <= PrefixSegGs)
|
|
info.SegmentPrefix = b;
|
|
if (b == PrefixAddressSize)
|
|
info.AddressSize32 = true;
|
|
if (b == PrefixOperandSize)
|
|
operandSizeOverride = true;
|
|
info.RexPrefix = 0;
|
|
++pos;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
info.OpcodeOffset = pos;
|
|
|
|
if (pos >= info.Length)
|
|
return info;
|
|
|
|
const auto readModRm = [&](const std::size_t modrmPos, const bool registerOnly) {
|
|
const std::uint8_t modrm = data[modrmPos];
|
|
info.HasModRm = true;
|
|
info.ModRmByte = modrm;
|
|
info.ModRmRegField = (modrm >> ModRmRegShift) & ModRmRegMask;
|
|
const std::uint8_t mod = registerOnly ? ModRmModRegister : (modrm >> ModRmModShift) & ModRmModMask;
|
|
const std::uint8_t rm = modrm & ModRmRmMask;
|
|
if (mod == ModRmModIndirect && rm == ModRmRmRipRelative) {
|
|
info.HasRipRelativeDisp = true;
|
|
info.RipRelativeDispOffset = modrmPos + 1;
|
|
}
|
|
};
|
|
|
|
std::uint8_t op = data[pos++];
|
|
bool twoByteOpcode = false;
|
|
|
|
const bool xop = op == XopPrefix && pos < info.Length && (data[pos] & Vex3MapMask) >= XopMapMin;
|
|
if (op == OneByteVex2 || op == OneByteVex3 || op == EvexPrefix || xop) {
|
|
pos += (op == OneByteVex2 ? 1 : (op == OneByteVex3 || xop ? 2 : EvexPrefixLength - 1)) + 1;
|
|
if (pos < info.Length)
|
|
readModRm(pos, false);
|
|
info.FlowKind = ControlFlowKind::Sequential;
|
|
return info;
|
|
}
|
|
if (op == TwoByteOpcodeEscape && pos < info.Length) {
|
|
twoByteOpcode = true;
|
|
op = data[pos++];
|
|
if (op == ThreeByteEscape38 || op == ThreeByteEscape3A)
|
|
++pos;
|
|
}
|
|
|
|
info.Opcode = op;
|
|
info.IsTwoByteOpcode = twoByteOpcode;
|
|
|
|
const bool relativeNearBranch = twoByteOpcode
|
|
? op >= TwoByteJccRel32Min && op <= TwoByteJccRel32Max
|
|
: op == OneByteCallRel32 || op == OneByteJmpRel32 || op == OneByteJmpRel8 ||
|
|
(op >= OneByteJccRel8Min && op <= OneByteJccRel8Max) ||
|
|
op == OneByteJrcxz || (op >= OneByteLoop && op <= OneByteLoopMax);
|
|
if (relativeNearBranch && operandSizeOverride && (info.RexPrefix & RexWBit) == 0) {
|
|
info.TruncatesBranchTarget = true;
|
|
info.FlowKind = twoByteOpcode || (op != OneByteCallRel32 && op != OneByteJmpRel32 && op != OneByteJmpRel8)
|
|
? ControlFlowKind::ConditionalBranch
|
|
: op == OneByteCallRel32 ? ControlFlowKind::Call : ControlFlowKind::UnconditionalJump;
|
|
return info;
|
|
}
|
|
|
|
if (!twoByteOpcode) {
|
|
if (op == OneByteCallRel32) {
|
|
std::int32_t disp = 0;
|
|
std::memcpy(&disp, data + pos, 4);
|
|
info.FlowKind = ControlFlowKind::Call;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = disp;
|
|
return info;
|
|
}
|
|
if (op == OneByteJmpRel32) {
|
|
std::int32_t disp = 0;
|
|
std::memcpy(&disp, data + pos, 4);
|
|
info.FlowKind = ControlFlowKind::UnconditionalJump;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = disp;
|
|
return info;
|
|
}
|
|
if (op == OneByteJmpRel8) {
|
|
info.FlowKind = ControlFlowKind::UnconditionalJump;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = static_cast<std::int8_t>(data[pos]);
|
|
return info;
|
|
}
|
|
if (op >= OneByteJccRel8Min && op <= OneByteJccRel8Max) {
|
|
info.FlowKind = ControlFlowKind::ConditionalBranch;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = static_cast<std::int8_t>(data[pos]);
|
|
return info;
|
|
}
|
|
if (op == OneByteJrcxz || (op >= OneByteLoop && op <= OneByteLoopMax)) {
|
|
info.FlowKind = ControlFlowKind::ConditionalBranch;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = static_cast<std::int8_t>(data[pos]);
|
|
return info;
|
|
}
|
|
if (op == 0xC3 || op == 0xCB || op == 0xC2 || op == 0xCA) {
|
|
info.FlowKind = ControlFlowKind::Return;
|
|
return info;
|
|
}
|
|
if (op == OneByteGrp5Rm && pos < info.Length) {
|
|
std::uint8_t modrm = data[pos];
|
|
info.HasModRm = true;
|
|
info.ModRmByte = modrm;
|
|
std::uint8_t reg = (modrm >> ModRmRegShift) & ModRmRegMask;
|
|
info.ModRmRegField = reg;
|
|
std::uint8_t mod = (modrm >> ModRmModShift) & ModRmModMask;
|
|
std::uint8_t rm = modrm & ModRmRmMask;
|
|
if (reg == 2) {
|
|
if (mod == ModRmModIndirect && rm == ModRmRmRipRelative) {
|
|
info.FlowKind = ControlFlowKind::Call;
|
|
info.HasRipRelativeDisp = true;
|
|
info.RipRelativeDispOffset = pos + 1;
|
|
} else {
|
|
info.FlowKind = ControlFlowKind::IndirectCall;
|
|
}
|
|
return info;
|
|
}
|
|
if (reg == 4) {
|
|
if (mod == ModRmModIndirect && rm == ModRmRmRipRelative) {
|
|
std::int32_t disp = 0;
|
|
std::memcpy(&disp, data + pos + 1, 4);
|
|
info.FlowKind = ControlFlowKind::UnconditionalJump;
|
|
info.HasRipRelativeDisp = true;
|
|
info.RipRelativeDispOffset = pos + 1;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = disp;
|
|
} else {
|
|
info.FlowKind = ControlFlowKind::IndirectJump;
|
|
}
|
|
return info;
|
|
}
|
|
if (reg == 3 || reg == 5) {
|
|
if (mod == ModRmModIndirect && rm == ModRmRmRipRelative) {
|
|
info.HasRipRelativeDisp = true;
|
|
info.RipRelativeDispOffset = pos + 1;
|
|
}
|
|
info.FlowKind = reg == 3 ? ControlFlowKind::IndirectCall : ControlFlowKind::IndirectJump;
|
|
return info;
|
|
}
|
|
}
|
|
} else {
|
|
if (op == 0x0B) {
|
|
info.FlowKind = ControlFlowKind::Trap;
|
|
return info;
|
|
}
|
|
if (op == TwoByteUd1) {
|
|
if (pos < info.Length)
|
|
readModRm(pos, false);
|
|
info.FlowKind = ControlFlowKind::Trap;
|
|
return info;
|
|
}
|
|
if (op >= TwoByteJccRel32Min && op <= TwoByteJccRel32Max) {
|
|
std::int32_t disp = 0;
|
|
std::memcpy(&disp, data + pos, 4);
|
|
info.FlowKind = ControlFlowKind::ConditionalBranch;
|
|
info.HasBranchTarget = true;
|
|
info.BranchDisp = disp;
|
|
return info;
|
|
}
|
|
}
|
|
|
|
bool hasModRm = false;
|
|
if (!twoByteOpcode) {
|
|
if ((op >= OneByteModRmRangeAMin && op <= OneByteModRmRangeAMax) ||
|
|
(op >= OneByteModRmRangeBMin && op <= OneByteModRmRangeBMax) ||
|
|
(op >= OneByteModRmRangeCMin && op <= OneByteModRmRangeCMax) ||
|
|
(op >= OneByteModRmRangeDMin && op <= OneByteModRmRangeDMax) ||
|
|
(op >= OneByteModRmRangeEMin && op <= OneByteModRmRangeEMax) ||
|
|
(op >= OneByteModRmRangeFMin && op <= OneByteModRmRangeFMax) ||
|
|
(op >= OneByteModRmRangeGMin && op <= OneByteModRmRangeGMax) ||
|
|
(op >= OneByteModRmRangeHMin && op <= OneByteModRmRangeHMax) ||
|
|
(op >= OneByteModRmRangeIMin && op <= OneByteModRmRangeIMax) ||
|
|
(op >= OneByteModRmRangeJMin && op <= OneByteModRmRangeJMax) ||
|
|
op == OneByteArpl || op == OneByteMovsxd ||
|
|
op == OneByteGrp2Rm8Imm8 || op == OneByteGrp2RmImm8 ||
|
|
op == OneByteMovImm8 || op == OneByteMovImm32 ||
|
|
op == OneByteImm32AluCmp || op == OneByteImm8Grp1 ||
|
|
op == OneByteImm8AluCmp ||
|
|
op == OneByteImulRm32Imm32 || op == OneByteImulRm32Imm8 ||
|
|
op == OneByteShiftRm8By1 || op == OneByteShiftRmBy1 ||
|
|
op == OneByteShiftRm8ByCl || op == OneByteShiftRmByCl ||
|
|
op == OneByteTestGrp3Rm8 || op == OneByteTestGrp3Rm ||
|
|
op == OneByteIncDecRm8 || op == OneByteGrp5Rm ||
|
|
(op >= OneByteX87Min && op <= OneByteX87Max))
|
|
hasModRm = true;
|
|
} else {
|
|
if ((op >= TwoByteCmovRangeMin && op <= TwoByteCmovRangeMax) ||
|
|
(op >= TwoByteModRmRangeAMin && op <= TwoByteModRmRangeAMax) ||
|
|
op == TwoByteBts ||
|
|
(op >= TwoByteModRmRangeBMin && op <= TwoByteModRmRangeBMax) ||
|
|
(op >= TwoByteModRmRangeCMin && op <= TwoByteModRmRangeCMax) ||
|
|
(op >= TwoByteModRmRangeDMin && op <= TwoByteModRmRangeDMax) ||
|
|
(op >= TwoByteModRmRangeEMin && op <= TwoByteModRmRangeEMax) ||
|
|
(op >= TwoByteModRmRangeGMin && op <= TwoByteModRmRangeGMax) ||
|
|
(op >= TwoByteModRmRangeHMin && op <= TwoByteModRmRangeHMax) ||
|
|
(op >= TwoByteModRmRangeIMin && op <= TwoByteModRmRangeIMax) ||
|
|
(op >= TwoBytePrefetchGrpMin && op <= TwoBytePrefetchGrpMax) ||
|
|
(op >= TwoByteSetccMin && op <= TwoByteSetccMax) ||
|
|
op == TwoByteImulRmModRm || op == TwoByteGrp7 ||
|
|
op == TwoByteGrp15 || op == TwoByteXadd ||
|
|
op == TwoByteGrp9 || op == TwoByteNopModRm ||
|
|
op == TwoByteEndbr || op == TwoByteMovImm8ModRm || op == TwoByte3DNow ||
|
|
op == ThreeByteEscape38 || op == ThreeByteEscape3A ||
|
|
(op >= TwoByteShiftImm8Min && op <= TwoByteShiftImm8Max) ||
|
|
op == TwoByteShldImm8 || op == TwoByteShrdImm8 ||
|
|
op == TwoByteShufpsImm8 || op == TwoByteShufpdImm8 ||
|
|
op == TwoBytePextrw || op == TwoBytePinsrw ||
|
|
op == TwoByteShldCl || op == TwoByteShrdCl ||
|
|
op == TwoBytePopcnt || op == TwoByteUd1 || op == TwoByteBtc ||
|
|
op == TwoBytePrefetchw || op == TwoByteXaddRm8 ||
|
|
op == TwoByteMovnti || op == TwoByteGrp6 ||
|
|
op == TwoByteLar || op == TwoByteLsl ||
|
|
(op >= TwoByteMovCrDrMin && op <= TwoByteMovCrDrMax))
|
|
hasModRm = true;
|
|
}
|
|
|
|
if (hasModRm && pos < info.Length)
|
|
readModRm(pos, twoByteOpcode && op >= TwoByteMovCrDrMin && op <= TwoByteMovCrDrMax);
|
|
|
|
info.FlowKind = ControlFlowKind::Sequential;
|
|
return info;
|
|
}
|
|
|
|
}
|