diff --git a/core/codegen/include/codegen/x86/X64OpcodeConstants.hpp b/core/codegen/include/codegen/x86/X64OpcodeConstants.hpp index 32d18863e..c88ef7cf9 100644 --- a/core/codegen/include/codegen/x86/X64OpcodeConstants.hpp +++ b/core/codegen/include/codegen/x86/X64OpcodeConstants.hpp @@ -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; diff --git a/core/codegen/src/x86/X64InstructionDecoder.cpp b/core/codegen/src/x86/X64InstructionDecoder.cpp index 648d22c76..270513870 100644 --- a/core/codegen/src/x86/X64InstructionDecoder.cpp +++ b/core/codegen/src/x86/X64InstructionDecoder.cpp @@ -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(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((modrm >> ModRmModShift) & ModRmModMask); - const std::uint8_t reg = static_cast((modrm >> ModRmRegShift) & ModRmRegMask); - const std::uint8_t rm = static_cast(modrm & ModRmRmMask); + const auto mod = static_cast((modrm >> ModRmModShift) & ModRmModMask); + const auto reg = static_cast((modrm >> ModRmRegShift) & ModRmRegMask); + const auto rm = static_cast(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(sib & SibBaseMask); + const auto base = static_cast(sib & SibBaseMask); pos += 1; if (mod == ModRmModIndirect && base == SibBaseDisp32) {