Skip to content

Commit

Permalink
starting a simple compiler interface which wraps asmjit
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewfl committed Jul 9, 2016
1 parent 6f60867 commit 1e56f32
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 61 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "deps/udis86"]
path = deps/udis86
url = https://github.com/vmt/udis86.git
[submodule "deps/asmjit"]
path = deps/asmjit
url = https://github.com/kobalicek/asmjit.git
1 change: 1 addition & 0 deletions deps/asmjit
Submodule asmjit added at c908c3
8 changes: 6 additions & 2 deletions deps/fabricate/fabricate.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,12 @@ def relative_to_abs_paths(args):
ret.append(' '.join(s))
return ret

def Shell(args, **kwargs):
return shell(*shlex.split(args), **kwargs)
def Shell(args, silent=False, **kwargs):
#if silent:
return shell(*shlex.split(args), silent=silent, **kwargs)
# import ipdb; ipdb.set_trace();
# pwd = os.path.abspath('.')
# return run('sh', '-c', 'cd {} && {}'.format(pwd, args))

def shell(*args, **kwargs):
r""" Run a command: program name is given in first arg and command line
Expand Down
25 changes: 19 additions & 6 deletions make
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ CXX_FLAGS = (
'-ggdb '
'-O0 '
'-I ./deps/udis86 '
'-I ./deps/asmjit/src '
)
CXX_FLAGS_UNIT = (
'-I ./deps/catch/ '
Expand All @@ -36,18 +37,21 @@ LD_FLAGS = ''
CXX='g++'
CC='gcc'
LD='g++'
RELEASE = False

def build():
deps()
compile()
link()

def release():
global CXX_FLAGS, LD_FLAGS
global CXX_FLAGS, LD_FLAGS, RELEASE
RELEASE = True
CXX_FLAGS = CXX_FLAGS.replace('-O0', '-O2')
CXX_FLAGS = CXX_FLAGS.replace('-ggdb', '')
CXX_FLAGS += ' -DNDEBUG -fdata-sections -ffunction-sections -flto '
LD_FLAGS += '-flto '
LD_FLAGS += '-flto ' #-Wl,--gc-sections -Wl,--print-gc-sections '
clean()
build()
Run('mkdir -p release')
Run('cp build/libredmagic.so.1.0.0 release/')
Expand All @@ -58,6 +62,7 @@ def release():
def clean():
autoclean()
Shell('cd deps/udis86 && make clean', shell=True)
Shell('rm -rf build/asmjit')

def run():
build()
Expand All @@ -75,7 +80,9 @@ def link():
# **dict(globals(), **locals())
# ))
udis_libs = ' '.join(glob.glob('deps/udis86/libudis86/.libs/*.o'))
Run('{LD} {LD_FLAGS} -shared -fPIC -Wl,-soname,libredmagic.so.1.0.0 -o build/libredmagic.so.1.0.0 {objs} {udis_libs} {LIBS}'.format(
# we are not using the compiler interface, just the assembler, would be nice if we could strip all the functions
asmjit_libs = ' '.join(filter(lambda x: 'compiler' not in x, glob.glob('build/asmjit/CMakeFiles/asmjit.dir/src/asmjit/*/*.o')))
Run('{LD} {LD_FLAGS} -shared -fPIC -Wl,-soname,libredmagic.so.1.0.0 -o build/libredmagic.so.1.0.0 {objs} {udis_libs} {asmjit_libs} {LIBS}'.format(
**dict(globals(), **locals())
))
after()
Expand Down Expand Up @@ -145,10 +152,16 @@ def unit():

def deps():
# udis86 version 1.7.2
if not os.path.isfile('deps/udis86/libudis86/.libs/libudis86.so') or not os.path.isfile('deps/udis86/libudis86/itab.h'):
Shell('cd deps/udis86 && ./autogen.sh && PYTHON=`which python2` ./configure && make', shell=True)
if not os.path.isfile('build'):
if not os.path.isdir('build'):
Shell('mkdir -p build')
if not os.path.isfile('deps/udis86/libudis86/.libs/libudis86.so') or not os.path.isfile('deps/udis86/libudis86/itab.h'):
Shell('cd deps/udis86 && ./autogen.sh && PYTHON=`which python2` ./configure && make', shell=True)
if not os.path.isfile('build/asmjit/libasmjit.so'):
Shell('mkdir -p build/asmjit')
if RELEASE:
Shell('cd build/asmjit && cmake ../../deps/asmjit -DASMJIT_CFLAGS=\'-O2\' && make VERBOSE=1 && touch release', shell=True)
else:
Shell('cd build/asmjit && cmake ../../deps/asmjit -DASMJIT_CFLAGS=\'-ggdb\' && make VERBOSE=1 && touch debug', shell=True)
after()


Expand Down
6 changes: 4 additions & 2 deletions src/asm_macros.S
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
* N.L represents a new line in the macro expansion
*/

#include "constants.h"

////////////////////////////////////////////////////
.macro m_push_all_regs
// should match sys/regs.h, sys/user.h
// 216 bytes for the struct, and then offset by 512 from the current stack
sub $728, %rsp
sub $TRACE_STACK_OFFSET, %rsp

movq %r15, 0(%rsp)
movq %r14, 8(%rsp)
Expand Down Expand Up @@ -97,7 +99,7 @@
//mov 208(%rsp), %gs

movq 152(%rsp), %rsp
add $728, %rsp
add $TRACE_STACK_OFFSET, %rsp

.endm

Expand Down
3 changes: 0 additions & 3 deletions src/asm_snippets.S
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,5 @@ red_asm_write_mem_to_reg_R15_start:
red_asm_write_mem_to_reg_R15_end:





// we don't need executable stack
.section .note.GNU-stack,"",%progbits
2 changes: 2 additions & 0 deletions src/constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

#define TRACE_STACK_OFFSET 728 /* hardcode offset from this base stack */
3 changes: 3 additions & 0 deletions src/jit_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace redmagic {
class Manager;
class CodeBuffer;
class Tracer;
class SimpleCompiler;

typedef decltype(((struct user_regs_struct*)(NULL))->r15) register_t;
typedef uint64_t mem_loc_t; // a memory location in the debugged program
Expand Down Expand Up @@ -124,6 +125,8 @@ namespace redmagic {
size_t buffer_consumed;
bool owns_buffer;
bool can_write_buffer;

friend class SimpleCompiler;
// struct rebind_jumps {
// mem_loc_t buffer_offset;
// // suppose that this could disappear so might not be best idea to deallcate these and reallocate?
Expand Down
108 changes: 108 additions & 0 deletions src/simple_compiler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "simple_compiler.h"

using namespace redmagic;
using namespace asmjit;

SimpleCompiler::~SimpleCompiler() {
if(buffer) {
finalize();
}
}

CodeBuffer SimpleCompiler::finalize() {
assert(buffer);
// check that no one else used this buffer while this was running
assert(buffer->getRawBuffer() + buffer->getOffset() == buffer_cursor);
restore_registers();
getOffset();
getCodeSize();
void *start = make();
assert(start == (void*)buffer_cursor);
size_t len = runtime.getBaseAddress() - buffer_cursor;
buffer->setOffset(runtime.getBaseAddress() - buffer->getRawBuffer());

buffer = NULL;
CodeBuffer ret(buffer_cursor, len);
ret.can_write_buffer = true;
return ret;
}

void SimpleCompiler::restore_registers() {
uint64_t restore = clobbered_registers;
int indx = 0;
while(restore) {
if(restore & 0x1) {
mov(get_register_from_id(indx), x86::ptr(x86::rsp, -TRACE_STACK_OFFSET + indx * 8 + move_stack_by));
}
restore >>= 1;
indx++;
}
clobbered_registers = 0;
}

void SimpleCompiler::protect_register(int id) {
if(clobbered_registers & (1 << id) == 0) {
mov(x86::ptr(x86::rsp, -TRACE_STACK_OFFSET + id * 8 + move_stack_by), get_register_from_id(id));
clobbered_registers |= 1 << id;
}
}

const asmjit::X86GpReg& SimpleCompiler::get_scratch_register() {
int indx = 0;
if(~regs_using & clobbered_registers) {
// if there is a clobbered register that we can use as scratch then favor that
while(indx <= RDI) {
if((~regs_using & clobbered_registers & (1 << indx)) == 0) {
regs_using |= 1 << indx;
return get_register(indx);
}
}
}
while(indx <= RDI) {
if((regs_using & (1 << indx)) == 0) {
protect_register(indx);
regs_using |= 1 << indx;
clobbered_registers |= 1 << indx;
return get_register_from_id(indx);
}
}
// did not find a register
assert(0);
}

const asmjit::X86GpReg& SimpleCompiler::get_register(int id) {
assert((clobbered_registers & 1 << id) == 0);
regs_using |= 1 << id;
return get_register_from_id(id);
}


void SimpleCompiler::MemToRegister(mem_loc_t mem, int reg) {
auto r = get_register(reg);
mov(r, imm_u(mem));
mov(r, x86::ptr(r));
}

void SimpleCompiler::RegisterToMem(int reg, mem_loc_t mem) {
auto r = get_register(reg);
auto scr = get_scratch_register();
mov(scr, imm_u(mem));
mov(x86::ptr(scr), r);
}

void SimpleCompiler::SetRegister(int reg, register_t val) {
mov(get_register(reg), imm_u(val));
}

void SimpleCompiler::TestRegister(int reg, register_t val) {
auto r = get_register(reg);
Label success = newLabel();
pushf();
test(r, imm_u(val));
je(success);
// TODO: make this use some label for a generated address
popf();
jmp(imm_u(0xfafafafafafafafa));
bind(success);
popf();
}
91 changes: 91 additions & 0 deletions src/simple_compiler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#ifndef REDMAGIC_ASMJIT_WRAP_H_
#define REDMAGIC_ASMJIT_WRAP_H_

#include "jit_internal.h"
#include "constants.h"
#include <asmjit/asmjit.h>

namespace redmagic {
class SimpleCompiler final : public asmjit::X86Assembler {
public:
SimpleCompiler(CodeBuffer *buffer):
buffer(buffer),
runtime((void*)(buffer->getRawBuffer() + buffer->getOffset()), buffer->getSize() - buffer->getOffset()),
//assembler(&runtime),
buffer_cursor(buffer->getRawBuffer() + buffer->getOffset()),
asmjit::X86Assembler(&runtime)
{
}

// trigger generating the code to the buffer;
~SimpleCompiler();
CodeBuffer finalize();

// asmjit::X86Assembler assembler;

auto& get_register_from_id(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);
}

// stash the register
void protect_register(int id);
void restore_registers();
void move_stack(int amount);

// argument of which registers it should avoid when allocating a new scratch register
const asmjit::X86GpReg& get_scratch_register();
// get the current value of the register
// should be called first since it will add to protection
const asmjit::X86GpReg& get_register(int id);

void MemToRegister(mem_loc_t where, int reg);
void RegisterToMem(int reg, mem_loc_t where);
void SetRegister(int reg, register_t val);

void TestRegister(int reg, register_t val);

private:
CodeBuffer *buffer;
mem_loc_t buffer_cursor;

// registers that we have clobbered and thus have to restore at the end
uint64_t clobbered_registers = 0;
// registers that our program is using for something
// so dont reallocate these
uint64_t regs_using = 0;;

int32_t move_stack_by = 0;

asmjit::StaticRuntime runtime;

};

}

#endif // REDMAGIC_ASMJIT_WRAP_H_
Loading

0 comments on commit 1e56f32

Please sign in to comment.