cleaned the project, added a bunch of lifters... adding more...

merge-requests/1/merge
_xeroxz 3 years ago
parent 332f9e4d2e
commit e846560010

@ -41,10 +41,15 @@ set(vmdevirt_SOURCES "")
list(APPEND vmdevirt_SOURCES
"src/lifters/add.cpp"
"src/lifters/div.cpp"
"src/lifters/lconst.cpp"
"src/lifters/lreg.cpp"
"src/lifters/mul.cpp"
"src/lifters/nand.cpp"
"src/lifters/pushvsp.cpp"
"src/lifters/read.cpp"
"src/lifters/shl.cpp"
"src/lifters/shr.cpp"
"src/lifters/sreg.cpp"
"src/main.cpp"
"src/vmp_rtn.cpp"

@ -16,41 +16,68 @@
#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
namespace vmp2::lifters
namespace vm
{
using lifter_callback_t =
std::function< void( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) >;
class lifters_t
{
// private default constructor...
// used for singleton...
lifters_t()
{
}
extern lifter_callback_t lconstq;
extern lifter_callback_t lconstdwsxq;
extern lifter_callback_t lconstwsxq;
using lifter_callback_t =
std::function< void( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) >;
extern lifter_callback_t pushvsp;
static lifter_callback_t lconstq, lconstdwsxq, lconstwsxq, lconstbzxw, lconstbsxq;
static lifter_callback_t addq, adddw, addw;
static lifter_callback_t sregq, sregdw;
static lifter_callback_t lregq, lregdw;
extern lifter_callback_t addq;
extern lifter_callback_t adddw;
extern lifter_callback_t addw;
static lifter_callback_t pushvsp;
static lifter_callback_t readq;
static lifter_callback_t nandq;
static lifter_callback_t shrq;
extern lifter_callback_t sregq;
extern lifter_callback_t lregq;
std::map< vm::handler::mnemonic_t, lifter_callback_t * > lifters = { { vm::handler::LCONSTQ, &lconstq },
{ vm::handler::LCONSTDWSXQ, &lconstdwsxq },
{ vm::handler::LCONSTWSXQ, &lconstwsxq },
{ vm::handler::LCONSTBZXW, &lconstbzxw },
{ vm::handler::LCONSTBSXQ, &lconstbsxq },
{ vm::handler::ADDQ, &addq },
{ vm::handler::ADDDW, &adddw },
{ vm::handler::ADDW, &addw },
{ vm::handler::SHRQ, &shrq },
{ vm::handler::PUSHVSP, &pushvsp },
{ vm::handler::SREGQ, &sregq },
{ vm::handler::SREGDW, &sregdw },
{ vm::handler::LREGQ, &lregq },
{ vm::handler::LREGDW, &lregdw },
{ vm::handler::READQ, &readq },
{ vm::handler::NANDQ, &nandq } };
extern lifter_callback_t readq;
static vm::llvm_value_t *add_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs,
vm::llvm_value_t *rhs );
inline std::map< vm::handler::mnemonic_t, lifter_callback_t * > lifters = {
{ vm::handler::LCONSTQ, &lconstq }, { vm::handler::LCONSTDWSXQ, &lconstdwsxq },
{ vm::handler::LCONSTWSXQ, &lconstwsxq }, { vm::handler::ADDQ, &addq },
{ vm::handler::ADDDW, &adddw }, { vm::handler::ADDW, &addw },
{ vm::handler::PUSHVSP, &pushvsp }, { vm::handler::SREGQ, &sregq },
{ vm::handler::LREGQ, &lregq }, { vm::handler::READQ, &readq } };
static vm::llvm_value_t *and_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs,
vm::llvm_value_t *rhs );
inline bool lift( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder )
{
if ( vinstr.mnemonic_t == vm::handler::INVALID || lifters.find( vinstr.mnemonic_t ) == lifters.end() )
return false;
public:
static lifters_t *get_instance( void )
{
static lifters_t obj;
return &obj;
}
bool lift( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder )
{
if ( vinstr.mnemonic_t == vm::handler::INVALID || lifters.find( vinstr.mnemonic_t ) == lifters.end() )
return false;
( *( lifters[ vinstr.mnemonic_t ] ) )( rtn, vm_code_block, vinstr, ir_builder );
return true;
}
} // namespace vmp2::lifters
( *( lifters[ vinstr.mnemonic_t ] ) )( rtn, vm_code_block, vinstr, ir_builder );
return true;
}
};
} // namespace vm

