Skip to content

Commit

Permalink
got it aligning the instructions from udis with asmjit, but asmjit is…
Browse files Browse the repository at this point in the history
… choking on valid instructions like `push 0xfa(%rip)`
  • Loading branch information
matthewfl committed Jul 10, 2016
1 parent fae861c commit b6aa4b7
Show file tree
Hide file tree
Showing 6 changed files with 422 additions and 41 deletions.
252 changes: 252 additions & 0 deletions src/align_udis_asmjit.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#include "align_udis_asmjit.h"

#include <iostream>
using namespace std;

using namespace redmagic;
using namespace asmjit;


struct aligned_instruction_info {
enum ud_mnemonic_code ud_code;
enum X86InstId asm_code;
};

static aligned_instruction_info aligned_instructions[UD_MAX_MNEMONIC_CODE];

namespace {
#define MANUAL_ALIGN(UD_I, ASM_I) \
aligned_instructions[UD_I].ud_code = UD_I ; \
aligned_instructions[UD_I].asm_code = ASM_I ;

struct _do_alignment {
_do_alignment() {
for(int ud_i = 0; ud_i < UD_MAX_MNEMONIC_CODE; ud_i++) {
enum ud_mnemonic_code ud_c = (enum ud_mnemonic_code)ud_i;
const char *name = ud_lookup_mnemonic(ud_c);
// if can't find instruction then returns kX86InstIdNone
uint32_t asm_id = X86Util::getInstIdByName(name);
aligned_instructions[ud_c].ud_code = ud_c;
aligned_instructions[ud_c].asm_code = (enum X86InstId)asm_id;
}

MANUAL_ALIGN(UD_Ijcxz, kX86InstIdJecxz);
MANUAL_ALIGN(UD_Ipopfd, kX86InstIdPopf);
MANUAL_ALIGN(UD_Ipopfq, kX86InstIdPopf);
MANUAL_ALIGN(UD_Ipopfw, kX86InstIdPopf);
MANUAL_ALIGN(UD_Ipushfd, kX86InstIdPushf);
MANUAL_ALIGN(UD_Ipushfq, kX86InstIdPushf);
MANUAL_ALIGN(UD_Ipushfw, kX86InstIdPushf);
}
} _do_alignment_inst;
}

enum X86InstId AlignedInstructions::get_asm_mnem() {
return aligned_instructions[ud_mnem].asm_code;
}


AlignedInstructions::AlignedInstructions(ud_t *disassm) {
ud_mnem = ud_insn_mnemonic(disassm);
pc = ud_insn_off(disassm);
len = ud_insn_len(disassm);

for(int i = 0;; i++) {
const ud_operand_t *opr = ud_insn_opr(disassm, i);
if(opr == NULL)
break;
number_operands = i + 1;
operand_info *info = &operands[i];
info->type = opr->type;
switch(opr->type) {
case UD_OP_IMM:
case UD_OP_CONST:
switch(opr->size) {
case 8:
info->imm_value = opr->lval.sbyte;
break;
case 16:
info->imm_value = opr->lval.sword;
break;
case 32:
info->imm_value = opr->lval.sdword;
break;
case 64:
info->imm_value = opr->lval.sqword;
break;
default:
assert(0);
}
break;
case UD_OP_JIMM:
switch(opr->size) {
case 8:
info->address = pc + opr->lval.sbyte;
break;
case 16:
info->address = pc + opr->lval.sword;
break;
case 32:
info->address = pc + opr->lval.sdword;
break;
case 64:
info->address = pc + opr->lval.sqword;
break;
default:
assert(0);
}
break;
case UD_OP_REG: {
info->register_i = ud_register_to_sys(opr->base);
break;
}
case UD_OP_MEM: {
info->base_register = info->index_register = info->index_scale = -1;
if(opr->base != UD_NONE)
info->base_register = ud_register_to_sys(opr->base);
if(opr->index != UD_NONE) {
info->index_register = ud_register_to_sys(opr->index);
info->index_scale = opr->scale;
}
switch(opr->offset) {
case 8:
info->offset = opr->lval.sbyte;
break;
case 16:
info->offset = opr->lval.sword;
break;
case 32:
info->offset = opr->lval.sdword;
break;
case 64:
info->offset = opr->lval.sqword;
break;
default:
assert(0);
}
break;
}
case UD_OP_PTR:
assert(0);
default:
assert(0);
}
}
}

const asmjit::Operand AlignedInstructions::get_asm_op(unsigned int i) {
assert(i < number_operands);
operand_info *info = &operands[i];

switch(info->type) {
case UD_OP_CONST:
case UD_OP_IMM:
return imm(info->imm_value);
case UD_OP_JIMM:
return imm_u(info->address);
case UD_OP_REG:
return get_asm_register_from_sys(info->register_i);
case UD_OP_MEM: {
assert(info->base_register != -1);
if(info->index_register == -1) {
return x86::ptr(get_asm_register_from_sys(info->base_register), info->offset);
}
int scale = 0;
switch(info->index_scale) {
case 0: scale = 0; break;
case 8: scale = 1; break;
case 16: scale = 2; break;
case 32: scale = 3; break;
case 64: scale = 4; break;
default: assert(0);
}
return x86::ptr(get_asm_register_from_sys(info->base_register), get_asm_register_from_sys(info->index_register), scale, info->offset);
}
default:
assert(0);
}
}

