fix(code): decode setcc, evex, x87, of38/3a, shld/shrd + fix c1/of a4 immediate size bugs

This commit is contained in:
boykopovar 2026-08-05 10:49:02 +03:00
parent ab78ae90e2
commit c3e7b4c14a
2 changed files with 105 additions and 13 deletions

View File

@ -61,6 +61,8 @@ inline constexpr std::uint8_t OneByteModRmRangeJMin = 0x88;
inline constexpr std::uint8_t OneByteModRmRangeJMax = 0x8B;
inline constexpr std::uint8_t OneByteImulRm32Imm32 = 0x69;
inline constexpr std::uint8_t OneByteImulRm32Imm8 = 0x6B;
inline constexpr std::uint8_t OneByteX87Min = 0xD8;
inline constexpr std::uint8_t OneByteX87Max = 0xDF;
inline constexpr std::uint8_t OneByteImm8AluOrGrp3 = 0xC6;
inline constexpr std::uint8_t OneByteImm8AluCmp = 0x80;
@ -99,12 +101,15 @@ inline constexpr std::uint8_t OneByteJccRel8Max = 0x7F;
inline constexpr std::uint8_t OneByteCallRel32 = 0xE8;
inline constexpr std::uint8_t OneByteJmpRel32 = 0xE9;
inline constexpr std::uint8_t OneByteJmpRel8 = 0xEB;
inline constexpr std::uint8_t OneByteJrcxz = 0xE3;
inline constexpr std::uint8_t OneByteLoop = 0xE0;
inline constexpr std::uint8_t OneByteLoopMax = 0xE2;
inline constexpr std::uint8_t OneByteInOutImm8Min = 0xE4;
inline constexpr std::uint8_t OneByteInOutImm8Max = 0xE7;
inline constexpr std::uint8_t TwoByteJccRel32Min = 0x80;
inline constexpr std::uint8_t TwoByteJccRel32Max = 0x8F;
inline constexpr std::uint8_t TwoByteMovImm8ModRm = 0xBA;
inline constexpr std::uint8_t TwoByteStringOpMovs = 0xA4;
inline constexpr std::uint8_t TwoByteStringOpCmps = 0xAC;
inline constexpr std::uint8_t TwoByteCmovRangeMin = 0x40;
inline constexpr std::uint8_t TwoByteCmovRangeMax = 0x4F;
inline constexpr std::uint8_t TwoByteModRmRangeAMin = 0xA3;
@ -120,11 +125,46 @@ inline constexpr std::uint8_t TwoByteModRmRangeEMax = 0x2F;
inline constexpr std::uint8_t TwoByteModRmRangeFMin = 0x38;
inline constexpr std::uint8_t TwoByteModRmRangeFMax = 0x3A;
inline constexpr std::uint8_t TwoByteModRmRangeGMin = 0x54;
inline constexpr std::uint8_t TwoByteModRmRangeGMax = 0x77;
inline constexpr std::uint8_t TwoByteModRmRangeGMax = 0x7F;
inline constexpr std::uint8_t TwoByteModRmRangeHMin = 0xD0;
inline constexpr std::uint8_t TwoByteModRmRangeHMax = 0xFE;
inline constexpr std::uint8_t TwoByteNopModRm = 0x1F;
inline constexpr std::uint8_t TwoByteEndbr = 0x1E;
inline constexpr std::uint8_t TwoBytePrefetchGrpMin = 0x18;
inline constexpr std::uint8_t TwoBytePrefetchGrpMax = 0x1D;
inline constexpr std::uint8_t TwoByteSetccMin = 0x90;
inline constexpr std::uint8_t TwoByteSetccMax = 0x9F;
inline constexpr std::uint8_t TwoByteImulRmModRm = 0xAF;
inline constexpr std::uint8_t TwoByteMovdMovq = 0x7E;
inline constexpr std::uint8_t TwoByteMovqMmxXmm = 0x6F;
inline constexpr std::uint8_t TwoByteMovdqu = 0x7F;
inline constexpr std::uint8_t TwoByteGrp7 = 0x01;
inline constexpr std::uint8_t TwoByteShiftImm8Min = 0x70;
inline constexpr std::uint8_t TwoByteShiftImm8Max = 0x73;
inline constexpr std::uint8_t ThreeByteEscape38 = 0x38;
inline constexpr std::uint8_t ThreeByteEscape3A = 0x3A;
inline constexpr std::uint8_t TwoByteModRmRangeIMin = 0x50;
inline constexpr std::uint8_t TwoByteModRmRangeIMax = 0x53;
inline constexpr std::uint8_t TwoByteShldImm8 = 0xA4;
inline constexpr std::uint8_t TwoByteShldCl = 0xA5;
inline constexpr std::uint8_t TwoByteShrdImm8 = 0xAC;
inline constexpr std::uint8_t TwoByteShrdCl = 0xAD;
inline constexpr std::uint8_t TwoByteGrp15 = 0xAE;
inline constexpr std::uint8_t TwoByteXadd = 0xC1;
inline constexpr std::uint8_t TwoBytePextrw = 0xC5;
inline constexpr std::uint8_t TwoByteShufpsImm8 = 0xC2;
inline constexpr std::uint8_t TwoByteShufpdImm8 = 0xC6;
inline constexpr std::uint8_t TwoByteGrp9 = 0xC7;
inline constexpr std::uint8_t VexNoModRmMin = 0x77;
inline constexpr std::uint8_t VexNoModRmMax = 0x77;
inline constexpr std::uint8_t EvexPrefix = 0x62;
inline constexpr std::size_t EvexPrefixLength = 4;
inline constexpr std::uint8_t EvexMapMask = 0x03;
inline constexpr std::uint8_t EvexMap0F3A = 0x03;
inline constexpr std::uint8_t EvexMap0F38 = 0x02;
inline constexpr std::size_t ImmSizeNone = 0;
inline constexpr std::size_t ImmSize8 = 1;

