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:
Ryan Houdek 2020-06-10 13:47:52 -07:00
parent 8ca73a63cc
commit b262b59916
8 changed files with 114 additions and 64 deletions

View File

@ -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() {

View File

@ -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);

View File

@ -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]));
}
}
}

View File

@ -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

View File

@ -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)))

View File

@ -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

View File

@ -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)

View File

@ -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}")