uint64_t AlignedInstructions::registers_used() {
uint64_t ret = 0;
for(int i = 0; i < number_operands; i++) {
operand_info *info = &operands[i];
switch(info->type) {
case UD_OP_REG: {
ret |= 1 << info->register_i;
break;
}
case UD_OP_MEM: {
if(info->base_register != -1)
ret |= 1 << info->base_register;
if(info->index_register != -1)
ret |= 1 << info->index_register;
break;
}
case UD_OP_CONST:
case UD_OP_IMM:
case UD_OP_JIMM:
break;
default:
assert(0);
}
}
return ret;
}

void AlignedInstructions::ReplaceReigster(int from, int to) {
bool did_replace = false;

for(int i = 0; i < number_operands; i++) {
operand_info *info = &operands[i];
switch(info->type) {
case UD_OP_REG: {
if(info->register_i == from) {
did_replace = true;
info->register_i = to;
}
break;
}
case UD_OP_MEM: {
if(info->base_register == from) {
did_replace = true;
info->base_register = to;
}
if(info->index_register == from) {
did_replace = true;
info->index_register = to;
}
break;
}
case UD_OP_CONST:
case UD_OP_IMM:
case UD_OP_JIMM:
break;
default:
assert(0);
}
}

assert(did_replace);
}

void AlignedInstructions::Emit(asmjit::Assembler *assem) {
enum X86InstId inst = get_asm_mnem();
assert(inst != kX86InstIdNone);
switch(number_operands) {
case 0:
assem->emit(inst);
return;
case 1:
assem->emit(inst, get_asm_op(0));
return;
case 2:
assem->emit(inst, get_asm_op(0), get_asm_op(1));
return;
case 3:
assem->emit(inst, get_asm_op(0), get_asm_op(1), get_asm_op(2));
return;
default:
assert(0);
}
}
121 changes: 121 additions & 0 deletions src/align_udis_asmjit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#ifndef REDMAGIC_ALIGN_UDIS_ASMJIT_H_
#define REDMAGIC_ALIGN_UDIS_ASMJIT_H_

#include <asmjit/asmjit.h>
#include <udis86.h>

#include "jit_internal.h"


/**
* Attempt to align the instructions between udis86 and asmjit so that we can directly convert from a udis decompile to a asmjit instruction
* this is helpful since we can use this to slightly modify one of the instructions
*/

namespace redmagic {

class AlignedInstructions {
public:
AlignedInstructions(ud_t *disassm);

struct operand_info {
// UD_OP_*
enum ud_type type;

int8_t base_register;
int8_t index_register;
int8_t index_scale;
int64_t offset;

int8_t register_i;

int64_t imm_value;

mem_loc_t address;
};

inline size_t num_ops() { return number_operands; }
inline operand_info* get_op(unsigned int i) {
if(i >= number_operands)
return nullptr;
return &operands[i];
}

inline enum ud_mnemonic_code get_ud_mnem() { return ud_mnem; }
enum asmjit::X86InstId get_asm_mnem();

const asmjit::Operand get_asm_op(unsigned int i);

uint64_t registers_used();

// replace all references to one register with another
void ReplaceReigster(int from, int to);

void Emit(asmjit::Assembler *assem);

private:
enum ud_mnemonic_code ud_mnem;
int number_operands;
operand_info operands[3];
mem_loc_t pc;
size_t len;

void findAlignedAsmjit();
};

static auto& get_asm_register_from_sys(int id) {
// take the sys struct register id and convert it to asmjit
using namespace asmjit::x86;
switch(id) {
case R15: return r15;
case R14: return r14;
case R13: return r13;
case R12: return r12;
case RBP: return rbp;
case RBX: return rbx;
case R11: return r11;
case R10: return r10;
case R9: return r9;
case R8: return r8;
case RAX: return rax;
case RCX: return rcx;
case RDX: return rdx;
case RSI: return rsi;
case RDI: return rdi;
//case RIP: return rip;
//case CS: return cs;
// case RSP: return rsp;
// case DS: return ds;
// case ES: return es;
// case FS: return fs;
// case GS: return gs;
}
assert(0);
}

static int get_sys_register_from_asm(asmjit::X86GpReg& reg) {
using namespace asmjit::x86;
if(reg == r15) return R15;
if(reg == r14) return R14;
if(reg == r13) return R13;
if(reg == r12) return R12;
if(reg == rbp) return RBP;
if(reg == rbx) return RBX;
if(reg == r11) return R11;
if(reg == r10) return R10;
if(reg == r9 ) return R9;
if(reg == r8 ) return R8;
if(reg == rax) return RAX;
if(reg == rcx) return RCX;
if(reg == rdx) return RDX;
if(reg == rsi) return RSI;
if(reg == rdi) return RDI;

assert(0);
}


}


#endif // REDMAGIC_ALIGN_UDIS_ASMJIT_H_
2 changes: 1 addition & 1 deletion src/jit_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <memory>


#include "udis86.h"
#include <udis86.h>

namespace redmagic {

Expand Down
Loading

0 comments on commit b6aa4b7

Please sign in to comment.