diff --git a/mcsema/Arch/Instr.h b/mcsema/Arch/Instr.h index 4e5749a6..300113ca 100644 --- a/mcsema/Arch/Instr.h +++ b/mcsema/Arch/Instr.h @@ -13,6 +13,7 @@ class Instr; } // namespace cfg class BlockMap; +class Intrinsic; class Instr { public: @@ -22,7 +23,10 @@ class Instr { // Lift an instruction. If the lifter returns `false` then lifting of the // block has completed. - virtual bool Lift(const BlockMap &blocks, llvm::BasicBlock *B) = 0; + // + // TODO(pag): I'm not pleased with this interface. + virtual bool Lift(const Intrinsic *intrinsic, const BlockMap &blocks, + llvm::BasicBlock *B) = 0; protected: const cfg::Instr * const instr; diff --git a/mcsema/Arch/Semantics/CONTROL.inc b/mcsema/Arch/Semantics/CONTROL.inc new file mode 100644 index 00000000..da50b775 --- /dev/null +++ b/mcsema/Arch/Semantics/CONTROL.inc @@ -0,0 +1,30 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +extern "C" { + +// Control-flow intrinsics. +[[gnu::used]] +extern void __mcsema_error(State &); + +[[gnu::used]] +extern void __mcsema_function_call(State &); + +[[gnu::used]] +extern void __mcsema_function_return(State &); + +[[gnu::used]] +extern void __mcsema_jump(State &); + +[[gnu::used]] +extern void __mcsema_system_call(State &); + +[[gnu::used]] +extern void __mcsema_system_return(State &); + +[[gnu::used]] +extern void __mcsema_interrupt_call(State &); + +[[gnu::used]] +extern void __mcsema_interrupt_return(State &); + +} // extern diff --git a/mcsema/Arch/Semantics/MACROS.inc b/mcsema/Arch/Semantics/MACROS.inc new file mode 100644 index 00000000..1529e792 --- /dev/null +++ b/mcsema/Arch/Semantics/MACROS.inc @@ -0,0 +1,8 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +#ifndef MCSEMA_ARCH_SEMANTICS_MACROS_INC_ +#define MCSEMA_ARCH_SEMANTICS_MACROS_INC_ + +#define ALWAYS_INLINE [[gnu::always_inline, gnu::gnu_inline, gnu::flatten]] + +#endif // MCSEMA_ARCH_SEMANTICS_MACROS_INC_ diff --git a/mcsema/Arch/Semantics/MEMORY.inc b/mcsema/Arch/Semantics/MEMORY.inc new file mode 100644 index 00000000..f92a3821 --- /dev/null +++ b/mcsema/Arch/Semantics/MEMORY.inc @@ -0,0 +1,69 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +extern "C" { + +// Address computation intrinsic. This is only used for non-zero +// `address_space`d memory accesses. +extern uintptr_t __mcsema_compute_address(const State &state, + uintptr_t address, + int address_space); + +// Memory read intrinsics. +extern uint8_t __mcsema_read_memory_8(uintptr_t); +extern uint16_t __mcsema_read_memory_16(uintptr_t); +extern uint32_t __mcsema_read_memory_32(uintptr_t); +extern uint64_t __mcsema_read_memory_64(uintptr_t); +extern vec128_t __mcsema_read_memory_128(uintptr_t); +extern vec256_t __mcsema_read_memory_256(uintptr_t); +extern vec512_t __mcsema_read_memory_512(uintptr_t); + +// Memory write intrinsics. +extern void __mcsema_write_memory_8(uintptr_t, uint8_t); +extern void __mcsema_write_memory_16(uintptr_t, uint16_t); +extern void __mcsema_write_memory_32(uintptr_t, uint32_t); +extern void __mcsema_write_memory_64(uintptr_t, uint64_t); +extern void __mcsema_write_memory_128(uintptr_t, vec128_t); +extern void __mcsema_write_memory_256(uintptr_t, vec256_t); +extern void __mcsema_write_memory_512(uintptr_t, vec512_t); + +} // extern C + +template +struct Mn; + +#define MAKE_TYPE(prefix, T, size) \ + template <> \ + struct Mn { \ + ALWAYS_INLINE \ + inline void operator=(T that) { \ + __mcsema_write_memory_ ## size (addr, that); \ + } \ + ALWAYS_INLINE \ + inline void Write(T val) const { \ + return __mcsema_write_memory_ ## size (addr, val); \ + } \ + ALWAYS_INLINE \ + inline T Read(void) const { \ + return __mcsema_read_memory_ ## size (addr); \ + } \ + ALWAYS_INLINE \ + inline static void Write(uintptr_t addr_, T val) { \ + return __mcsema_write_memory_ ## size (addr_, val); \ + } \ + ALWAYS_INLINE \ + inline static T Read(uintptr_t addr_) { \ + return __mcsema_read_memory_ ## size (addr_); \ + } \ + uintptr_t addr; \ + }; \ + using prefix ## size = prefix ## n < T > ; + + + +MAKE_TYPE(M, uint8_t, 8); +MAKE_TYPE(M, uint16_t, 16); +MAKE_TYPE(M, uint32_t, 32); +MAKE_TYPE(M, uint64_t, 64); +MAKE_TYPE(M, vec128_t, 128); +MAKE_TYPE(M, vec256_t, 256); +MAKE_TYPE(M, vec512_t, 512); diff --git a/mcsema/Arch/Semantics/TYPES.inc b/mcsema/Arch/Semantics/TYPES.inc new file mode 100644 index 00000000..8834f876 --- /dev/null +++ b/mcsema/Arch/Semantics/TYPES.inc @@ -0,0 +1,72 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +typedef float float32_t; +static_assert(4 == sizeof(float32_t), "Invalid `float32_t` size."); + +typedef double float64_t; +static_assert(8 == sizeof(float64_t), "Invalid `float64_t` size."); + +struct alignas(16) float80_t { + long double f; +}; +static_assert(16 == sizeof(float80_t), "Invalid `float80_t` size."); + +typedef uint8_t uint8v16_t __attribute__ ((vector_size (16))); +typedef uint16_t uint16v8_t __attribute__ ((vector_size (16))); +typedef uint32_t uint32v4_t __attribute__ ((vector_size (16))); +typedef uint64_t uint64v2_t __attribute__ ((vector_size (16))); +typedef float32_t float32v4_t __attribute__ ((vector_size (16))); +typedef float64_t float64v2_t __attribute__ ((vector_size (16))); + +union vec128_t { + uint8v16_t bytes; + uint16v8_t words; + uint32v4_t dwords; + uint64v2_t qwords; + float32v4_t floats; + float64v2_t doubles; +} __attribute__((packed)); + +static_assert(16 == sizeof(vec128_t), + "Invalid structure packing of `vec128_t`."); + +typedef uint8_t uint8v32_t __attribute__ ((vector_size (32))); +typedef uint16_t uint16v16_t __attribute__ ((vector_size (32))); +typedef uint32_t uint32v8_t __attribute__ ((vector_size (32))); +typedef uint64_t uint64v4_t __attribute__ ((vector_size (32))); +typedef float32_t float32v8_t __attribute__ ((vector_size (32))); +typedef float64_t float64v4_t __attribute__ ((vector_size (32))); + +union vec256_t { + uint8v32_t bytes; + uint16v16_t words; + uint32v8_t dwords; + uint64v4_t qwords; + float32v8_t floats; + float64v4_t doubles; +} __attribute__((packed)); + +static_assert(32 == sizeof(vec256_t), + "Invalid structure packing of `vec256_t`."); + +typedef uint8_t uint8v64_t __attribute__ ((vector_size (64))); +typedef uint16_t uint16v32_t __attribute__ ((vector_size (64))); +typedef uint32_t uint32v16_t __attribute__ ((vector_size (64))); +typedef uint64_t uint64v8_t __attribute__ ((vector_size (64))); +typedef float32_t float32v16_t __attribute__ ((vector_size (64))); +typedef float64_t float64v8_t __attribute__ ((vector_size (64))); + +union vec512_t { + uint8v64_t bytes; + uint16v32_t words; + uint32v16_t dwords; + uint64v8_t qwords; + float32v16_t floats; + float64v8_t doubles; +} __attribute__((packed)); + +static_assert(64 == sizeof(vec512_t), + "Invalid structure packing of `vec512_t`."); + +[[gnu::used]] +extern "C" bool __mcsema_undefined_bool(void); diff --git a/mcsema/Arch/X86/Arch.cpp b/mcsema/Arch/X86/Arch.cpp index 6b10eda3..ebb16018 100644 --- a/mcsema/Arch/X86/Arch.cpp +++ b/mcsema/Arch/X86/Arch.cpp @@ -68,9 +68,9 @@ llvm::Module *Arch::CreateModule(void) const { llvm::SMDiagnostic err; if (64 == address_size) { - module_file = MCSEMA_DIR "/generated/Arch/X86/Semantics/State64.bc"; + module_file = MCSEMA_DIR "/generated/Arch/X86/Semantics/MACHINE64.bc"; } else { - module_file = MCSEMA_DIR "/generated/Arch/X86/Semantics/State32.bc"; + module_file = MCSEMA_DIR "/generated/Arch/X86/Semantics/MACHINE32.bc"; } // Load the arch-specific bitcode file as a module. diff --git a/mcsema/Arch/X86/Instr.cpp b/mcsema/Arch/X86/Instr.cpp index 6ce41ea7..28230094 100644 --- a/mcsema/Arch/X86/Instr.cpp +++ b/mcsema/Arch/X86/Instr.cpp @@ -12,6 +12,7 @@ #include "mcsema/Arch/X86/Instr.h" #include "mcsema/Arch/X86/XED.h" +#include "mcsema/BC/Intrinsic.h" #include "mcsema/BC/Util.h" #include "mcsema/CFG/CFG.h" @@ -26,6 +27,7 @@ Instr::Instr(const cfg::Instr *instr_, const struct xed_decoded_inst_s *xedd_) xedd(xedd_), xedi(xed_decoded_inst_inst(xedd)), iclass(xed_decoded_inst_get_iclass(xedd)), + intrinsic(nullptr), B(nullptr), F(nullptr), M(nullptr), @@ -49,99 +51,6 @@ static std::string InstructionFunctionName(const xed_decoded_inst_t *xedd) { return ss.str(); } -// Return the type for a given operand. -static llvm::Type *OperandType(llvm::LLVMContext &C, - const xed_operand_t *xedo, - unsigned op_size) { - - // Special case: treat AGEN operands (e.g. LEA, BND*) as having any type. - if (XED_OPERAND_AGEN == xed_operand_name(xedo)) { - return llvm::Type::getInt8Ty(C); - } - - switch (xed_operand_xtype(xedo)) { - case XED_OPERAND_XTYPE_INVALID: - LOG(FATAL) << "Invalid operand type: XED_OPERAND_XTYPE_INVALID."; - return nullptr; - - // Binary coded decimal. Really an array of char, and only accessed via - // memory. - case XED_OPERAND_XTYPE_B80: - return llvm::Type::getInt8Ty(C); - - // Half-precision floating point. Usually packed into an XMM register. - // What we get is a memory operand that's a pointer to four of these. - case XED_OPERAND_XTYPE_F16: - return llvm::Type::getHalfTy(C); - - // Single-precision floating point type. - case XED_OPERAND_XTYPE_F32: - return llvm::Type::getFloatTy(C); - - // Double-precision floating point type. - case XED_OPERAND_XTYPE_F64: - return llvm::Type::getDoubleTy(C); - - // Extended precision (internal to X87 FPU) floating point type. - case XED_OPERAND_XTYPE_F80: - return llvm::Type::getX86_FP80Ty(C); - - case XED_OPERAND_XTYPE_I1: - return llvm::Type::getInt1Ty(C); - - case XED_OPERAND_XTYPE_I16: - return llvm::Type::getInt16Ty(C); - - case XED_OPERAND_XTYPE_I32: - return llvm::Type::getInt32Ty(C); - - case XED_OPERAND_XTYPE_I64: - return llvm::Type::getInt64Ty(C); - - case XED_OPERAND_XTYPE_I8: - return llvm::Type::getInt8Ty(C); - - // Specific to the effective operand size. - case XED_OPERAND_XTYPE_INT: - return llvm::Type::getIntNTy(C, op_size); - - case XED_OPERAND_XTYPE_STRUCT: - LOG(WARNING) - << "Treating XED_OPERAND_XTYPE_STRUCT as a " - << op_size << "-bit integer."; - return llvm::Type::getIntNTy(C, op_size); - - case XED_OPERAND_XTYPE_U128: - return llvm::Type::getInt128Ty(C); - - case XED_OPERAND_XTYPE_U16: - return llvm::Type::getInt16Ty(C); - - case XED_OPERAND_XTYPE_U256: - return llvm::Type::getIntNTy(C, 256); - - case XED_OPERAND_XTYPE_U32: - return llvm::Type::getInt32Ty(C); - - case XED_OPERAND_XTYPE_U64: - return llvm::Type::getInt64Ty(C); - - case XED_OPERAND_XTYPE_U8: - return llvm::Type::getInt8Ty(C); - - case XED_OPERAND_XTYPE_UINT: - return llvm::Type::getIntNTy(C, op_size); - - case XED_OPERAND_XTYPE_VAR: - LOG(FATAL) << "Unsupported operand type: XED_OPERAND_XTYPE_VAR."; - return nullptr; - - case XED_OPERAND_XTYPE_LAST: - LOG(FATAL) << "Invalid operand type: XED_OPERAND_XTYPE_LAST."; - return nullptr; - } -} - // Returns the address space associated with a segment register. This is a // GNU-specific extension. static unsigned AddressSpace(xed_reg_enum_t seg, xed_operand_enum_t name) { @@ -158,16 +67,16 @@ static unsigned AddressSpace(xed_reg_enum_t seg, xed_operand_enum_t name) { } // namespace -bool Instr::Lift(const BlockMap &blocks, llvm::BasicBlock *B_) { +bool Instr::Lift(const Intrinsic *intrinsic_, const BlockMap &blocks, + llvm::BasicBlock *B_) { B = B_; F = B->getParent(); M = F->getParent(); C = &(F->getContext()); - - LiftPC(); + intrinsic = intrinsic_; if (IsError()) { - AddTerminatingTailCall(B, ExitProgramErrorDispatcher(M)); + AddTerminatingTailCall(B, intrinsic->error); return false; } else if (IsDirectJump()) { @@ -175,46 +84,61 @@ bool Instr::Lift(const BlockMap &blocks, llvm::BasicBlock *B_) { return false; } else if (IsIndirectJump()) { + LiftPC(); LiftGeneric(); // loads target into `gpr.rip`. - AddTerminatingTailCall(B, IndirectJumpDispatcher(M)); + AddTerminatingTailCall(B, intrinsic->jump); return false; } else if (IsDirectFunctionCall()) { + LiftPC(); LiftGeneric(); // Adjusts the stack, stores `gpr.rip` to the stack. AddTerminatingTailCall(B, blocks[TargetPC()]); return false; } else if (IsIndirectFunctionCall()) { + LiftPC(); LiftGeneric(); // Adjusts the stack, loads target into `gpr.rip`. - AddTerminatingTailCall(B, IndirectFunctionCallDispatcher(M)); + AddTerminatingTailCall(B, intrinsic->function_call); return false; } else if (IsFunctionReturn()) { + LiftPC(); LiftGeneric(); // Adjusts the stack, loads target into `gpr.rip`. - AddTerminatingTailCall(B, FunctionReturnDispatcher(M)); + AddTerminatingTailCall(B, intrinsic->function_return); return false; } else if (IsBranch()) { + LiftPC(); LiftConditionalBranch(blocks); return false; // Instruction implementation handles syscall emulation. } else if (IsSystemCall()) { + LiftPC(); LiftGeneric(); + AddTerminatingTailCall(B, intrinsic->system_call); return false; } else if (IsSystemReturn()) { - LOG(FATAL) + LiftPC(); + LiftGeneric(); + AddTerminatingTailCall(B, intrinsic->system_return); + LOG(WARNING) << "Unsupported instruction (system return) at PC " << instr->address(); return false; // Instruction implementation handles syscall (x86, x32) emulation. } else if (IsInterruptCall()) { + LiftPC(); LiftGeneric(); + AddTerminatingTailCall(B, intrinsic->interrupt_call); return false; } else if (IsInterruptReturn()) { - LOG(FATAL) + LiftPC(); + LiftGeneric(); + AddTerminatingTailCall(B, intrinsic->interrupt_return); + LOG(WARNING) << "Unsupported instruction (system return) at PC " << instr->address(); return false; @@ -362,7 +286,6 @@ void Instr::LiftOperand(unsigned op_num) { // The challenge is that we don't want to have void Instr::LiftMemory(const xed_operand_t *xedo, unsigned op_num) { auto op_name = xed_operand_name(xedo); - auto op_width = xed_decoded_inst_operand_length_bits(xedd, op_num); auto mem_index = (XED_OPERAND_MEM1 == op_name) ? 1 : 0; // Handles AGEN. auto seg = xed_decoded_inst_get_seg_reg(xedd, mem_index); auto base = xed_decoded_inst_get_base_reg(xedd, mem_index); @@ -373,13 +296,9 @@ void Instr::LiftMemory(const xed_operand_t *xedo, unsigned op_num) { auto addr_space = AddressSpace(seg, op_name); llvm::IRBuilder<> ir(B); - llvm::Type *ValTy = OperandType(*C, xedo, op_width); - llvm::Type *PtrTy = ValTy->getPointerTo(addr_space); llvm::Type *IntPtrTy = llvm::Type::getIntNTy(*C, addr_width); llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*C); llvm::Value *A = nullptr; // Address (as an integer). - llvm::Value *P = nullptr; // Pointer (address space 0). - llvm::Value *M = nullptr; // Pointer (address space specific). // Address is in the displacement. if (XED_REG_INVALID == base && XED_REG_INVALID == index) { @@ -421,22 +340,15 @@ void Instr::LiftMemory(const xed_operand_t *xedo, unsigned op_num) { A = ir.CreateAdd(ir.CreateAdd(B, ir.CreateMul(I, S)), D); } - M = ir.CreateIntToPtr(A, PtrTy); if (addr_space) { - P = ir.CreateAlloca(ValTy); - if (xed_operand_read(xedo)) { - ir.CreateStore(ir.CreateLoad(M), P); - } - if (xed_operand_written(xedo)) { - auto V = new llvm::LoadInst(P); - append_instrs.push_back(V); - append_instrs.push_back(new llvm::StoreInst(V, M)); - } - } else { - P = M; + std::vector args = { + FindStatePointer(F), // Machine state. + A, // Address. + llvm::ConstantInt::get(Int32Ty, addr_space, true)}; + A = ir.CreateCall(intrinsic->compute_address, args); } - args.push_back(P); + args.push_back(A); } // Convert an immediate constant into an LLVM `Value` for passing into the diff --git a/mcsema/Arch/X86/Instr.h b/mcsema/Arch/X86/Instr.h index 3bb7338a..cf6ed78e 100644 --- a/mcsema/Arch/X86/Instr.h +++ b/mcsema/Arch/X86/Instr.h @@ -24,7 +24,8 @@ class Instr : public ::mcsema::Instr { Instr(const cfg::Instr *, const struct xed_decoded_inst_s *xedd_); virtual ~Instr(void); - virtual bool Lift(const BlockMap &blocks, llvm::BasicBlock *B_) override; + virtual bool Lift(const Intrinsic *intrinsic, const BlockMap &blocks, + llvm::BasicBlock *B_) override; private: void LiftPC(void); @@ -63,6 +64,8 @@ class Instr : public ::mcsema::Instr { const xed_inst_t * const xedi; const xed_iclass_enum_t iclass; + const Intrinsic *intrinsic; + llvm::BasicBlock *B; llvm::Function *F; llvm::Module *M; diff --git a/mcsema/Arch/X86/Semantics/BINARY.inc b/mcsema/Arch/X86/Semantics/BINARY.inc new file mode 100644 index 00000000..cb427a2c --- /dev/null +++ b/mcsema/Arch/X86/Semantics/BINARY.inc @@ -0,0 +1,114 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +#include + +namespace { + +template +DEF_SEM(BINARY_OP, D dst_src1, S1 src2_) { + auto src1 = R(dst_src1); + auto src2 = R(src2_); + auto res = Op()(src1, src2); + SET_AFLAGS(src1, src2, res); + W(dst_src1) = res; +} + +template +DEF_SEM(BINARY_OP2, D dst, S1 src1_, S2 src2_) { + auto src1 = R(src1_); + auto src2 = R(src2_); + auto res = Op()(src1, src2); + SET_AFLAGS(src1, src2, res); + W(dst) = res; +} + +#define DEFINE_OP(name, op) \ + template \ + DEF_SEM(name, D dst_src1, S1 src2_) { \ + BINARY_OP, D, S1>(state, dst_src1, src2_); \ + } \ + template \ + DEF_SEM(name ## 2, D dst, S1 src1_, S2 src2_) { \ + BINARY_OP2, D, S1, S2>(state, dst, src1_, src2_); \ + } + +DEFINE_OP(ADD, std::plus) +DEFINE_OP(SUB, std::minus) +DEFINE_OP(MUL, std::multiplies) +DEFINE_OP(DIV, std::divides) + +#undef DEFINE_OP + +} // namespace + +DEF_ISEL(ADD_MEMb_IMMb_80r0_8) = ADD; +DEF_ISEL(ADD_GPR8_IMMb_80r0_8) = ADD2; +DEF_ISEL_Mn_Mn_In(ADD_MEMv_IMMz, ADD); +DEF_ISEL_Rn_Rn_In(ADD_GPRv_IMMz, ADD2); +DEF_ISEL(ADD_MEMb_IMMb_82r0_8) = ADD; +DEF_ISEL(ADD_GPR8_IMMb_82r0_8) = ADD2; +DEF_ISEL_Mn_Mn_In(ADD_MEMv_IMMb, ADD); +DEF_ISEL_Rn_Rn_In(ADD_GPRv_IMMb, ADD2); +DEF_ISEL(ADD_MEMb_GPR8_8) = ADD; +DEF_ISEL(ADD_GPR8_GPR8_00_8) = ADD2; +DEF_ISEL_Mn_Mn_Rn(ADD_MEMv_GPRv, ADD); +DEF_ISEL_Rn_Rn_Rn(ADD_GPRv_GPRv_01, ADD2); +DEF_ISEL(ADD_GPR8_MEMb_8) = ADD2; +DEF_ISEL(ADD_GPR8_GPR8_02_8) = ADD2; +DEF_ISEL_Rn_Rn_Mn(ADD_GPRv_MEMv, ADD2); +DEF_ISEL_Rn_Rn_Rn(ADD_GPRv_GPRv_03, ADD2); +DEF_ISEL(ADD_AL_IMMb) = ADD2; +DEF_ISEL_Rn_Rn_In(ADD_OrAX_IMMz, ADD2); + +DEF_ISEL(SUB_MEMb_IMMb_80r5_8) = SUB; +DEF_ISEL(SUB_GPR8_IMMb_80r5_8) = SUB2; +DEF_ISEL_Mn_Mn_In(SUB_MEMv_IMMz, SUB); +DEF_ISEL_Rn_Rn_In(SUB_GPRv_IMMz, SUB2); +DEF_ISEL(SUB_MEMb_IMMb_82r5_8) = SUB; +DEF_ISEL(SUB_GPR8_IMMb_82r5_8) = SUB2; +DEF_ISEL_Mn_Mn_In(SUB_MEMv_IMMb, SUB); +DEF_ISEL_Rn_Rn_In(SUB_GPRv_IMMb, SUB2); +DEF_ISEL(SUB_MEMb_GPR8_8) = SUB; +DEF_ISEL(SUB_GPR8_GPR8_28_8) = SUB2; +DEF_ISEL_Mn_Mn_Rn(SUB_MEMv_GPRv, SUB); +DEF_ISEL_Rn_Rn_Rn(SUB_GPRv_GPRv_29, SUB2); +DEF_ISEL(SUB_GPR8_GPR8_2A_8) = SUB2; +DEF_ISEL(SUB_GPR8_MEMb_8) = SUB2; +DEF_ISEL_Rn_Rn_Rn(SUB_GPRv_GPRv_2B, SUB2); +DEF_ISEL_Rn_Rn_Mn(SUB_GPRv_MEMv, SUB2); +DEF_ISEL(SUB_AL_IMMb_8) = SUB2; +DEF_ISEL_Rn_Rn_In(SUB_OrAX_IMMz, SUB2); + +/* +1254 IMUL IMUL_MEMb BINARY BASE I86 ATTRIBUTES: BYTEOP +1255 IMUL IMUL_GPR8 BINARY BASE I86 ATTRIBUTES: BYTEOP +1256 IMUL IMUL_MEMv BINARY BASE I86 ATTRIBUTES: SCALABLE +1257 IMUL IMUL_GPRv BINARY BASE I86 ATTRIBUTES: SCALABLE +1258 IMUL IMUL_GPRv_MEMv_IMMz BINARY BASE I186 ATTRIBUTES: SCALABLE +1259 IMUL IMUL_GPRv_GPRv_IMMz BINARY BASE I186 ATTRIBUTES: SCALABLE +1260 IMUL IMUL_GPRv_MEMv_IMMb BINARY BASE I186 ATTRIBUTES: SCALABLE +1261 IMUL IMUL_GPRv_GPRv_IMMb BINARY BASE I186 ATTRIBUTES: SCALABLE +1262 IMUL IMUL_GPRv_MEMv BINARY BASE I86 ATTRIBUTES: SCALABLE +1263 IMUL IMUL_GPRv_GPRv BINARY BASE I86 ATTRIBUTES: SCALABLE + */ + +/* +740 MUL MUL_MEMb BINARY BASE I86 ATTRIBUTES: BYTEOP +741 MUL MUL_GPR8 BINARY BASE I86 ATTRIBUTES: BYTEOP +742 MUL MUL_MEMv BINARY BASE I86 ATTRIBUTES: SCALABLE +743 MUL MUL_GPRv BINARY BASE I86 ATTRIBUTES: SCALABLE + */ + +/* +557 IDIV IDIV_MEMb BINARY BASE I86 ATTRIBUTES: BYTEOP +558 IDIV IDIV_GPR8 BINARY BASE I86 ATTRIBUTES: BYTEOP +559 IDIV IDIV_MEMv BINARY BASE I86 ATTRIBUTES: SCALABLE +560 IDIV IDIV_GPRv BINARY BASE I86 ATTRIBUTES: SCALABLE + */ + +/* +1293 DIV DIV_MEMb BINARY BASE I86 ATTRIBUTES: BYTEOP +1294 DIV DIV_GPR8 BINARY BASE I86 ATTRIBUTES: BYTEOP +1295 DIV DIV_MEMv BINARY BASE I86 ATTRIBUTES: SCALABLE +1296 DIV DIV_GPRv BINARY BASE I86 ATTRIBUTES: SCALABLE + */ diff --git a/mcsema/Arch/X86/Semantics/CALL_RET.inc b/mcsema/Arch/X86/Semantics/CALL_RET.inc index 2edda3a5..a8da522e 100644 --- a/mcsema/Arch/X86/Semantics/CALL_RET.inc +++ b/mcsema/Arch/X86/Semantics/CALL_RET.inc @@ -5,26 +5,23 @@ namespace { template DEF_SEM(CALL, T target_pc) { CLEAR_AFLAGS(); - *state.gpr.rsp.ptr-- = state.gpr.rip.full; - state.gpr.rip.full = static_cast(target_pc); + state.gpr.rsp.full -= sizeof(state.gpr.rsp.full); + Mn::Write(state.gpr.rsp.full, state.gpr.rip.full); + state.gpr.rip.full = R(target_pc); } -template -DEF_SEM(INDIRECT_CALL, T *target_pc) { +DEF_SEM(RET_IMM, I16 bytes) { CLEAR_AFLAGS(); - *state.gpr.rsp.ptr-- = state.gpr.rip.full; - state.gpr.rip.full = static_cast(*target_pc); -} - -DEF_SEM(RET_IMM, IMM16 bytes) { - CLEAR_AFLAGS(); - state.gpr.rip.full = *state.gpr.rsp.ptr++; - state.gpr.rsp.full += bytes; + auto addr = Mn::Read(state.gpr.rsp.full); + state.gpr.rip.full = addr; + state.gpr.rsp.full += bytes + sizeof(PC); } DEF_SEM(RET) { CLEAR_AFLAGS(); - state.gpr.rip.full = *state.gpr.rsp.ptr++; + auto addr = Mn::Read(state.gpr.rsp.full); + state.gpr.rip.full = addr; + state.gpr.rsp.full += sizeof(PC); } } // namespace @@ -32,8 +29,8 @@ DEF_SEM(RET) { DEF_ISEL_32UP(CALL_NEAR_RELBRz, CALL); DEF_ISEL_32UP(CALL_NEAR_RELBRd, CALL); -DEF_ISEL(CALL_NEAR_MEMv_32) = INDIRECT_CALL; -DEF_ISEL(CALL_NEAR_MEMv_64) = INDIRECT_CALL; +DEF_ISEL(CALL_NEAR_MEMv_32) = CALL; +IF_64BIT( DEF_ISEL(CALL_NEAR_MEMv_64) = CALL; ) DEF_ISEL_Rn(CALL_NEAR_GRPv, CALL); diff --git a/mcsema/Arch/X86/Semantics/DATAXFER.inc b/mcsema/Arch/X86/Semantics/DATAXFER.inc index 040c1eb9..62d32a50 100644 --- a/mcsema/Arch/X86/Semantics/DATAXFER.inc +++ b/mcsema/Arch/X86/Semantics/DATAXFER.inc @@ -9,22 +9,22 @@ DEF_SEM(MOV, D dst, S src) { } // namespace -DEF_ISEL(MOV_GPR8_IMMb_C6r0_8) = MOV; -DEF_ISEL(MOV_MEMb_IMMb_8) = MOV; +DEF_ISEL(MOV_GPR8_IMMb_C6r0_8) = MOV; +DEF_ISEL(MOV_MEMb_IMMb_8) = MOV; -DEF_ISEL_WRn_In(MOV_GPRv_IMMz, MOV); +DEF_ISEL_Rn_In(MOV_GPRv_IMMz, MOV); DEF_ISEL_Mn_In(MOV_MEMv_IMMz, MOV); DEF_ISEL(MOV_GPR8_GPR8_88_8) = MOV; DEF_ISEL(MOV_MEMb_GPR8_8) = MOV; DEF_ISEL_Mn_Rn(MOV_MEMv_GPRv, MOV); -DEF_ISEL_WRn_Rn(MOV_GPRv_GPRv_89, MOV); +DEF_ISEL_Rn_Rn(MOV_GPRv_GPRv_89, MOV); DEF_ISEL(MOV_GPR8_MEMb_8) = MOV; DEF_ISEL(MOV_GPR8_GPR8_8A_8) = MOV; -DEF_ISEL_WRn_Mn(MOV_GPRv_MEMv, MOV); +DEF_ISEL_Rn_Mn(MOV_GPRv_MEMv, MOV); DEF_ISEL_Mn_Rn(MOV_MEMv_GPRv_8B, MOV); //1148 MOV MOV_MEMw_SEG DATAXFER BASE I86 ATTRIBUTES: @@ -34,12 +34,12 @@ DEF_ISEL_Mn_Rn(MOV_MEMv_GPRv_8B, MOV); DEF_ISEL(MOV_AL_MEMb_8) = MOV; -DEF_ISEL_WRn_Mn(MOV_OrAX_MEMv, MOV); +DEF_ISEL_Rn_Mn(MOV_OrAX_MEMv, MOV); DEF_ISEL(MOV_MEMb_AL_8) = MOV; DEF_ISEL_Mn_Rn(MOV_MEMv_OrAX, MOV); -DEF_ISEL(MOV_GPR8_IMMb_D0_8) = MOV; +DEF_ISEL(MOV_GPR8_IMMb_D0_8) = MOV; -DEF_ISEL_WRn_In(MOV_GPRv_IMMv, MOV); +DEF_ISEL_Rn_In(MOV_GPRv_IMMv, MOV); diff --git a/mcsema/Arch/X86/Semantics/FLAGS.inc b/mcsema/Arch/X86/Semantics/FLAGS.inc new file mode 100644 index 00000000..d329ecbc --- /dev/null +++ b/mcsema/Arch/X86/Semantics/FLAGS.inc @@ -0,0 +1,52 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +template +[[gnu::const]] +extern bool CarryFlag(S1 lhs, S2 rhs, R result); + +template +[[gnu::const]] +extern bool ParityFlag(S1 lhs, S2 rhs, R result); + +template +[[gnu::const]] +extern bool AuxCarryFlag(S1 lhs, S2 rhs, R result); + +template +[[gnu::const]] +extern bool ZeroFlag(S1 lhs, S2 rhs, R result); + +template +[[gnu::const]] +extern bool SignFlag(S1 lhs, S2 rhs, R result); + +template +[[gnu::const]] +extern bool OverflowFlag(S1 lhs, S2 rhs, R result); + +// Arithmetic flags. +#define SET_AFLAGS(lhs, rhs, result) \ + state.aflag.of = OverflowFlag(lhs, rhs, result); \ + state.aflag.sf = SignFlag(lhs, rhs, result); \ + state.aflag.zf = ZeroFlag(lhs, rhs, result); \ + state.aflag.af = AuxCarryFlag(lhs, rhs, result); \ + state.aflag.pf = ParityFlag(lhs, rhs, result); \ + state.aflag.cf = CarryFlag(lhs, rhs, result) + +// Bitwise flags. +// +// Note: We'll leave the auxiliary carry flag as-is. +#define SET_BFLAGS(lhs, rhs, result) \ + state.aflag.of = __mcsema_undefined_bool(); \ + state.aflag.sf = SignFlag(lhs, rhs, result); \ + state.aflag.zf = ZeroFlag(lhs, rhs, result); \ + state.aflag.pf = ParityFlag(lhs, rhs, result); \ + state.aflag.cf = __mcsema_undefined_bool() + +#define CLEAR_AFLAGS() \ + state.aflag.of = __mcsema_undefined_bool(); \ + state.aflag.sf = __mcsema_undefined_bool(); \ + state.aflag.zf = __mcsema_undefined_bool(); \ + state.aflag.af = __mcsema_undefined_bool(); \ + state.aflag.pf = __mcsema_undefined_bool(); \ + state.aflag.of = __mcsema_undefined_bool() diff --git a/mcsema/Arch/X86/Semantics/Flags.inc b/mcsema/Arch/X86/Semantics/Flags.inc deleted file mode 100644 index 1bbf154b..00000000 --- a/mcsema/Arch/X86/Semantics/Flags.inc +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ - -template -__attribute__((noinline, const)) -extern bool CarryFlag(T lhs, T rhs, R result); - -template -__attribute__((noinline, const)) -extern bool ParityFlag(T lhs, T rhs, R result); - -template -__attribute__((noinline, const)) -extern bool AuxCarryFlag(T lhs, T rhs, R result); - -template -__attribute__((noinline, const)) -extern bool ZeroFlag(T lhs, T rhs, R result); - -template -__attribute__((noinline, const)) -extern bool SignFlag(T lhs, T rhs, R result); - -template -__attribute__((noinline, const)) -extern bool OverflowFlag(T lhs, T rhs, R result); - -__attribute__((always_inline, const)) -inline static bool Undefined(void) { - bool undefined; // Ideally should produce an LLVM `undef` value. - return undefined; -} - -#define SET_AFLAGS(lhs, rhs, result) \ - state.aflag.of = OverflowFlag(lhs, rhs, result); \ - state.aflag.sf = SignFlag(lhs, rhs, result); \ - state.aflag.zf = ZeroFlag(lhs, rhs, result); \ - state.aflag.af = AuxCarryFlag(lhs, rhs, result); \ - state.aflag.pf = ParityFlag(lhs, rhs, result); \ - state.aflag.of = OverflowFlag(lhs, rhs, result) - -#define CLEAR_AFLAGS() \ - state.aflag.of = Undefined(); \ - state.aflag.sf = Undefined(); \ - state.aflag.zf = Undefined(); \ - state.aflag.af = Undefined(); \ - state.aflag.pf = Undefined(); \ - state.aflag.of = Undefined() diff --git a/mcsema/Arch/X86/Semantics/LOGICAL.inc b/mcsema/Arch/X86/Semantics/LOGICAL.inc index e69de29b..67b1c8aa 100644 --- a/mcsema/Arch/X86/Semantics/LOGICAL.inc +++ b/mcsema/Arch/X86/Semantics/LOGICAL.inc @@ -0,0 +1,50 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +namespace { + +template +DEF_SEM(BITWISE_OP, D dst_src1, S1 src2_) { + auto src1 = R(dst_src1); + auto src2 = R(src2_); + auto res = Op()(src1, src2); + SET_BFLAGS(src1, src2, res); + W(dst_src1) = res; +} + +template +DEF_SEM(BITWISE_OP2, D dst, S1 src1_, S2 src2_) { + auto src1 = R(src1_); + auto src2 = R(src2_); + auto res = Op()(src1, src2); + SET_BFLAGS(src1, src2, res); + W(dst) = res; +} + +#define DEFINE_OP(name, op) \ + template \ + DEF_SEM(name, D dst_src1, S1 src2_) { \ + BITWISE_OP, D, S1>(state, dst_src1, src2_); \ + } \ + template \ + DEF_SEM(name ## 2, D dst, S1 src1_, S2 src2_) { \ + BITWISE_OP2, D, S1>(state, dst, src1_, src2_); \ + } + +DEFINE_OP(AND, std::bit_and) +DEFINE_OP(OR, std::bit_or) +DEFINE_OP(XOR, std::bit_xor) + +#undef DEFINE_OP + +template +DEF_SEM(NOT_REG, D dst_src1, S1 src1_) { + W(dst_src1) = ~R(src1_); +} + +template +DEF_SEM(NOT_MEM, D dst_src1) { + W(dst_src1) = ~R(dst_src1); +} + +} // namespace + diff --git a/mcsema/Arch/X86/Semantics/State.inc b/mcsema/Arch/X86/Semantics/MACHINE.inc similarity index 57% rename from mcsema/Arch/X86/Semantics/State.inc rename to mcsema/Arch/X86/Semantics/MACHINE.inc index ad3d9bdf..97d6af98 100644 --- a/mcsema/Arch/X86/Semantics/State.inc +++ b/mcsema/Arch/X86/Semantics/MACHINE.inc @@ -1,29 +1,22 @@ /* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ -#include #include +#include -#include "mcsema/Arch/X86/Semantics/Register.inc" +struct State; -typedef float float32_t; -static_assert(4 == sizeof(float32_t), "Invalid `float32_t` size."); +#include "mcsema/Arch/Semantics/CONTROL.inc" +#include "mcsema/Arch/Semantics/TYPES.inc" +#include "mcsema/Arch/Semantics/MACROS.inc" +#include "mcsema/Arch/Semantics/MEMORY.inc" -typedef double float64_t; -static_assert(8 == sizeof(float64_t), "Invalid `float64_t` size."); +#if 64 == ADDRESS_SIZE_BITS +# define IF_64BIT(...) __VA_ARGS__ +#else +# define IF_64BIT(...) +#endif -struct alignas(16) float80_t { - long double f; -}; -static_assert(16 == sizeof(float80_t), "Invalid `float80_t` size."); - -typedef unsigned uint128_t __attribute__ ((vector_size (16))); -static_assert(16 == sizeof(uint128_t), "Invalid `uint128_t` size."); - -typedef unsigned uint256_t __attribute__ ((vector_size (32))); -static_assert(32 == sizeof(uint256_t), "Invalid `uint256_t` size."); - -typedef unsigned uint512_t __attribute__ ((vector_size (64))); -static_assert(64 == sizeof(uint512_t), "Invalid `uint512_t` size."); +#include "mcsema/Arch/X86/Semantics/REGISTER.inc" union FPUStatusWord { struct { @@ -68,87 +61,6 @@ union FPUControlWord { static_assert(2 == sizeof(FPUControlWord), "Invalid structure packing of `FPUControl`."); -typedef uint8_t uint8v16_t __attribute__ ((vector_size (16))); -typedef uint16_t uint16v8_t __attribute__ ((vector_size (16))); -typedef uint32_t uint32v4_t __attribute__ ((vector_size (16))); -typedef uint64_t uint64v2_t __attribute__ ((vector_size (16))); -typedef float32_t float32v4_t __attribute__ ((vector_size (16))); -typedef float64_t float64v2_t __attribute__ ((vector_size (16))); - -union XMMReg { - uint8v16_t bytes; - uint16v8_t words; - uint32v4_t dwords; - uint64v2_t qwords; - float32v4_t floats; - float64v2_t doubles; -} __attribute__((packed)); - -static_assert(16 == sizeof(XMMReg), - "Invalid structure packing of `XMMReg`."); - -#if 64 == ADDRESS_SIZE_BITS - -typedef uint8_t uint8v32_t __attribute__ ((vector_size (32))); -typedef uint16_t uint16v16_t __attribute__ ((vector_size (32))); -typedef uint32_t uint32v8_t __attribute__ ((vector_size (32))); -typedef uint64_t uint64v4_t __attribute__ ((vector_size (32))); -typedef float32_t float32v8_t __attribute__ ((vector_size (32))); -typedef float64_t float64v4_t __attribute__ ((vector_size (32))); - -union YMMReg { - uint8v32_t bytes; - uint16v16_t words; - uint32v8_t dwords; - uint64v4_t qwords; - float32v8_t floats; - float64v4_t doubles; -} __attribute__((packed)); - -static_assert(32 == sizeof(YMMReg), - "Invalid structure packing of `YMMReg`."); - -typedef uint8_t uint8v64_t __attribute__ ((vector_size (64))); -typedef uint16_t uint16v32_t __attribute__ ((vector_size (64))); -typedef uint32_t uint32v16_t __attribute__ ((vector_size (64))); -typedef uint64_t uint64v8_t __attribute__ ((vector_size (64))); -typedef float32_t float32v16_t __attribute__ ((vector_size (64))); -typedef float64_t float64v8_t __attribute__ ((vector_size (64))); - -union ZMMReg { - uint8v64_t bytes; - uint16v32_t words; - uint32v16_t dwords; - uint64v8_t qwords; - float32v16_t floats; - float64v8_t doubles; -} __attribute__((packed)); - -static_assert(64 == sizeof(ZMMReg), - "Invalid structure packing of `ZMMReg`."); - -#endif // 64 == ADDRESS_SIZE_BITS - -union alignas(64) VectorReg { - XMMReg xmm; -#if 64 == ADDRESS_SIZE_BITS - YMMReg ymm; - ZMMReg zmm; -#endif // 64 == ADDRESS_SIZE_BITS -} __attribute__((packed)); - -static_assert(sizeof(uint512_t) == sizeof(VectorReg), - "Invalid structure packing of `VectorReg`."); -static_assert(0 == __builtin_offsetof(VectorReg, xmm), - "Invalid packing of `VectorReg::xmm`."); - -#if 64 == ADDRESS_SIZE_BITS -static_assert(0 == __builtin_offsetof(VectorReg, ymm), - "Invalid packing of `VectorReg::ymm`."); -static_assert(0 == __builtin_offsetof(VectorReg, zmm), - "Invalid packing of `VectorReg::zmm`."); -#endif // 64 == ADDRESS_SIZE_BITS - union FPUStackElem { float80_t st; double mmx; @@ -175,7 +87,7 @@ class FPU { // Note: This is consistent with `fxsave64`, but doesn't handle things like // ZMM/YMM registers. Therefore, we use a different set of registers // for those. - uint128_t xmm[16]; // 16*16 bytes for each XMM reg = 256 bytes. + vec128_t xmm[16]; // 16*16 bytes for each XMM reg = 256 bytes. uint32_t padding[24]; } __attribute__((packed)); @@ -248,8 +160,8 @@ union Reg { alignas(2) uint16_t word; alignas(4) uint32_t dword; alignas(8) uint64_t full; - alignas(8) uint64_t *ptr; -}; + alignas(8) int64_t sfull; +} __attribute__((packed)); #else @@ -261,8 +173,8 @@ union Reg { alignas(2) uint16_t word; alignas(4) uint32_t dword; alignas(4) uint32_t full; - alignas(4) uint32_t *ptr; -}; + alignas(4) int32_t sfull; +} __attribute__((packed)); #endif // 64 != ADDRESS_SIZE_BITS @@ -272,6 +184,25 @@ static_assert(1 == __builtin_offsetof(Reg, byte.high), "Invalid packing of `Reg: static_assert(0 == __builtin_offsetof(Reg, word), "Invalid packing of `Reg::word`."); static_assert(0 == __builtin_offsetof(Reg, dword), "Invalid packing of `Reg::dword`."); static_assert(0 == __builtin_offsetof(Reg, full), "Invalid packing of `Reg::full`."); +static_assert(0 == __builtin_offsetof(Reg, sfull), "Invalid packing of `Reg::sfull`."); + +union alignas(64) VectorReg { + vec128_t xmm; + + IF_64BIT( vec256_t ymm; ) + IF_64BIT( vec512_t zmm; ) + +} __attribute__((packed)); + +static_assert(0 == __builtin_offsetof(VectorReg, xmm), + "Invalid packing of `VectorReg::xmm`."); + +#if 64 == ADDRESS_SIZE_BITS +static_assert(0 == __builtin_offsetof(VectorReg, ymm), + "Invalid packing of `VectorReg::ymm`."); +static_assert(0 == __builtin_offsetof(VectorReg, zmm), + "Invalid packing of `VectorReg::zmm`."); +#endif // 64 == ADDRESS_SIZE_BITS class alignas(8) GPR { public: @@ -322,7 +253,7 @@ extern "C" { // Method that will implement a basic block. We will clone this method for // each basic block in the code being lifted. [[gnu::used]] -void BlockMethod(State &state) noexcept { +void __mcsema_basic_block(State &state) noexcept { // Define read- and write-specific aliases of each register. We will // reference these variables from the bitcode side of things so that, @@ -345,68 +276,75 @@ void BlockMethod(State &state) noexcept { #undef REG_INFO64 } -// TODO(pag): Perform exit the program due to an error. -[[gnu::used, gnu::noinline]] -void DispatchExitProgramError(State &state) noexcept { - (void) state.gpr.rip; -} - -// TODO(pag): Perform indirect branch based on program counter. -[[gnu::used, gnu::noinline]] -void DispatchIndirectFunctionCall(State &state) noexcept { - (void) state.gpr.rip; -} - -// TODO(pag): Perform indirect branch based on program counter. -[[gnu::used, gnu::noinline]] -void DispatchIndirectJump(State &state) noexcept { - (void) state.gpr.rip; -} - -// TODO(pag): Perform indirect branch based on program counter. -[[gnu::used, gnu::noinline]] -void DispatchFunctionReturn(State &state) noexcept { - (void) state.gpr.rip; +// This is just a hack to make sure all these functions appear in the bitcode +// file! +[[gnu::used]] +void __mcsema_intrinsics(void) { + (void) __mcsema_basic_block; + (void) __mcsema_error; + (void) __mcsema_function_call; + (void) __mcsema_function_return; + (void) __mcsema_jump; + (void) __mcsema_system_call; + (void) __mcsema_system_return; + (void) __mcsema_interrupt_call; + (void) __mcsema_interrupt_return; + (void) __mcsema_read_memory_8; + (void) __mcsema_read_memory_16; + (void) __mcsema_read_memory_32; + (void) __mcsema_read_memory_64; + (void) __mcsema_read_memory_128; + (void) __mcsema_read_memory_256; + (void) __mcsema_read_memory_512; + (void) __mcsema_write_memory_8; + (void) __mcsema_write_memory_16; + (void) __mcsema_write_memory_32; + (void) __mcsema_write_memory_64; + (void) __mcsema_write_memory_128; + (void) __mcsema_write_memory_256; + (void) __mcsema_write_memory_512; + (void) __mcsema_compute_address; + (void) __mcsema_undefined_bool; } } // extern C -typedef uint64_t &R64W; -typedef uint64_t R64; - -typedef decltype(Reg().full) &R32W; -typedef uint32_t R32; - -typedef uint16_t &R16W; -typedef uint16_t R16; +// Unsigned ------------- typedef uint8_t &R8W; typedef uint8_t R8; +typedef uint16_t &R16W; +typedef uint16_t R16; +typedef decltype(Reg().full) &R32W; +typedef uint32_t R32; +IF_64BIT( typedef uint64_t &R64W; ) +IF_64BIT( typedef uint64_t R64; ) +typedef vec128_t &R128W; +typedef vec128_t R128; +typedef vec256_t &R256W; +typedef vec256_t R256; +typedef vec512_t &R512W; +typedef vec512_t R512; -// TODO(pag): These could be turned into references. It would be interesting -// to see if this has any effect in terms of optimization, as the -// pointers would be marked as `dereferencable`. -typedef uint64_t *M64; -typedef uint32_t *M32; -typedef uint16_t *M16; -typedef uint8_t *M8; +IF_64BIT( typedef uint64_t I64; ) +typedef uint32_t I32; +typedef uint16_t I16; +typedef uint8_t I8; -typedef uint64_t IMM64; -typedef uint32_t IMM32; -typedef uint16_t IMM16; -typedef uint8_t IMM8; +IF_64BIT( typedef int64_t SI64; ) +typedef int32_t SI32; +typedef int16_t SI16; +typedef int8_t SI8; -typedef int64_t SIMM64; -typedef int32_t SIMM32; -typedef int16_t SIMM16; -typedef int8_t SIMM8; +// Immediate selectors ------------- typedef uintptr_t PC; -#define INSTR_ATTRIBS [[gnu::always_inline, gnu::gnu_inline, gnu::flatten]] +#define INSTR_ATTRIBS ALWAYS_INLINE // Define a specific instruction selection variable. -#define DEF_ISEL(name) extern "C" constexpr auto name __attribute__((used, visibility("default"))) +#define DEF_ISEL(name) \ + extern "C" constexpr auto name __attribute__((used, visibility("default"))) // Define a semantics implementing function. #define DEF_SEM(name, ...) \ @@ -419,69 +357,123 @@ typedef uintptr_t PC; DEF_ISEL(name ## _64) = func #define DEF_ISEL_32UP(name, func) \ - DEF_ISEL(name ## _32) = func ; \ - DEF_ISEL(name ## _64) = func + DEF_ISEL(name ## _32) = func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = func ) #define DEF_ISEL_Rn(name, tpl_func) \ DEF_ISEL(name ## _8) = tpl_func ; \ DEF_ISEL(name ## _16) = tpl_func ; \ - DEF_ISEL(name ## _32) = tpl_func ; \ - DEF_ISEL(name ## _64) = tpl_func + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) -#define DEF_ISEL_WRn_Mn(name, tpl_func) \ +#define DEF_ISEL_Mn(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +#define DEF_ISEL_In(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +// Two operand (dst <- src) +#define DEF_ISEL_Rn_Mn(name, tpl_func) \ DEF_ISEL(name ## _8) = tpl_func ; \ DEF_ISEL(name ## _16) = tpl_func ; \ - DEF_ISEL(name ## _32) = tpl_func ; \ - DEF_ISEL(name ## _64) = tpl_func + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) -#define DEF_ISEL_WRn_Rn(name, tpl_func) \ +#define DEF_ISEL_Rn_Rn(name, tpl_func) \ DEF_ISEL(name ## _8) = tpl_func ; \ DEF_ISEL(name ## _16) = tpl_func ; \ - DEF_ISEL(name ## _32) = tpl_func ; \ - DEF_ISEL(name ## _64) = tpl_func + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) -#define DEF_ISEL_WRn_In(name, tpl_func) \ - DEF_ISEL(name ## _8) = tpl_func ; \ - DEF_ISEL(name ## _16) = tpl_func ; \ - DEF_ISEL(name ## _32) = tpl_func ; \ - DEF_ISEL(name ## _64) = tpl_func +#define DEF_ISEL_Rn_In(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) #define DEF_ISEL_Mn_In(name, tpl_func) \ - DEF_ISEL(name ## _8) = tpl_func ; \ - DEF_ISEL(name ## _16) = tpl_func ; \ - DEF_ISEL(name ## _32) = tpl_func ; \ - DEF_ISEL(name ## _64) = tpl_func + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) #define DEF_ISEL_Mn_Rn(name, tpl_func) \ DEF_ISEL(name ## _8) = tpl_func ; \ DEF_ISEL(name ## _16) = tpl_func ; \ - DEF_ISEL(name ## _32) = tpl_func ; \ - DEF_ISEL(name ## _64) = tpl_func + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +// 3-operand dst <- (src1 op src2) +#define DEF_ISEL_Rn_Rn_Mn(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +#define DEF_ISEL_Rn_Rn_Rn(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +#define DEF_ISEL_Rn_Rn_In(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +#define DEF_ISEL_Mn_Mn_In(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) + +#define DEF_ISEL_Mn_Mn_Rn(name, tpl_func) \ + DEF_ISEL(name ## _8) = tpl_func ; \ + DEF_ISEL(name ## _16) = tpl_func ; \ + DEF_ISEL(name ## _32) = tpl_func \ + IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func ) namespace { +// Write to memory. template INSTR_ATTRIBS -static inline T &W(T *v) { return *v; } +static inline Mn W(Mn addr) { + return addr; +} +// Write to a register. template INSTR_ATTRIBS static inline T &W(T &v) { return v; } template INSTR_ATTRIBS -static inline T R(T *v) { return *v; } +static inline T R(Mn addr) { + return addr.Read(); +} template INSTR_ATTRIBS -static inline T R(T v) { return v; } - -#include "mcsema/Arch/X86/Semantics/Flags.inc" +static inline T R(T v) { + return v; +} } // namespace +#include "mcsema/Arch/X86/Semantics/FLAGS.inc" +#include "mcsema/Arch/X86/Semantics/BINARY.inc" #include "mcsema/Arch/X86/Semantics/CALL_RET.inc" #include "mcsema/Arch/X86/Semantics/COND_BR.inc" #include "mcsema/Arch/X86/Semantics/DATAXFER.inc" #include "mcsema/Arch/X86/Semantics/LOGICAL.inc" #include "mcsema/Arch/X86/Semantics/MISC.inc" +#include "mcsema/Arch/X86/Semantics/STACK.inc" +#include "mcsema/Arch/X86/Semantics/UNCOND_BR.inc" diff --git a/mcsema/Arch/X86/Semantics/MISC.inc b/mcsema/Arch/X86/Semantics/MISC.inc index b1598198..15c6950d 100644 --- a/mcsema/Arch/X86/Semantics/MISC.inc +++ b/mcsema/Arch/X86/Semantics/MISC.inc @@ -3,10 +3,10 @@ namespace { template DEF_SEM(LEA, D dst, S src) { - W(dst) = reinterpret_cast(src); + W(dst) = src.addr; } } // namespace DEF_ISEL(LEA_GPRv_AGEN_32) = LEA; -DEF_ISEL(LEA_GPRv_AGEN_64) = LEA; +IF_64BIT( DEF_ISEL(LEA_GPRv_AGEN_64) = LEA; ) diff --git a/mcsema/Arch/X86/Semantics/Register.inc b/mcsema/Arch/X86/Semantics/REGISTER.inc similarity index 100% rename from mcsema/Arch/X86/Semantics/Register.inc rename to mcsema/Arch/X86/Semantics/REGISTER.inc diff --git a/mcsema/Arch/X86/Semantics/STACK.inc b/mcsema/Arch/X86/Semantics/STACK.inc new file mode 100644 index 00000000..37207794 --- /dev/null +++ b/mcsema/Arch/X86/Semantics/STACK.inc @@ -0,0 +1,28 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +namespace { + +template +DEF_SEM(PUSH, T val_) { + auto val = R(val_); + state.gpr.rsp.full -= sizeof(val); + Mn::Write(state.gpr.rsp.full, val); +} + +} // namespace + +DEF_ISEL_Mn(PUSH_MEMv, PUSH); +DEF_ISEL_Rn(PUSH_GPRv, PUSH); +DEF_ISEL_Rn(PUSH_GPRv_50, PUSH); +DEF_ISEL_In(PUSH_IMMz, PUSH); +DEF_ISEL_In(PUSH_IMMb, PUSH); + +/* +759 PUSH PUSH_ES PUSH BASE I86 ATTRIBUTES: FIXED_BASE0 SCALABLE STACKPUSH0 +760 PUSH PUSH_CS PUSH BASE I86 ATTRIBUTES: FIXED_BASE0 SCALABLE STACKPUSH0 +761 PUSH PUSH_SS PUSH BASE I86 ATTRIBUTES: FIXED_BASE0 SCALABLE STACKPUSH0 +762 PUSH PUSH_DS PUSH BASE I86 ATTRIBUTES: FIXED_BASE0 SCALABLE STACKPUSH0 + +766 PUSH PUSH_FS PUSH BASE I86 ATTRIBUTES: FIXED_BASE0 SCALABLE STACKPUSH0 +767 PUSH PUSH_GS PUSH BASE I86 ATTRIBUTES: FIXED_BASE0 SCALABLE STACKPUSH0 + */ diff --git a/mcsema/Arch/X86/Semantics/UNCOND_BR.inc b/mcsema/Arch/X86/Semantics/UNCOND_BR.inc new file mode 100644 index 00000000..6e52756e --- /dev/null +++ b/mcsema/Arch/X86/Semantics/UNCOND_BR.inc @@ -0,0 +1,37 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +namespace { + +template +DEF_SEM(JMP, T target_pc) { + state.gpr.rip.full = static_cast(target_pc); +} + +template +DEF_SEM(INDIRECT_JMP, T target_pc) { + CLEAR_AFLAGS(); + state.gpr.rip.full = static_cast(R(target_pc)); +} + +} // namespace + +DEF_ISEL_32UP(JMP_RELBRd, JMP); +DEF_ISEL_32UP(JMP_RELBRz, JMP); +DEF_ISEL_32UP(JMP_RELBRb, JMP); + +#if 64 == ADDRESS_SIZE_BITS +DEF_ISEL(JMP_MEMv_64) = INDIRECT_JMP; +DEF_ISEL(JMP_GRPv_32) = INDIRECT_JMP; +#else +DEF_ISEL(JMP_MEMv_16) = INDIRECT_JMP; +DEF_ISEL(JMP_MEMv_32) = INDIRECT_JMP; +DEF_ISEL(JMP_GRPv_16) = INDIRECT_JMP; +DEF_ISEL(JMP_GRPv_32) = INDIRECT_JMP; +#endif + +/* +625 XABORT XABORT_IMMb UNCOND_BR RTM RTM ATTRIBUTES: + +1807 JMP_FAR JMP_FAR_MEMp2 UNCOND_BR BASE I86 ATTRIBUTES: FAR_XFER NOTSX SCALABLE +1808 JMP_FAR JMP_FAR_PTRp_IMMw UNCOND_BR BASE I86 ATTRIBUTES: FAR_XFER NOTSX SCALABLE + */ diff --git a/mcsema/BC/BC.cpp b/mcsema/BC/BC.cpp index eab33eb1..2f014e44 100644 --- a/mcsema/BC/BC.cpp +++ b/mcsema/BC/BC.cpp @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -24,7 +25,9 @@ #include "mcsema/Arch/Instr.h" #include "mcsema/BC/BC.h" +#include "mcsema/BC/Intrinsic.h" #include "mcsema/BC/Util.h" + #include "mcsema/CFG/CFG.h" namespace llvm { @@ -45,17 +48,13 @@ static std::string NamedSymbolMetaId(std::string func_name) { BC::BC(const Arch *arch_, llvm::Module *module_) : arch(arch_), module(module_), + intrinsic(Intrinsic::FindInModule(module)), blocks(), functions(), symbols(), - next_symbol_id(0), - method(BlockMethod(module)) { + next_symbol_id(0) { IdentifyExistingSymbols(); - InitFunctionAttributes(method); - InitFunctionAttributes(IndirectFunctionCallDispatcher(module)); - InitFunctionAttributes(IndirectJumpDispatcher(module)); - InitFunctionAttributes(FunctionReturnDispatcher(module)); - InitFunctionAttributes(ExitProgramErrorDispatcher(module)); + RemoveUndefinedIntrinsics(); } // Find existing exported functions and variables. This is for the sake of @@ -80,13 +79,15 @@ void BC::IdentifyExistingSymbols(void) { // Create functions for every block in the CFG. void BC::CreateBlocks(const cfg::Module *cfg) { - auto block_type = method->getFunctionType(); + auto block_type = intrinsic->basic_block->getFunctionType(); for (const auto &block : cfg->blocks()) { auto &BF = blocks[block.address()]; if (!BF) { - auto name = "__mcsema_block_" + std::to_string(next_symbol_id++); + std::stringstream ss; + ss << "__mcsema_block_" << (next_symbol_id++) << "_0x" + << std::hex << block.address(); BF = llvm::dyn_cast( - module->getOrInsertFunction(name, block_type)); + module->getOrInsertFunction(ss.str(), block_type)); InitFunctionAttributes(BF); } } @@ -94,7 +95,7 @@ void BC::CreateBlocks(const cfg::Module *cfg) { // Create functions for every function in the CFG. void BC::CreateFunctions(const cfg::Module *cfg) { - auto func_type = method->getFunctionType(); + auto func_type = intrinsic->basic_block->getFunctionType(); for (const auto &func : cfg->functions()) { if (!func.is_exported() && !func.is_imported()) continue; @@ -117,7 +118,6 @@ void BC::CreateFunctions(const cfg::Module *cfg) { // if we merge another CFG into this bitcode module. module->getOrInsertNamedMetadata(NamedSymbolMetaId(func.name())); } - } // Link together functions and basic blocks. @@ -184,11 +184,11 @@ static uint64_t FallThroughPC(const cfg::Block &block) { return instr.address() + instr.size(); } +} // namespace + // Add a fall-through terminator to the block method just in case one is // missing. -static void TerminateBlockMethod(const BlockMap &blocks, - const cfg::Block &block, - llvm::Function *BF) { +void BC::TerminateBlockMethod(const cfg::Block &block, llvm::Function *BF) { auto &B = BF->back(); if (B.getTerminator()) { return; @@ -197,10 +197,25 @@ static void TerminateBlockMethod(const BlockMap &blocks, AddTerminatingTailCall(BF, blocks[FallThroughPC(block)]); } else { LOG(WARNING) << "Empty basic block at " << block.address(); - AddTerminatingTailCall(BF, ExitProgramErrorDispatcher(BF->getParent())); + AddTerminatingTailCall(BF, intrinsic->error); + } +} + +// Remove calls to the undefined intrinsics. +void BC::RemoveUndefinedIntrinsics(void) { + std::vector Cs; + for (auto U : intrinsic->undefined_bool->users()) { + if (auto C = llvm::dyn_cast(U)) { + Cs.push_back(C); + } + } + + auto Undef = llvm::UndefValue::get(llvm::Type::getInt1Ty( + intrinsic->undefined_bool->getContext())); + for (auto C : Cs) { + C->replaceAllUsesWith(Undef); } } -} // namespace // Lift code contained in blocks into the block methods. void BC::LiftBlocks(const cfg::Module *cfg) { @@ -223,11 +238,11 @@ void BC::LiftBlocks(const cfg::Module *cfg) { continue; } - CreateMethodForBlock(BF, method); + CreateMethodForBlock(BF, intrinsic->basic_block); if (block.instructions_size()) { LiftBlockIntoMethod(block, BF); } - TerminateBlockMethod(blocks, block, BF); + TerminateBlockMethod(block, BF); // Perform simple, incremental optimizations on the block functions to // avoid OOMs. @@ -267,7 +282,7 @@ bool BC::LiftInstruction(const cfg::Block &block, const cfg::Instr &instr, llvm::IRBuilder<> ir(P); ir.CreateBr(B); - return arch_instr.Lift(blocks, B); + return arch_instr.Lift(intrinsic, blocks, B); } void BC::LiftCFG(const cfg::Module *cfg) { diff --git a/mcsema/BC/BC.h b/mcsema/BC/BC.h index 9a9cd9b7..abdd2bec 100644 --- a/mcsema/BC/BC.h +++ b/mcsema/BC/BC.h @@ -20,6 +20,7 @@ class Block; } // namespace cfg class Arch; +class Intrinsic; class BC { public: @@ -55,12 +56,22 @@ class BC { bool LiftInstruction(const cfg::Block &block, const cfg::Instr &instr, Instr &ainstr, llvm::Function *BF); + // Add a fall-through terminator to the block method just in case one is + // missing. + void TerminateBlockMethod(const cfg::Block &block, llvm::Function *BF); + + // Remove calls to the undefined intrinsics. + void RemoveUndefinedIntrinsics(void); + // Architecture of the code contained within the CFG being lifted. const Arch * const arch; // Module into which code is lifted. llvm::Module * const module; + // MCSema-specific intrinsics available in the module. + Intrinsic * const intrinsic; + // Blocks that we've added, indexed by their entry address. BlockMap blocks; @@ -76,10 +87,6 @@ class BC { // with their address because they might conflict. So, we give a unique // name to every non-exported symbol we introduce. int next_symbol_id; - - // Functions inside of `module` that we will clone for creating new function / - // block methods. - llvm::Function * const method; }; } // namespace mcsema diff --git a/mcsema/BC/Intrinsic.cpp b/mcsema/BC/Intrinsic.cpp new file mode 100644 index 00000000..90f16b36 --- /dev/null +++ b/mcsema/BC/Intrinsic.cpp @@ -0,0 +1,63 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +#include + +#include + +#include "mcsema/BC/Intrinsic.h" +#include "mcsema/BC/Util.h" + +DECLARE_string(os); + +namespace mcsema { +namespace { + +// Find a specific function. +static llvm::Function *FindIntrinsic(llvm::Module *M, const char *name) { + llvm::Function *F = nullptr; + F = M->getFunction(name); + if (!F && FLAGS_os == "mac") { + F = M->getFunction(std::string("_") + name); + } + LOG_IF(FATAL, !F) << "Missing intrinsic " << name << "for OS: " << FLAGS_os; + InitFunctionAttributes(F); + + F->setDoesNotAccessMemory(); + F->setCannotDuplicate(); + return F; +} + +} // namespace + +Intrinsic::Intrinsic(llvm::Module *M) + : basic_block(FindIntrinsic(M, "__mcsema_basic_block")), + error(FindIntrinsic(M, "__mcsema_error")), + function_call(FindIntrinsic(M, "__mcsema_function_call")), + function_return(FindIntrinsic(M, "__mcsema_function_return")), + jump(FindIntrinsic(M, "__mcsema_jump")), + system_call(FindIntrinsic(M, "__mcsema_system_call")), + system_return(FindIntrinsic(M, "__mcsema_system_return")), + interrupt_call(FindIntrinsic(M, "__mcsema_interrupt_call")), + interrupt_return(FindIntrinsic(M, "__mcsema_interrupt_return")), + read_memory_8(FindIntrinsic(M, "__mcsema_read_memory_8")), + read_memory_16(FindIntrinsic(M, "__mcsema_read_memory_16")), + read_memory_32(FindIntrinsic(M, "__mcsema_read_memory_32")), + read_memory_64(FindIntrinsic(M, "__mcsema_read_memory_64")), + read_memory_128(FindIntrinsic(M, "__mcsema_read_memory_128")), + read_memory_256(FindIntrinsic(M, "__mcsema_read_memory_256")), + read_memory_512(FindIntrinsic(M, "__mcsema_read_memory_512")), + write_memory_8(FindIntrinsic(M, "__mcsema_write_memory_8")), + write_memory_16(FindIntrinsic(M, "__mcsema_write_memory_16")), + write_memory_32(FindIntrinsic(M, "__mcsema_write_memory_32")), + write_memory_64(FindIntrinsic(M, "__mcsema_write_memory_64")), + write_memory_128(FindIntrinsic(M, "__mcsema_write_memory_128")), + write_memory_256(FindIntrinsic(M, "__mcsema_write_memory_256")), + write_memory_512(FindIntrinsic(M, "__mcsema_write_memory_512")), + compute_address(FindIntrinsic(M, "__mcsema_compute_address")), + undefined_bool(FindIntrinsic(M, "__mcsema_undefined_bool")) {} + +Intrinsic *Intrinsic::FindInModule(llvm::Module *M) { + return new Intrinsic(M); +} + +} // namespace mcsema diff --git a/mcsema/BC/Intrinsic.h b/mcsema/BC/Intrinsic.h new file mode 100644 index 00000000..531007c2 --- /dev/null +++ b/mcsema/BC/Intrinsic.h @@ -0,0 +1,59 @@ +/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */ + +#ifndef MCSEMA_BC_INTRINSIC_H_ +#define MCSEMA_BC_INTRINSIC_H_ + +namespace llvm { +class Function; +} // namespace llvm +namespace mcsema { + +class Intrinsic { + public: + static Intrinsic *FindInModule(llvm::Module *M); + + // Basic block template. + llvm::Function * const basic_block; + + // Control-transfer intrinsics. + llvm::Function * const error; + llvm::Function * const function_call; + llvm::Function * const function_return; + llvm::Function * const jump; + llvm::Function * const system_call; + llvm::Function * const system_return; + llvm::Function * const interrupt_call; + llvm::Function * const interrupt_return; + + // Memory read intrinsics. + llvm::Function * const read_memory_8; + llvm::Function * const read_memory_16; + llvm::Function * const read_memory_32; + llvm::Function * const read_memory_64; + llvm::Function * const read_memory_128; + llvm::Function * const read_memory_256; + llvm::Function * const read_memory_512; + + // Memory write intrinsics. + llvm::Function * const write_memory_8; + llvm::Function * const write_memory_16; + llvm::Function * const write_memory_32; + llvm::Function * const write_memory_64; + llvm::Function * const write_memory_128; + llvm::Function * const write_memory_256; + llvm::Function * const write_memory_512; + + // Addressing intrinsics. + llvm::Function * const compute_address; + + // Undefined values. + llvm::Function * const undefined_bool; + + private: + Intrinsic(void) = delete; + explicit Intrinsic(llvm::Module *M); +}; + +} // namespace mcsema + +#endif // MCSEMA_BC_INTRINSIC_H_ diff --git a/mcsema/BC/Util.cpp b/mcsema/BC/Util.cpp index 03c5f116..b4ab6724 100644 --- a/mcsema/BC/Util.cpp +++ b/mcsema/BC/Util.cpp @@ -9,8 +9,6 @@ #include "mcsema/BC/Util.h" -DECLARE_string(os); - namespace mcsema { llvm::Function *&BlockMap::operator[](uintptr_t pc) { @@ -54,8 +52,7 @@ void AddTerminatingTailCall(llvm::BasicBlock *B, llvm::Function *To) { ir.CreateUnreachable(); } else { llvm::Function *F = B->getParent(); - llvm::Argument *SP = &*F->getArgumentList().begin(); // Machine state ptr. - llvm::CallInst *C = ir.CreateCall(To, {SP}); + llvm::CallInst *C = ir.CreateCall(To, {FindStatePointer(F)}); C->setTailCallKind(llvm::CallInst::TCK_MustTail); C->setCallingConv(llvm::CallingConv::Fast); ir.CreateRetVoid(); @@ -75,59 +72,9 @@ llvm::Value *FindVarInFunction(llvm::Function *F, std::string name) { return nullptr; } -// Return a pointer to the block method template. -llvm::Function *BlockMethod(llvm::Module *M) { - llvm::Function *F = nullptr; - F = M->getFunction("BlockMethod"); - if (!F && FLAGS_os == "mac") { - F = M->getFunction("_BlockMethod"); - } - LOG_IF(FATAL, !F) << "Missing block method for OS: " << FLAGS_os; - return F; -} - -// Return a pointer to the method that exits the program. -llvm::Function *ExitProgramErrorDispatcher(llvm::Module *M) { - llvm::Function *F = nullptr; - F = M->getFunction("DispatchExitProgramError"); - if (!F && FLAGS_os == "mac") { - F = M->getFunction("_DispatchExitProgramError"); - } - LOG_IF(FATAL, !F) << "Missing program exit dispatcher for OS: " << FLAGS_os; - return F; -} - -// Return a pointer to the indirect branch method. -llvm::Function *IndirectFunctionCallDispatcher(llvm::Module *M) { - llvm::Function *F = nullptr; - F = M->getFunction("DispatchIndirectFunctionCall"); - if (!F && FLAGS_os == "mac") { - F = M->getFunction("_DispatchIndirectFunctionCall"); - } - LOG_IF(FATAL, !F) << "Missing indirect call dispatcher for OS: " << FLAGS_os; - return F; -} - -// Return a pointer to the indirect branch method. -llvm::Function *IndirectJumpDispatcher(llvm::Module *M) { - llvm::Function *F = nullptr; - F = M->getFunction("DispatchIndirectJump"); - if (!F && FLAGS_os == "mac") { - F = M->getFunction("_DispatchIndirectJump"); - } - LOG_IF(FATAL, !F) << "Missing indirect jump dispatcher for OS: " << FLAGS_os; - return F; -} - -// Return a pointer to the indirect branch method. -llvm::Function *FunctionReturnDispatcher(llvm::Module *M) { - llvm::Function *F = nullptr; - F = M->getFunction("DispatchFunctionReturn"); - if (!F && FLAGS_os == "mac") { - F = M->getFunction("_DispatchFunctionReturn"); - } - LOG_IF(FATAL, !F) << "Missing return dispatcher for OS: " << FLAGS_os; - return F; +// Find the machine state pointer. +llvm::Value *FindStatePointer(llvm::Function *F) { + return &*F->getArgumentList().begin(); } } // namespace mcsema diff --git a/mcsema/BC/Util.h b/mcsema/BC/Util.h index ac3a2b71..bdb81d5c 100644 --- a/mcsema/BC/Util.h +++ b/mcsema/BC/Util.h @@ -31,16 +31,8 @@ void AddTerminatingTailCall(llvm::BasicBlock *From, llvm::Function *To); // this to find register variables. llvm::Value *FindVarInFunction(llvm::Function *F, std::string name); -// Return a pointer to the block method template. -llvm::Function *BlockMethod(llvm::Module *M); - -// Return a pointer to the method that exits the program. -llvm::Function *ExitProgramErrorDispatcher(llvm::Module *M); - -// Return a pointer to the indirect branch method. -llvm::Function *IndirectFunctionCallDispatcher(llvm::Module *M); -llvm::Function *IndirectJumpDispatcher(llvm::Module *M); -llvm::Function *FunctionReturnDispatcher(llvm::Module *M); +// Find the machine state pointer. +llvm::Value *FindStatePointer(llvm::Function *F); } // namespace mcsema diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index a222abeb..090a3890 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -86,20 +86,20 @@ echo "${YELLOW}Generating architecture-specific state files.${RESET}" cd $DIR CXXFLAGS="-std=gnu++11 -g0 -O0 -fno-exceptions -fno-rtti -fno-asynchronous-unwind-tables -I${DIR}" $DIR/third_party/llvm/build/bin/clang++ -x c++ -m32 -DADDRESS_SIZE_BITS=32 $CXXFLAGS -E - \ - < $DIR/mcsema/Arch/X86/Semantics/State.inc \ - > $DIR/generated/Arch/X86/Semantics/State32.cpp + < $DIR/mcsema/Arch/X86/Semantics/MACHINE.inc \ + > $DIR/generated/Arch/X86/Semantics/MACHINE32.cpp $DIR/third_party/llvm/build/bin/clang++ -x c++ -m64 -DADDRESS_SIZE_BITS=64 $CXXFLAGS -E - \ - < $DIR/mcsema/Arch/X86/Semantics/State.inc \ - > $DIR/generated/Arch/X86/Semantics/State64.cpp + < $DIR/mcsema/Arch/X86/Semantics/MACHINE.inc \ + > $DIR/generated/Arch/X86/Semantics/MACHINE64.cpp $DIR/third_party/llvm/build/bin/clang++ -g3 -m32 -DADDRESS_SIZE_BITS=32 $CXXFLAGS -emit-llvm \ - -c $DIR/generated/Arch/X86/Semantics/State32.cpp \ - -o $DIR/generated/Arch/X86/Semantics/State32.bc + -c $DIR/generated/Arch/X86/Semantics/MACHINE32.cpp \ + -o $DIR/generated/Arch/X86/Semantics/MACHINE32.bc $DIR/third_party/llvm/build/bin/clang++ -g3 -m64 -DADDRESS_SIZE_BITS=64 $CXXFLAGS -emit-llvm \ - -c $DIR/generated/Arch/X86/Semantics/State64.cpp \ - -o $DIR/generated/Arch/X86/Semantics/State64.bc + -c $DIR/generated/Arch/X86/Semantics/MACHINE64.cpp \ + -o $DIR/generated/Arch/X86/Semantics/MACHINE64.bc # Generate the protocol buffer file for the CFG definition. The lifter will