@ -17,33 +17,54 @@
namespace vm
{
// Obsessive-compulsive disorder is characterized by unreasonable
// thoughts and fears (obsessions) that lead to compulsive behaviors.
using llvm_type_t = llvm::Type;
using llvm_value_t = llvm::Value;
using llvm_module_t = llvm::Module;
using llvm_context_t = llvm::LLVMContext;
using llvm_function_t = llvm::Function;
using llvm_irbuilder_t = llvm::IRBuilder<>;
using llvm_alloca_inst_t = llvm::AllocaInst;
using llvm_basic_block_t = llvm::BasicBlock;
using llvm_global_value_t = llvm::GlobalValue;
class vmp_rtn_t
{
friend class lifters_t;
public:
explicit vmp_rtn_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, vm::ctx_t *vm_ctx,
explicit vmp_rtn_t( llvm_context_t *llvm_ctx, llvm_module_t *llvm_module, vm::ctx_t *vm_ctx,
std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks );
llvm::Function *lift( void );
llvm::LLVMContext *llvm_ctx;
llvm_function_t *lift( void );
private:
llvm_context_t *llvm_ctx;
llvm_module_t *llvm_module;
llvm_function_t *llvm_fptr;
llvm_alloca_inst_t *virtual_stack, *stack_ptr, *flags;
vm::ctx_t *vm_ctx;
llvm::Module *llvm_module;
std::uintptr_t rtn_begin;
llvm::Function *llvm_fptr;
std::shared_ptr< llvm::IRBuilder<> > ir_builder;
llvm::AllocaInst *virtual_stack, *stack_ptr, *flags;
std::shared_ptr< llvm_irbuilder_t > ir_builder;
std::map< ZydisRegister, llvm::GlobalVariable * > native_registers;
std::vector< llvm::AllocaInst * > virtual_registers;
std::vector< llvm::BasicBlock * > llvm_code_blocks;
std::map< zydis_register_t, llvm_global_value_t * > native_registers;
std::vector< llvm_alloca_inst_t * > virtual_registers;
std::vector< llvm_basic_block_t * > llvm_code_blocks;
std::vector< vm::instrs::code_block_t > vmp2_code_blocks;
void push( std::uint8_t byte_size, llvm::Value *input_val );
llvm::Value *pop( std::uint8_t byte_size );
llvm::Value *peek( std::uint8_t byte_size, std::uint8_t byte_offset = 0u );
llvm::Value *load_value( std::uint8_t byte_size, llvm::GlobalValue *global );
llvm::Value *load_value( std::uint8_t byte_size, llvm::AllocaInst *var );
llvm::Value *load_value( std::uint8_t byte_size, llvm_global_value_t *global );
llvm::Value *load_value( std::uint8_t byte_size, llvm_alloca_inst_t *var );
private:
llvm_value_t *compute_sf( std::uint8_t byte_size, llvm_value_t *val );
llvm_value_t *compute_zf( std::uint8_t byte_size, llvm_value_t *val );
llvm_value_t *compute_pf( std::uint8_t byte_size, llvm_value_t *val );
llvm_value_t *combine_flags( llvm_value_t *cf, llvm_value_t *pf, llvm_value_t *af, llvm_value_t *zf,
llvm_value_t *sf, llvm_value_t *of );
void create_native_registers( void );
void create_virtual_registers( void );
void create_routine( void );

@ -1,50 +1,77 @@
#include <vm_lifters.hpp>
namespace vmp2::lifters
namespace vm
{
lifter_callback_t addq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto t2 = rtn->pop( 8 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
rtn->push( 8, t3 );
// TODO: compute and update RFLAGS...
// do the updating here on rtn->flags before we push it...
//
//
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
lifter_callback_t adddw = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 4 );
auto t2 = rtn->pop( 4 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
rtn->push( 4, t3 );
// TODO: compute and update RFLAGS...
// do the updating here on rtn->flags before we push it...
//
//
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
lifter_callback_t addw = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 2 );
auto t2 = rtn->pop( 2 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
rtn->push( 2, t3 );
// TODO: compute and update RFLAGS...
// do the updating here on rtn->flags before we push it...
//
//
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
} // namespace vmp2::lifters
vm::llvm_value_t *lifters_t::add_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs,
vm::llvm_value_t *rhs )
{
auto op_size = llvm::IntegerType::get( *rtn->llvm_ctx, byte_size * 8 );
std::vector< llvm::Type * > intrinsic_arg_types;
intrinsic_arg_types.push_back( op_size );
intrinsic_arg_types.push_back( op_size );
auto sadd_with_overflow = llvm::Intrinsic::getDeclaration(
rtn->llvm_module, llvm::Intrinsic::sadd_with_overflow, intrinsic_arg_types );
auto uadd_with_overflow = llvm::Intrinsic::getDeclaration(
rtn->llvm_module, llvm::Intrinsic::uadd_with_overflow, intrinsic_arg_types );
auto u_add = rtn->ir_builder->CreateCall( uadd_with_overflow, { lhs, rhs } );
auto u_sum = rtn->ir_builder->CreateExtractValue( u_add, { 0 } );
auto u_of_bit = rtn->ir_builder->CreateExtractValue( u_add, { 1 } );
auto cf = rtn->ir_builder->CreateZExt( u_of_bit, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ) );
auto s_add = rtn->ir_builder->CreateCall( sadd_with_overflow, { lhs, rhs } );
auto s_sum = rtn->ir_builder->CreateExtractValue( s_add, { 0 } );
auto s_of_bit = rtn->ir_builder->CreateExtractValue( s_add, { 1 } );
auto of = rtn->ir_builder->CreateZExt( s_of_bit, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ) );
auto sf = rtn->compute_sf( byte_size, u_sum );
auto zf = rtn->compute_zf( byte_size, u_sum );
auto pf = rtn->compute_pf( byte_size, u_sum );
auto flags_calc = rtn->combine_flags(
cf, pf, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ), zf, sf, of );
return flags_calc;
}
lifters_t::lifter_callback_t lifters_t::addq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto t2 = rtn->pop( 8 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
rtn->push( 8, t3 );
auto flags = lifters_t::add_flags( rtn, 8, t1, t2 );
ir_builder->CreateStore( flags, rtn->flags );
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::adddw =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 4 );
auto t2 = rtn->pop( 4 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
rtn->push( 4, t3 );
auto flags = lifters_t::add_flags( rtn, 4, t1, t2 );
ir_builder->CreateStore( flags, rtn->flags );
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
lifters_t::lifter_callback_t lifters_t::addw =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 2 );
auto t2 = rtn->pop( 2 );
auto t3 = ir_builder->CreateAdd( t1, t2 );
rtn->push( 2, t3 );
auto flags = lifters_t::add_flags( rtn, 2, t1, t2 );
ir_builder->CreateStore( flags, rtn->flags );
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
} // namespace vm

