|
|
@ -3,28 +3,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
namespace vm
|
|
|
|
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 )
|
|
|
|
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 ),
|
|
|
|
: llvm_ctx( llvm_ctx ), llvm_module( llvm_module ), vm_ctx( vm_ctx ), rtn_begin( rtn_begin ),
|
|
|
|
vmp2_code_blocks( vmp2_code_blocks )
|
|
|
|
vmp2_code_blocks( vmp2_code_blocks )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// create llvm::Function and llvm::BasicBlock's...
|
|
|
|
// do not change the ordering of these function calls...
|
|
|
|
create_routine();
|
|
|
|
create_routine();
|
|
|
|
|
|
|
|
ir_builder = std::make_shared< llvm_irbuilder_t >( *llvm_ctx );
|
|
|
|
// set the insert point to the first code block...
|
|
|
|
|
|
|
|
ir_builder = std::make_shared< llvm::IRBuilder<> >( *llvm_ctx );
|
|
|
|
|
|
|
|
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ] );
|
|
|
|
ir_builder->SetInsertPoint( llvm_code_blocks[ 0 ] );
|
|
|
|
|
|
|
|
|
|
|
|
// create native registers...
|
|
|
|
// do not change the ordering of these function calls...
|
|
|
|
create_native_registers();
|
|
|
|
create_native_registers();
|
|
|
|
|
|
|
|
|
|
|
|
// create stack and stack pointer...
|
|
|
|
|
|
|
|
create_virtual_stack();
|
|
|
|
create_virtual_stack();
|
|
|
|
|
|
|
|
|
|
|
|
// lift vm enter pushes to llvm ir...
|
|
|
|
|
|
|
|
lift_vm_entry();
|
|
|
|
lift_vm_entry();
|
|
|
|
|
|
|
|
|
|
|
|
// create virtual registers...
|
|
|
|
|
|
|
|
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...
|
|
|
|
// convert the rtn_begin address to a hex string and prepend "rtn_" to it...
|
|
|
|
std::stringstream rtn_name;
|
|
|
|
std::stringstream rtn_name;
|
|
|
|
rtn_name << "rtn_" << std::hex << rtn_begin;
|
|
|
|
rtn_name << "rtn_" << std::hex << rtn_begin;
|
|
|
|
|
|
|
|
|
|
|
|
llvm_fptr = llvm::Function::Create( func_ty, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
|
|
|
|
llvm_fptr = llvm::Function::Create( func_ty, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
|
|
|
|
rtn_name.str().c_str(), *llvm_module );
|
|
|
|
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 spi = ir_builder->CreateLoad( ir_builder->getInt64Ty(), stack_ptr, false );
|
|
|
|
auto current_stack_index = 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 *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
|
|
|
|
auto new_stack_index =
|
|
|
|
llvm_value_t *indices[ 2 ] = { i64_zero, new_spi };
|
|
|
|
ir_builder->CreateSub( current_stack_index, llvm::ConstantInt::get( ir_builder->getInt64Ty(), byte_size ) );
|
|
|
|
auto stack_ptr = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm_value_t * >( indices, 2 ) );
|
|
|
|
|
|
|
|
|
|
|
|
// Store the newly calculated stack index into VSP
|
|
|
|
if ( byte_size > 1 )
|
|
|
|
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
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Cast the pointer so the stack item width matches the width of the input value
|
|
|
|
|
|
|
|
auto casted_ptr = ir_builder->CreatePointerCast(
|
|
|
|
auto casted_ptr = ir_builder->CreatePointerCast(
|
|
|
|
stack_ptr, llvm::PointerType::get( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), 0 ) );
|
|
|
|
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 );
|
|
|
|
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_t *i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
|
|
|
|
llvm::Value *indices[ 2 ] = { i64_zero, current_spi };
|
|
|
|
llvm_value_t *indices[ 2 ] = { i64_zero, current_spi };
|
|
|
|
auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
|
|
|
auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
|
|
|
|
|
|
|
|
|
|
|
if ( byte_size > 1 )
|
|
|
|
if ( byte_size > 1 )
|
|
|
@ -196,14 +176,14 @@ namespace vm
|
|
|
|
else
|
|
|
|
else
|
|
|
|
output_value = ir_builder->CreateLoad( ir_builder->getInt8Ty(), top_stack );
|
|
|
|
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 ) );
|
|
|
|
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;
|
|
|
|
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 );
|
|
|
|
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 );
|
|
|
|
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 ) );
|
|
|
|
auto i64_zero = llvm::ConstantInt::get( *llvm_ctx, llvm::APInt( 64, 0 ) );
|
|
|
|
llvm::Value *indices[ 2 ] = { i64_zero, current_spi };
|
|
|
|
llvm_value_t *indices[ 2 ] = { i64_zero, current_spi };
|
|
|
|
auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
|
|
|
auto top_stack = ir_builder->CreateInBoundsGEP( virtual_stack, llvm::ArrayRef< llvm::Value * >( indices, 2 ) );
|
|
|
|
|
|
|
|
|
|
|
|
if ( byte_size > 1 )
|
|
|
|
if ( byte_size > 1 )
|
|
|
@ -227,18 +207,30 @@ namespace vm
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr );
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), casted_ptr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), top_stack );
|
|
|
|
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 )
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if ( byte_size * 8 != var->getType()->getPrimitiveSizeInBits() )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), global );
|
|
|
|
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 );
|
|
|
|
return ir_builder->CreateLoad( llvm::IntegerType::get( *llvm_ctx, byte_size * 8 ), var );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -254,22 +246,68 @@ namespace vm
|
|
|
|
stack_ptr );
|
|
|
|
stack_ptr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
llvm::Function *vmp_rtn_t::lift( void )
|
|
|
|
llvm_function_t *vmp_rtn_t::lift( void )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
auto &code_blocks = llvm_fptr->getBasicBlockList();
|
|
|
|
auto &code_blocks = llvm_fptr->getBasicBlockList();
|
|
|
|
|
|
|
|
auto lifters = vm::lifters_t::get_instance();
|
|
|
|
|
|
|
|
|
|
|
|
for ( auto idx = 0u; idx < code_blocks.size(); ++idx )
|
|
|
|
for ( auto idx = 0u; idx < code_blocks.size(); ++idx )
|
|
|
|
{
|
|
|
|
{
|
|
|
|
for ( auto &vinstr : vmp2_code_blocks[ idx ].vinstrs )
|
|
|
|
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 );
|
|
|
|
std::printf( "> failed to devirtualize virtual instruction with opcode = %d\n", vinstr.opcode );
|
|
|
|
|
|
|
|
|
|
|
|
llvm_module->print( llvm::outs(), nullptr );
|
|
|
|
llvm_module->print( llvm::outs(), nullptr );
|
|
|
|
return nullptr;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return llvm_fptr;
|
|
|
|
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
|
|
|
|
} // namespace vm
|