mirror of
https://github.com/FEX-Emu/FEX.git
synced 2024-12-17 02:47:48 +00:00
Fixes up prefix handling for 32bit
Moves REX to a 64bit only table entry. This allows the missing INC/DEC instructions to exist in 32bit space
This commit is contained in:
parent
8ca73a63cc
commit
b262b59916
@ -641,6 +641,30 @@ bool Decoder::NormalOpHeader(FEXCore::X86Tables::X86InstInfo const *Info, uint16
|
||||
uint8_t EVEXOp = ReadByte();
|
||||
return NormalOp(&EVEXTableOps[EVEXOp], EVEXOp);
|
||||
}
|
||||
else if (Info->Type == FEXCore::X86Tables::TYPE_REX_PREFIX) {
|
||||
LogMan::Throw::A(CTX->Config.Is64BitMode, "Got REX prefix in 32bit mode");
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX;
|
||||
|
||||
// Widening displacement
|
||||
if (Op & 0b1000) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_WIDENING;
|
||||
DecodeInst->Flags = (DecodeInst->Flags & ~DecodeFlags::FLAG_OPADDR_MASK) | DecodeFlags::FLAG_WIDENING_SIZE_LAST;
|
||||
}
|
||||
|
||||
// XGPR_B bit set
|
||||
if (Op & 0b0001)
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B;
|
||||
|
||||
// XGPR_X bit set
|
||||
if (Op & 0b0010)
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X;
|
||||
|
||||
// XGPR_R bit set
|
||||
if (Op & 0b0100)
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_R;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return NormalOp(Info, Op);
|
||||
}
|
||||
@ -649,13 +673,12 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
InstructionSize = 0;
|
||||
Instruction.fill(0);
|
||||
bool InstructionDecoded = false;
|
||||
bool ErrorDuringDecoding = false;
|
||||
|
||||
DecodeInst = &DecodedBuffer[DecodedSize];
|
||||
memset(DecodeInst, 0, sizeof(DecodedInst));
|
||||
DecodeInst->PC = PC;
|
||||
|
||||
while (!InstructionDecoded && !ErrorDuringDecoding) {
|
||||
while (!InstructionDecoded) {
|
||||
uint8_t Op = ReadByte();
|
||||
switch (Op) {
|
||||
case 0x0F: {// Escape Op
|
||||
@ -777,49 +800,29 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_ADDRESS_SIZE;
|
||||
break;
|
||||
case 0x26: // ES legacy prefix
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_ES_PREFIX;
|
||||
}
|
||||
break;
|
||||
case 0x2E: // CS legacy prefix
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_CS_PREFIX;
|
||||
}
|
||||
break;
|
||||
case 0x36: // SS legacy prefix
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_SS_PREFIX;
|
||||
}
|
||||
break;
|
||||
case 0x3E: // DS legacy prefix
|
||||
// Annoyingly GCC generates NOP ops with these prefixes
|
||||
// Just ignore them for now
|
||||
// eg. 66 2e 0f 1f 84 00 00 00 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
|
||||
break;
|
||||
case 0x40: // REX - 0x40-0x4F
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F: {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_PREFIX;
|
||||
|
||||
// Widening displacement
|
||||
if (Op & 0b1000) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_WIDENING;
|
||||
DecodeInst->Flags = (DecodeInst->Flags & ~DecodeFlags::FLAG_OPADDR_MASK) | DecodeFlags::FLAG_WIDENING_SIZE_LAST;
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_DS_PREFIX;
|
||||
}
|
||||
|
||||
// XGPR_B bit set
|
||||
if (Op & 0b0001)
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_B;
|
||||
|
||||
// XGPR_X bit set
|
||||
if (Op & 0b0010)
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_X;
|
||||
|
||||
// XGPR_R bit set
|
||||
if (Op & 0b0100)
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_REX_XGPR_R;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case 0xF0: // LOCK prefix
|
||||
DecodeInst->Flags |= DecodeFlags::FLAG_LOCK;
|
||||
break;
|
||||
@ -841,16 +844,13 @@ bool Decoder::DecodeInstruction(uint64_t PC) {
|
||||
if (NormalOpHeader(&FEXCore::X86Tables::BaseOps[Op], Op)) {
|
||||
InstructionDecoded = true;
|
||||
}
|
||||
else {
|
||||
LogMan::Msg::E("Error during instruction decoding");
|
||||
ErrorDuringDecoding = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return !ErrorDuringDecoding;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Decoder::BranchTargetInMultiblockRange() {
|
||||
|
@ -6824,6 +6824,11 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
{0xFC, 2, &OpDispatchBuilder::FLAGControlOp},
|
||||
};
|
||||
|
||||
const std::vector<std::tuple<uint8_t, uint8_t, X86Tables::OpDispatchPtr>> BaseOpTable_32 = {
|
||||
{0x40, 8, &OpDispatchBuilder::INCOp},
|
||||
{0x48, 8, &OpDispatchBuilder::DECOp},
|
||||
};
|
||||
|
||||
const std::vector<std::tuple<uint8_t, uint8_t, FEXCore::X86Tables::OpDispatchPtr>> TwoByteOpTable = {
|
||||
// Instructions
|
||||
{0x00, 1, nullptr}, // GROUP 6
|
||||
@ -7750,6 +7755,9 @@ constexpr uint16_t PF_F2 = 3;
|
||||
};
|
||||
|
||||
InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable);
|
||||
if (Mode == Context::MODE_32BIT) {
|
||||
InstallToTable(FEXCore::X86Tables::BaseOps, BaseOpTable_32);
|
||||
}
|
||||
InstallToTable(FEXCore::X86Tables::SecondBaseOps, TwoByteOpTable);
|
||||
InstallToTable(FEXCore::X86Tables::PrimaryInstGroupOps, PrimaryGroupOpTable);
|
||||
|
||||
|
@ -9,22 +9,19 @@ void InitializeBaseTables(Context::OperatingMode Mode) {
|
||||
const U8U8InfoStruct BaseOpTable[] = {
|
||||
// Prefixes
|
||||
// Operand size overide
|
||||
{0x66, 1, X86InstInfo{"", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x66, 1, X86InstInfo{"", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
// Address size override
|
||||
{0x67, 1, X86InstInfo{"", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x2E, 1, X86InstInfo{"CS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x3E, 1, X86InstInfo{"DS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x67, 1, X86InstInfo{"", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x26, 1, X86InstInfo{"ES", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x2E, 1, X86InstInfo{"CS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x36, 1, X86InstInfo{"SS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x3E, 1, X86InstInfo{"DS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
// These are still invalid on 64bit
|
||||
{0x64, 1, X86InstInfo{"FS", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x65, 1, X86InstInfo{"GS", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0x36, 1, X86InstInfo{"SS", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0xF0, 1, X86InstInfo{"LOCK", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0xF2, 1, X86InstInfo{"REPNE", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0xF3, 1, X86InstInfo{"REP", TYPE_LEGACY_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
|
||||
// REX
|
||||
{0x40, 16, X86InstInfo{"", TYPE_REX_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0xF0, 1, X86InstInfo{"LOCK", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0xF2, 1, X86InstInfo{"REPNE", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
{0xF3, 1, X86InstInfo{"REP", TYPE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
|
||||
// Instructions
|
||||
{0x00, 1, X86InstInfo{"ADD", TYPE_INST, GenFlagsSameSize(SIZE_8BIT) | FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}},
|
||||
@ -135,9 +132,9 @@ void InitializeBaseTables(Context::OperatingMode Mode) {
|
||||
{0x89, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}},
|
||||
{0x8A, 1, X86InstInfo{"MOV", TYPE_INST, GenFlagsSameSize(SIZE_8BIT) | FLAGS_MODRM, 0, nullptr}},
|
||||
{0x8B, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM, 0, nullptr}},
|
||||
{0x8C, 1, X86InstInfo{"MOV", TYPE_INVALID, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}},
|
||||
{0x8C, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM | FLAGS_SF_MOD_DST, 0, nullptr}},
|
||||
{0x8D, 1, X86InstInfo{"LEA", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_MODRM, 0, nullptr}},
|
||||
{0x8E, 1, X86InstInfo{"MOV", TYPE_INVALID, FLAGS_MODRM, 0, nullptr}}, // MOV seg, modrM == invalid on x86-64
|
||||
{0x8E, 1, X86InstInfo{"MOV", TYPE_INST, FLAGS_MODRM, 0, nullptr}}, // MOV seg, modrM == invalid on x86-64
|
||||
{0x8F, 1, X86InstInfo{"POP", TYPE_INST, GenFlagsSameSize(SIZE_64BITDEF) | FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_DEBUG_MEM_ACCESS, 0, nullptr}},
|
||||
{0x90, 8, X86InstInfo{"XCHG", TYPE_INST, FLAGS_SF_REX_IN_BYTE | FLAGS_SF_SRC_RAX, 0, nullptr}},
|
||||
{0x98, 1, X86InstInfo{"CDQE", TYPE_INST, FLAGS_SF_DST_RAX | FLAGS_SF_SRC_RAX, 0, nullptr}},
|
||||
@ -246,7 +243,24 @@ void InitializeBaseTables(Context::OperatingMode Mode) {
|
||||
{0xC4, 2, X86InstInfo{"", TYPE_VEX_TABLE_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
};
|
||||
|
||||
const U8U8InfoStruct BaseOpTable_64[] = {
|
||||
// REX
|
||||
{0x40, 16, X86InstInfo{"", TYPE_REX_PREFIX, FLAGS_NONE, 0, nullptr}},
|
||||
};
|
||||
|
||||
const U8U8InfoStruct BaseOpTable_32[] = {
|
||||
{0x40, 8, X86InstInfo{"INC", TYPE_INST, FLAGS_SF_REX_IN_BYTE, 0, nullptr}},
|
||||
{0x48, 8, X86InstInfo{"DEC", TYPE_INST, FLAGS_SF_REX_IN_BYTE, 0, nullptr}},
|
||||
};
|
||||
|
||||
GenerateTable(BaseOps, BaseOpTable, sizeof(BaseOpTable) / sizeof(BaseOpTable[0]));
|
||||
|
||||
if (Mode == Context::MODE_64BIT) {
|
||||
GenerateTable(BaseOps, BaseOpTable_64, sizeof(BaseOpTable_64) / sizeof(BaseOpTable_64[0]));
|
||||
}
|
||||
else {
|
||||
GenerateTable(BaseOps, BaseOpTable_32, sizeof(BaseOpTable_32) / sizeof(BaseOpTable_32[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,16 @@ constexpr uint32_t FLAG_REX_WIDENING = (1 << 7);
|
||||
constexpr uint32_t FLAG_REX_XGPR_B = (1 << 8);
|
||||
constexpr uint32_t FLAG_REX_XGPR_X = (1 << 9);
|
||||
constexpr uint32_t FLAG_REX_XGPR_R = (1 << 10);
|
||||
constexpr uint32_t FLAG_FS_PREFIX = (1 << 11);
|
||||
constexpr uint32_t FLAG_GS_PREFIX = (1 << 12);
|
||||
constexpr uint32_t FLAG_REP_PREFIX = (1 << 13);
|
||||
constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 14);
|
||||
constexpr uint32_t FLAG_ES_PREFIX = (1 << 11);
|
||||
constexpr uint32_t FLAG_CS_PREFIX = (1 << 12);
|
||||
constexpr uint32_t FLAG_SS_PREFIX = (1 << 13);
|
||||
constexpr uint32_t FLAG_DS_PREFIX = (1 << 14);
|
||||
constexpr uint32_t FLAG_FS_PREFIX = (1 << 15);
|
||||
constexpr uint32_t FLAG_GS_PREFIX = (1 << 16);
|
||||
constexpr uint32_t FLAG_REP_PREFIX = (1 << 17);
|
||||
constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 18);
|
||||
// Size flags
|
||||
constexpr uint32_t FLAG_SIZE_DST_OFF = 15;
|
||||
constexpr uint32_t FLAG_SIZE_DST_OFF = 19;
|
||||
constexpr uint32_t FLAG_SIZE_SRC_OFF = FLAG_SIZE_DST_OFF + 3;
|
||||
constexpr uint32_t SIZE_MASK = 0b111;
|
||||
constexpr uint32_t SIZE_DEF = 0b000; // This should be invalid past decoding
|
||||
|
@ -58,6 +58,10 @@ class ABI(Flag) :
|
||||
ABI_WIN64 = 1
|
||||
ABI_NONE = 2
|
||||
|
||||
class Mode(Flag) :
|
||||
MODE_32 = 0
|
||||
MODE_64 = 1
|
||||
|
||||
RegStringLookup = {
|
||||
"NONE": Regs.REG_NONE,
|
||||
"RAX": Regs.REG_RAX,
|
||||
@ -114,11 +118,17 @@ ABIStringLookup = {
|
||||
"NONE": ABI.ABI_NONE,
|
||||
}
|
||||
|
||||
ModeStringLookup = {
|
||||
"32BIT": Mode.MODE_32,
|
||||
"64BIT": Mode.MODE_64,
|
||||
}
|
||||
|
||||
def parse_json(json_text, output_file):
|
||||
# Default options
|
||||
OptionMatch = Regs.REG_INVALID
|
||||
OptionIgnore = Regs.REG_NONE
|
||||
OptionABI = ABI.ABI_SYSTEMV
|
||||
OptionMode = Mode.MODE_64
|
||||
OptionStackSize = 4096
|
||||
OptionEntryPoint = 1
|
||||
OptionRegData = {}
|
||||
@ -164,6 +174,13 @@ def parse_json(json_text, output_file):
|
||||
sys.exit("Invalid ABI")
|
||||
OptionABI = ABIStringLookup[data]
|
||||
|
||||
if ("MODE" in json_object):
|
||||
data = json_object["MODE"]
|
||||
data = data.upper()
|
||||
if not (data in ModeStringLookup):
|
||||
sys.exit("Invalid Mode")
|
||||
OptionMode = ModeStringLookup[data]
|
||||
|
||||
if ("STACKSIZE" in json_object):
|
||||
data = json_object["STACKSIZE"]
|
||||
OptionStackSize = int(data, 0)
|
||||
@ -212,6 +229,7 @@ def parse_json(json_text, output_file):
|
||||
config_file.write(struct.pack('Q', OptionStackSize))
|
||||
config_file.write(struct.pack('Q', OptionEntryPoint))
|
||||
config_file.write(struct.pack('I', OptionABI.value))
|
||||
config_file.write(struct.pack('I', OptionMode.value))
|
||||
|
||||
# Number of memory regions
|
||||
config_file.write(struct.pack('I', len(OptionMemoryRegions)))
|
||||
|
@ -263,6 +263,8 @@ namespace FEX::HarnessHelper {
|
||||
return Matches;
|
||||
}
|
||||
|
||||
bool Is64BitMode() const { return BaseConfig.OptionMode == 1; }
|
||||
|
||||
private:
|
||||
FEX::Config::Value<bool> ConfigDumpGPRs{"DumpGPRs", false};
|
||||
|
||||
@ -272,6 +274,7 @@ namespace FEX::HarnessHelper {
|
||||
uint64_t OptionStackSize;
|
||||
uint64_t OptionEntryPoint;
|
||||
uint32_t OptionABI;
|
||||
uint32_t OptionMode;
|
||||
uint32_t OptionMemoryRegionCount;
|
||||
uint32_t OptionRegDataCount;
|
||||
uint8_t AdditionalData[];
|
||||
@ -366,6 +369,8 @@ namespace FEX::HarnessHelper {
|
||||
return Config.CompareStates(State1, State2);
|
||||
}
|
||||
|
||||
bool Is64BitMode() const { return Config.Is64BitMode(); }
|
||||
|
||||
private:
|
||||
constexpr static uint64_t STACK_SIZE = PAGE_SIZE;
|
||||
// Zero is special case to know when we are done
|
||||
|
@ -69,21 +69,21 @@ int main(int argc, char **argv, char **const envp) {
|
||||
auto SHM = FEXCore::SHM::AllocateSHMRegion(1ULL << 34);
|
||||
auto CTX = FEXCore::Context::CreateNewContext();
|
||||
|
||||
FEX::HarnessHelper::HarnessCodeLoader Loader{Args[0], Args[1].c_str()};
|
||||
|
||||
FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory);
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_UNIFIED_MEMORY, 0); // ensure TestHarnessRunner doesn't enable UnifiedMemory.
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_DEFAULTCORE, CoreConfig() > 3 ? FEXCore::Config::CONFIG_CUSTOM : CoreConfig());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MULTIBLOCK, MultiblockConfig());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_SINGLESTEP, SingleStepConfig());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MAXBLOCKINST, BlockSizeConfig());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, true);
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode());
|
||||
FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory);
|
||||
|
||||
FEXCore::Context::AddGuestMemoryRegion(CTX, SHM);
|
||||
|
||||
FEXCore::Context::InitializeContext(CTX);
|
||||
|
||||
FEX::HarnessHelper::HarnessCodeLoader Loader{Args[0], Args[1].c_str()};
|
||||
|
||||
bool Result1 = FEXCore::Context::InitCore(CTX, &Loader);
|
||||
|
||||
if (!Result1)
|
||||
|
@ -25,6 +25,7 @@ foreach(ASM_SRC ${ASM_SOURCES})
|
||||
|
||||
add_custom_command(OUTPUT ${OUTPUT_CONFIG_NAME}
|
||||
DEPENDS "${ASM_SRC}"
|
||||
DEPENDS "${CMAKE_SOURCE_DIR}/Scripts/json_asm_config_parse.py"
|
||||
COMMAND "python3" ARGS "${CMAKE_SOURCE_DIR}/Scripts/json_asm_config_parse.py" "${ASM_SRC}" "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_CONFIG_NAME}")
|
||||
|
||||
list(APPEND ASM_DEPENDS "${OUTPUT_NAME};${OUTPUT_CONFIG_NAME}")
|
||||
|
Loading…
Reference in New Issue
Block a user