@ -1,19 +1,34 @@
#include <vm_lifters.hpp>
namespace vmp2::lifters
namespace vm
{
lifter_callback_t lconstq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifter_callback_t lconstdwsxq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstdwsxq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifter_callback_t lconstwsxq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
} // namespace vmp2::lifters
lifters_t::lifter_callback_t lifters_t::lconstwsxq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstbsxq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 8, llvm::ConstantInt::get( ir_builder->getInt64Ty(), vinstr.operand.imm.u ) );
};
lifters_t::lifter_callback_t lifters_t::lconstbzxw =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
rtn->push( 2, llvm::ConstantInt::get( ir_builder->getInt16Ty(), vinstr.operand.imm.u ) );
};
} // namespace vm

@ -1,10 +1,18 @@
#include <vm_lifters.hpp>
namespace vmp2::lifters
namespace vm
{
lifter_callback_t lregq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
rtn->push( 8, rtn->load_value( 8, vreg ) );
};
}
lifters_t::lifter_callback_t lifters_t::lregq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
rtn->push( 8, rtn->load_value( 8, vreg ) );
};
lifters_t::lifter_callback_t lifters_t::lregdw =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
rtn->push( 4, rtn->load_value( 4, vreg ) );
};
} // namespace vm

@ -0,0 +1,36 @@
#include <vm_lifters.hpp>
namespace vm
{
vm::llvm_value_t *lifters_t::and_flags( vm::vmp_rtn_t *rtn, std::uint8_t byte_size, vm::llvm_value_t *lhs,
vm::llvm_value_t *rhs )
{
auto t0 = rtn->ir_builder->CreateAnd( lhs, rhs );
auto cf = llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, byte_size * 8 ), 0 );
auto of = llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, byte_size * 8 ), 0 );
auto sf = rtn->compute_sf( byte_size, t0 );
auto zf = rtn->compute_zf( byte_size, t0 );
auto pf = rtn->compute_pf( byte_size, t0 );
return rtn->combine_flags( cf, pf, llvm::ConstantInt::get( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), 0 ),
zf, sf, of );
}
lifters_t::lifter_callback_t lifters_t::nandq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto t2 = rtn->pop( 8 );
auto t1_not = ir_builder->CreateNot( t1 );
auto t2_not = ir_builder->CreateNot( t2 );
auto t3 = ir_builder->CreateAnd( { t1_not, t2_not } );
rtn->push( 8, t3 );
auto flags = and_flags( rtn, 8, t1, t2 );
ir_builder->CreateStore( flags, rtn->flags );
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
} // namespace vm

