Merge pull request #1381 from overlordxrz-source/fix/relinker-decoder-0f-no-modrm
fix(relinker): decode 0F A8-AA without a ModRM and MOV CR/DR without a memory operand
This commit is contained in:
commit
9e5ade70fb
|
|
@ -119,7 +119,7 @@ inline constexpr std::uint8_t TwoByteMovImm8ModRm = 0xBA;
|
|||
inline constexpr std::uint8_t TwoByteCmovRangeMin = 0x40;
|
||||
inline constexpr std::uint8_t TwoByteCmovRangeMax = 0x4F;
|
||||
inline constexpr std::uint8_t TwoByteModRmRangeAMin = 0xA3;
|
||||
inline constexpr std::uint8_t TwoByteModRmRangeAMax = 0xAB;
|
||||
inline constexpr std::uint8_t TwoByteModRmRangeAMax = 0xA7;
|
||||
inline constexpr std::uint8_t TwoByteModRmRangeBMin = 0xB0;
|
||||
inline constexpr std::uint8_t TwoByteModRmRangeBMax = 0xB7;
|
||||
inline constexpr std::uint8_t TwoByteModRmRangeCMin = 0xBC;
|
||||
|
|
@ -174,6 +174,7 @@ inline constexpr std::uint8_t TwoByteMovCrDrMin = 0x20;
|
|||
inline constexpr std::uint8_t TwoByteMovCrDrMax = 0x23;
|
||||
inline constexpr std::uint8_t TwoBytePopcnt = 0xB8;
|
||||
inline constexpr std::uint8_t TwoByteUd1 = 0xB9;
|
||||
inline constexpr std::uint8_t TwoByteBts = 0xAB;
|
||||
inline constexpr std::uint8_t TwoByteBtc = 0xBB;
|
||||
inline constexpr std::uint8_t TwoByteXaddRm8 = 0xC0;
|
||||
inline constexpr std::uint8_t TwoByteMovnti = 0xC3;
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
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) ||
|
||||
|
|
@ -279,7 +280,8 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t
|
|||
const std::uint8_t modrm = data[pos];
|
||||
pos += 1;
|
||||
|
||||
const auto mod = static_cast<std::uint8_t>((modrm >> ModRmModShift) & ModRmModMask);
|
||||
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);
|
||||
|
||||
|
|
@ -361,12 +363,12 @@ DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction(
|
|||
if (pos >= info.Length)
|
||||
return info;
|
||||
|
||||
const auto readModRm = [&](const std::size_t modrmPos) {
|
||||
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 = (modrm >> ModRmModShift) & ModRmModMask;
|
||||
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;
|
||||
|
|
@ -380,7 +382,7 @@ DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction(
|
|||
if (op == OneByteVex2 || op == OneByteVex3 || op == EvexPrefix) {
|
||||
pos += (op == OneByteVex2 ? 1 : (op == OneByteVex3 ? 2 : EvexPrefixLength - 1)) + 1;
|
||||
if (pos < info.Length)
|
||||
readModRm(pos);
|
||||
readModRm(pos, false);
|
||||
info.FlowKind = ControlFlowKind::Sequential;
|
||||
return info;
|
||||
}
|
||||
|
|
@ -516,6 +518,7 @@ DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction(
|
|||
} else {
|
||||
if ((op >= TwoByteCmovRangeMin && op <= TwoByteCmovRangeMax) ||
|
||||
(op >= TwoByteModRmRangeAMin && op <= TwoByteModRmRangeAMax) ||
|
||||
op == TwoByteBts ||
|
||||
(op >= TwoByteModRmRangeBMin && op <= TwoByteModRmRangeBMax) ||
|
||||
(op >= TwoByteModRmRangeCMin && op <= TwoByteModRmRangeCMax) ||
|
||||
(op >= TwoByteModRmRangeDMin && op <= TwoByteModRmRangeDMax) ||
|
||||
|
|
@ -544,7 +547,7 @@ DecodedInstructionInfo X64InstructionDecoder::DecodeInstruction(
|
|||
}
|
||||
|
||||
if (hasModRm && pos < info.Length)
|
||||
readModRm(pos);
|
||||
readModRm(pos, twoByteOpcode && op >= TwoByteMovCrDrMin && op <= TwoByteMovCrDrMax);
|
||||
|
||||
info.FlowKind = ControlFlowKind::Sequential;
|
||||
return info;
|
||||
|
|
|
|||
|
|
@ -169,6 +169,33 @@ void decoderRipRelative() {
|
|||
require(!decoder.DecodeInstruction(instruction.data(), instruction.size()).HasRipRelativeDisp, "Vector instruction without a RIP-relative operand was reported as RIP-relative");
|
||||
}
|
||||
|
||||
void decoderTwoByteOpcodeLengths() {
|
||||
const Codegen::X64InstructionDecoder decoder;
|
||||
const std::vector<Bytes> instructions = {
|
||||
{0x0F, 0xA8}, {0x0F, 0xA9}, {0x0F, 0xAA}, {0x66, 0x0F, 0xA8}, {0x41, 0x0F, 0xA9},
|
||||
{0x0F, 0xAB, 0xC8}, {0x0F, 0xAB, 0x05, 0x10, 0x00, 0x00, 0x00}, {0x48, 0x0F, 0xAB, 0x44, 0x24, 0x08},
|
||||
{0x0F, 0x20, 0xC0}, {0x0F, 0x20, 0x05}, {0x0F, 0x22, 0x04}, {0x0F, 0x21, 0x45}, {0x0F, 0x23, 0x85},
|
||||
{0x66, 0x0F, 0x38, 0x20, 0x05, 0x10, 0x00, 0x00, 0x00}, {0x66, 0x0F, 0x38, 0x23, 0x44, 0x24, 0x08}};
|
||||
Bytes padded;
|
||||
for (const auto& instruction : instructions) {
|
||||
padded = instruction;
|
||||
padded.insert(padded.end(), 8, 0x90);
|
||||
require(decoder.Decode(padded.data(), padded.size()) == instruction.size(), "Two-byte opcode was decoded with operand bytes it does not have");
|
||||
require(decoder.DecodeInstruction(padded.data(), padded.size()).Length == instruction.size(), "Two-byte opcode was described with operand bytes it does not have");
|
||||
}
|
||||
const Bytes controlRegister = {0x0F, 0x20, 0x05, 0x90, 0x90, 0x90, 0x90};
|
||||
const auto control = decoder.DecodeInstruction(controlRegister.data(), controlRegister.size());
|
||||
require(control.Length == 3 && control.HasModRm && control.ModRmByte == 0x05 && !control.HasRipRelativeDisp, "MOV from a control register was reported as RIP-relative");
|
||||
const Bytes debugRegister = {0x0F, 0x23, 0x05, 0x90, 0x90, 0x90, 0x90};
|
||||
require(!decoder.DecodeInstruction(debugRegister.data(), debugRegister.size()).HasRipRelativeDisp, "MOV to a debug register was reported as RIP-relative");
|
||||
const Bytes extend = {0x66, 0x0F, 0x38, 0x20, 0x05, 0x10, 0x00, 0x00, 0x00};
|
||||
const auto extended = decoder.DecodeInstruction(extend.data(), extend.size());
|
||||
require(extended.HasRipRelativeDisp && read<std::int32_t>(extend, extended.RipRelativeDispOffset) == 0x10, "PMOVSXBW lost its RIP-relative operand");
|
||||
const Bytes bitTest = {0x0F, 0xAB, 0x05, 0x10, 0x00, 0x00, 0x00};
|
||||
const auto bts = decoder.DecodeInstruction(bitTest.data(), bitTest.size());
|
||||
require(bts.HasRipRelativeDisp && read<std::int32_t>(bitTest, bts.RipRelativeDispOffset) == 0x10, "BTS lost its RIP-relative operand");
|
||||
}
|
||||
|
||||
void sse4aOperands() {
|
||||
const auto check = [](const Bytes& site, const bool insertq, const int dst, const int src, const int length, const int index) {
|
||||
const auto operands = Codegen::DecodeSse4a(site.data(), site.size());
|
||||
|
|
@ -1120,6 +1147,7 @@ int main() {
|
|||
try {
|
||||
decoderLengths();
|
||||
decoderRipRelative();
|
||||
decoderTwoByteOpcodeLengths();
|
||||
sse4aOperands();
|
||||
sha256Operands();
|
||||
sha1Operands();
|
||||
|
|
|
|||
Loading…
Reference in New Issue