View File

@ -50,7 +50,10 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
pos += 1;
bool twoByteOpcode = false;
bool vexPresent = false;
bool evexPresent = false;
std::uint8_t vexMap = 0;
std::uint8_t threeByteMap = 0;
bool threeByteEscape = false;
if (opcode == OneByteVex2) {
if (pos >= available) {
@ -70,6 +73,13 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
throw CodegenException("Instruction truncated after VEX3 prefix");
}
pos += 1;
} 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");
@ -77,9 +87,18 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
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) {
if (vexPresent || evexPresent) {
if (pos >= available) {
throw CodegenException("Instruction truncated after VEX prefix");
}
@ -91,8 +110,22 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
std::size_t immediateSize = ImmSizeNone;
if (vexPresent) {
if (vexMap == TwoByteOpcodeEscape && opcode >= VexNoModRmMin && opcode <= VexNoModRmMax) {
hasModRm = false;
} else {
hasModRm = true;
if (vexMap == Vex3Map0F3A) {
immediateSize = ImmSize8;
}
}
} else if (evexPresent) {
hasModRm = true;
if (vexMap == Vex3Map0F3A) {
if (vexMap == EvexMap0F3A) {
immediateSize = ImmSize8;
}
} else if (threeByteEscape) {
hasModRm = true;
if (threeByteMap == ThreeByteEscape3A) {
immediateSize = ImmSize8;
}
} else if (!twoByteOpcode) {
@ -115,7 +148,8 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
opcode == OneByteShiftRm8ByCl || opcode == OneByteShiftRmByCl ||
opcode == OneByteTestGrp3Rm8 || opcode == OneByteTestGrp3Rm ||
opcode == OneByteIncDecRm8 || opcode == OneByteGrp5Rm ||
(opcode >= OneByteModRmRangeJMin && opcode <= OneByteModRmRangeJMax)) {
(opcode >= OneByteModRmRangeJMin && opcode <= OneByteModRmRangeJMax) ||
(opcode >= OneByteX87Min && opcode <= OneByteX87Max)) {
hasModRm = true;
}
@ -124,6 +158,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
opcode == OneByteImm8AdcAl || opcode == OneByteImm8SbbAl ||
opcode == OneByteImm8AndAl || opcode == OneByteImm8SubAl ||
opcode == OneByteImm8XorAl || opcode == OneByteImm8CmpAl ||
opcode == OneByteGrp2Rm8Imm8 || opcode == OneByteGrp2RmImm8 ||
(opcode >= OneByteMovImm8RegMin && opcode <= OneByteMovImm8RegMax) ||
opcode == OneBytePushImm8 ||
opcode == OneByteTestAlImm8) {
@ -155,7 +190,9 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
immediateSize = ImmSize32;
}
if (opcode == OneByteJmpRel8) {
if (opcode == OneByteJmpRel8 || opcode == OneByteJrcxz ||
(opcode >= OneByteLoop && opcode <= OneByteLoopMax) ||
(opcode >= OneByteInOutImm8Min && opcode <= OneByteInOutImm8Max)) {
immediateSize = ImmSize8;
}
} else {
@ -164,17 +201,32 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
} else if (opcode == TwoByteMovImm8ModRm) {
hasModRm = true;
immediateSize = ImmSize8;
} else if (opcode == TwoByteStringOpMovs || opcode == TwoByteStringOpCmps) {
} else if (opcode >= TwoByteShiftImm8Min && opcode <= TwoByteShiftImm8Max) {
hasModRm = true;
immediateSize = ImmSize8;
} else if (opcode == TwoByteShldImm8 || opcode == TwoByteShrdImm8 ||
opcode == TwoByteShufpsImm8 || opcode == TwoByteShufpdImm8 ||
opcode == TwoBytePextrw) {
hasModRm = true;
immediateSize = ImmSize8;
} else if (opcode == TwoByteShldCl || opcode == TwoByteShrdCl) {
hasModRm = true;
} else if ((opcode >= TwoByteCmovRangeMin && opcode <= TwoByteCmovRangeMax) ||
(opcode >= TwoByteModRmRangeAMin && opcode <= TwoByteModRmRangeAMax) ||
(opcode >= TwoByteModRmRangeBMin && opcode <= TwoByteModRmRangeBMax) ||
(opcode >= TwoByteModRmRangeCMin && opcode <= TwoByteModRmRangeCMax) ||
(opcode >= TwoByteModRmRangeDMin && opcode <= TwoByteModRmRangeDMax) ||
(opcode >= TwoByteModRmRangeEMin && opcode <= TwoByteModRmRangeEMax) ||
(opcode >= TwoByteModRmRangeFMin && opcode <= TwoByteModRmRangeFMax) ||
(opcode >= TwoByteModRmRangeGMin && opcode <= TwoByteModRmRangeGMax) ||
(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;
}
@ -194,9 +246,9 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
const std::uint8_t modrm = data[pos];
pos += 1;
const std::uint8_t mod = static_cast<std::uint8_t>((modrm >> ModRmModShift) & ModRmModMask);
const std::uint8_t reg = static_cast<std::uint8_t>((modrm >> ModRmRegShift) & ModRmRegMask);
const std::uint8_t rm = static_cast<std::uint8_t>(modrm & ModRmRmMask);
const auto mod = 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 && !twoByteOpcode &&
(opcode == OneByteTestGrp3Rm8 || opcode == OneByteTestGrp3Rm) &&
@ -211,7 +263,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
throw CodegenException("Instruction truncated before SIB byte");
}
const std::uint8_t sib = data[pos];
const std::uint8_t base = static_cast<std::uint8_t>(sib & SibBaseMask);
const auto base = static_cast<std::uint8_t>(sib & SibBaseMask);
pos += 1;
if (mod == ModRmModIndirect && base == SibBaseDisp32) {