@ -1,20 +1,19 @@
#include <vm_lifters.hpp>
namespace vmp2::lifters
namespace vm
{
lifter_callback_t pushvsp = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
// Load the current stack index into a temporary variable
auto current_stack_index =
ir_builder->CreateLoad( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), rtn->stack_ptr, false );
lifters_t::lifter_callback_t lifters_t::pushvsp =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto current_spi =
ir_builder->CreateLoad( llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), rtn->stack_ptr, false );
// Get a pointer to the top byte of the stack
llvm::Value *i64_zero = llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) );
llvm::Value *indices[ 2 ] = { i64_zero, current_stack_index };
auto stack_ptr =
ir_builder->CreateInBoundsGEP( rtn->virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
auto *i64_zero = llvm::ConstantInt::get( *rtn->llvm_ctx, llvm::APInt( 64, 0 ) );
llvm_value_t *indices[ 2 ] = { i64_zero, current_spi };
auto stack_ptr =
ir_builder->CreateInBoundsGEP( rtn->virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
auto stack_ptr_val = ir_builder->CreatePtrToInt( stack_ptr, ir_builder->getInt64Ty() );
rtn->push( 8, stack_ptr_val );
};
auto stack_ptr_val = ir_builder->CreatePtrToInt( stack_ptr, ir_builder->getInt64Ty() );
rtn->push( 8, stack_ptr_val );
};
}

@ -1,12 +1,13 @@
#include <vm_lifters.hpp>
namespace vmp2::lifters
namespace vm
{
lifter_callback_t readq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto t2 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt64Ty(), 0ull ) );
auto t3 = ir_builder->CreateLoad( ir_builder->getInt64Ty(), t2 );
rtn->push( 8, t3 );
};
lifters_t::lifter_callback_t lifters_t::readq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto t2 = ir_builder->CreateIntToPtr( t1, llvm::PointerType::get( ir_builder->getInt64Ty(), 0ull ) );
auto t3 = ir_builder->CreateLoad( ir_builder->getInt64Ty(), t2 );
rtn->push( 8, t3 );
};
}

@ -0,0 +1,20 @@
#include <vm_lifters.hpp>
namespace vm
{
lifters_t::lifter_callback_t lifters_t::shrq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto t2 = rtn->pop( 2 );
auto t3 = ir_builder->CreateIntCast( t2, llvm::IntegerType::get( *rtn->llvm_ctx, 64 ), false );
auto t4 = ir_builder->CreateLShr( t1, t3 );
// TODO: Compute flags
//
//
rtn->push( 8, t4 );
rtn->push( 8, rtn->load_value( 8, rtn->flags ) );
};
}

@ -1,14 +1,22 @@
#include <vm_lifters.hpp>
namespace vmp2::lifters
namespace vm
{
// %t1 = %stack[%sp]
// add %sp, 8
// %vregX = %1
lifter_callback_t sregq = [ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
ir_builder->CreateStore( t1, vreg )->setAlignment( llvm::Align( 8 ) );
};
} // namespace vmp2::lifters
lifters_t::lifter_callback_t lifters_t::sregq =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 8 );
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
ir_builder->CreateStore( t1, vreg )->setAlignment( llvm::Align( 8 ) );
};
lifters_t::lifter_callback_t lifters_t::sregdw =
[ & ]( vm::vmp_rtn_t *rtn, const vm::instrs::code_block_t &vm_code_block,
const vm::instrs::virt_instr_t &vinstr, llvm::IRBuilder<> *ir_builder ) {
auto t1 = rtn->pop( 4 );
auto vreg = rtn->virtual_registers[ vinstr.operand.imm.u ? vinstr.operand.imm.u / 8 : 0 ];
auto vregdw = ir_builder->CreatePointerCast(
vreg, llvm::PointerType::get( llvm::IntegerType::get( *rtn->llvm_ctx, 32 ), 0 ) );
ir_builder->CreateStore( t1, vregdw );
};
} // namespace vm

