updated to vmp2 file format version 4... can devirt multiple routines at once now.... See merge request vmp2/vmdevirt!6merge-requests/7/merge
commit
547d1a78d6
@ -1 +1 @@
|
|||||||
Subproject commit f06bf5f6b72b1d52a6156d6828675c77ceaee7e2
|
Subproject commit 05c98b1ef57c3375ffd455221a3be1be6110d4eb
|
@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vmp_rtn_t.hpp>
|
||||||
|
|
||||||
|
#include "llvm/IR/BasicBlock.h"
|
||||||
|
#include "llvm/IR/Constants.h"
|
||||||
|
#include "llvm/IR/DataLayout.h"
|
||||||
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
|
#include "llvm/IR/IRPrintingPasses.h"
|
||||||
|
#include "llvm/IR/LLVMContext.h"
|
||||||
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
|
#include "llvm/IR/Mangler.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/IR/Type.h"
|
||||||
|
#include "llvm/IR/Verifier.h"
|
||||||
|
|
||||||
|
#include "llvm/Transforms/InstCombine/InstCombine.h"
|
||||||
|
#include "llvm/Transforms/Scalar.h"
|
||||||
|
#include "llvm/Transforms/Scalar/GVN.h"
|
||||||
|
|
||||||
|
#include "X86TargetMachine.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Passes/PassBuilder.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
#include "llvm/Support/Host.h"
|
||||||
|
#include "llvm/Support/TargetRegistry.h"
|
||||||
|
#include "llvm/Support/TargetSelect.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
#include "llvm/Target/TargetOptions.h"
|
||||||
|
|
||||||
|
namespace llvm
|
||||||
|
{
|
||||||
|
extern "C" void LLVMInitializeX86TargetInfo();
|
||||||
|
extern "C" void LLVMInitializeX86Target();
|
||||||
|
extern "C" void LLVMInitializeX86TargetMC();
|
||||||
|
extern "C" void LLVMInitializeX86AsmParser();
|
||||||
|
extern "C" void LLVMInitializeX86AsmPrinter();
|
||||||
|
} // namespace llvm
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
class devirt_t
|
||||||
|
{
|
||||||
|
friend class lifters_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit devirt_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module );
|
||||||
|
llvm::Function *lift( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks );
|
||||||
|
bool compile( std::vector< std::uint8_t > &obj );
|
||||||
|
|
||||||
|
private:
|
||||||
|
llvm::LLVMContext *llvm_ctx;
|
||||||
|
llvm::Module *llvm_module;
|
||||||
|
std::shared_ptr< llvm::IRBuilder<> > ir_builder;
|
||||||
|
std::vector< std::shared_ptr< vm::vmp_rtn_t > > vmp_rtns;
|
||||||
|
|
||||||
|
void create_routine( void );
|
||||||
|
void push( std::uint8_t byte_size, llvm::Value *input_val );
|
||||||
|
llvm::Value *pop( std::uint8_t byte_size );
|
||||||
|
|
||||||
|
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 *compute_sf( std::uint8_t byte_size, llvm::Value *val );
|
||||||
|
llvm::Value *compute_zf( std::uint8_t byte_size, llvm::Value *val );
|
||||||
|
llvm::Value *compute_pf( std::uint8_t byte_size, llvm::Value *val );
|
||||||
|
llvm::Value *combine_flags( llvm::Value *cf, llvm::Value *pf, llvm::Value *af, llvm::Value *zf, llvm::Value *sf,
|
||||||
|
llvm::Value *of );
|
||||||
|
};
|
||||||
|
} // namespace vm
|
@ -1,71 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vmprofiler.hpp>
|
|
||||||
|
|
||||||
#include "llvm/IR/BasicBlock.h"
|
|
||||||
#include "llvm/IR/Constants.h"
|
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
|
||||||
#include "llvm/IR/Function.h"
|
|
||||||
#include "llvm/IR/IRBuilder.h"
|
|
||||||
#include "llvm/IR/IRPrintingPasses.h"
|
|
||||||
#include "llvm/IR/LLVMContext.h"
|
|
||||||
#include "llvm/IR/Module.h"
|
|
||||||
#include "llvm/IR/PassManager.h"
|
|
||||||
#include "llvm/IR/Type.h"
|
|
||||||
#include "llvm/IR/Verifier.h"
|
|
||||||
#include "llvm/Pass.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
|
||||||
|
|
||||||
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_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_t *lift( void );
|
|
||||||
|
|
||||||
private:
|
|
||||||
llvm_context_t *llvm_ctx;
|
|
||||||
llvm_module_t *llvm_module;
|
|
||||||
llvm_function_t *llvm_fptr;
|
|
||||||
llvm_alloca_inst_t *flags, *stack;
|
|
||||||
|
|
||||||
vm::ctx_t *vm_ctx;
|
|
||||||
std::uintptr_t rtn_begin;
|
|
||||||
std::shared_ptr< llvm_irbuilder_t > ir_builder;
|
|
||||||
|
|
||||||
std::vector< llvm_alloca_inst_t * > virtual_registers;
|
|
||||||
std::vector< std::pair< std::uintptr_t, 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_t *input_val );
|
|
||||||
llvm::Value *pop( std::uint8_t byte_size );
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
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_virtual_registers( void );
|
|
||||||
void create_routine( void );
|
|
||||||
};
|
|
||||||
} // namespace vm
|
|
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vmprofiler.hpp>
|
||||||
|
|
||||||
|
#include "llvm/IR/BasicBlock.h"
|
||||||
|
#include "llvm/IR/Constants.h"
|
||||||
|
#include "llvm/IR/DataLayout.h"
|
||||||
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
|
#include "llvm/IR/IRPrintingPasses.h"
|
||||||
|
#include "llvm/IR/LLVMContext.h"
|
||||||
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
|
#include "llvm/IR/Mangler.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/IR/Type.h"
|
||||||
|
#include "llvm/IR/Verifier.h"
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
class vmp_rtn_t
|
||||||
|
{
|
||||||
|
llvm::Function *llvm_fptr;
|
||||||
|
llvm::AllocaInst *flags, *stack;
|
||||||
|
llvm::Module *llvm_module;
|
||||||
|
|
||||||
|
std::uintptr_t rtn_begin;
|
||||||
|
std::shared_ptr< llvm::IRBuilder<> > ir_builder;
|
||||||
|
std::vector< llvm::AllocaInst * > virtual_registers;
|
||||||
|
std::vector< std::pair< std::uintptr_t, llvm::BasicBlock * > > llvm_code_blocks;
|
||||||
|
std::vector< vm::instrs::code_block_t > vmp2_code_blocks;
|
||||||
|
void create_virtual_registers( void );
|
||||||
|
void create_routine( void );
|
||||||
|
|
||||||
|
friend class devirt_t;
|
||||||
|
friend class lifters_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit vmp_rtn_t( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks,
|
||||||
|
std::shared_ptr< llvm::IRBuilder<> > &ir_builder, llvm::Module *llvm_module );
|
||||||
|
};
|
||||||
|
} // namespace vm
|
@ -0,0 +1,141 @@
|
|||||||
|
#include <devirt_t.hpp>
|
||||||
|
#include <vm_lifters.hpp>
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
devirt_t::devirt_t( llvm::LLVMContext *llvm_ctx, llvm::Module *llvm_module )
|
||||||
|
: llvm_ctx( llvm_ctx ), llvm_module( llvm_module )
|
||||||
|
{
|
||||||
|
ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
void devirt_t::push( std::uint8_t num_bytes, llvm::Value *val )
|
||||||
|
{
|
||||||
|
// sub rsp, num_bytes
|
||||||
|
auto current_rtn = vmp_rtns.back();
|
||||||
|
auto rsp_addr = ir_builder->CreateLoad( current_rtn->stack );
|
||||||
|
auto sub_rsp_val =
|
||||||
|
ir_builder->CreateGEP( ir_builder->getInt8Ty(), rsp_addr, ir_builder->getInt8( 0 - num_bytes ) );
|
||||||
|
|
||||||
|
ir_builder->CreateStore( sub_rsp_val, current_rtn->stack );
|
||||||
|
|
||||||
|
// mov [rsp], val
|
||||||
|
auto resized_new_rsp_addr = ir_builder->CreateBitCast(
|
||||||
|
sub_rsp_val, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), 0ull ) );
|
||||||
|
ir_builder->CreateStore( val, resized_new_rsp_addr );
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *devirt_t::pop( std::uint8_t num_bytes )
|
||||||
|
{
|
||||||
|
// mov rax, [rsp]
|
||||||
|
auto current_rtn = vmp_rtns.back();
|
||||||
|
auto rsp_addr = ir_builder->CreateLoad( current_rtn->stack );
|
||||||
|
auto new_rsp_addr =
|
||||||
|
ir_builder->CreateGEP( ir_builder->getInt8Ty(), rsp_addr, ir_builder->getInt8( num_bytes ) );
|
||||||
|
|
||||||
|
auto resized_new_rsp_addr = ir_builder->CreateBitCast(
|
||||||
|
rsp_addr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), 0ull ) );
|
||||||
|
auto pop_val = ir_builder->CreateLoad( resized_new_rsp_addr );
|
||||||
|
ir_builder->CreateStore( new_rsp_addr, current_rtn->stack );
|
||||||
|
ir_builder->CreateStore( llvm::UndefValue::get( ir_builder->getInt8Ty() ), rsp_addr );
|
||||||
|
return pop_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *devirt_t::load_value( std::uint8_t byte_size, llvm::GlobalValue *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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *devirt_t::load_value( std::uint8_t byte_size, llvm::AllocaInst *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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool devirt_t::compile( std::vector< std::uint8_t > &obj )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Function *devirt_t::lift( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > code_blocks )
|
||||||
|
{
|
||||||
|
vmp_rtns.push_back( std::make_shared< vm::vmp_rtn_t >( rtn_begin, code_blocks, ir_builder, llvm_module ) );
|
||||||
|
|
||||||
|
auto &vmp_rtn = vmp_rtns.back();
|
||||||
|
auto lifters = vm::lifters_t::get_instance();
|
||||||
|
|
||||||
|
for ( auto idx = 0u; idx < vmp_rtn->vmp2_code_blocks.size(); ++idx )
|
||||||
|
{
|
||||||
|
ir_builder->SetInsertPoint( vmp_rtn->llvm_code_blocks[ idx ].second );
|
||||||
|
for ( auto &vinstr : vmp_rtn->vmp2_code_blocks[ idx ].vinstrs )
|
||||||
|
{
|
||||||
|
if ( !lifters->lift( this, vmp_rtn->vmp2_code_blocks[ idx ], vinstr, ir_builder.get() ) )
|
||||||
|
{
|
||||||
|
std::printf(
|
||||||
|
"> failed to devirtualize virtual instruction with opcode = %d, handler table rva = 0x%x\n",
|
||||||
|
vinstr.opcode, vinstr.trace_data.regs.r12 - vinstr.trace_data.regs.r13 );
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vmp_rtn->llvm_fptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value *devirt_t::compute_sf( std::uint8_t byte_size, llvm::Value *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 *devirt_t::compute_zf( std::uint8_t byte_size, llvm::Value *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 *devirt_t::compute_pf( std::uint8_t byte_size, llvm::Value *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 *devirt_t::combine_flags( llvm::Value *cf, llvm::Value *pf, llvm::Value *af, llvm::Value *zf,
|
||||||
|
llvm::Value *sf, llvm::Value *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
|
@ -1,177 +0,0 @@
|
|||||||
#include <vm_lifters.hpp>
|
|
||||||
#include <vmp_rtn.hpp>
|
|
||||||
|
|
||||||
namespace vm
|
|
||||||
{
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
// do not change the ordering of these function calls...
|
|
||||||
create_routine();
|
|
||||||
ir_builder = std::make_shared< llvm_irbuilder_t >( *llvm_ctx );
|
|
||||||
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ].second );
|
|
||||||
flags = ir_builder->CreateAlloca( ir_builder->getInt64Ty(), nullptr, "flags" );
|
|
||||||
stack = ir_builder->CreateAlloca( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), nullptr, "sp" );
|
|
||||||
|
|
||||||
ir_builder->CreateStore( llvm_fptr->getArg( 0 ), stack );
|
|
||||||
create_virtual_registers();
|
|
||||||
}
|
|
||||||
|
|
||||||
void vmp_rtn_t::create_virtual_registers( void )
|
|
||||||
{
|
|
||||||
for ( auto idx = 0u; idx < 24; ++idx )
|
|
||||||
// allocate virtual register space...
|
|
||||||
virtual_registers.push_back(
|
|
||||||
ir_builder->CreateAlloca( llvm::IntegerType::get( *llvm_ctx, 64 ), nullptr,
|
|
||||||
( std::string( "vreg" ) + std::to_string( idx ) ).c_str() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void vmp_rtn_t::create_routine( void )
|
|
||||||
{
|
|
||||||
// function has no arguments and returns void... maybe change this in the future as i learn
|
|
||||||
// more and more LLVM...
|
|
||||||
auto func_ty = llvm::FunctionType::get( llvm::Type::getVoidTy( *llvm_ctx ),
|
|
||||||
{ llvm::PointerType::getInt8PtrTy( *llvm_ctx ) }, false );
|
|
||||||
|
|
||||||
// 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 );
|
|
||||||
|
|
||||||
for ( const auto &vmp2_code_block : vmp2_code_blocks )
|
|
||||||
{
|
|
||||||
// create basic block name... block_xxxxxxxx format...
|
|
||||||
std::stringstream blk_name;
|
|
||||||
blk_name << "blk_" << std::hex << vmp2_code_block.vip_begin;
|
|
||||||
llvm_code_blocks.push_back( { vmp2_code_block.vip_begin,
|
|
||||||
llvm::BasicBlock::Create( *llvm_ctx, blk_name.str().c_str(), llvm_fptr ) } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void vmp_rtn_t::push( std::uint8_t num_bytes, llvm_value_t *val )
|
|
||||||
{
|
|
||||||
// sub rsp, num_bytes
|
|
||||||
auto rsp_addr = ir_builder->CreateLoad( stack );
|
|
||||||
auto rsp_i64 = ir_builder->CreatePtrToInt( rsp_addr, ir_builder->getInt64Ty() );
|
|
||||||
auto sub_rsp_val = ir_builder->CreateSub( rsp_i64, ir_builder->getInt64( num_bytes ) );
|
|
||||||
ir_builder->CreateStore(
|
|
||||||
ir_builder->CreateIntToPtr( sub_rsp_val, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) ), stack );
|
|
||||||
|
|
||||||
// mov [rsp], val
|
|
||||||
rsp_addr = ir_builder->CreateLoad( stack );
|
|
||||||
auto rsp_cast_ptr = ir_builder->CreatePointerCast(
|
|
||||||
rsp_addr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), false ) );
|
|
||||||
ir_builder->CreateStore( val, rsp_cast_ptr );
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm_value_t *vmp_rtn_t::pop( std::uint8_t num_bytes )
|
|
||||||
{
|
|
||||||
// mov rax, [rsp]
|
|
||||||
auto rsp_addr = ir_builder->CreateLoad( stack );
|
|
||||||
auto rsp_cast_ptr = ir_builder->CreatePointerCast(
|
|
||||||
rsp_addr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, num_bytes * 8 ), false ) );
|
|
||||||
auto pop_val = ir_builder->CreateLoad( rsp_cast_ptr );
|
|
||||||
|
|
||||||
// add rsp, num_bytes
|
|
||||||
auto rsp_i64 = ir_builder->CreatePtrToInt( rsp_addr, ir_builder->getInt64Ty() );
|
|
||||||
auto sub_rsp_val = ir_builder->CreateAdd( rsp_i64, ir_builder->getInt64( num_bytes ) );
|
|
||||||
auto sub_rsp_val_ptr =
|
|
||||||
ir_builder->CreateIntToPtr( sub_rsp_val, llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ) );
|
|
||||||
|
|
||||||
ir_builder->CreateStore( sub_rsp_val_ptr, stack );
|
|
||||||
return pop_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm_value_t *vmp_rtn_t::load_value( std::uint8_t byte_size, llvm_global_value_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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
ir_builder->SetInsertPoint( llvm_code_blocks[ idx ].second );
|
|
||||||
for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs )
|
|
||||||
{
|
|
||||||
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
|
|
@ -0,0 +1,52 @@
|
|||||||
|
#include <vmp_rtn_t.hpp>
|
||||||
|
|
||||||
|
namespace vm
|
||||||
|
{
|
||||||
|
vmp_rtn_t::vmp_rtn_t( std::uintptr_t rtn_begin, std::vector< vm::instrs::code_block_t > vmp2_code_blocks,
|
||||||
|
std::shared_ptr< llvm::IRBuilder<> > &ir_builder, llvm::Module *llvm_module )
|
||||||
|
: ir_builder( ir_builder ), vmp2_code_blocks( vmp2_code_blocks ), rtn_begin( rtn_begin ),
|
||||||
|
llvm_module( llvm_module )
|
||||||
|
{
|
||||||
|
create_routine();
|
||||||
|
// create virtual registers in the first code block...
|
||||||
|
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ].second );
|
||||||
|
flags = ir_builder->CreateAlloca( ir_builder->getInt64Ty(), nullptr, "flags" );
|
||||||
|
stack = ir_builder->CreateAlloca( llvm::PointerType::get( ir_builder->getInt8Ty(), 0ull ), nullptr, "sp" );
|
||||||
|
ir_builder->CreateStore( llvm_fptr->getArg( 0 ), stack );
|
||||||
|
create_virtual_registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmp_rtn_t::create_virtual_registers( void )
|
||||||
|
{
|
||||||
|
for ( auto idx = 0u; idx < 24; ++idx )
|
||||||
|
// allocate virtual register space...
|
||||||
|
virtual_registers.push_back(
|
||||||
|
ir_builder->CreateAlloca( llvm::IntegerType::get( ir_builder->getContext(), 64 ), nullptr,
|
||||||
|
( std::string( "vreg" ) + std::to_string( idx ) ).c_str() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmp_rtn_t::create_routine( void )
|
||||||
|
{
|
||||||
|
// function has no arguments and returns void... maybe change this in the future as i learn
|
||||||
|
// more and more LLVM...
|
||||||
|
auto func_ty =
|
||||||
|
llvm::FunctionType::get( llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ),
|
||||||
|
{ llvm::PointerType::getInt8PtrTy( ir_builder->getContext() ) }, false );
|
||||||
|
|
||||||
|
// 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 );
|
||||||
|
|
||||||
|
for ( const auto &vmp2_code_block : vmp2_code_blocks )
|
||||||
|
{
|
||||||
|
// create basic block name... block_xxxxxxxx format...
|
||||||
|
std::stringstream blk_name;
|
||||||
|
blk_name << "blk_" << std::hex << vmp2_code_block.vip_begin;
|
||||||
|
llvm_code_blocks.push_back(
|
||||||
|
{ vmp2_code_block.vip_begin,
|
||||||
|
llvm::BasicBlock::Create( ir_builder->getContext(), blk_name.str().c_str(), llvm_fptr ) } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace vm
|
Loading…
Reference in new issue