Bringing things in the direction of using 'memory' intrinsics. I'm still not super pleased with some of the APIs but its a reasonable start and things seem to be working (I think).

This commit is contained in:
Peter Goodman
2015-11-14 01:30:01 -05:00
parent 602c927559
commit 8d7cb99f8f
26 changed files with 878 additions and 474 deletions
+5 -1
View File
@@ -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;
+30
View File
@@ -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
+8
View File
@@ -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_
+69
View File
@@ -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 <typename T>
struct Mn;
#define MAKE_TYPE(prefix, T, size) \
template <> \
struct Mn<T> { \
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);
+72
View File
@@ -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);
+2 -2
View File
@@ -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.
+32 -120
View File
@@ -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<llvm::Value *> 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
+4 -1
View File
@@ -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;
+114
View File
@@ -0,0 +1,114 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
#include <functional>
namespace {
template <typename Op, typename D, typename S1>
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 <typename Op, typename D, typename S1, typename S2>
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 <typename D, typename S1> \
DEF_SEM(name, D dst_src1, S1 src2_) { \
BINARY_OP<op<S1>, D, S1>(state, dst_src1, src2_); \
} \
template <typename D, typename S1, typename S2> \
DEF_SEM(name ## 2, D dst, S1 src1_, S2 src2_) { \
BINARY_OP2<op<S1>, 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<M8, I8>;
DEF_ISEL(ADD_GPR8_IMMb_80r0_8) = ADD2<R8W, R8, I8>;
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<M8, I8>;
DEF_ISEL(ADD_GPR8_IMMb_82r0_8) = ADD2<R8W, R8, I8>;
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<M8, R8>;
DEF_ISEL(ADD_GPR8_GPR8_00_8) = ADD2<R8W, R8, R8>;
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<R8W, R8, M8>;
DEF_ISEL(ADD_GPR8_GPR8_02_8) = ADD2<R8W, R8, R8>;
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<R8W, R8, I8>;
DEF_ISEL_Rn_Rn_In(ADD_OrAX_IMMz, ADD2);
DEF_ISEL(SUB_MEMb_IMMb_80r5_8) = SUB<M8, I8>;
DEF_ISEL(SUB_GPR8_IMMb_80r5_8) = SUB2<R8W, R8, I8>;
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<M8, I8>;
DEF_ISEL(SUB_GPR8_IMMb_82r5_8) = SUB2<R8W, R8, I8>;
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<M8, I8>;
DEF_ISEL(SUB_GPR8_GPR8_28_8) = SUB2<R8W, R8, R8>;
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<R8W, R8, R8>;
DEF_ISEL(SUB_GPR8_MEMb_8) = SUB2<R8W, R8, M8>;
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<R8W, R8, I8>;
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
*/
+12 -15
View File
@@ -5,26 +5,23 @@ namespace {
template <typename T>
DEF_SEM(CALL, T target_pc) {
CLEAR_AFLAGS();
*state.gpr.rsp.ptr-- = state.gpr.rip.full;
state.gpr.rip.full = static_cast<PC>(target_pc);
state.gpr.rsp.full -= sizeof(state.gpr.rsp.full);
Mn<PC>::Write(state.gpr.rsp.full, state.gpr.rip.full);
state.gpr.rip.full = R(target_pc);
}
template <typename T>
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<uintptr_t>(*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<PC>::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<PC>::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<PC>);
DEF_ISEL_32UP(CALL_NEAR_RELBRd, CALL<PC>);
DEF_ISEL(CALL_NEAR_MEMv_32) = INDIRECT_CALL<uint32_t>;
DEF_ISEL(CALL_NEAR_MEMv_64) = INDIRECT_CALL<uint64_t>;
DEF_ISEL(CALL_NEAR_MEMv_32) = CALL<M32>;
IF_64BIT( DEF_ISEL(CALL_NEAR_MEMv_64) = CALL<M64>; )
DEF_ISEL_Rn(CALL_NEAR_GRPv, CALL);
+8 -8
View File
@@ -9,22 +9,22 @@ DEF_SEM(MOV, D dst, S src) {
} // namespace
DEF_ISEL(MOV_GPR8_IMMb_C6r0_8) = MOV<R8W, IMM8>;
DEF_ISEL(MOV_MEMb_IMMb_8) = MOV<R8W, IMM8>;
DEF_ISEL(MOV_GPR8_IMMb_C6r0_8) = MOV<R8W, I8>;
DEF_ISEL(MOV_MEMb_IMMb_8) = MOV<M8, I8>;
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<R8W, R8>;
DEF_ISEL(MOV_MEMb_GPR8_8) = MOV<M8, R8>;
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<R8W, M8>;
DEF_ISEL(MOV_GPR8_GPR8_8A_8) = MOV<R8W, R8>;
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<R8W, M8>;
DEF_ISEL_WRn_Mn(MOV_OrAX_MEMv, MOV);
DEF_ISEL_Rn_Mn(MOV_OrAX_MEMv, MOV);
DEF_ISEL(MOV_MEMb_AL_8) = MOV<M8, R8>;
DEF_ISEL_Mn_Rn(MOV_MEMv_OrAX, MOV);
DEF_ISEL(MOV_GPR8_IMMb_D0_8) = MOV<R8W, IMM8>;
DEF_ISEL(MOV_GPR8_IMMb_D0_8) = MOV<R8W, I8>;
DEF_ISEL_WRn_In(MOV_GPRv_IMMv, MOV);
DEF_ISEL_Rn_In(MOV_GPRv_IMMv, MOV);
+52
View File
@@ -0,0 +1,52 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
template <typename S1, typename S2, typename R>
[[gnu::const]]
extern bool CarryFlag(S1 lhs, S2 rhs, R result);
template <typename S1, typename S2, typename R>
[[gnu::const]]
extern bool ParityFlag(S1 lhs, S2 rhs, R result);
template <typename S1, typename S2, typename R>
[[gnu::const]]
extern bool AuxCarryFlag(S1 lhs, S2 rhs, R result);
template <typename S1, typename S2, typename R>
[[gnu::const]]
extern bool ZeroFlag(S1 lhs, S2 rhs, R result);
template <typename S1, typename S2, typename R>
[[gnu::const]]
extern bool SignFlag(S1 lhs, S2 rhs, R result);
template <typename S1, typename S2, typename R>
[[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()
-47
View File
@@ -1,47 +0,0 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
template <typename T, typename R>
__attribute__((noinline, const))
extern bool CarryFlag(T lhs, T rhs, R result);
template <typename T, typename R>
__attribute__((noinline, const))
extern bool ParityFlag(T lhs, T rhs, R result);
template <typename T, typename R>
__attribute__((noinline, const))
extern bool AuxCarryFlag(T lhs, T rhs, R result);
template <typename T, typename R>
__attribute__((noinline, const))
extern bool ZeroFlag(T lhs, T rhs, R result);
template <typename T, typename R>
__attribute__((noinline, const))
extern bool SignFlag(T lhs, T rhs, R result);
template <typename T, typename R>
__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()
+50
View File
@@ -0,0 +1,50 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
namespace {
template <typename Op, typename D, typename S1>
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 <typename Op, typename D, typename S1, typename S2>
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 <typename D, typename S1> \
DEF_SEM(name, D dst_src1, S1 src2_) { \
BITWISE_OP<op<S1>, D, S1>(state, dst_src1, src2_); \
} \
template <typename D, typename S1, typename S2> \
DEF_SEM(name ## 2, D dst, S1 src1_, S2 src2_) { \
BITWISE_OP2<op<S1>, 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 <typename Op, typename D, typename S1>
DEF_SEM(NOT_REG, D dst_src1, S1 src1_) {
W(dst_src1) = ~R(src1_);
}
template <typename Op, typename D>
DEF_SEM(NOT_MEM, D dst_src1) {
W(dst_src1) = ~R(dst_src1);
}
} // namespace
@@ -1,29 +1,22 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
#include <cstdint>
#include <type_traits>
#include <cstdint>
#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<R8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32> ; \
DEF_ISEL(name ## _64) = tpl_func<R64>
DEF_ISEL(name ## _32) = tpl_func<R32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64> )
#define DEF_ISEL_WRn_Mn(name, tpl_func) \
#define DEF_ISEL_Mn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<M8> ; \
DEF_ISEL(name ## _16) = tpl_func<M16> ; \
DEF_ISEL(name ## _32) = tpl_func<M32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64> )
#define DEF_ISEL_In(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<I8> ; \
DEF_ISEL(name ## _16) = tpl_func<I16> ; \
DEF_ISEL(name ## _32) = tpl_func<I32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<I64> )
// Two operand (dst <- src)
#define DEF_ISEL_Rn_Mn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, M8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, M16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, M32> ; \
DEF_ISEL(name ## _64) = tpl_func<R64W, M64>
DEF_ISEL(name ## _32) = tpl_func<R32W, M32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W, M64> )
#define DEF_ISEL_WRn_Rn(name, tpl_func) \
#define DEF_ISEL_Rn_Rn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, R8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, R16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, R32> ; \
DEF_ISEL(name ## _64) = tpl_func<R64W, R64>
DEF_ISEL(name ## _32) = tpl_func<R32W, R32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W, R64> )
#define DEF_ISEL_WRn_In(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, IMM8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, IMM16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, IMM32> ; \
DEF_ISEL(name ## _64) = tpl_func<R64W, IMM64>
#define DEF_ISEL_Rn_In(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, I8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, I16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, I32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W, I64> )
#define DEF_ISEL_Mn_In(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<M8, IMM8> ; \
DEF_ISEL(name ## _16) = tpl_func<M16, IMM16> ; \
DEF_ISEL(name ## _32) = tpl_func<M32, IMM32> ; \
DEF_ISEL(name ## _64) = tpl_func<M64, IMM64>
DEF_ISEL(name ## _8) = tpl_func<M8, I8> ; \
DEF_ISEL(name ## _16) = tpl_func<M16, I16> ; \
DEF_ISEL(name ## _32) = tpl_func<M32, I32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64, I64> )
#define DEF_ISEL_Mn_Rn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<M8, R8> ; \
DEF_ISEL(name ## _16) = tpl_func<M16, R16> ; \
DEF_ISEL(name ## _32) = tpl_func<M32, R32> ; \
DEF_ISEL(name ## _64) = tpl_func<M64, R64>
DEF_ISEL(name ## _32) = tpl_func<M32, R32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64, R64> )
// 3-operand dst <- (src1 op src2)
#define DEF_ISEL_Rn_Rn_Mn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, R8, M8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, R16, M16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, R32, M32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W, R64, M64> )
#define DEF_ISEL_Rn_Rn_Rn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, R8, R8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, R16, R16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, R32, R32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W, R64, R64> )
#define DEF_ISEL_Rn_Rn_In(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<R8W, R8, I8> ; \
DEF_ISEL(name ## _16) = tpl_func<R16W, R16, I16> ; \
DEF_ISEL(name ## _32) = tpl_func<R32W, R32, I32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W, R64, I64> )
#define DEF_ISEL_Mn_Mn_In(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<M8, I8> ; \
DEF_ISEL(name ## _16) = tpl_func<M16, I16> ; \
DEF_ISEL(name ## _32) = tpl_func<M32, I32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64, I64> )
#define DEF_ISEL_Mn_Mn_Rn(name, tpl_func) \
DEF_ISEL(name ## _8) = tpl_func<M8, R8> ; \
DEF_ISEL(name ## _16) = tpl_func<M16, R16> ; \
DEF_ISEL(name ## _32) = tpl_func<M32, R32> \
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64, R64> )
namespace {
// Write to memory.
template <typename T>
INSTR_ATTRIBS
static inline T &W(T *v) { return *v; }
static inline Mn<T> W(Mn<T> addr) {
return addr;
}
// Write to a register.
template <typename T>
INSTR_ATTRIBS
static inline T &W(T &v) { return v; }
template <typename T>
INSTR_ATTRIBS
static inline T R(T *v) { return *v; }
static inline T R(Mn<T> addr) {
return addr.Read();
}
template <typename T>
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"
+2 -2
View File
@@ -3,10 +3,10 @@ namespace {
template <typename D, typename S>
DEF_SEM(LEA, D dst, S src) {
W(dst) = reinterpret_cast<uintptr_t>(src);
W(dst) = src.addr;
}
} // namespace
DEF_ISEL(LEA_GPRv_AGEN_32) = LEA<R32W, M8>;
DEF_ISEL(LEA_GPRv_AGEN_64) = LEA<R64W, M8>;
IF_64BIT( DEF_ISEL(LEA_GPRv_AGEN_64) = LEA<R64W, M8>; )
+28
View File
@@ -0,0 +1,28 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
namespace {
template <typename T>
DEF_SEM(PUSH, T val_) {
auto val = R(val_);
state.gpr.rsp.full -= sizeof(val);
Mn<decltype(val)>::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
*/
+37
View File
@@ -0,0 +1,37 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
namespace {
template <typename T>
DEF_SEM(JMP, T target_pc) {
state.gpr.rip.full = static_cast<PC>(target_pc);
}
template <typename T>
DEF_SEM(INDIRECT_JMP, T target_pc) {
CLEAR_AFLAGS();
state.gpr.rip.full = static_cast<PC>(R(target_pc));
}
} // namespace
DEF_ISEL_32UP(JMP_RELBRd, JMP<PC>);
DEF_ISEL_32UP(JMP_RELBRz, JMP<PC>);
DEF_ISEL_32UP(JMP_RELBRb, JMP<PC>);
#if 64 == ADDRESS_SIZE_BITS
DEF_ISEL(JMP_MEMv_64) = INDIRECT_JMP<M64>;
DEF_ISEL(JMP_GRPv_32) = INDIRECT_JMP<R64>;
#else
DEF_ISEL(JMP_MEMv_16) = INDIRECT_JMP<M16>;
DEF_ISEL(JMP_MEMv_32) = INDIRECT_JMP<M32>;
DEF_ISEL(JMP_GRPv_16) = INDIRECT_JMP<R16>;
DEF_ISEL(JMP_GRPv_32) = INDIRECT_JMP<R32>;
#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
*/
+35 -20
View File
@@ -9,6 +9,7 @@
#include <llvm/ADT/SmallVector.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IRBuilder.h>
@@ -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<llvm::Function>(
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<llvm::CallInst *> Cs;
for (auto U : intrinsic->undefined_bool->users()) {
if (auto C = llvm::dyn_cast<llvm::CallInst>(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) {
+11 -4
View File
@@ -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
+63
View File
@@ -0,0 +1,63 @@
/* Copyright 2015 Peter Goodman (peter@trailofbits.com), all rights reserved. */
#include <glog/logging.h>
#include <llvm/IR/Module.h>
#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
+59
View File
@@ -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_
+4 -57
View File
@@ -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
+2 -10
View File
@@ -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
+8 -8
View File
@@ -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