From 91f04f5eb996f109bc231b6389d58d185189c736 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Tue, 24 Mar 2026 17:17:03 +0100 Subject: [PATCH] Add a few missing instructions/tests --- include/remill/Arch/Runtime/HyperCall.h | 2 + lib/Arch/Runtime/HyperCall.cpp | 34 +++- lib/Arch/X86/Semantics/BINARY.cpp | 4 + lib/Arch/X86/Semantics/BITBYTE.cpp | 205 ++++++++++++++++++++++++ lib/Arch/X86/Semantics/CMOV.cpp | 14 ++ lib/Arch/X86/Semantics/COND_BR.cpp | 18 +++ lib/Arch/X86/Semantics/LOGICAL.cpp | 21 +++ lib/Arch/X86/Semantics/SHIFT.cpp | 43 +++-- lib/Arch/X86/Semantics/SSE.cpp | 52 +++--- lib/Arch/X86/Semantics/SYSTEM.cpp | 24 +++ lib/Arch/X86/Semantics/XSAVE.cpp | 2 + tests/X86/BITBYTE/BEXTR.S | 111 +++++++++++++ tests/X86/BITBYTE/BZHI.S | 119 ++++++++++++++ tests/X86/BITBYTE/CRC32.S | 95 +++++++++++ tests/X86/BITBYTE/PDEP.S | 103 ++++++++++++ tests/X86/BITBYTE/PEXT.S | 103 ++++++++++++ tests/X86/BITBYTE/POPCNT.S | 78 +++++++++ tests/X86/BITBYTE/SETE.S | 20 +++ tests/X86/BRANCH/CALL.S | 32 ++++ tests/X86/BRANCH/JAE.S | 35 ++++ tests/X86/BRANCH/JE.S | 35 ++++ tests/X86/BRANCH/JMP.S | 28 ++++ tests/X86/BRANCH/JNE.S | 35 ++++ tests/X86/BRANCH/RET.S | 33 ++++ tests/X86/CMOV/CMOVE.S | 57 +++++++ tests/X86/CMOV/CMOVNE.S | 57 +++++++ tests/X86/INTERRUPT/INT3.S | 25 +++ tests/X86/LOGICAL/ANDN.S | 107 +++++++++++++ tests/X86/MISC/NOP.S | 27 ++++ tests/X86/Run.cpp | 52 ++++-- tests/X86/SHIFT/SHLX.S | 103 ++++++++++++ tests/X86/SYSTEM/LAR.S | 23 +++ tests/X86/SYSTEM/RDTSC.S | 43 +++++ tests/X86/SYSTEM/VERR.S | 22 +++ tests/X86/SYSTEM/XGETBV.S | 31 ++++ tests/X86/Tests.S | 26 +++ 36 files changed, 1777 insertions(+), 42 deletions(-) create mode 100644 tests/X86/BITBYTE/BEXTR.S create mode 100644 tests/X86/BITBYTE/BZHI.S create mode 100644 tests/X86/BITBYTE/CRC32.S create mode 100644 tests/X86/BITBYTE/PDEP.S create mode 100644 tests/X86/BITBYTE/PEXT.S create mode 100644 tests/X86/BITBYTE/POPCNT.S create mode 100644 tests/X86/BITBYTE/SETE.S create mode 100644 tests/X86/BRANCH/CALL.S create mode 100644 tests/X86/BRANCH/JAE.S create mode 100644 tests/X86/BRANCH/JE.S create mode 100644 tests/X86/BRANCH/JMP.S create mode 100644 tests/X86/BRANCH/JNE.S create mode 100644 tests/X86/BRANCH/RET.S create mode 100644 tests/X86/CMOV/CMOVE.S create mode 100644 tests/X86/CMOV/CMOVNE.S create mode 100644 tests/X86/INTERRUPT/INT3.S create mode 100644 tests/X86/LOGICAL/ANDN.S create mode 100644 tests/X86/MISC/NOP.S create mode 100644 tests/X86/SHIFT/SHLX.S create mode 100644 tests/X86/SYSTEM/LAR.S create mode 100644 tests/X86/SYSTEM/RDTSC.S create mode 100644 tests/X86/SYSTEM/VERR.S create mode 100644 tests/X86/SYSTEM/XGETBV.S diff --git a/include/remill/Arch/Runtime/HyperCall.h b/include/remill/Arch/Runtime/HyperCall.h index 1a32eeaf..1c8c8830 100644 --- a/include/remill/Arch/Runtime/HyperCall.h +++ b/include/remill/Arch/Runtime/HyperCall.h @@ -32,6 +32,8 @@ class SyncHyperCall { kX86ReadTSCP, kX86LoadGlobalDescriptorTable, kX86LoadInterruptDescriptorTable, + kX86LoadAccessRights, + kX86VerifySegmentReadable, kX86ReadModelSpecificRegister, kX86WriteModelSpecificRegister, kX86WriteBackInvalidate, diff --git a/lib/Arch/Runtime/HyperCall.cpp b/lib/Arch/Runtime/HyperCall.cpp index 1768b267..824e9f3a 100644 --- a/lib/Arch/Runtime/HyperCall.cpp +++ b/lib/Arch/Runtime/HyperCall.cpp @@ -78,7 +78,7 @@ Memory *__remill_sync_hyper_call(State &state, Memory *mem, case SyncHyperCall::kX86ReadTSC: asm volatile("rdtsc" - : "=a"(state.gpr.rax.dword), "=d"(state.gpr.rdx.dword)); + : "=a"(state.gpr.rax.aword), "=d"(state.gpr.rdx.aword)); break; case SyncHyperCall::kX86ReadTSCP: @@ -113,6 +113,38 @@ Memory *__remill_sync_hyper_call(State &state, Memory *mem, break; } + case SyncHyperCall::kX86LoadAccessRights: { + const auto selector = static_cast(state.addr_to_load); + uint8_t zf = 0; +#if REMILL_HYPERCALL_X86 + uint32_t result = 0; +#else + uint64_t result = 0; +#endif + asm volatile("lar %[src], %[dst] \n\t" + "setz %[zf]" + : [dst] "=r"(result), [zf] "=qm"(zf) + : [src] "rm"(selector) + : "cc"); + state.addr_to_store = result; + state.rflag.zf = zf; + state.aflag.zf = zf; + break; + } + + case SyncHyperCall::kX86VerifySegmentReadable: { + const auto selector = static_cast(state.addr_to_load); + uint8_t zf = 0; + asm volatile("verr %[src] \n\t" + "setz %[zf]" + : [zf] "=qm"(zf) + : [src] "rm"(selector) + : "cc"); + state.rflag.zf = zf; + state.aflag.zf = zf; + break; + } + case SyncHyperCall::kX86ReadModelSpecificRegister: asm volatile("rdmsr" : "=c"(state.gpr.rcx.dword) diff --git a/lib/Arch/X86/Semantics/BINARY.cpp b/lib/Arch/X86/Semantics/BINARY.cpp index f29c8457..add39e56 100644 --- a/lib/Arch/X86/Semantics/BINARY.cpp +++ b/lib/Arch/X86/Semantics/BINARY.cpp @@ -402,8 +402,12 @@ IF_64BIT(DEF_ISEL(MUL_GPRv_64) = MULrax;) DEF_ISEL(MULX_GPR32d_GPR32d_GPR32d) = MULX; DEF_ISEL(MULX_GPR32d_GPR32d_MEMd) = MULX; +DEF_ISEL(MULX_VGPR32d_VGPR32d_VGPR32d) = MULX; +DEF_ISEL(MULX_VGPR32d_VGPR32d_MEMd) = MULX; IF_64BIT(DEF_ISEL(MULX_GPR64q_GPR64q_GPR64q) = MULX;) IF_64BIT(DEF_ISEL(MULX_GPR64q_GPR64q_MEMq) = MULX;) +IF_64BIT(DEF_ISEL(MULX_VGPR64q_VGPR64q_VGPR64q) = MULX;) +IF_64BIT(DEF_ISEL(MULX_VGPR64q_VGPR64q_MEMq) = MULX;) DEF_ISEL(MULPS_XMMps_MEMps) = MULPS; DEF_ISEL(MULPS_XMMps_XMMps) = MULPS; diff --git a/lib/Arch/X86/Semantics/BITBYTE.cpp b/lib/Arch/X86/Semantics/BITBYTE.cpp index ffea5d27..7a8a82c9 100644 --- a/lib/Arch/X86/Semantics/BITBYTE.cpp +++ b/lib/Arch/X86/Semantics/BITBYTE.cpp @@ -123,6 +123,8 @@ DEF_ISEL(SETP_MEMb) = SETP; DEF_ISEL(SETP_GPR8) = SETP; DEF_ISEL(SETZ_MEMb) = SETZ; DEF_ISEL(SETZ_GPR8) = SETZ; +DEF_ISEL(SETE_MEMb) = SETZ; +DEF_ISEL(SETE_GPR8) = SETZ; DEF_ISEL(SETS_MEMb) = SETS; DEF_ISEL(SETS_GPR8) = SETS; DEF_ISEL(SETNO_MEMb) = SETNO; @@ -323,6 +325,159 @@ DEF_SEM(LZCNT, D dst, S src) { return memory; } +template +ALWAYS_INLINE static T LowBitMask(T count, T bit_size) { + if (UCmpEq(count, 0)) { + return Literal(0); + } + if (!UCmpLt(count, bit_size)) { + return Maximize(Literal(0)); + } + return USub(UShl(Literal(1), count), Literal(1)); +} + +template +ALWAYS_INLINE static T PopulationCount(T val) { + auto count = Literal(0); + for (unsigned i = 0; i < (sizeof(T) * 8U); ++i) { + count = UAdd(count, UAnd(UShr(val, Literal(i)), Literal(1))); + } + return count; +} + +ALWAYS_INLINE static uint32_t CRC32Byte(uint32_t crc, uint8_t byte) { + crc = UXor(crc, ZExtTo(byte)); + for (unsigned i = 0; i < 8U; ++i) { + auto low_bit_set = UCmpNeq(UAnd(crc, Literal(1)), 0U); + crc = UShr(crc, 1U); + crc = Select(low_bit_set, UXor(crc, Literal(0x82F63B78U)), crc); + } + return crc; +} + +template +ALWAYS_INLINE static uint32_t CRC32Value(uint32_t crc, T val) { + for (unsigned i = 0; i < sizeof(T); ++i) { + crc = CRC32Byte(crc, + TruncTo(UShr(val, Literal(i * 8U)))); + } + return crc; +} + +template +DEF_SEM(BEXTR, D dst, S1 src1, S2 src2) { + auto val = Read(src1); + auto control = Read(src2); + auto bit_size = BitSizeOf(src1); + auto start = ZExtTo(TruncTo(control)); + auto length = + ZExtTo(TruncTo(UShr(control, Literal(8)))); + auto res = Literal(0); + + if (UCmpLt(start, bit_size) && UCmpNeq(length, 0)) { + auto avail = USub(bit_size, start); + auto use_len = Select(UCmpLt(avail, length), avail, length); + auto mask = LowBitMask(use_len, bit_size); + res = UAnd(UShr(val, start), mask); + } + + WriteZExt(dst, res); + Write(FLAG_CF, false); + Write(FLAG_OF, false); + Write(FLAG_ZF, ZeroFlag(res)); + UndefFlag(sf); + UndefFlag(af); + UndefFlag(pf); + return memory; +} + +template +DEF_SEM(BZHI, D dst, S1 src1, S2 src2) { + auto val = Read(src1); + auto count = ZExtTo(TruncTo(Read(src2))); + auto bit_size = BitSizeOf(src1); + auto out_of_range = !UCmpLt(count, bit_size); + auto mask = LowBitMask(count, bit_size); + auto res = Select(out_of_range, val, UAnd(val, mask)); + + WriteZExt(dst, res); + Write(FLAG_CF, out_of_range); + Write(FLAG_OF, false); + Write(FLAG_ZF, ZeroFlag(res)); + Write(FLAG_SF, SignFlag(res)); + UndefFlag(af); + UndefFlag(pf); + return memory; +} + +template +DEF_SEM(POPCNT, D dst, S src) { + auto val = Read(src); + auto count = PopulationCount(val); + WriteZExt(dst, count); + Write(FLAG_CF, false); + Write(FLAG_PF, false); + Write(FLAG_AF, false); + Write(FLAG_ZF, ZeroFlag(val)); + Write(FLAG_SF, false); + Write(FLAG_OF, false); + return memory; +} + +template +DEF_SEM(PDEP, D dst, S1 src1, S2 src2) { + auto src = Read(src1); + auto mask = Read(src2); + auto res = Literal(0); + unsigned src_index = 0; + + for (unsigned i = 0; i < (sizeof(decltype(src)) * 8U); ++i) { + auto mask_bit = UShl(Literal(1), Literal(i)); + if (UCmpNeq(UAnd(mask, mask_bit), 0)) { + auto src_bit = + UAnd(UShr(src, Literal(src_index)), Literal(1)); + if (UCmpNeq(src_bit, 0)) { + res = UOr(res, mask_bit); + } + ++src_index; + } + } + + WriteZExt(dst, res); + return memory; +} + +template +DEF_SEM(PEXT, D dst, S1 src1, S2 src2) { + auto src = Read(src1); + auto mask = Read(src2); + auto res = Literal(0); + unsigned dst_index = 0; + + for (unsigned i = 0; i < (sizeof(decltype(src)) * 8U); ++i) { + auto mask_bit = UShl(Literal(1), Literal(i)); + if (UCmpNeq(UAnd(mask, mask_bit), 0)) { + auto src_bit = UAnd(UShr(src, Literal(i)), Literal(1)); + if (UCmpNeq(src_bit, 0)) { + res = UOr(res, UShl(Literal(1), Literal(dst_index))); + } + ++dst_index; + } + } + + WriteZExt(dst, res); + return memory; +} + +template +DEF_SEM(CRC32, D dst, S1 src1, S2 src2) { + auto seed = TruncTo(Read(src1)); + auto val = Read(src2); + auto crc = CRC32Value(seed, val); + WriteZExt(dst, crc); + return memory; +} + } // namespace DEF_ISEL(BSWAP_GPRv_16) = BSWAP_16; @@ -335,6 +490,56 @@ DEF_ISEL_RnW_Rn(TZCNT_GPRv_GPRv, TZCNT); DEF_ISEL_RnW_Mn(LZCNT_GPRv_MEMv, LZCNT); DEF_ISEL_RnW_Rn(LZCNT_GPRv_GPRv, LZCNT); +DEF_ISEL(BEXTR_GPR32d_MEMd_GPR32d) = BEXTR; +DEF_ISEL(BEXTR_GPR32d_GPR32d_GPR32d) = BEXTR; +DEF_ISEL(BEXTR_VGPR32d_MEMd_VGPR32d) = BEXTR; +DEF_ISEL(BEXTR_VGPR32d_VGPR32d_VGPR32d) = BEXTR; +IF_64BIT(DEF_ISEL(BEXTR_GPR64q_MEMq_GPR64q) = BEXTR;) +IF_64BIT(DEF_ISEL(BEXTR_GPR64q_GPR64q_GPR64q) = BEXTR;) +IF_64BIT(DEF_ISEL(BEXTR_VGPR64q_MEMq_VGPR64q) = BEXTR;) +IF_64BIT(DEF_ISEL(BEXTR_VGPR64q_VGPR64q_VGPR64q) = BEXTR;) + +DEF_ISEL(BZHI_GPR32d_MEMd_GPR32d) = BZHI; +DEF_ISEL(BZHI_GPR32d_GPR32d_GPR32d) = BZHI; +DEF_ISEL(BZHI_VGPR32d_MEMd_VGPR32d) = BZHI; +DEF_ISEL(BZHI_VGPR32d_VGPR32d_VGPR32d) = BZHI; +IF_64BIT(DEF_ISEL(BZHI_GPR64q_MEMq_GPR64q) = BZHI;) +IF_64BIT(DEF_ISEL(BZHI_GPR64q_GPR64q_GPR64q) = BZHI;) +IF_64BIT(DEF_ISEL(BZHI_VGPR64q_MEMq_VGPR64q) = BZHI;) +IF_64BIT(DEF_ISEL(BZHI_VGPR64q_VGPR64q_VGPR64q) = BZHI;) + +DEF_ISEL_RnW_Mn(POPCNT_GPRv_MEMv, POPCNT); +DEF_ISEL_RnW_Rn(POPCNT_GPRv_GPRv, POPCNT); + +DEF_ISEL(PDEP_GPR32d_GPR32d_MEMd) = PDEP; +DEF_ISEL(PDEP_GPR32d_GPR32d_GPR32d) = PDEP; +DEF_ISEL(PDEP_VGPR32d_VGPR32d_MEMd) = PDEP; +DEF_ISEL(PDEP_VGPR32d_VGPR32d_VGPR32d) = PDEP; +IF_64BIT(DEF_ISEL(PDEP_GPR64q_GPR64q_MEMq) = PDEP;) +IF_64BIT(DEF_ISEL(PDEP_GPR64q_GPR64q_GPR64q) = PDEP;) +IF_64BIT(DEF_ISEL(PDEP_VGPR64q_VGPR64q_MEMq) = PDEP;) +IF_64BIT(DEF_ISEL(PDEP_VGPR64q_VGPR64q_VGPR64q) = PDEP;) + +DEF_ISEL(PEXT_GPR32d_GPR32d_MEMd) = PEXT; +DEF_ISEL(PEXT_GPR32d_GPR32d_GPR32d) = PEXT; +DEF_ISEL(PEXT_VGPR32d_VGPR32d_MEMd) = PEXT; +DEF_ISEL(PEXT_VGPR32d_VGPR32d_VGPR32d) = PEXT; +IF_64BIT(DEF_ISEL(PEXT_GPR64q_GPR64q_MEMq) = PEXT;) +IF_64BIT(DEF_ISEL(PEXT_GPR64q_GPR64q_GPR64q) = PEXT;) +IF_64BIT(DEF_ISEL(PEXT_VGPR64q_VGPR64q_MEMq) = PEXT;) +IF_64BIT(DEF_ISEL(PEXT_VGPR64q_VGPR64q_VGPR64q) = PEXT;) + +DEF_ISEL(CRC32_GPRyy_MEMb_32) = CRC32; +IF_64BIT(DEF_ISEL(CRC32_GPRyy_MEMb_64) = CRC32;) +DEF_ISEL(CRC32_GPRyy_GPR8b_32) = CRC32; +IF_64BIT(DEF_ISEL(CRC32_GPRyy_GPR8b_64) = CRC32;) +DEF_ISEL(CRC32_GPRyy_MEMv_16) = CRC32; +DEF_ISEL(CRC32_GPRyy_MEMv_32) = CRC32; +IF_64BIT(DEF_ISEL(CRC32_GPRyy_MEMv_64) = CRC32;) +DEF_ISEL(CRC32_GPRyy_GPRv_16) = CRC32; +DEF_ISEL(CRC32_GPRyy_GPRv_32) = CRC32; +IF_64BIT(DEF_ISEL(CRC32_GPRyy_GPRv_64) = CRC32;) + namespace { template DEF_SEM(BSR, D dst, S src) { diff --git a/lib/Arch/X86/Semantics/CMOV.cpp b/lib/Arch/X86/Semantics/CMOV.cpp index 90b56164..2959491c 100644 --- a/lib/Arch/X86/Semantics/CMOV.cpp +++ b/lib/Arch/X86/Semantics/CMOV.cpp @@ -52,6 +52,11 @@ DEF_SEM(CMOVNZ, D dst, S1 src1) { return memory; } +template +DEF_SEM(CMOVNE, D dst, S1 src1) { + return CMOVNZ(dst, src1); +} + template DEF_SEM(CMOVNB, D dst, S1 src1) { WriteZExt(dst, Select(__remill_compare_uge(BNot(FLAG_CF)), Read(src1), @@ -94,6 +99,11 @@ DEF_SEM(CMOVZ, D dst, S1 src1) { return memory; } +template +DEF_SEM(CMOVE, D dst, S1 src1) { + return CMOVZ(dst, src1); +} + template DEF_SEM(CMOVP, D dst, S1 src1) { WriteZExt(dst, Select(FLAG_PF, Read(src1), TruncTo(Read(dst)))); @@ -151,6 +161,10 @@ DEF_ISEL_RnW_Mn(CMOVO_GPRv_MEMv, CMOVO); DEF_ISEL_RnW_Rn(CMOVO_GPRv_GPRv, CMOVO); DEF_ISEL_RnW_Mn(CMOVZ_GPRv_MEMv, CMOVZ); DEF_ISEL_RnW_Rn(CMOVZ_GPRv_GPRv, CMOVZ); +DEF_ISEL_RnW_Mn(CMOVE_GPRv_MEMv, CMOVZ); +DEF_ISEL_RnW_Rn(CMOVE_GPRv_GPRv, CMOVZ); +DEF_ISEL_RnW_Mn(CMOVNE_GPRv_MEMv, CMOVNZ); +DEF_ISEL_RnW_Rn(CMOVNE_GPRv_GPRv, CMOVNZ); DEF_ISEL_RnW_Mn(CMOVP_GPRv_MEMv, CMOVP); DEF_ISEL_RnW_Rn(CMOVP_GPRv_GPRv, CMOVP); DEF_ISEL_RnW_Mn(CMOVS_GPRv_MEMv, CMOVS); diff --git a/lib/Arch/X86/Semantics/COND_BR.cpp b/lib/Arch/X86/Semantics/COND_BR.cpp index faebe863..662e0c43 100644 --- a/lib/Arch/X86/Semantics/COND_BR.cpp +++ b/lib/Arch/X86/Semantics/COND_BR.cpp @@ -213,6 +213,12 @@ DEF_ISEL(JNZ_RELBRz_16) = JNZ; DEF_ISEL(JNZ_RELBRz_32) = JNZ; IF_64BIT(DEF_ISEL(JNZ_RELBRz_64) = JNZ;) DEF_ISEL(JNZ_RELBRd) = JNZ; +DEF_ISEL(JNE_RELBRb) = JNZ; +DEF_ISEL(JNE_RELBRz_8) = JNZ; +DEF_ISEL(JNE_RELBRz_16) = JNZ; +DEF_ISEL(JNE_RELBRz_32) = JNZ; +IF_64BIT(DEF_ISEL(JNE_RELBRz_64) = JNZ;) +DEF_ISEL(JNE_RELBRd) = JNZ; DEF_ISEL(JNB_RELBRb) = JNB; DEF_ISEL(JNB_RELBRz_8) = JNB; @@ -220,6 +226,12 @@ DEF_ISEL(JNB_RELBRz_16) = JNB; DEF_ISEL(JNB_RELBRz_32) = JNB; IF_64BIT(DEF_ISEL(JNB_RELBRz_64) = JNB;) DEF_ISEL(JNB_RELBRd) = JNB; +DEF_ISEL(JAE_RELBRb) = JNB; +DEF_ISEL(JAE_RELBRz_8) = JNB; +DEF_ISEL(JAE_RELBRz_16) = JNB; +DEF_ISEL(JAE_RELBRz_32) = JNB; +IF_64BIT(DEF_ISEL(JAE_RELBRz_64) = JNB;) +DEF_ISEL(JAE_RELBRd) = JNB; DEF_ISEL(JNO_RELBRb) = JNO; DEF_ISEL(JNO_RELBRz_8) = JNO; @@ -255,6 +267,12 @@ DEF_ISEL(JZ_RELBRz_16) = JZ; DEF_ISEL(JZ_RELBRz_32) = JZ; IF_64BIT(DEF_ISEL(JZ_RELBRz_64) = JZ;) DEF_ISEL(JZ_RELBRd) = JZ; +DEF_ISEL(JE_RELBRb) = JZ; +DEF_ISEL(JE_RELBRz_8) = JZ; +DEF_ISEL(JE_RELBRz_16) = JZ; +DEF_ISEL(JE_RELBRz_32) = JZ; +IF_64BIT(DEF_ISEL(JE_RELBRz_64) = JZ;) +DEF_ISEL(JE_RELBRd) = JZ; DEF_ISEL(JP_RELBRb) = JP; DEF_ISEL(JP_RELBRz_8) = JP; diff --git a/lib/Arch/X86/Semantics/LOGICAL.cpp b/lib/Arch/X86/Semantics/LOGICAL.cpp index 4d62cbd1..6e971e00 100644 --- a/lib/Arch/X86/Semantics/LOGICAL.cpp +++ b/lib/Arch/X86/Semantics/LOGICAL.cpp @@ -38,6 +38,18 @@ DEF_SEM(AND, D dst, S1 src1, S2 src2) { return memory; } +template +DEF_SEM(ANDN, D dst, S1 src1, S2 src2) { + auto lhs = Read(src1); + auto rhs = Read(src2); + auto res = UAnd(UNot(lhs), rhs); + WriteZExt(dst, res); + SetFlagsLogical(state, lhs, rhs, res); + UndefFlag(af); + UndefFlag(pf); + return memory; +} + template DEF_SEM(OR, D dst, S1 src1, S2 src2) { auto lhs = Read(src1); @@ -97,6 +109,15 @@ DEF_ISEL_RnW_Rn_Mn(AND_GPRv_MEMv, AND); DEF_ISEL(AND_AL_IMMb) = AND; DEF_ISEL_RnW_Rn_In(AND_OrAX_IMMz, AND); +DEF_ISEL(ANDN_GPR32d_GPR32d_MEMd) = ANDN; +DEF_ISEL(ANDN_GPR32d_GPR32d_GPR32d) = ANDN; +DEF_ISEL(ANDN_VGPR32d_VGPR32d_MEMd) = ANDN; +DEF_ISEL(ANDN_VGPR32d_VGPR32d_VGPR32d) = ANDN; +IF_64BIT(DEF_ISEL(ANDN_GPR64q_GPR64q_MEMq) = ANDN;) +IF_64BIT(DEF_ISEL(ANDN_GPR64q_GPR64q_GPR64q) = ANDN;) +IF_64BIT(DEF_ISEL(ANDN_VGPR64q_VGPR64q_MEMq) = ANDN;) +IF_64BIT(DEF_ISEL(ANDN_VGPR64q_VGPR64q_VGPR64q) = ANDN;) + DEF_ISEL(OR_MEMb_IMMb_80r1) = OR; DEF_ISEL(OR_GPR8_IMMb_80r1) = OR; DEF_ISEL_MnW_Mn_In(OR_MEMv_IMMz, OR); diff --git a/lib/Arch/X86/Semantics/SHIFT.cpp b/lib/Arch/X86/Semantics/SHIFT.cpp index cc462849..43a70061 100644 --- a/lib/Arch/X86/Semantics/SHIFT.cpp +++ b/lib/Arch/X86/Semantics/SHIFT.cpp @@ -148,9 +148,8 @@ DEF_SEM(SHL, D dst, S1 src1, S2 src2) { new_val = UShl(res, 1); } else { - new_of = BUndefined(); // Undefined, probably 1. - // TODO(lukas): Double check. - new_cf = 0; // Undefined, probably 0. + new_of = BUndefined(); + new_cf = BUndefined(); new_val = 0; } @@ -163,6 +162,19 @@ DEF_SEM(SHL, D dst, S1 src1, S2 src2) { Write(FLAG_OF, new_of); return memory; } + +template +DEF_SEM(SHLX, D dst, S1 src1, S2 src2) { + auto val = Read(src1); + auto shift = ZExtTo(TruncTo(Read(src2))); + auto long_mask = Literal(0x3F); + auto short_mask = Literal(0x1F); + auto op_size = BitSizeOf(src1); + auto shift_mask = Select(UCmpEq(op_size, 64), long_mask, short_mask); + auto masked_shift = UAnd(shift, shift_mask); + WriteZExt(dst, UShl(val, masked_shift)); + return memory; +} } // namespace DEF_ISEL(SHR_MEMb_IMMb) = SHR; @@ -216,6 +228,15 @@ DEF_ISEL_RnW_Rn_Rn(SHL_GPRv_CL_D3r4, SHL); DEF_ISEL_MnW_Mn_Rn(SHL_MEMv_CL_D3r6, SHL); DEF_ISEL_RnW_Rn_Rn(SHL_GPRv_CL_D3r6, SHL); +DEF_ISEL(SHLX_GPR32d_MEMd_GPR32d) = SHLX; +DEF_ISEL(SHLX_GPR32d_GPR32d_GPR32d) = SHLX; +DEF_ISEL(SHLX_VGPR32d_MEMd_VGPR32d) = SHLX; +DEF_ISEL(SHLX_VGPR32d_VGPR32d_VGPR32d) = SHLX; +IF_64BIT(DEF_ISEL(SHLX_GPR64q_MEMq_GPR64q) = SHLX;) +IF_64BIT(DEF_ISEL(SHLX_GPR64q_GPR64q_GPR64q) = SHLX;) +IF_64BIT(DEF_ISEL(SHLX_VGPR64q_MEMq_VGPR64q) = SHLX;) +IF_64BIT(DEF_ISEL(SHLX_VGPR64q_VGPR64q_VGPR64q) = SHLX;) + namespace { template @@ -262,9 +283,11 @@ DEF_SEM(SHRD, D dst, S1 src1, S2 src2, S3 src3) { Write(FLAG_AF, BUndefined()); Write(FLAG_ZF, ZeroFlag(res)); Write(FLAG_SF, SignFlag(res)); - Write(FLAG_OF, BXor(SignFlag(val1), FLAG_SF)); - - // OF undefined for `1 == temp_count`. + if (UCmpEq(masked_shift, Literal(1))) { + Write(FLAG_OF, BXor(SignFlag(val1), FLAG_SF)); + } else { + Write(FLAG_OF, BUndefined()); + } return memory; } @@ -322,9 +345,11 @@ DEF_SEM(SHLD, D dst, S1 src1, S2 src2, S3 src3) { Write(FLAG_AF, BUndefined()); Write(FLAG_ZF, ZeroFlag(res)); Write(FLAG_SF, SignFlag(res)); - Write(FLAG_OF, BXor(SignFlag(val1), FLAG_SF)); - - // OF undefined for `1 == temp_count`. + if (UCmpEq(masked_shift, Literal(1))) { + Write(FLAG_OF, BXor(SignFlag(val1), FLAG_SF)); + } else { + Write(FLAG_OF, BUndefined()); + } return memory; } diff --git a/lib/Arch/X86/Semantics/SSE.cpp b/lib/Arch/X86/Semantics/SSE.cpp index f52ef3f2..50b6df6f 100644 --- a/lib/Arch/X86/Semantics/SSE.cpp +++ b/lib/Arch/X86/Semantics/SSE.cpp @@ -1682,15 +1682,17 @@ IF_AVX(DEF_ISEL(VMOVSHDUP_YMMqq_YMMqq) = MOVSHDUP;) namespace { -template -DEF_SEM(SQRTSS, D dst, D _nop_read, S1 src1) { +template +DEF_SEM(SQRTSS, D dst, S1 src1, S2 src2) { - // Extract a "single-precision" (32-bit) float from [31:0] of src1 vector: - auto src_float = FExtractV32(FReadV32(src1), 0); + // Extract a "single-precision" (32-bit) float from [31:0] of src2 vector: + auto src_float = FExtractV32(FReadV32(src2), 0); - // Store the square root result in dest[32:0]: + // Initialize dest vector, while also copying src1[127:32] -> dst[127:32]. + auto temp_vec = FReadV32(src1); + + // Store the square root result in dest[31:0]: auto square_root = SquareRoot32(memory, state, src_float); - auto temp_vec = FReadV32(dst); // initialize a destination vector temp_vec = FInsertV32(temp_vec, 0, square_root); // Write out the result and return memory state: @@ -1698,15 +1700,17 @@ DEF_SEM(SQRTSS, D dst, D _nop_read, S1 src1) { return memory; } -template -DEF_SEM(RSQRTSS, D dst, D _nop_read, S1 src1) { +template +DEF_SEM(RSQRTSS, D dst, S1 src1, S2 src2) { - // Extract a "single-precision" (32-bit) float from [31:0] of src1 vector: - auto src_float = FExtractV32(FReadV32(src1), 0); + // Extract a "single-precision" (32-bit) float from [31:0] of src2 vector: + auto src_float = FExtractV32(FReadV32(src2), 0); - // Store the square root result in dest[32:0]: + // Initialize dest vector, while also copying src1[127:32] -> dst[127:32]. + auto temp_vec = FReadV32(src1); + + // Store the square root result in dest[31:0]: auto square_root = SquareRoot32(memory, state, src_float); - auto temp_vec = FReadV32(dst); // initialize a destination vector temp_vec = FInsertV32(temp_vec, 0, FDiv(1.0f, square_root)); // Write out the result and return memory state: @@ -1753,8 +1757,8 @@ DEF_SEM(VRSQRTSS, D dst, S1 src1, S2 src2) { #endif // HAS_FEATURE_AVX } // namespace -DEF_ISEL(SQRTSS_XMMss_MEMss) = SQRTSS; -DEF_ISEL(SQRTSS_XMMss_XMMss) = SQRTSS; +DEF_ISEL(SQRTSS_XMMss_MEMss) = SQRTSS; +DEF_ISEL(SQRTSS_XMMss_XMMss) = SQRTSS; IF_AVX(DEF_ISEL(VSQRTSS_XMMdq_XMMdq_MEMd) = VSQRTSS;) IF_AVX(DEF_ISEL(VSQRTSS_XMMdq_XMMdq_XMMd) = VSQRTSS;) /* @@ -1763,8 +1767,8 @@ IF_AVX(DEF_ISEL(VSQRTSS_XMMdq_XMMdq_XMMd) = VSQRTSS;) 4318 VSQRTSS VSQRTSS_XMMf32_MASKmskw_XMMf32_MEMf32_AVX512 AVX512 AVX512EVEX AVX512F_SCALAR ATTRIBUTES: DISP8_SCALAR MASKOP_EVEX MEMORY_FAULT_SUPPRESSION MXCSR SIMD_SCALAR */ -DEF_ISEL(RSQRTSS_XMMss_MEMss) = RSQRTSS; -DEF_ISEL(RSQRTSS_XMMss_XMMss) = RSQRTSS; +DEF_ISEL(RSQRTSS_XMMss_MEMss) = RSQRTSS; +DEF_ISEL(RSQRTSS_XMMss_XMMss) = RSQRTSS; IF_AVX(DEF_ISEL(VRSQRTSS_XMMdq_XMMdq_MEMd) = VRSQRTSS;) IF_AVX(DEF_ISEL(VRSQRTSS_XMMdq_XMMdq_XMMd) = VRSQRTSS;) @@ -1801,15 +1805,17 @@ DEF_HELPER(SquareRoot64, float64_t src_float)->float64_t { return square_root; } -template -DEF_SEM(SQRTSD, D dst, D _nop_read, S1 src1) { +template +DEF_SEM(SQRTSD, D dst, S1 src1, S2 src2) { - // Extract a "double-precision" (64-bit) float from [63:0] of src1 vector: - auto src_float = FExtractV64(FReadV64(src1), 0); + // Extract a "double-precision" (64-bit) float from [63:0] of src2 vector: + auto src_float = FExtractV64(FReadV64(src2), 0); + + // Initialize dest vector, while also copying src1[127:64] -> dst[127:64]. + auto temp_vec = FReadV64(src1); // Store the square root result in dest[63:0]: auto square_root = SquareRoot64(memory, state, src_float); - auto temp_vec = FReadV64(dst); // initialize a destination vector temp_vec = FInsertV64(temp_vec, 0, square_root); // Write out the result and return memory state: @@ -1839,8 +1845,8 @@ DEF_SEM(VSQRTSD, D dst, S1 src1, S2 src2) { } // namespace -DEF_ISEL(SQRTSD_XMMsd_MEMsd) = SQRTSD; -DEF_ISEL(SQRTSD_XMMsd_XMMsd) = SQRTSD; +DEF_ISEL(SQRTSD_XMMsd_MEMsd) = SQRTSD; +DEF_ISEL(SQRTSD_XMMsd_XMMsd) = SQRTSD; IF_AVX(DEF_ISEL(VSQRTSD_XMMdq_XMMdq_MEMq) = VSQRTSD;) IF_AVX(DEF_ISEL(VSQRTSD_XMMdq_XMMdq_XMMq) = VSQRTSD;) /* diff --git a/lib/Arch/X86/Semantics/SYSTEM.cpp b/lib/Arch/X86/Semantics/SYSTEM.cpp index e47490c8..cf8d7249 100644 --- a/lib/Arch/X86/Semantics/SYSTEM.cpp +++ b/lib/Arch/X86/Semantics/SYSTEM.cpp @@ -24,6 +24,24 @@ DEF_SEM(DoRDTSCP) { return __remill_sync_hyper_call(state, memory, SyncHyperCall::kX86ReadTSCP); } +template +DEF_SEM(LAR, D dst, S src) { + auto old_dst = Read(dst); + state.addr_to_load = ZExtTo(TruncTo(Read(src))); + memory = + __remill_sync_hyper_call(state, memory, SyncHyperCall::kX86LoadAccessRights); + auto new_dst = static_cast(state.addr_to_store); + Write(dst, Select(FLAG_ZF, new_dst, old_dst)); + return memory; +} + +template +DEF_SEM(VERR, S src) { + state.addr_to_load = ZExtTo(TruncTo(Read(src))); + return __remill_sync_hyper_call(state, memory, + SyncHyperCall::kX86VerifySegmentReadable); +} + DEF_SEM(LGDT, M32 src) { memory = __remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged); @@ -161,6 +179,12 @@ DEF_ISEL(WRMSR) = DoWRMSR; DEF_ISEL(WBINVD) = DoWBINVD; DEF_ISEL(LGDT_MEMs_32) = LGDT; DEF_ISEL(LIDT_MEMs_32) = LIDT; +DEF_ISEL(LAR_GPRv_MEMw_32) = LAR; +IF_64BIT(DEF_ISEL(LAR_GPRv_MEMw_64) = LAR;) +DEF_ISEL(LAR_GPRv_GPRv_32) = LAR; +IF_64BIT(DEF_ISEL(LAR_GPRv_GPRv_64) = LAR;) +DEF_ISEL(VERR_MEMw) = VERR; +DEF_ISEL(VERR_GPR16) = VERR; DEF_ISEL(MOV_CR_CR_GPR32_CR0) = WRITE_CONTROL_REG_32; DEF_ISEL(MOV_CR_CR_GPR32_CR1) = diff --git a/lib/Arch/X86/Semantics/XSAVE.cpp b/lib/Arch/X86/Semantics/XSAVE.cpp index 060f7b18..087e9fc8 100644 --- a/lib/Arch/X86/Semantics/XSAVE.cpp +++ b/lib/Arch/X86/Semantics/XSAVE.cpp @@ -35,6 +35,8 @@ DEF_SEM(DoXGETBV, PC next_pc) { 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; } diff --git a/tests/X86/BITBYTE/BEXTR.S b/tests/X86/BITBYTE/BEXTR.S new file mode 100644 index 00000000..db07bc73 --- /dev/null +++ b/tests/X86/BITBYTE/BEXTR.S @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(BEXTRr32r32, 2) +TEST_IGNORE_FLAGS(AF PF SF) +TEST_INPUTS( + 0x12345678, 0x0000, + 0x12345678, 0x0804, + 0x12345678, 0x0408, + 0xFFFFFFFF, 0x2000, + 0x80000000, 0x2000, + 0x0000FFFF, 0x1008, + 0xDEADBEEF, 0x4000) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz bextr_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + bextr edx, eax, ebx + +bextr_nop1: nop +TEST_END + +TEST_BEGIN_MEM(BEXTRr32m32, 2) +TEST_IGNORE_FLAGS(AF PF SF) +TEST_INPUTS( + 0x12345678, 0x0000, + 0x12345678, 0x0804, + 0x12345678, 0x0408, + 0xFFFFFFFF, 0x2000, + 0x80000000, 0x2000, + 0x0000FFFF, 0x1008, + 0xDEADBEEF, 0x4000) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz bextr_nop2 + + mov DWORD PTR [rsp - 8], ARG1_32 + mov ebx, ARG2_32 + bextr edx, DWORD PTR [rsp - 8], ebx + +bextr_nop2: nop +TEST_END_MEM + +TEST_BEGIN_64(BEXTRr64r64, 2) +TEST_IGNORE_FLAGS(AF PF SF) +TEST_INPUTS( + 0x123456789ABCDEF0, 0x0000, + 0x123456789ABCDEF0, 0x0804, + 0x123456789ABCDEF0, 0x1010, + 0xFFFFFFFFFFFFFFFF, 0x4000, + 0x8000000000000000, 0x4000, + 0x00000000FFFFFFFF, 0x2010, + 0xDEADBEEFCAFEBABE, 0x8000) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz bextr_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + bextr rdx, rax, rbx + +bextr_nop3: nop +TEST_END_64 + +TEST_BEGIN_MEM_64(BEXTRr64m64, 2) +TEST_IGNORE_FLAGS(AF PF SF) +TEST_INPUTS( + 0x123456789ABCDEF0, 0x0000, + 0x123456789ABCDEF0, 0x0804, + 0x123456789ABCDEF0, 0x1010, + 0xFFFFFFFFFFFFFFFF, 0x4000, + 0x8000000000000000, 0x4000, + 0x00000000FFFFFFFF, 0x2010, + 0xDEADBEEFCAFEBABE, 0x8000) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz bextr_nop4 + + mov QWORD PTR [rsp - 8], ARG1_64 + mov rbx, ARG2_64 + bextr rdx, QWORD PTR [rsp - 8], rbx + +bextr_nop4: nop +TEST_END_MEM_64 diff --git a/tests/X86/BITBYTE/BZHI.S b/tests/X86/BITBYTE/BZHI.S new file mode 100644 index 00000000..0864a983 --- /dev/null +++ b/tests/X86/BITBYTE/BZHI.S @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(BZHIr32r32, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0x12345678, 0, + 0x12345678, 4, + 0x12345678, 8, + 0x12345678, 31, + 0x12345678, 32, + 0x12345678, 40, + 0x12345678, 256, + 0xFFFFFFFF, 1, + 0x80000000, 31) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz bzhi_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + bzhi edx, eax, ebx + +bzhi_nop1: nop +TEST_END + +TEST_BEGIN_MEM(BZHIr32m32, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0x12345678, 0, + 0x12345678, 4, + 0x12345678, 8, + 0x12345678, 31, + 0x12345678, 32, + 0x12345678, 40, + 0x12345678, 256, + 0xFFFFFFFF, 1, + 0x80000000, 31) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz bzhi_nop2 + + mov DWORD PTR [rsp - 8], ARG1_32 + mov ebx, ARG2_32 + bzhi edx, DWORD PTR [rsp - 8], ebx + +bzhi_nop2: nop +TEST_END_MEM + +TEST_BEGIN_64(BZHIr64r64, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0x123456789ABCDEF0, 0, + 0x123456789ABCDEF0, 4, + 0x123456789ABCDEF0, 8, + 0x123456789ABCDEF0, 63, + 0x123456789ABCDEF0, 64, + 0x123456789ABCDEF0, 72, + 0x123456789ABCDEF0, 256, + 0xFFFFFFFFFFFFFFFF, 1, + 0x8000000000000000, 63) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz bzhi_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + bzhi rdx, rax, rbx + +bzhi_nop3: nop +TEST_END_64 + +TEST_BEGIN_MEM_64(BZHIr64m64, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0x123456789ABCDEF0, 0, + 0x123456789ABCDEF0, 4, + 0x123456789ABCDEF0, 8, + 0x123456789ABCDEF0, 63, + 0x123456789ABCDEF0, 64, + 0x123456789ABCDEF0, 72, + 0x123456789ABCDEF0, 256, + 0xFFFFFFFFFFFFFFFF, 1, + 0x8000000000000000, 63) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz bzhi_nop4 + + mov QWORD PTR [rsp - 8], ARG1_64 + mov rbx, ARG2_64 + bzhi rdx, QWORD PTR [rsp - 8], rbx + +bzhi_nop4: nop +TEST_END_MEM_64 diff --git a/tests/X86/BITBYTE/CRC32.S b/tests/X86/BITBYTE/CRC32.S new file mode 100644 index 00000000..e22f40f1 --- /dev/null +++ b/tests/X86/BITBYTE/CRC32.S @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(CRC32r32r8, 2) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFF, 0xFF, + 0x12345678, 0xAB, + 0x89ABCDEF, 0x80, + 0xDEADBEEF, 0x01) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00100000 + jz crc32_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + crc32 eax, bl + +crc32_nop1: nop +TEST_END + +TEST_BEGIN(CRC32r32r32, 2) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFF, 0xFFFFFFFF, + 0x12345678, 0xABCDEF01, + 0x89ABCDEF, 0x80000000, + 0xDEADBEEF, 0x01020304) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00100000 + jz crc32_nop2 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + crc32 eax, ebx + +crc32_nop2: nop +TEST_END + +TEST_BEGIN_64(CRC32r64r8, 2) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFFFFFFFFFF, 0xFF, + 0x123456789ABCDEF0, 0xAB, + 0x89ABCDEF01234567, 0x80, + 0xDEADBEEFCAFEBABE, 0x01) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00100000 + jz crc32_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + crc32 rax, bl + +crc32_nop3: nop +TEST_END_64 + +TEST_BEGIN_64(CRC32r64r64, 2) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0xABCDEF0102030405, + 0x89ABCDEF01234567, 0x8000000000000000, + 0xDEADBEEFCAFEBABE, 0x0102030405060708) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00100000 + jz crc32_nop4 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + crc32 rax, rbx + +crc32_nop4: nop +TEST_END_64 diff --git a/tests/X86/BITBYTE/PDEP.S b/tests/X86/BITBYTE/PDEP.S new file mode 100644 index 00000000..38ae3e3c --- /dev/null +++ b/tests/X86/BITBYTE/PDEP.S @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(PDEPr32r32, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFF, + 0x12345678, 0x0F0F0F0F, + 0xFFFFFFFF, 0x55555555, + 0xAAAAAAAA, 0x33333333, + 0xDEADBEEF, 0x80000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pdep_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + pdep edx, eax, ebx + +pdep_nop1: nop +TEST_END + +TEST_BEGIN_MEM(PDEPr32m32, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFF, + 0x12345678, 0x0F0F0F0F, + 0xFFFFFFFF, 0x55555555, + 0xAAAAAAAA, 0x33333333, + 0xDEADBEEF, 0x80000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pdep_nop2 + + mov eax, ARG1_32 + mov DWORD PTR [rsp - 8], ARG2_32 + pdep edx, eax, DWORD PTR [rsp - 8] + +pdep_nop2: nop +TEST_END_MEM + +TEST_BEGIN_64(PDEPr64r64, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0x0F0F0F0F0F0F0F0F, + 0xFFFFFFFFFFFFFFFF, 0x5555555555555555, + 0xAAAAAAAAAAAAAAAA, 0x3333333333333333, + 0xDEADBEEFCAFEBABE, 0x8000000000000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pdep_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + pdep rdx, rax, rbx + +pdep_nop3: nop +TEST_END_64 + +TEST_BEGIN_MEM_64(PDEPr64m64, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0x0F0F0F0F0F0F0F0F, + 0xFFFFFFFFFFFFFFFF, 0x5555555555555555, + 0xAAAAAAAAAAAAAAAA, 0x3333333333333333, + 0xDEADBEEFCAFEBABE, 0x8000000000000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pdep_nop4 + + mov rax, ARG1_64 + mov QWORD PTR [rsp - 8], ARG2_64 + pdep rdx, rax, QWORD PTR [rsp - 8] + +pdep_nop4: nop +TEST_END_MEM_64 diff --git a/tests/X86/BITBYTE/PEXT.S b/tests/X86/BITBYTE/PEXT.S new file mode 100644 index 00000000..f59605a5 --- /dev/null +++ b/tests/X86/BITBYTE/PEXT.S @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(PEXTr32r32, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFF, + 0x12345678, 0x0F0F0F0F, + 0xFFFFFFFF, 0x55555555, + 0xAAAAAAAA, 0x33333333, + 0xDEADBEEF, 0x80000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pext_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + pext edx, eax, ebx + +pext_nop1: nop +TEST_END + +TEST_BEGIN_MEM(PEXTr32m32, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFF, + 0x12345678, 0x0F0F0F0F, + 0xFFFFFFFF, 0x55555555, + 0xAAAAAAAA, 0x33333333, + 0xDEADBEEF, 0x80000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pext_nop2 + + mov eax, ARG1_32 + mov DWORD PTR [rsp - 8], ARG2_32 + pext edx, eax, DWORD PTR [rsp - 8] + +pext_nop2: nop +TEST_END_MEM + +TEST_BEGIN_64(PEXTr64r64, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0x0F0F0F0F0F0F0F0F, + 0xFFFFFFFFFFFFFFFF, 0x5555555555555555, + 0xAAAAAAAAAAAAAAAA, 0x3333333333333333, + 0xDEADBEEFCAFEBABE, 0x8000000000000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pext_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + pext rdx, rax, rbx + +pext_nop3: nop +TEST_END_64 + +TEST_BEGIN_MEM_64(PEXTr64m64, 2) +TEST_INPUTS( + 0, 0, + 1, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0x0F0F0F0F0F0F0F0F, + 0xFFFFFFFFFFFFFFFF, 0x5555555555555555, + 0xAAAAAAAAAAAAAAAA, 0x3333333333333333, + 0xDEADBEEFCAFEBABE, 0x8000000000000001) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz pext_nop4 + + mov rax, ARG1_64 + mov QWORD PTR [rsp - 8], ARG2_64 + pext rdx, rax, QWORD PTR [rsp - 8] + +pext_nop4: nop +TEST_END_MEM_64 diff --git a/tests/X86/BITBYTE/POPCNT.S b/tests/X86/BITBYTE/POPCNT.S new file mode 100644 index 00000000..5a1d5af0 --- /dev/null +++ b/tests/X86/BITBYTE/POPCNT.S @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(POPCNTr16r16, 1) +TEST_INPUTS( + 0, + 1, + 0x8000, + 0xFFFF, + 0x1234, + 0xAAAA, + 0x5555) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00800000 + jz popcnt_nop1 + + mov eax, ARG1_32 + popcnt dx, ax + +popcnt_nop1: nop +TEST_END + +TEST_BEGIN(POPCNTr32r32, 1) +TEST_INPUTS( + 0, + 1, + 0x80000000, + 0xFFFFFFFF, + 0x12345678, + 0xAAAAAAAA, + 0x55555555) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00800000 + jz popcnt_nop2 + + mov eax, ARG1_32 + popcnt edx, eax + +popcnt_nop2: nop +TEST_END + +TEST_BEGIN_64(POPCNTr64r64, 1) +TEST_INPUTS( + 0, + 1, + 0x8000000000000000, + 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, + 0xAAAAAAAAAAAAAAAA, + 0x5555555555555555) + + mov eax, 0x00000001 + cpuid + test ecx, 0x00800000 + jz popcnt_nop3 + + mov rax, ARG1_64 + popcnt rdx, rax + +popcnt_nop3: nop +TEST_END_64 diff --git a/tests/X86/BITBYTE/SETE.S b/tests/X86/BITBYTE/SETE.S new file mode 100644 index 00000000..ad217e51 --- /dev/null +++ b/tests/X86/BITBYTE/SETE.S @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(SETEr8, 1) +TEST_INPUTS(0) + sete al +TEST_END diff --git a/tests/X86/BRANCH/CALL.S b/tests/X86/BRANCH/CALL.S new file mode 100644 index 00000000..2917909f --- /dev/null +++ b/tests/X86/BRANCH/CALL.S @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(CALLrel, 1) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0x7FFFFFFF) + + mov RET_32, ARG1_32 + call call_target1 + jmp call_done1 +call_target1: + add RET_32, ARG1_32 + ret +call_done1: + nop +TEST_END diff --git a/tests/X86/BRANCH/JAE.S b/tests/X86/BRANCH/JAE.S new file mode 100644 index 00000000..b1869ccf --- /dev/null +++ b/tests/X86/BRANCH/JAE.S @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(JAEr32, 2) +TEST_INPUTS( + 0, 0, + 1, 0, + 0, 1, + 0x12345678, 0x12345678, + 0xFFFFFFFF, 0x7FFFFFFF) + + mov eax, ARG1_32 + cmp eax, ARG2_32 + mov RET_32, 0 + jae jae_taken1 + mov RET_32, 1 + jmp jae_done1 +jae_taken1: + mov RET_32, 2 +jae_done1: + nop +TEST_END diff --git a/tests/X86/BRANCH/JE.S b/tests/X86/BRANCH/JE.S new file mode 100644 index 00000000..17314119 --- /dev/null +++ b/tests/X86/BRANCH/JE.S @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(JEr32, 2) +TEST_INPUTS( + 0, 0, + 1, 0, + 0, 1, + 0x12345678, 0x12345678, + 0xFFFFFFFF, 0xFFFFFFFF) + + mov eax, ARG1_32 + cmp eax, ARG2_32 + mov RET_32, 0 + je je_taken1 + mov RET_32, 1 + jmp je_done1 +je_taken1: + mov RET_32, 2 +je_done1: + nop +TEST_END diff --git a/tests/X86/BRANCH/JMP.S b/tests/X86/BRANCH/JMP.S new file mode 100644 index 00000000..7e44f5aa --- /dev/null +++ b/tests/X86/BRANCH/JMP.S @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(JMPrel, 1) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0xFFFFFFFF) + + jmp jmp_target1 + mov RET_32, 0xDEADBEEF +jmp_target1: + mov RET_32, ARG1_32 +TEST_END diff --git a/tests/X86/BRANCH/JNE.S b/tests/X86/BRANCH/JNE.S new file mode 100644 index 00000000..b5a8f8e2 --- /dev/null +++ b/tests/X86/BRANCH/JNE.S @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(JNEr32, 2) +TEST_INPUTS( + 0, 0, + 1, 0, + 0, 1, + 0x12345678, 0x12345678, + 0xFFFFFFFF, 0xFFFFFFFF) + + mov eax, ARG1_32 + cmp eax, ARG2_32 + mov RET_32, 0 + jne jne_taken1 + mov RET_32, 1 + jmp jne_done1 +jne_taken1: + mov RET_32, 2 +jne_done1: + nop +TEST_END diff --git a/tests/X86/BRANCH/RET.S b/tests/X86/BRANCH/RET.S new file mode 100644 index 00000000..d9450d92 --- /dev/null +++ b/tests/X86/BRANCH/RET.S @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(RETnear, 1) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0x7FFFFFFF) + + mov RET_32, ARG1_32 + call ret_target1 + add RET_32, 1 + jmp ret_done1 +ret_target1: + add RET_32, ARG1_32 + ret +ret_done1: + nop +TEST_END diff --git a/tests/X86/CMOV/CMOVE.S b/tests/X86/CMOV/CMOVE.S new file mode 100644 index 00000000..64ccd38e --- /dev/null +++ b/tests/X86/CMOV/CMOVE.S @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(CMOVEr16r16, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmove ARG2_16, ARG1_16 +TEST_END + +TEST_BEGIN(CMOVEr32r32, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmove ARG2_32, ARG1_32 +TEST_END + +TEST_BEGIN_64(CMOVEr64r64, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmove ARG2_64, ARG1_64 +TEST_END_64 + +TEST_BEGIN_64(CMOVEr16m16, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmove ARG2_16, WORD PTR [rsp - 8] +TEST_END_64 + +TEST_BEGIN_64(CMOVEr32m32, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmove ARG2_32, DWORD PTR [rsp - 8] +TEST_END_64 + +TEST_BEGIN_64(CMOVEr64m64, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmove ARG2_64, QWORD PTR [rsp - 8] +TEST_END_64 diff --git a/tests/X86/CMOV/CMOVNE.S b/tests/X86/CMOV/CMOVNE.S new file mode 100644 index 00000000..4e8349b5 --- /dev/null +++ b/tests/X86/CMOV/CMOVNE.S @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(CMOVNEr16r16, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmovne ARG2_16, ARG1_16 +TEST_END + +TEST_BEGIN(CMOVNEr32r32, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmovne ARG2_32, ARG1_32 +TEST_END + +TEST_BEGIN_64(CMOVNEr64r64, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmovne ARG2_64, ARG1_64 +TEST_END_64 + +TEST_BEGIN_64(CMOVNEr16m16, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmovne ARG2_16, WORD PTR [rsp - 8] +TEST_END_64 + +TEST_BEGIN_64(CMOVNEr32m32, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmovne ARG2_32, DWORD PTR [rsp - 8] +TEST_END_64 + +TEST_BEGIN_64(CMOVNEr64m64, 1) +TEST_INPUTS( + 0x4141414141414141) + + cmovne ARG2_64, QWORD PTR [rsp - 8] +TEST_END_64 diff --git a/tests/X86/INTERRUPT/INT3.S b/tests/X86/INTERRUPT/INT3.S new file mode 100644 index 00000000..19c30f1c --- /dev/null +++ b/tests/X86/INTERRUPT/INT3.S @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(INT3basic, 1) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0xFFFFFFFF) + + int3 +TEST_END diff --git a/tests/X86/LOGICAL/ANDN.S b/tests/X86/LOGICAL/ANDN.S new file mode 100644 index 00000000..85a2e60b --- /dev/null +++ b/tests/X86/LOGICAL/ANDN.S @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(ANDNr32r32, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFF, 0, + 0, 0xFFFFFFFF, + 0x12345678, 0x0F0F0F0F, + 0x80000000, 0xFFFFFFFF, + 0xAAAAAAAA, 0x55555555) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz andn_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + andn edx, eax, ebx + +andn_nop1: nop +TEST_END + +TEST_BEGIN_MEM(ANDNr32m32, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFF, 0, + 0, 0xFFFFFFFF, + 0x12345678, 0x0F0F0F0F, + 0x80000000, 0xFFFFFFFF, + 0xAAAAAAAA, 0x55555555) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz andn_nop2 + + mov eax, ARG1_32 + mov DWORD PTR [rsp - 8], ARG2_32 + andn edx, eax, DWORD PTR [rsp - 8] + +andn_nop2: nop +TEST_END_MEM + +TEST_BEGIN_64(ANDNr64r64, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFFFFFFFFFF, 0, + 0, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0x0F0F0F0F0F0F0F0F, + 0x8000000000000000, 0xFFFFFFFFFFFFFFFF, + 0xAAAAAAAAAAAAAAAA, 0x5555555555555555) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz andn_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + andn rdx, rax, rbx + +andn_nop3: nop +TEST_END_64 + +TEST_BEGIN_MEM_64(ANDNr64m64, 2) +TEST_IGNORE_FLAGS(AF PF) +TEST_INPUTS( + 0, 0, + 0xFFFFFFFFFFFFFFFF, 0, + 0, 0xFFFFFFFFFFFFFFFF, + 0x123456789ABCDEF0, 0x0F0F0F0F0F0F0F0F, + 0x8000000000000000, 0xFFFFFFFFFFFFFFFF, + 0xAAAAAAAAAAAAAAAA, 0x5555555555555555) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000008 + jz andn_nop4 + + mov rax, ARG1_64 + mov QWORD PTR [rsp - 8], ARG2_64 + andn rdx, rax, QWORD PTR [rsp - 8] + +andn_nop4: nop +TEST_END_MEM_64 diff --git a/tests/X86/MISC/NOP.S b/tests/X86/MISC/NOP.S new file mode 100644 index 00000000..f1624f88 --- /dev/null +++ b/tests/X86/MISC/NOP.S @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(NOPbasic, 1) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0xFFFFFFFF) + + mov RET_32, ARG1_32 + nop + nop +TEST_END diff --git a/tests/X86/Run.cpp b/tests/X86/Run.cpp index c4f4bb64..bf77370e 100644 --- a/tests/X86/Run.cpp +++ b/tests/X86/Run.cpp @@ -441,20 +441,30 @@ Memory *__remill_write_io_port_32(Memory *, addr_t, uint32_t) { abort(); } -Memory *__remill_function_call(State &, addr_t, Memory *) { - abort(); +Memory *__remill_function_call(State &, addr_t, Memory *memory) { + return memory; } -Memory *__remill_function_return(State &, addr_t, Memory *) { - abort(); +Memory *__remill_function_return(State &, addr_t, Memory *memory) { + return memory; } -Memory *__remill_jump(State &, addr_t, Memory *) { - abort(); +Memory *__remill_jump(State &, addr_t, Memory *memory) { + return memory; } -Memory *__remill_async_hyper_call(State &, addr_t, Memory *) { - abort(); +Memory *__remill_async_hyper_call(State &state, addr_t, Memory *memory) { + switch (state.hyper_call) { + case AsyncHyperCall::kX86Int1: + case AsyncHyperCall::kX86Int3: + case AsyncHyperCall::kX86IntO: + case AsyncHyperCall::kX86IntN: + case AsyncHyperCall::kX86Bound: + return memory; + + default: + abort(); + } } uint8_t __remill_undefined_8(void) { @@ -904,6 +914,26 @@ 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); @@ -1321,7 +1351,11 @@ static void RecoverFromError(int sig_num, siginfo_t *, void *context_) { siglongjmp(gJmpBuf, 0); } -static void ConsumeTrap(int, siginfo_t *, void *) {} +static void ConsumeTrap(int, siginfo_t *, void *) { + auto native_state = reinterpret_cast(&gNativeState); + native_state->hyper_call = AsyncHyperCall::kX86Int3; + native_state->hyper_call_vector = 3; +} static void HandleUnsupportedInstruction(int, siginfo_t *, void *) { siglongjmp(gUnsupportedInstrBuf, 0); diff --git a/tests/X86/SHIFT/SHLX.S b/tests/X86/SHIFT/SHLX.S new file mode 100644 index 00000000..c4c74e2a --- /dev/null +++ b/tests/X86/SHIFT/SHLX.S @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(SHLXr32r32, 2) +TEST_INPUTS( + 0x1, 0, + 0x1, 1, + 0x1, 8, + 0x1, 40, + 0x12345678, 4, + 0x80000000, 1) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz shlx_nop1 + + mov eax, ARG1_32 + mov ebx, ARG2_32 + shlx edx, eax, ebx + +shlx_nop1: nop +TEST_END + +TEST_BEGIN_MEM(SHLXr32m32, 2) +TEST_INPUTS( + 0x1, 0, + 0x1, 1, + 0x1, 8, + 0x1, 40, + 0x12345678, 4, + 0x80000000, 1) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz shlx_nop2 + + mov DWORD PTR [rsp - 8], ARG1_32 + mov ebx, ARG2_32 + shlx edx, DWORD PTR [rsp - 8], ebx + +shlx_nop2: nop +TEST_END_MEM + +TEST_BEGIN_64(SHLXr64r64, 2) +TEST_INPUTS( + 0x1, 0, + 0x1, 1, + 0x1, 8, + 0x1, 72, + 0x123456789ABCDEF0, 4, + 0x8000000000000000, 1) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz shlx_nop3 + + mov rax, ARG1_64 + mov rbx, ARG2_64 + shlx rdx, rax, rbx + +shlx_nop3: nop +TEST_END_64 + +TEST_BEGIN_MEM_64(SHLXr64m64, 2) +TEST_INPUTS( + 0x1, 0, + 0x1, 1, + 0x1, 8, + 0x1, 72, + 0x123456789ABCDEF0, 4, + 0x8000000000000000, 1) + + mov eax, 0x00000007 + mov ecx, 0x0 + cpuid + test ebx, 0x00000100 + jz shlx_nop4 + + mov QWORD PTR [rsp - 8], ARG1_64 + mov rbx, ARG2_64 + shlx rdx, QWORD PTR [rsp - 8], rbx + +shlx_nop4: nop +TEST_END_MEM_64 diff --git a/tests/X86/SYSTEM/LAR.S b/tests/X86/SYSTEM/LAR.S new file mode 100644 index 00000000..604251e1 --- /dev/null +++ b/tests/X86/SYSTEM/LAR.S @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(LARr32r32, 1) +TEST_INPUTS(0) + + mov ax, cs + movzx eax, ax + lar edx, eax +TEST_END diff --git a/tests/X86/SYSTEM/RDTSC.S b/tests/X86/SYSTEM/RDTSC.S new file mode 100644 index 00000000..ee2ee342 --- /dev/null +++ b/tests/X86/SYSTEM/RDTSC.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(RDTSCbasic, 1) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0xFFFFFFFF) + + rdtsc + mov RET_32, ARG1_32 + mov edx, ARG1_32 +TEST_END + +TEST_BEGIN_64(RDTSCzeroExt_64, 1) +TEST_IGNORE_FLAGS(OF SF ZF AF PF CF) +TEST_INPUTS( + 0, + 1, + 0x12345678, + 0xFFFFFFFF) + + mov rax, 0xFFFFFFFFFFFFFFFF + mov rdx, 0xFFFFFFFFFFFFFFFF + rdtsc + shr rax, 32 + shr rdx, 32 + mov RET_64, rax +TEST_END_64 diff --git a/tests/X86/SYSTEM/VERR.S b/tests/X86/SYSTEM/VERR.S new file mode 100644 index 00000000..4b094415 --- /dev/null +++ b/tests/X86/SYSTEM/VERR.S @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(VERRr16, 1) +TEST_INPUTS(0) + + mov ax, cs + verr ax +TEST_END diff --git a/tests/X86/SYSTEM/XGETBV.S b/tests/X86/SYSTEM/XGETBV.S new file mode 100644 index 00000000..9b40217b --- /dev/null +++ b/tests/X86/SYSTEM/XGETBV.S @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Trail of Bits, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_BEGIN(XGETBVxcr0, 1) +TEST_INPUTS(0) + + mov eax, 0x00000001 + cpuid + mov ebx, ecx + and ebx, 0x0C000000 + cmp ebx, 0x0C000000 + jne xgetbv_nop1 + + xor ecx, ecx + xgetbv + +xgetbv_nop1: nop +TEST_END diff --git a/tests/X86/Tests.S b/tests/X86/Tests.S index 5141e096..da6b31aa 100644 --- a/tests/X86/Tests.S +++ b/tests/X86/Tests.S @@ -400,17 +400,26 @@ SYMBOL(__x86_test_table_begin): #include "tests/X86/BITBYTE/BSWAP.S" #include "tests/X86/BITBYTE/BT.S" #include "tests/X86/BITBYTE/BTC.S" +#include "tests/X86/BITBYTE/BEXTR.S" #include "tests/X86/BITBYTE/BTR.S" #include "tests/X86/BITBYTE/BTS.S" +#include "tests/X86/BITBYTE/BZHI.S" +#include "tests/X86/BITBYTE/CRC32.S" #include "tests/X86/BITBYTE/LZCNT.S" +#include "tests/X86/BITBYTE/PDEP.S" +#include "tests/X86/BITBYTE/PEXT.S" +#include "tests/X86/BITBYTE/POPCNT.S" #include "tests/X86/BITBYTE/SETcc.S" +#include "tests/X86/BITBYTE/SETE.S" #include "tests/X86/BITBYTE/TZCNT.S" #include "tests/X86/CMOV/CMOVB.S" #include "tests/X86/CMOV/CMOVBE.S" +#include "tests/X86/CMOV/CMOVE.S" #include "tests/X86/CMOV/CMOVL.S" #include "tests/X86/CMOV/CMOVLE.S" #include "tests/X86/CMOV/CMOVNB.S" +#include "tests/X86/CMOV/CMOVNE.S" #include "tests/X86/CMOV/CMOVNBE.S" #include "tests/X86/CMOV/CMOVNL.S" #include "tests/X86/CMOV/CMOVNLE.S" @@ -454,15 +463,19 @@ SYMBOL(__x86_test_table_begin): #include "tests/X86/DECIMAL/DAA.S" #include "tests/X86/LOGICAL/AND.S" +#include "tests/X86/LOGICAL/ANDN.S" #include "tests/X86/LOGICAL/NOT.S" #include "tests/X86/LOGICAL/OR.S" #include "tests/X86/LOGICAL/TEST.S" #include "tests/X86/LOGICAL/XOR.S" +#include "tests/X86/INTERRUPT/INT3.S" + #include "tests/X86/MISC/CPUID.S" #include "tests/X86/MISC/ENTER.S" #include "tests/X86/MISC/LEA.S" #include "tests/X86/MISC/LEAVE.S" +#include "tests/X86/MISC/NOP.S" #include "tests/X86/MISC/XLAT.S" #include "tests/X86/MMX/MISC.S" @@ -502,6 +515,7 @@ SYMBOL(__x86_test_table_begin): #include "tests/X86/SHIFT/SAR.S" #include "tests/X86/SHIFT/SHL.S" #include "tests/X86/SHIFT/SHLD.S" +#include "tests/X86/SHIFT/SHLX.S" #include "tests/X86/SHIFT/SHR.S" #include "tests/X86/SHIFT/SHRD.S" @@ -564,6 +578,18 @@ SYMBOL(__x86_test_table_begin): #include "tests/X86/FMA/VFMADDSD.S" #include "tests/X86/FMA/VFMSUBSD.S" +#include "tests/X86/BRANCH/CALL.S" +#include "tests/X86/BRANCH/JAE.S" +#include "tests/X86/BRANCH/JE.S" +#include "tests/X86/BRANCH/JMP.S" +#include "tests/X86/BRANCH/JNE.S" +#include "tests/X86/BRANCH/RET.S" + +#include "tests/X86/SYSTEM/LAR.S" +#include "tests/X86/SYSTEM/RDTSC.S" +#include "tests/X86/SYSTEM/VERR.S" +#include "tests/X86/SYSTEM/XGETBV.S" + #endif /* Create a symbol that represents the end of the test information table. */