diff --git a/CMakeLists.txt b/CMakeLists.txt index e1af35b..7f4b344 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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" diff --git a/include/vm_lifters.hpp b/include/vm_lifters.hpp index f6dc366..e8cd511 100644 --- a/include/vm_lifters.hpp +++ b/include/vm_lifters.hpp @@ -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 \ No newline at end of file + ( *( lifters[ vinstr.mnemonic_t ] ) )( rtn, vm_code_block, vinstr, ir_builder ); + return true; + } + }; +} // namespace vm \ No newline at end of file diff --git a/include/vmp_rtn.hpp b/include/vmp_rtn.hpp index c794615..32d5afe 100644 --- a/include/vmp_rtn.hpp +++ b/include/vmp_rtn.hpp @@ -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 ); diff --git a/src/lifters/add.cpp b/src/lifters/add.cpp index 945778c..608feab 100644 --- a/src/lifters/add.cpp +++ b/src/lifters/add.cpp @@ -1,50 +1,77 @@ #include -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/src/lifters/div.cpp b/src/lifters/div.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/lifters/lconst.cpp b/src/lifters/lconst.cpp index 55cfbc7..cf65c49 100644 --- a/src/lifters/lconst.cpp +++ b/src/lifters/lconst.cpp @@ -1,19 +1,34 @@ #include -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/src/lifters/lreg.cpp b/src/lifters/lreg.cpp index c1097b3..aac1486 100644 --- a/src/lifters/lreg.cpp +++ b/src/lifters/lreg.cpp @@ -1,10 +1,18 @@ #include -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 ) ); - }; -} \ No newline at end of file + 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 \ No newline at end of file diff --git a/src/lifters/mul.cpp b/src/lifters/mul.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/lifters/nand.cpp b/src/lifters/nand.cpp new file mode 100644 index 0000000..76510f9 --- /dev/null +++ b/src/lifters/nand.cpp @@ -0,0 +1,36 @@ +#include + +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 \ No newline at end of file diff --git a/src/lifters/pushvsp.cpp b/src/lifters/pushvsp.cpp index a815d08..f789364 100644 --- a/src/lifters/pushvsp.cpp +++ b/src/lifters/pushvsp.cpp @@ -1,20 +1,19 @@ #include -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 ); + }; } \ No newline at end of file diff --git a/src/lifters/read.cpp b/src/lifters/read.cpp index 1fd2b8a..bbee6f9 100644 --- a/src/lifters/read.cpp +++ b/src/lifters/read.cpp @@ -1,12 +1,13 @@ #include -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 ); + }; } \ No newline at end of file diff --git a/src/lifters/shl.cpp b/src/lifters/shl.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/lifters/shr.cpp b/src/lifters/shr.cpp new file mode 100644 index 0000000..3d69695 --- /dev/null +++ b/src/lifters/shr.cpp @@ -0,0 +1,20 @@ +#include + +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 ) ); + }; +} \ No newline at end of file diff --git a/src/lifters/sreg.cpp b/src/lifters/sreg.cpp index 3125176..72087b8 100644 --- a/src/lifters/sreg.cpp +++ b/src/lifters/sreg.cpp @@ -1,14 +1,22 @@ #include -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/src/vmp_rtn.cpp b/src/vmp_rtn.cpp index 0543411..0538ee4 100644 --- a/src/vmp_rtn.cpp +++ b/src/vmp_rtn.cpp @@ -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 \ No newline at end of file