fix(code): support vex prefix and imul decoding
This commit is contained in:
parent
aeb9adfb33
commit
ab78ae90e2
|
|
@ -59,6 +59,8 @@ inline constexpr std::uint8_t OneByteIncDecRm8 = 0xFE;
|
|||
inline constexpr std::uint8_t OneByteGrp5Rm = 0xFF;
|
||||
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 OneByteImm8AluOrGrp3 = 0xC6;
|
||||
inline constexpr std::uint8_t OneByteImm8AluCmp = 0x80;
|
||||
|
|
@ -122,6 +124,7 @@ inline constexpr std::uint8_t TwoByteModRmRangeGMax = 0x77;
|
|||
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::size_t ImmSizeNone = 0;
|
||||
inline constexpr std::size_t ImmSize8 = 1;
|
||||
|
|
@ -131,6 +134,8 @@ inline constexpr std::size_t ImmSize64 = 8;
|
|||
|
||||
inline constexpr std::uint8_t ModRmModShift = 6;
|
||||
inline constexpr std::uint8_t ModRmModMask = 0x03;
|
||||
inline constexpr std::uint8_t ModRmRegShift = 3;
|
||||
inline constexpr std::uint8_t ModRmRegMask = 0x07;
|
||||
inline constexpr std::uint8_t ModRmRmMask = 0x07;
|
||||
inline constexpr std::uint8_t ModRmModIndirect = 0x00;
|
||||
inline constexpr std::uint8_t ModRmModDisp8 = 0x01;
|
||||
|
|
@ -139,6 +144,7 @@ inline constexpr std::uint8_t ModRmModRegister = 0x03;
|
|||
inline constexpr std::uint8_t ModRmRmSibPresent = 0x04;
|
||||
inline constexpr std::uint8_t ModRmRmRipRelative = 0x05;
|
||||
|
||||
inline constexpr std::uint8_t Grp3RegTestMax = 0x01;
|
||||
inline constexpr std::uint8_t SibBaseMask = 0x07;
|
||||
inline constexpr std::uint8_t SibBaseDisp32 = 0x05;
|
||||
|
||||
|
|
@ -147,6 +153,11 @@ inline constexpr std::size_t Disp32Size = 4;
|
|||
|
||||
inline constexpr std::size_t Rel32InstructionLength = 5;
|
||||
|
||||
inline constexpr std::size_t Vex2PrefixLength = 2;
|
||||
inline constexpr std::size_t Vex3PrefixLength = 3;
|
||||
inline constexpr std::uint8_t Vex3MapMask = 0x1F;
|
||||
inline constexpr std::uint8_t Vex3Map0F3A = 0x03;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -49,8 +49,28 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
std::uint8_t opcode = data[pos];
|
||||
pos += 1;
|
||||
bool twoByteOpcode = false;
|
||||
bool vexPresent = false;
|
||||
std::uint8_t vexMap = 0;
|
||||
|
||||
if (opcode == TwoByteOpcodeEscape) {
|
||||
if (opcode == OneByteVex2) {
|
||||
if (pos >= available) {
|
||||
throw CodegenException("Instruction truncated after VEX2 prefix");
|
||||
}
|
||||
vexPresent = true;
|
||||
vexMap = TwoByteOpcodeEscape;
|
||||
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 == TwoByteOpcodeEscape) {
|
||||
if (pos >= available) {
|
||||
throw CodegenException("Instruction truncated after two-byte opcode escape");
|
||||
}
|
||||
|
|
@ -59,10 +79,23 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
pos += 1;
|
||||
}
|
||||
|
||||
if (vexPresent) {
|
||||
if (pos >= available) {
|
||||
throw CodegenException("Instruction truncated after VEX prefix");
|
||||
}
|
||||
opcode = data[pos];
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
bool hasModRm = false;
|
||||
std::size_t immediateSize = ImmSizeNone;
|
||||
|
||||
if (!twoByteOpcode) {
|
||||
if (vexPresent) {
|
||||
hasModRm = true;
|
||||
if (vexMap == Vex3Map0F3A) {
|
||||
immediateSize = ImmSize8;
|
||||
}
|
||||
} else if (!twoByteOpcode) {
|
||||
if ((opcode >= OneByteModRmRangeAMin && opcode <= OneByteModRmRangeAMax) ||
|
||||
(opcode >= OneByteModRmRangeBMin && opcode <= OneByteModRmRangeBMax) ||
|
||||
(opcode >= OneByteModRmRangeCMin && opcode <= OneByteModRmRangeCMax) ||
|
||||
|
|
@ -74,8 +107,10 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
opcode == OneByteArpl || opcode == OneByteMovsxd ||
|
||||
(opcode >= OneByteModRmRangeIMin && opcode <= OneByteModRmRangeIMax) ||
|
||||
opcode == OneByteGrp2Rm8Imm8 || opcode == OneByteGrp2RmImm8 ||
|
||||
opcode == OneByteVex3 || opcode == OneByteVex2 ||
|
||||
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 ||
|
||||
|
|
@ -93,7 +128,8 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
opcode == OneBytePushImm8 ||
|
||||
opcode == OneByteTestAlImm8) {
|
||||
immediateSize = ImmSize8;
|
||||
} else if (opcode == OneByteImm32AluCmp ||
|
||||
} else if (opcode == OneByteImm32AluCmp || opcode == OneByteMovImm32 ||
|
||||
opcode == OneByteImulRm32Imm32 ||
|
||||
opcode == OneByteImm32AddEax || opcode == OneByteImm32OrEax ||
|
||||
opcode == OneByteImm32AdcEax || opcode == OneByteImm32SbbEax ||
|
||||
opcode == OneByteImm32AndEax || opcode == OneByteImm32SubEax ||
|
||||
|
|
@ -107,7 +143,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
} else {
|
||||
immediateSize = operandSizeOverride ? ImmSize16 : ImmSize32;
|
||||
}
|
||||
} else if (opcode == OneByteImm8Grp1) {
|
||||
} else if (opcode == OneByteImm8Grp1 || opcode == OneByteImulRm32Imm8) {
|
||||
immediateSize = ImmSize8;
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +175,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
(opcode >= TwoByteModRmRangeFMin && opcode <= TwoByteModRmRangeFMax) ||
|
||||
(opcode >= TwoByteModRmRangeGMin && opcode <= TwoByteModRmRangeGMax) ||
|
||||
(opcode >= TwoByteModRmRangeHMin && opcode <= TwoByteModRmRangeHMax) ||
|
||||
opcode == TwoByteNopModRm) {
|
||||
opcode == TwoByteNopModRm || opcode == TwoByteEndbr) {
|
||||
hasModRm = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -159,8 +195,17 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
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);
|
||||
|
||||
if (!vexPresent && !twoByteOpcode &&
|
||||
(opcode == OneByteTestGrp3Rm8 || opcode == OneByteTestGrp3Rm) &&
|
||||
reg <= Grp3RegTestMax) {
|
||||
immediateSize = (opcode == OneByteTestGrp3Rm8)
|
||||
? ImmSize8
|
||||
: (operandSizeOverride ? ImmSize16 : ImmSize32);
|
||||
}
|
||||
|
||||
if (mod != ModRmModRegister && rm == ModRmRmSibPresent) {
|
||||
if (pos >= available) {
|
||||
throw CodegenException("Instruction truncated before SIB byte");
|
||||
|
|
|
|||
Loading…
Reference in New Issue