@ -3,28 +3,20 @@
namespace vm
{
vmp_rtn_t::vmp_rtn_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module, vm::ctx_t *vm_ctx,
vmp_rtn_t::vmp_rtn_t( llvm_context_t *llvm_ctx, llvm_module_t *llvm_module, vm::ctx_t *vm_ctx,
std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks )
: llvm_ctx( llvm_ctx ), llvm_module( llvm_module ), vm_ctx( vm_ctx ), rtn_begin( rtn_begin ),
vmp2_code_blocks( vmp2_code_blocks )
{
// create llvm::Function and llvm::BasicBlock's...
// do not change the ordering of these function calls...
create_routine();
// set the insert point to the first code block...
ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx );
ir_builder = std::make_shared< llvm_irbuilder_t >( *llvm_ctx );
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ] );
// create native registers...
// do not change the ordering of these function calls...
create_native_registers();
// create stack and stack pointer...
create_virtual_stack();
// lift vm enter pushes to llvm ir...
lift_vm_entry();
// create virtual registers...
create_virtual_registers();
}
@ -132,7 +124,6 @@ namespace vm
// convert the rtn_begin address to a hex string and prepend "rtn_" to it...
std::stringstream rtn_name;
rtn_name << "rtn_" << std::hex << rtn_begin;
llvm_fptr = llvm::Function::Create( func_ty, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
rtn_name.str().c_str(), *llvm_module );
@ -145,45 +136,34 @@ namespace vm
}
}
void vmp_rtn_t::push( std::uint8_t byte_size, llvm::Value *input_value )
void vmp_rtn_t::push( std::uint8_t byte_size, llvm_value_t *val )
{
// Load the current stack index into a temporary variable
auto current_stack_index = ir_builder->CreateLoad( ir_builder->getInt64Ty(), stack_ptr, false );
auto spi = ir_builder->CreateLoad( ir_builder->getInt64Ty(), stack_ptr, false );
auto new_spi = ir_builder->CreateSub( spi, llvm::ConstantInt::get( ir_builder->getInt64Ty(), byte_size ) );
ir_builder->CreateStore( new_spi, stack_ptr );
// Subtract the input value size from the current stack index
auto new_stack_index =
ir_builder->CreateSub( current_stack_index, llvm::ConstantInt::get( ir_builder->getInt64Ty(), byte_size ) );
auto *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
llvm_value_t *indices[ 2 ] = { i64_zero, new_spi };
auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm_value_t * >( indices, 2 ) );
// Store the newly calculated stack index into VSP
ir_builder->CreateStore( new_stack_index, stack_ptr );
// Get a pointer to the top byte of the stack
llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
llvm::Value *indices[ 2 ] = { i64_zero, new_stack_index };
auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
// Store the input value at the calculated stack address
if ( byte_size == 1 )
{
ir_builder->CreateStore( input_value, stack_ptr );
}
else
if ( byte_size > 1 )
{
// Cast the pointer so the stack item width matches the width of the input value
auto casted_ptr = ir_builder->CreatePointerCast(
stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
ir_builder->CreateStore( input_value, casted_ptr );
ir_builder->CreateStore( val, casted_ptr );
}
else
ir_builder->CreateStore( val, stack_ptr );
}
llvm::Value *vmp_rtn_t::pop( std::uint8_t byte_size )
llvm_value_t *vmp_rtn_t::pop( std::uint8_t byte_size )
{
llvm::Value *output_value = nullptr;
llvm_value_t *output_value = nullptr;
auto current_spi = ir_builder->CreateLoad( ir_builder->getInt64Ty(), stack_ptr, false );
llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
llvm::Value *indices[ 2 ] = { i64_zero, current_spi };
llvm_value_t *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
llvm_value_t *indices[ 2 ] = { i64_zero, current_spi };
auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
if ( byte_size > 1 )
@ -196,14 +176,14 @@ namespace vm
else
output_value = ir_builder->CreateLoad( ir_builder->getInt8Ty(), top_stack );
auto new_stack_index = ir_builder->CreateAdd(
auto new_spi = ir_builder->CreateAdd(
current_spi, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), byte_size ) );
ir_builder->CreateStore( new_stack_index, stack_ptr );
ir_builder->CreateStore( new_spi, stack_ptr );
return output_value;
}
llvm::Value *vmp_rtn_t::peek( std::uint8_t byte_size, std::uint8_t byte_offset )
llvm_value_t *vmp_rtn_t::peek( std::uint8_t byte_size, std::uint8_t byte_offset )
{
auto current_spi = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), stack_ptr, false );
@ -215,8 +195,8 @@ namespace vm
current_spi = ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, 64 ), t1, false );
}
llvm::Value *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
llvm::Value *indices[ 2 ] = { i64_zero, current_spi };
auto i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
llvm_value_t *indices[ 2 ] = { i64_zero, current_spi };
auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
if ( byte_size > 1 )
@ -227,18 +207,30 @@ namespace vm
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr );
}
else
{
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), top_stack );
}
}
llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::GlobalValue *global )
llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_global_value_t *var )
{
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), global );
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
{
auto cast_ptr = ir_builder->CreatePointerCast(
var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
}
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
}
llvm::Value *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *var )
llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_alloca_inst_t *var )
{
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
{
auto cast_ptr = ir_builder->CreatePointerCast(
var, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), cast_ptr );
}
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
}
@ -254,22 +246,68 @@ namespace vm
stack_ptr );
}
llvm::Function *vmp_rtn_t::lift( void )
llvm_function_t *vmp_rtn_t::lift( void )
{
auto &code_blocks = llvm_fptr->getBasicBlockList();
auto lifters = vm::lifters_t::get_instance();
for ( auto idx = 0u; idx < code_blocks.size(); ++idx )
{
for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs )
{
if ( !vmp2::lifters::lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )
if ( !lifters->lift( this, vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )
{
std::printf( "> failed to devirtualize virtual instruction with opcode = %d\n", vinstr.opcode );
llvm_module->print( llvm::outs(), nullptr );
return nullptr;
}
}
}
return llvm_fptr;
}
llvm_value_t *vmp_rtn_t::compute_sf( std::uint8_t byte_size, llvm_value_t *val )
{
auto op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 );
auto msb = ir_builder->CreateLShr( val, ( byte_size * 8 ) - 1 );
return ir_builder->CreateZExt( msb, llvm::IntegerType::get( *llvm_ctx, 64 ) );
}
llvm_value_t *vmp_rtn_t::compute_zf( std::uint8_t byte_size, llvm_value_t *val )
{
auto op_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 );
auto is_zero = ir_builder->CreateICmpEQ( val, llvm::ConstantInt::get( op_size, 0 ) );
return ir_builder->CreateZExt( is_zero, llvm::IntegerType::get( *llvm_ctx, 64 ) );
}
llvm_value_t *vmp_rtn_t::compute_pf( std::uint8_t byte_size, llvm_value_t *val )
{
auto operand_size = llvm::IntegerType::get( *llvm_ctx, byte_size * 8 );
auto popcount_intrinsic = llvm::Intrinsic::getDeclaration( llvm_module, llvm::Intrinsic::ctpop,
{ llvm::IntegerType::get( *llvm_ctx, 64 ) } );
auto lower_bits = ir_builder->CreateIntCast( val, llvm::IntegerType::get( *llvm_ctx, 8 ), false );
auto extended_bits = ir_builder->CreateZExt( lower_bits, llvm::IntegerType::get( *llvm_ctx, 64 ) );
return ir_builder->CreateCall( popcount_intrinsic, { extended_bits } );
}
llvm_value_t *vmp_rtn_t::combine_flags( llvm_value_t *cf, llvm_value_t *pf, llvm_value_t *af, llvm_value_t *zf,
llvm_value_t *sf, llvm_value_t *of )
{
auto shifted_pf = ir_builder->CreateShl( pf, 2, "shifted_pf", true, true );
auto shifted_af = ir_builder->CreateShl( llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 0 ),
4, "shifted_af", true, true ); // treat af as zero
auto shifted_zf = ir_builder->CreateShl( zf, 6, "shifted_zf", true, true );
auto shifted_sf = ir_builder->CreateShl( sf, 7, "shifted_sf", true, true );
auto shifted_of = ir_builder->CreateShl( of, 11, "shifted_of", true, true );
auto or1 = ir_builder->CreateOr( cf, shifted_of );
auto or2 = ir_builder->CreateOr( or1, shifted_zf );
auto or3 = ir_builder->CreateOr( or2, shifted_sf );
auto or4 = ir_builder->CreateOr( or3, shifted_af );
auto or5 = ir_builder->CreateOr( or4, shifted_pf );
return ir_builder->CreateXor( or5, llvm::ConstantInt::get( llvm::IntegerType::get( *llvm_ctx, 64 ), 514 ) );
}
} // namespace vm
Loading…
Cancel
Save