diff --git a/include/remill/Arch/Runtime/HyperCall.h b/include/remill/Arch/Runtime/HyperCall.h index 1c8c8830..6cbd1d10 100644 --- a/include/remill/Arch/Runtime/HyperCall.h +++ b/include/remill/Arch/Runtime/HyperCall.h @@ -30,6 +30,7 @@ class SyncHyperCall { kX86CPUID, kX86ReadTSC, kX86ReadTSCP, + kX86XGetBV, kX86LoadGlobalDescriptorTable, kX86LoadInterruptDescriptorTable, kX86LoadAccessRights, diff --git a/include/remill/Arch/X86/Runtime/State.h b/include/remill/Arch/X86/Runtime/State.h index 4228258f..1d328af4 100644 --- a/include/remill/Arch/X86/Runtime/State.h +++ b/include/remill/Arch/X86/Runtime/State.h @@ -445,34 +445,6 @@ struct alignas(8) ArithFlags final { static_assert(16 == sizeof(ArithFlags), "Invalid packing of `ArithFlags`."); -union XCR0 { - uint64_t flat; - - struct { - uint32_t eax; - uint32_t edx; - } __attribute__((packed)); - - // Bits specify what process states should be saved. - struct { - uint64_t x87_fpu_mmx : 1; // Must be 1; bit 0. - uint64_t xmm : 1; // SSE. - uint64_t ymm : 1; // AVX and AVX2. - uint64_t bndreg : 1; // Part of MPX. - uint64_t bndcsr : 1; // Part of MPX. - uint64_t opmask : 1; // Registers k0 through k7, AVX512-only. - uint64_t - zmm_hi256 : 1; // High 256 bits of ZMM0 through ZMM15, AVX512-only. - uint64_t hi16_zmm : 1; // ZMM16 through ZMM31, AVX512-only. - uint64_t pkru : 1; // Protected key stuff. - uint64_t _reserved0 : 53; - uint64_t lwp : 1; // AMD lightweight profiling. - uint64_t _reserved1 : 1; - } __attribute__((packed)); -} __attribute__((packed)); - -static_assert(8 == sizeof(XCR0), "Invalid packing of `XCR0`."); - struct alignas(8) Segments final { volatile uint16_t _0; SegmentSelector ss; @@ -794,7 +766,7 @@ struct alignas(16) X86State : public ArchState { X87Stack st; // 128 bytes. MMX mmx; // 128 bytes. FPUStatusFlags sw; // 24 bytes - XCR0 xcr0; // 8 bytes. + uint8_t _padding[8]; // 8 bytes FPU x87; // 512 bytes SegmentCaches seg_caches; // 96 bytes K_REG k_reg; // 128 bytes. diff --git a/lib/Arch/Runtime/HyperCall.cpp b/lib/Arch/Runtime/HyperCall.cpp index 824e9f3a..c36acf42 100644 --- a/lib/Arch/Runtime/HyperCall.cpp +++ b/lib/Arch/Runtime/HyperCall.cpp @@ -89,6 +89,16 @@ Memory *__remill_sync_hyper_call(State &state, Memory *mem, "d"(state.gpr.rdx.aword)); break; + case SyncHyperCall::kX86XGetBV: { + uint32_t eax = 0; + uint32_t edx = 0; + const auto selector = static_cast(state.addr_to_load); + asm volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(selector)); + state.gpr.rax.aword = eax; + state.gpr.rdx.aword = edx; + break; + } + case SyncHyperCall::kX86LoadGlobalDescriptorTable: { const auto read = __remill_read_memory_64(mem, static_cast(state.addr_to_load)); diff --git a/lib/Arch/X86/Semantics/XSAVE.cpp b/lib/Arch/X86/Semantics/XSAVE.cpp index 087e9fc8..0e57e81d 100644 --- a/lib/Arch/X86/Semantics/XSAVE.cpp +++ b/lib/Arch/X86/Semantics/XSAVE.cpp @@ -16,33 +16,9 @@ namespace { -DEF_SEM(DoXGETBV, PC next_pc) { - switch (Read(REG_ECX)) { - - // Current state of the `xcr0` register. - case 0: - WriteZExt(IF_64BIT_ELSE(REG_RAX, REG_EAX), state.xcr0.eax); - WriteZExt(IF_64BIT_ELSE(REG_RDX, REG_EDX), state.xcr0.edx); - break; - - // Current state of the `xcr0` register, anded with the `xinuse` register. - // We fake this as saying: this is what - case 1: { - XCR0 xcr0 = {}; - xcr0.x87_fpu_mmx = 1; - xcr0.xmm = 1; - IF_AVX(xcr0.ymm = 1;) - IF_AVX512(xcr0.opmask = 1;) - IF_AVX512(xcr0.zmm_hi256 = 1;) - IF_AVX512(xcr0.hi16_zmm = 1;) - WriteZExt(IF_64BIT_ELSE(REG_RAX, REG_EAX), xcr0.eax); - WriteZExt(IF_64BIT_ELSE(REG_RDX, REG_EDX), xcr0.edx); - break; - } - - default: WriteZExt(REG_PC, Read(next_pc)); StopFailure(); - } - return memory; +DEF_SEM(DoXGETBV, PC) { + state.addr_to_load = ZExtTo(Read(REG_ECX)); + return __remill_sync_hyper_call(state, memory, SyncHyperCall::kX86XGetBV); } } // namespace diff --git a/tests/X86/Run.cpp b/tests/X86/Run.cpp index bf77370e..a8c998f3 100644 --- a/tests/X86/Run.cpp +++ b/tests/X86/Run.cpp @@ -914,26 +914,6 @@ static void RunWithFlags(const test::TestInfo *info, Flags flags, ImportX87State(native_state); ResetFlags(); -#if defined(__x86_64__) || defined(__i386__) - { - uint32_t eax = 1; - uint32_t ebx = 0; - uint32_t ecx = 0; - uint32_t edx = 0; - asm volatile("cpuid" - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(eax), "b"(ebx), "c"(ecx), "d"(edx)); - if (ecx & (1U << 26U)) { - uint32_t xcr0_lo = 0; - uint32_t xcr0_hi = 0; - asm volatile("xgetbv" : "=a"(xcr0_lo), "=d"(xcr0_hi) : "c"(0)); - native_state->xcr0.eax = xcr0_lo; - native_state->xcr0.edx = xcr0_hi; - lifted_state->xcr0 = native_state->xcr0; - } - } -#endif - // Set up the RIP correctly. lifted_state->gpr.rip.aword = static_cast(info->test_begin); native_state->gpr.rip.aword = static_cast(info->test_end); @@ -1206,7 +1186,6 @@ static void RunWithFlags(const test::TestInfo *info, Flags flags, << "st:" << offsetof(State, st) << "\n" << "mmx:" << offsetof(State, mmx) << "\n" << "sw:" << offsetof(State, sw) << "\n" - << "xcr0:" << offsetof(State, xcr0) << "\n" << "x87:" << offsetof(State, x87) << "\n" << "seg_caches:" << offsetof(State, seg_caches) << "\n"; }