mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-02-23 16:23:10 +00:00
Fixes 16bit ModRM rm decoding
When we are running in 32bit mode then it is possible to have an instruction's modrm working as 16bit mode. All one needs to do is prefix the instruction with an address size override
This commit is contained in:
parent
ee8dfb8fc5
commit
7ee6b68d03
203
External/FEXCore/Source/Interface/Core/Frontend.cpp
vendored
203
External/FEXCore/Source/Interface/Core/Frontend.cpp
vendored
@ -176,8 +176,12 @@ void Decoder::DecodeModRM(uint8_t *Displacement, FEXCore::X86Tables::ModRMDecode
|
||||
}
|
||||
|
||||
bool Decoder::DecodeSIB(uint8_t *Displacement, FEXCore::X86Tables::ModRMDecoded ModRM) {
|
||||
const bool Has16BitAddressing = !CTX->Config.Is64BitMode &&
|
||||
DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
|
||||
bool HasSIB = ((ModRM.mod != 0b11) &&
|
||||
(ModRM.rm == 0b100));
|
||||
(ModRM.rm == 0b100)) &&
|
||||
!Has16BitAddressing;
|
||||
|
||||
if (HasSIB) {
|
||||
FEXCore::X86Tables::SIBDecoded SIB;
|
||||
@ -212,6 +216,146 @@ bool Decoder::DecodeSIB(uint8_t *Displacement, FEXCore::X86Tables::ModRMDecoded
|
||||
return HasSIB;
|
||||
}
|
||||
|
||||
size_t Decoder::DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM, uint8_t Displacement) {
|
||||
// 16bit modrm behaves similar to SIB but encoded directly in modrm
|
||||
// mod != 0b11 case
|
||||
// RM | Result
|
||||
// ===============
|
||||
// 0b000 | [BX + SI]
|
||||
// 0b001 | [BX + DI]
|
||||
// 0b010 | [BP + SI]
|
||||
// 0b011 | [BP + DI]
|
||||
// 0b100 | [SI]
|
||||
// 0b101 | [DI]
|
||||
// 0b110 | {[BP], disp16}
|
||||
// 0b111 | [BX]
|
||||
// if mod = 0b00
|
||||
// 0b110 = disp16
|
||||
// if mod = 0b01
|
||||
// All encodings gain 8bit displacement
|
||||
// 0b110 = [BP] + disp8
|
||||
// if mod = 0b10
|
||||
// All encodings gain 16bit displacement
|
||||
// 0b110 = [BP] + disp16
|
||||
uint32_t Literal{};
|
||||
uint8_t DisplacementSize{};
|
||||
if ((ModRM.mod == 0 && ModRM.rm == 0b110) ||
|
||||
ModRM.mod == 0b10) {
|
||||
DisplacementSize = 2;
|
||||
}
|
||||
else if (ModRM.mod == 0b01) {
|
||||
DisplacementSize = 1;
|
||||
}
|
||||
if (DisplacementSize) {
|
||||
Literal = ReadData(DisplacementSize);
|
||||
if (DisplacementSize == 1) {
|
||||
Literal = static_cast<int8_t>(Literal);
|
||||
}
|
||||
}
|
||||
|
||||
Operand->TypeSIB.Type = DecodedOperand::TYPE_SIB;
|
||||
Operand->TypeSIB.Scale = 1;
|
||||
Operand->TypeSIB.Offset = Literal;
|
||||
|
||||
// Only called when ModRM.mod != 0b11
|
||||
struct Encodings {
|
||||
uint8_t Base;
|
||||
uint8_t Index;
|
||||
};
|
||||
constexpr static std::array<Encodings, 24> Lookup = {{
|
||||
// Mod = 0b00
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RSI, 255},
|
||||
{FEXCore::X86State::REG_RDI, 255},
|
||||
{255, 255},
|
||||
{FEXCore::X86State::REG_RBX, 255},
|
||||
// Mod = 0b01
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RSI, 255},
|
||||
{FEXCore::X86State::REG_RDI, 255},
|
||||
{FEXCore::X86State::REG_RBP, 255},
|
||||
{FEXCore::X86State::REG_RBX, 255},
|
||||
// Mod = 0b10
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBX, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RSI},
|
||||
{FEXCore::X86State::REG_RBP, FEXCore::X86State::REG_RDI},
|
||||
{FEXCore::X86State::REG_RSI, 255},
|
||||
{FEXCore::X86State::REG_RDI, 255},
|
||||
{FEXCore::X86State::REG_RBP, 255},
|
||||
{FEXCore::X86State::REG_RBX, 255},
|
||||
}};
|
||||
|
||||
uint8_t LookupIndex = ModRM.mod << 3 | ModRM.rm;
|
||||
auto it = Lookup[LookupIndex];
|
||||
Operand->TypeSIB.Base = it.Base;
|
||||
Operand->TypeSIB.Index = it.Index;
|
||||
|
||||
return DisplacementSize;
|
||||
}
|
||||
|
||||
size_t Decoder::DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM, uint8_t Displacement) {
|
||||
if (DecodeInst->DecodedSIB) {
|
||||
// SIB
|
||||
FEXCore::X86Tables::SIBDecoded SIB;
|
||||
SIB.Hex = DecodeInst->SIB;
|
||||
Operand->TypeSIB.Type = DecodedOperand::TYPE_SIB;
|
||||
Operand->TypeSIB.Scale = 1 << SIB.scale;
|
||||
|
||||
// The invalid encoding types are described at Table 1-12. "promoted nsigned is always non-zero"
|
||||
Operand->TypeSIB.Index = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_X ? 1 : 0, SIB.index, false, false, false, false, 0b100);
|
||||
Operand->TypeSIB.Base = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, SIB.base, false, false, false, false, ModRM.mod == 0 ? 0b101 : 16);
|
||||
|
||||
uint64_t Literal {0};
|
||||
LogMan::Throw::A(Displacement <= 4, "Number of bytes should be <= 4 for literal src");
|
||||
|
||||
Literal = ReadData(Displacement);
|
||||
if (Displacement == 1) {
|
||||
Literal = static_cast<int8_t>(Literal);
|
||||
}
|
||||
Operand->TypeSIB.Offset = Literal;
|
||||
}
|
||||
else if (ModRM.mod == 0) {
|
||||
// Explained in Table 1-14. "Operand Addressing Using ModRM and SIB Bytes"
|
||||
if (ModRM.rm == 0b101) {
|
||||
// 32bit Displacement
|
||||
uint32_t Literal;
|
||||
Literal = ReadData(4);
|
||||
Displacement = 4;
|
||||
|
||||
Operand->TypeRIPLiteral.Type = DecodedOperand::TYPE_RIP_RELATIVE;
|
||||
Operand->TypeRIPLiteral.Literal.u = Literal;
|
||||
}
|
||||
else {
|
||||
// Register-direct addressing
|
||||
Operand->TypeGPR.Type = DecodedOperand::TYPE_GPR_DIRECT;
|
||||
Operand->TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, false, false, false, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint8_t DisplacementSize = ModRM.mod == 1 ? 1 : 4;
|
||||
uint32_t Literal{};
|
||||
Literal = ReadData(DisplacementSize);
|
||||
if (DisplacementSize == 1) {
|
||||
Literal = static_cast<int8_t>(Literal);
|
||||
}
|
||||
|
||||
Displacement = DisplacementSize;
|
||||
|
||||
Operand->TypeGPRIndirect.Type = DecodedOperand::TYPE_GPR_INDIRECT;
|
||||
Operand->TypeGPRIndirect.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, false, false, false, false);
|
||||
Operand->TypeGPRIndirect.Displacement = Literal;
|
||||
}
|
||||
|
||||
return Displacement;
|
||||
}
|
||||
|
||||
bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op) {
|
||||
DecodeInst->OP = Op;
|
||||
DecodeInst->TableInfo = Info;
|
||||
@ -323,6 +467,8 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
bool Is8BitDest = (DecodeFlags::GetSizeDstFlags(DecodeInst->Flags) == DecodeFlags::SIZE_8BIT);
|
||||
bool HasREX = !!(DecodeInst->Flags & DecodeFlags::FLAG_REX_PREFIX);
|
||||
bool HasHighXMM = HAS_XMM_SUBFLAG(Info->Flags, FEXCore::X86Tables::InstFlags::FLAGS_SF_HIGH_XMM_REG);
|
||||
const bool Has16BitAddressing = !CTX->Config.Is64BitMode &&
|
||||
DecodeInst->Flags & DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
uint8_t Displacement = 0;
|
||||
|
||||
auto *CurrentDest = &DecodeInst->Dest;
|
||||
@ -395,59 +541,8 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op)
|
||||
NonGPR.TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, NonGPR8Bit, HasREX, HasXMMNonGPR, HasMMNonGPR);
|
||||
}
|
||||
else {
|
||||
if (HasSIB) {
|
||||
// SIB
|
||||
FEXCore::X86Tables::SIBDecoded SIB;
|
||||
SIB.Hex = DecodeInst->SIB;
|
||||
NonGPR.TypeSIB.Type = DecodedOperand::TYPE_SIB;
|
||||
NonGPR.TypeSIB.Scale = 1 << SIB.scale;
|
||||
|
||||
// The invalid encoding types are described at Table 1-12. "promoted nsigned is always non-zero"
|
||||
NonGPR.TypeSIB.Index = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_X ? 1 : 0, SIB.index, false, false, false, false, 0b100);
|
||||
NonGPR.TypeSIB.Base = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, SIB.base, false, false, false, false, ModRM.mod == 0 ? 0b101 : 16);
|
||||
|
||||
uint64_t Literal {0};
|
||||
LogMan::Throw::A(Displacement <= 4, "Number of bytes should be <= 4 for literal src");
|
||||
|
||||
Literal = ReadData(Displacement);
|
||||
if (Displacement == 1) {
|
||||
Literal = static_cast<int8_t>(Literal);
|
||||
}
|
||||
Bytes -= Displacement;
|
||||
NonGPR.TypeSIB.Offset = Literal;
|
||||
}
|
||||
else if (ModRM.mod == 0) {
|
||||
// Explained in Table 1-14. "Operand Addressing Using ModRM and SIB Bytes"
|
||||
LogMan::Throw::A(ModRM.rm != 0b100, "Shouldn't have hit this here");
|
||||
if (ModRM.rm == 0b101) {
|
||||
// 32bit Displacement
|
||||
uint32_t Literal;
|
||||
Literal = ReadData(4);
|
||||
Bytes -= 4;
|
||||
|
||||
NonGPR.TypeRIPLiteral.Type = DecodedOperand::TYPE_RIP_RELATIVE;
|
||||
NonGPR.TypeRIPLiteral.Literal.u = Literal;
|
||||
}
|
||||
else {
|
||||
// Register-direct addressing
|
||||
NonGPR.TypeGPR.Type = DecodedOperand::TYPE_GPR_DIRECT;
|
||||
NonGPR.TypeGPR.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, false, false, false, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint8_t DisplacementSize = ModRM.mod == 1 ? 1 : 4;
|
||||
uint32_t Literal{};
|
||||
Literal = ReadData(DisplacementSize);
|
||||
if (DisplacementSize == 1) {
|
||||
Literal = static_cast<int8_t>(Literal);
|
||||
}
|
||||
|
||||
Bytes -= DisplacementSize;
|
||||
|
||||
NonGPR.TypeGPRIndirect.Type = DecodedOperand::TYPE_GPR_INDIRECT;
|
||||
NonGPR.TypeGPRIndirect.GPR = MapModRMToReg(DecodeInst->Flags & DecodeFlags::FLAG_REX_XGPR_B ? 1 : 0, ModRM.rm, false, false, false, false);
|
||||
NonGPR.TypeGPRIndirect.Displacement = Literal;
|
||||
}
|
||||
auto Disp = DecodeModRMs_Disp[Has16BitAddressing];
|
||||
Bytes -= (this->*Disp)(&NonGPR, ModRM, Displacement);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -67,5 +67,15 @@ private:
|
||||
std::vector<DecodedBlocks> Blocks;
|
||||
std::set<uint64_t> BlocksToDecode;
|
||||
std::set<uint64_t> HasBlocks;
|
||||
|
||||
// ModRM rm decoding
|
||||
using DecodeModRMPtr = size_t (FEXCore::Frontend::Decoder::*)(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM, uint8_t Displacement);
|
||||
size_t DecodeModRM_16(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM, uint8_t Displacement);
|
||||
size_t DecodeModRM_64(X86Tables::DecodedOperand *Operand, X86Tables::ModRMDecoded ModRM, uint8_t Displacement);
|
||||
|
||||
const std::array<DecodeModRMPtr, 2> DecodeModRMs_Disp {
|
||||
&FEXCore::Frontend::Decoder::DecodeModRM_64,
|
||||
&FEXCore::Frontend::Decoder::DecodeModRM_16,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user