about summary refs log tree commit diff stats
path: root/src/miasm/jitter
diff options
context:
space:
mode:
Diffstat (limited to 'src/miasm/jitter')
-rw-r--r--src/miasm/jitter/JitCore.c247
-rw-r--r--src/miasm/jitter/JitCore.h242
-rw-r--r--src/miasm/jitter/Jitgcc.c100
-rw-r--r--src/miasm/jitter/Jitllvm.c96
-rw-r--r--src/miasm/jitter/__init__.py1
-rw-r--r--src/miasm/jitter/arch/JitCore_aarch64.c519
-rw-r--r--src/miasm/jitter/arch/JitCore_aarch64.h57
-rw-r--r--src/miasm/jitter/arch/JitCore_arm.c453
-rw-r--r--src/miasm/jitter/arch/JitCore_arm.h47
-rw-r--r--src/miasm/jitter/arch/JitCore_m68k.c467
-rw-r--r--src/miasm/jitter/arch/JitCore_m68k.h55
-rw-r--r--src/miasm/jitter/arch/JitCore_mep.c569
-rw-r--r--src/miasm/jitter/arch/JitCore_mep.h82
-rw-r--r--src/miasm/jitter/arch/JitCore_mips32.c484
-rw-r--r--src/miasm/jitter/arch/JitCore_mips32.h343
-rw-r--r--src/miasm/jitter/arch/JitCore_msp430.c423
-rw-r--r--src/miasm/jitter/arch/JitCore_msp430.h44
-rw-r--r--src/miasm/jitter/arch/JitCore_ppc32.c297
-rw-r--r--src/miasm/jitter/arch/JitCore_ppc32.h22
-rw-r--r--src/miasm/jitter/arch/JitCore_ppc32_regs.h192
-rw-r--r--src/miasm/jitter/arch/JitCore_x86.c903
-rw-r--r--src/miasm/jitter/arch/JitCore_x86.h136
-rw-r--r--src/miasm/jitter/arch/__init__.py0
-rw-r--r--src/miasm/jitter/bn.c933
-rw-r--r--src/miasm/jitter/bn.h163
-rw-r--r--src/miasm/jitter/codegen.py656
-rw-r--r--src/miasm/jitter/compat_py23.h228
-rw-r--r--src/miasm/jitter/csts.py50
-rw-r--r--src/miasm/jitter/emulatedsymbexec.py170
-rw-r--r--src/miasm/jitter/jitcore.py308
-rw-r--r--src/miasm/jitter/jitcore_cc_base.py127
-rw-r--r--src/miasm/jitter/jitcore_gcc.py141
-rw-r--r--src/miasm/jitter/jitcore_llvm.py144
-rw-r--r--src/miasm/jitter/jitcore_python.py219
-rw-r--r--src/miasm/jitter/jitload.py585
-rw-r--r--src/miasm/jitter/llvmconvert.py1935
-rw-r--r--src/miasm/jitter/loader/__init__.py0
-rw-r--r--src/miasm/jitter/loader/elf.py339
-rw-r--r--src/miasm/jitter/loader/pe.py834
-rw-r--r--src/miasm/jitter/loader/utils.py100
-rw-r--r--src/miasm/jitter/op_semantics.c853
-rw-r--r--src/miasm/jitter/op_semantics.h172
-rw-r--r--src/miasm/jitter/queue.h553
-rw-r--r--src/miasm/jitter/vm_mngr.c1032
-rw-r--r--src/miasm/jitter/vm_mngr.h311
-rw-r--r--src/miasm/jitter/vm_mngr_py.c1089
-rw-r--r--src/miasm/jitter/vm_mngr_py.h17
47 files changed, 16738 insertions, 0 deletions
diff --git a/src/miasm/jitter/JitCore.c b/src/miasm/jitter/JitCore.c
new file mode 100644
index 00000000..dfead5a8
--- /dev/null
+++ b/src/miasm/jitter/JitCore.c
@@ -0,0 +1,247 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <limits.h>
+#include <inttypes.h>
+#include "compat_py23.h"
+#include "queue.h"
+#include "vm_mngr.h"
+#include "bn.h"
+#include "vm_mngr_py.h"
+#include "JitCore.h"
+
+
+void JitCpu_dealloc(JitCpu* self)
+{
+    Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+PyObject * JitCpu_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    JitCpu *self;
+
+    self = (JitCpu *)type->tp_alloc(type, 0);
+    return (PyObject *)self;
+}
+
+PyObject * JitCpu_get_vmmngr(JitCpu *self, void *closure)
+{
+	if (self->pyvm) {
+		Py_INCREF(self->pyvm);
+		return (PyObject*)self->pyvm;
+	}
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject * JitCpu_set_vmmngr(JitCpu *self, PyObject *value, void *closure)
+{
+	self->pyvm = (VmMngr*)value;
+	return 0;
+}
+
+
+
+PyObject * JitCpu_get_vmcpu(JitCpu *self, void *closure)
+{
+	PyObject * ret;
+	uint64_t addr;
+	addr = (uint64_t) self->cpu;
+	ret = PyLong_FromUnsignedLongLong(addr);
+	return ret;
+}
+
+PyObject * JitCpu_set_vmcpu(JitCpu *self, PyObject *value, void *closure)
+{
+	fprintf(stderr, "Set vmcpu not supported yet\n");
+	exit(-1);
+}
+
+
+
+PyObject * JitCpu_get_jitter(JitCpu *self, void *closure)
+{
+	if (self->jitter) {
+		Py_INCREF(self->jitter);
+		return self->jitter;
+	}
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject * JitCpu_set_jitter(JitCpu *self, PyObject *value, void *closure)
+{
+	self->jitter = value;
+	return 0;
+}
+
+uint8_t MEM_LOOKUP_08(JitCpu* jitcpu, uint64_t addr)
+{
+    return vm_MEM_LOOKUP_08(&(jitcpu->pyvm->vm_mngr), addr);
+}
+
+uint16_t MEM_LOOKUP_16(JitCpu* jitcpu, uint64_t addr)
+{
+	return vm_MEM_LOOKUP_16(&(jitcpu->pyvm->vm_mngr), addr);
+}
+
+uint32_t MEM_LOOKUP_32(JitCpu* jitcpu, uint64_t addr)
+{
+    return vm_MEM_LOOKUP_32(&(jitcpu->pyvm->vm_mngr), addr);
+}
+
+uint64_t MEM_LOOKUP_64(JitCpu* jitcpu, uint64_t addr)
+{
+	return vm_MEM_LOOKUP_64(&(jitcpu->pyvm->vm_mngr), addr);
+}
+
+bn_t MEM_LOOKUP_BN_BN(JitCpu* jitcpu, int size, bn_t addr)
+{
+	uint64_t ptr;
+	int i;
+	uint8_t tmp;
+	bn_t val = bignum_from_int(0);
+
+	ptr = bignum_to_uint64(addr);
+
+
+	for (i=0; i < size; i += 8) {
+		tmp = vm_MEM_LOOKUP_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr);
+		ptr += 1;
+		val = bignum_or(val, bignum_lshift(bignum_from_int(tmp), i));
+	}
+
+	return val;
+}
+
+
+uint64_t MEM_LOOKUP_BN_INT(JitCpu* jitcpu, int size, bn_t addr)
+{
+	uint64_t ptr;
+	uint64_t val = 0;
+
+	ptr = bignum_to_uint64(addr);
+
+	switch (size) {
+		case 8:
+			val = vm_MEM_LOOKUP_08(&(jitcpu->pyvm->vm_mngr), ptr);
+			break;
+		case 16:
+			val = vm_MEM_LOOKUP_16(&(jitcpu->pyvm->vm_mngr), ptr);
+			break;
+		case 32:
+			val = vm_MEM_LOOKUP_32(&(jitcpu->pyvm->vm_mngr), ptr);
+			break;
+		case 64:
+			val = vm_MEM_LOOKUP_64(&(jitcpu->pyvm->vm_mngr), ptr);
+			break;
+		default:
+			fprintf(stderr, "Error: bad READ size %d\n", size);
+			exit(-1);
+			break;
+	}
+
+	return val;
+}
+
+
+
+bn_t MEM_LOOKUP_INT_BN(JitCpu* jitcpu, int size, uint64_t addr)
+{
+	int i;
+	uint8_t tmp;
+	bn_t val = bignum_from_int(0);
+
+	for (i=0; i < size; i += 8) {
+		tmp = vm_MEM_LOOKUP_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr);
+		addr += 1;
+		val = bignum_or(val, bignum_lshift(bignum_from_int(tmp), i));
+	}
+
+	return val;
+}
+
+
+void MEM_LOOKUP_INT_BN_TO_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr)
+{
+	bn_t ret;
+
+	if (size % 8) {
+		fprintf(stderr, "Bad size %d\n", size);
+		exit(-1);
+	}
+
+	ret = MEM_LOOKUP_INT_BN(jitcpu, size, addr);
+	memcpy(ptr, (char*)&ret, size / 8);
+}
+
+
+void MEM_WRITE_BN_BN(JitCpu* jitcpu, int size, bn_t addr, bn_t src)
+{
+	uint64_t ptr;
+	int val;
+	int i;
+
+	ptr = bignum_to_uint64(addr);
+	for (i=0; i < size; i += 8) {
+		val = bignum_to_uint64(src) & 0xFF;
+		vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, val);
+		ptr += 1;
+		src = bignum_rshift(src, 8);
+	}
+}
+
+
+void MEM_WRITE_BN_INT(JitCpu* jitcpu, int size, bn_t addr, uint64_t src)
+{
+	uint64_t ptr;
+	ptr = bignum_to_uint64(addr);
+
+	switch (size) {
+		case 8:
+			vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, (unsigned char)src);
+			break;
+		case 16:
+			vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, (unsigned short)src);
+			break;
+		case 32:
+			vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, (unsigned int)src);
+			break;
+		case 64:
+			vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, src);
+			break;
+		default:
+			fprintf(stderr, "Error: bad write size %d\n", size);
+			exit(-1);
+			break;
+	}
+}
+
+void MEM_WRITE_INT_BN(JitCpu* jitcpu, int size, uint64_t addr, bn_t src)
+{
+	int val;
+	int i;
+
+	for (i=0; i < size; i += 8) {
+		val = bignum_to_uint64(src) & 0xFF;
+		vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, val);
+		addr += 1;
+		src = bignum_rshift(src, 8);
+	}
+}
+
+
+void MEM_WRITE_INT_BN_FROM_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr)
+{
+	bn_t val;
+
+	if (size % 8) {
+		fprintf(stderr, "Bad size %d\n", size);
+		exit(-1);
+	}
+
+	val = bignum_from_int(0);
+	memcpy(&val, ptr, size / 8);
+	MEM_WRITE_INT_BN(jitcpu, size, addr, val);
+}
diff --git a/src/miasm/jitter/JitCore.h b/src/miasm/jitter/JitCore.h
new file mode 100644
index 00000000..ff6ff159
--- /dev/null
+++ b/src/miasm/jitter/JitCore.h
@@ -0,0 +1,242 @@
+#ifndef JITCORE_H
+#define JITCORE_H
+
+#if _WIN32
+#define _MIASM_EXPORT __declspec(dllexport)
+
+#ifndef SSIZE_MAX
+#ifdef _WIN64
+#define SSIZE_MAX _I64_MAX
+#else
+#define SSIZE_MAX INT_MAX
+#endif
+#endif
+
+#else
+#define _MIASM_EXPORT
+#endif
+
+#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;}
+#define RAISE_ret0(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return 0;}
+
+
+#if PY_MAJOR_VERSION >= 3
+#define getset_reg_bn(regname, size)					\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		bn_t bn;						\
+		PyObject* py_long;					\
+		bn = (self->cpu)->regname;				\
+		bn = bignum_mask(bn, (size));				\
+		py_long = bn_to_PyLong(bn);				\
+		return py_long;						\
+	}								\
+									\
+	static PyObject *JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		bn_t bn;						\
+		PyObject* py_long = value;				\
+		if (PyLong_Check(py_long)){				\
+				Py_INCREF(py_long);			\
+			} else {					\
+				RAISE(PyExc_TypeError,"arg must be int"); \
+			}						\
+									\
+		bn = PyLong_to_bn(py_long);				\
+									\
+		(self->cpu)->regname = bignum_mask(bn, (size));		\
+		return 0;						\
+	}
+
+
+#else
+#define getset_reg_bn(regname, size)					\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		bn_t bn;						\
+		PyObject* py_long;					\
+		bn = (self->cpu)->regname;				\
+		bn = bignum_mask(bn, (size));				\
+		py_long = bn_to_PyLong(bn);				\
+		return py_long;						\
+	}								\
+									\
+	static PyObject *JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		bn_t bn;						\
+		PyObject* py_long = value;				\
+		uint64_t tmp;						\
+									\
+		if (PyInt_Check(py_long)){				\
+			tmp = (uint64_t)PyInt_AsLong(py_long);		\
+			py_long = PyLong_FromLong((long)tmp);		\
+		} else if (PyLong_Check(py_long)){			\
+			Py_INCREF(py_long);				\
+		}							\
+		else{							\
+			RAISE(PyExc_TypeError,"arg must be int");	\
+		}							\
+									\
+		bn = PyLong_to_bn(py_long);				\
+									\
+		self->cpu->regname = bignum_mask(bn, (size));		\
+		return 0;						\
+	}
+#endif
+
+
+
+
+
+
+
+
+
+
+
+#define getset_reg_u64(regname)						\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		return PyLong_FromUnsignedLongLong(self->cpu->regname); \
+	}								\
+	static int JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		uint64_t val;						\
+		PyGetInt_uint64_t_retneg(value, val);			\
+		self->cpu->regname = val;				\
+		return 0;						\
+	}
+
+#define getset_reg_u32(regname)						\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		return PyLong_FromUnsignedLongLong(self->cpu->regname); \
+	}								\
+	static int JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		uint32_t val;						\
+		PyGetInt_uint32_t_retneg(value, val);			\
+		self->cpu->regname = val;				\
+		return 0;						\
+	}
+
+
+#define getset_reg_u16(regname)						\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		return PyLong_FromUnsignedLongLong(self->cpu->regname); \
+	}								\
+	static int JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		uint16_t val;						\
+		PyGetInt_uint16_t_retneg(value, val);			\
+		self->cpu->regname = val;				\
+		return 0;						\
+	}
+
+
+#define getset_reg_u8(regname)						\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		return PyLong_FromUnsignedLongLong(self->cpu->regname); \
+	}								\
+	static int JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		uint8_t val;						\
+		PyGetInt_uint8_t_retneg(value, val);			\
+		self->cpu->regname = val;				\
+		return 0;						\
+	}
+
+
+#define get_reg(reg)  do {						\
+		o = PyLong_FromUnsignedLongLong((uint64_t)self->cpu->reg); \
+		PyDict_SetItemString(dict, #reg, o);			\
+		Py_DECREF(o);						\
+	} while(0);
+
+
+#define get_reg_bn(reg, size)  do {					\
+		bn_t bn;						\
+		PyObject* py_long;					\
+		bn = self->cpu->reg;					\
+		bn = bignum_mask(bn, size);				\
+		py_long = bn_to_PyLong(bn);				\
+		PyDict_SetItemString(dict, #reg, py_long);		\
+		Py_DECREF(py_long);					\
+	} while(0);
+
+
+#define get_reg_off(reg)  do {						\
+		o = PyLong_FromUnsignedLongLong((uint64_t)offsetof(struct vm_cpu, reg)); \
+		PyDict_SetItemString(dict, #reg, o);			\
+		Py_DECREF(o);						\
+	} while(0);
+
+
+
+
+typedef struct {
+	uint8_t is_local;
+	uint64_t address;
+} block_id;
+
+struct vm_cpu;
+
+typedef struct {
+	PyObject_HEAD
+	VmMngr *pyvm;
+	PyObject *jitter;
+	struct vm_cpu *cpu;
+} JitCpu;
+
+
+typedef struct _reg_dict{
+    char* name;
+    size_t offset;
+    size_t size;
+} reg_dict;
+
+
+
+void JitCpu_dealloc(JitCpu* self);
+PyObject * JitCpu_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
+PyObject * JitCpu_get_vmmngr(JitCpu *self, void *closure);
+PyObject * JitCpu_set_vmmngr(JitCpu *self, PyObject *value, void *closure);
+PyObject * JitCpu_get_vmcpu(JitCpu *self, void *closure);
+PyObject * JitCpu_set_vmcpu(JitCpu *self, PyObject *value, void *closure);
+PyObject * JitCpu_get_jitter(JitCpu *self, void *closure);
+PyObject * JitCpu_set_jitter(JitCpu *self, PyObject *value, void *closure);
+void Resolve_dst(block_id* BlockDst, uint64_t addr, uint64_t is_local);
+
+#define Resolve_dst(b, arg_addr, arg_is_local) do {(b)->address = (arg_addr); (b)->is_local = (arg_is_local);} while(0)
+
+
+
+_MIASM_EXPORT uint8_t MEM_LOOKUP_08(JitCpu* jitcpu, uint64_t addr);
+_MIASM_EXPORT uint16_t MEM_LOOKUP_16(JitCpu* jitcpu, uint64_t addr);
+_MIASM_EXPORT uint32_t MEM_LOOKUP_32(JitCpu* jitcpu, uint64_t addr);
+_MIASM_EXPORT uint64_t MEM_LOOKUP_64(JitCpu* jitcpu, uint64_t addr);
+
+_MIASM_EXPORT bn_t MEM_LOOKUP_BN_BN(JitCpu* jitcpu, int size, bn_t addr);
+_MIASM_EXPORT bn_t MEM_LOOKUP_INT_BN(JitCpu* jitcpu, int size, uint64_t addr);
+
+_MIASM_EXPORT uint64_t MEM_LOOKUP_BN_INT(JitCpu* jitcpu, int size, bn_t addr);
+
+_MIASM_EXPORT void MEM_WRITE_BN_BN(JitCpu* jitcpu, int size, bn_t addr, bn_t src);
+_MIASM_EXPORT void MEM_WRITE_BN_INT(JitCpu* jitcpu, int size, bn_t addr, uint64_t src);
+_MIASM_EXPORT void MEM_WRITE_INT_BN(JitCpu* jitcpu, int size, uint64_t addr, bn_t src);
+
+
+_MIASM_EXPORT void MEM_LOOKUP_INT_BN_TO_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr);
+_MIASM_EXPORT void MEM_WRITE_INT_BN_FROM_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr);
+
+
+
+#define VM_exception_flag (jitcpu->pyvm->vm_mngr.exception_flags)
+#define CPU_exception_flag (((struct vm_cpu*)jitcpu->cpu)->exception_flags)
+#define CPU_exception_flag_at_instr ((CPU_exception_flag) && ((CPU_exception_flag) > EXCEPT_NUM_UPDT_EIP))
+#define JIT_RET_EXCEPTION 1
+#define JIT_RET_NO_EXCEPTION 0
+
+#endif
diff --git a/src/miasm/jitter/Jitgcc.c b/src/miasm/jitter/Jitgcc.c
new file mode 100644
index 00000000..9dc7b2fd
--- /dev/null
+++ b/src/miasm/jitter/Jitgcc.c
@@ -0,0 +1,100 @@
+#include <Python.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include "compat_py23.h"
+
+typedef struct {
+	uint8_t is_local;
+	uint64_t address;
+} block_id;
+
+typedef int (*jitted_func)(block_id*, PyObject*);
+
+
+PyObject* gcc_exec_block(PyObject* self, PyObject* args)
+{
+	jitted_func func;
+	PyObject* jitcpu;
+	PyObject* func_py;
+	PyObject* lbl2ptr;
+	PyObject* stop_offsets;
+	PyObject* retaddr = NULL;
+	int status;
+	block_id BlockDst;
+	uint64_t max_exec_per_call = 0;
+	uint64_t cpt;
+	int do_cpt;
+
+
+	if (!PyArg_ParseTuple(args, "OOOO|K",
+			      &retaddr, &jitcpu, &lbl2ptr, &stop_offsets,
+			      &max_exec_per_call))
+		return NULL;
+
+	/* The loop will decref retaddr always once */
+	Py_INCREF(retaddr);
+
+	if (max_exec_per_call == 0) {
+		do_cpt = 0;
+		cpt = 1;
+	} else {
+		do_cpt = 1;
+		cpt = max_exec_per_call;
+	}
+
+
+
+	for (;;) {
+		if (cpt == 0)
+			return retaddr;
+		if (do_cpt)
+			cpt --;
+		// Init
+		BlockDst.is_local = 0;
+		BlockDst.address = 0;
+
+		// Get the expected jitted function address
+		func_py = PyDict_GetItem(lbl2ptr, retaddr);
+		if (func_py)
+			func = (jitted_func) PyLong_AsVoidPtr((PyObject*) func_py);
+		else {
+			if (BlockDst.is_local == 1) {
+				fprintf(stderr, "return on local label!\n");
+				exit(EXIT_FAILURE);
+			}
+			// retaddr is not jitted yet
+			return retaddr;
+		}
+		// Execute it
+		status = func(&BlockDst, jitcpu);
+		Py_DECREF(retaddr);
+		retaddr = PyLong_FromUnsignedLongLong(BlockDst.address);
+
+		// Check exception
+		if (status)
+			return retaddr;
+
+		// Check stop offsets
+		if (PySet_Contains(stop_offsets, retaddr))
+			return retaddr;
+	}
+}
+
+
+
+static PyMethodDef GccMethods[] = {
+    {"gcc_exec_block",  gcc_exec_block, METH_VARARGS,
+     "gcc exec block"},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+
+MOD_INIT(Jitgcc)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "Jitgcc", "gcc module", GccMethods);
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/Jitllvm.c b/src/miasm/jitter/Jitllvm.c
new file mode 100644
index 00000000..3420c254
--- /dev/null
+++ b/src/miasm/jitter/Jitllvm.c
@@ -0,0 +1,96 @@
+#include <Python.h>
+
+#include <inttypes.h>
+
+#include <stdint.h>
+#include "compat_py23.h"
+#include "queue.h"
+#include "vm_mngr.h"
+#include "bn.h"
+#include "vm_mngr_py.h"
+#include "JitCore.h"
+// Needed to get the JitCpu.cpu offset, arch independent
+#include "arch/JitCore_x86.h"
+
+PyObject* llvm_exec_block(PyObject* self, PyObject* args)
+{
+	uint64_t (*func)(void*, void*, void*, uint8_t*);
+	struct vm_cpu* cpu;
+	vm_mngr_t* vm;
+	uint64_t ret;
+	JitCpu* jitcpu;
+	uint8_t status;
+	PyObject* func_py;
+	PyObject* lbl2ptr;
+	PyObject* stop_offsets;
+	PyObject* retaddr = NULL;
+	uint64_t max_exec_per_call = 0;
+	uint64_t cpt;
+	int do_cpt;
+
+	if (!PyArg_ParseTuple(args, "OOOO|K",
+			      &retaddr, &jitcpu, &lbl2ptr, &stop_offsets,
+			      &max_exec_per_call))
+		return NULL;
+
+	cpu = jitcpu->cpu;
+	vm = &(jitcpu->pyvm->vm_mngr);
+	/* The loop will decref retaddr always once */
+	Py_INCREF(retaddr);
+
+	if (max_exec_per_call == 0) {
+		do_cpt = 0;
+		cpt = 1;
+	} else {
+		do_cpt = 1;
+		cpt = max_exec_per_call;
+	}
+
+	for (;;) {
+		// Handle cpt
+		if (cpt == 0)
+			return retaddr;
+		if (do_cpt)
+			cpt --;
+
+		// Get the expected jitted function address
+		func_py = PyDict_GetItem(lbl2ptr, retaddr);
+		if (func_py)
+			func = PyLong_AsVoidPtr((PyObject*) func_py);
+		else
+			// retaddr is not jitted yet
+			return retaddr;
+
+		// Execute it
+		ret = func((void*) jitcpu, (void*)(intptr_t) cpu, (void*)(intptr_t) vm, &status);
+		Py_DECREF(retaddr);
+		retaddr = PyLong_FromUnsignedLongLong(ret);
+
+		// Check exception
+		if (status)
+			return retaddr;
+
+		// Check stop offsets
+		if (PySet_Contains(stop_offsets, retaddr))
+			return retaddr;
+	}
+}
+
+
+static PyMethodDef LLVMMethods[] = {
+    {"llvm_exec_block",  llvm_exec_block, METH_VARARGS,
+     "llvm exec block"},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+
+
+MOD_INIT(Jitllvm)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "Jitllvm", "llvm module", LLVMMethods);
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/__init__.py b/src/miasm/jitter/__init__.py
new file mode 100644
index 00000000..460e327d
--- /dev/null
+++ b/src/miasm/jitter/__init__.py
@@ -0,0 +1 @@
+"JustInTime compilation feature"
diff --git a/src/miasm/jitter/arch/JitCore_aarch64.c b/src/miasm/jitter/arch/JitCore_aarch64.c
new file mode 100644
index 00000000..7961f3cc
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_aarch64.c
@@ -0,0 +1,519 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "../op_semantics.h"
+#include "JitCore_aarch64.h"
+
+
+
+reg_dict gpreg_dict[] = {
+	{.name = "X0", .offset = offsetof(struct vm_cpu, X0), .size = 64},
+	{.name = "X1", .offset = offsetof(struct vm_cpu, X1), .size = 64},
+	{.name = "X2", .offset = offsetof(struct vm_cpu, X2), .size = 64},
+	{.name = "X3", .offset = offsetof(struct vm_cpu, X3), .size = 64},
+	{.name = "X4", .offset = offsetof(struct vm_cpu, X4), .size = 64},
+	{.name = "X5", .offset = offsetof(struct vm_cpu, X5), .size = 64},
+	{.name = "X6", .offset = offsetof(struct vm_cpu, X6), .size = 64},
+	{.name = "X7", .offset = offsetof(struct vm_cpu, X7), .size = 64},
+	{.name = "X8", .offset = offsetof(struct vm_cpu, X8), .size = 64},
+	{.name = "X9", .offset = offsetof(struct vm_cpu, X9), .size = 64},
+	{.name = "X10", .offset = offsetof(struct vm_cpu, X10), .size = 64},
+	{.name = "X11", .offset = offsetof(struct vm_cpu, X11), .size = 64},
+	{.name = "X12", .offset = offsetof(struct vm_cpu, X12), .size = 64},
+	{.name = "X13", .offset = offsetof(struct vm_cpu, X13), .size = 64},
+	{.name = "X14", .offset = offsetof(struct vm_cpu, X14), .size = 64},
+	{.name = "X15", .offset = offsetof(struct vm_cpu, X15), .size = 64},
+	{.name = "X16", .offset = offsetof(struct vm_cpu, X16), .size = 64},
+	{.name = "X17", .offset = offsetof(struct vm_cpu, X17), .size = 64},
+	{.name = "X18", .offset = offsetof(struct vm_cpu, X18), .size = 64},
+	{.name = "X19", .offset = offsetof(struct vm_cpu, X19), .size = 64},
+	{.name = "X20", .offset = offsetof(struct vm_cpu, X20), .size = 64},
+	{.name = "X21", .offset = offsetof(struct vm_cpu, X21), .size = 64},
+	{.name = "X22", .offset = offsetof(struct vm_cpu, X22), .size = 64},
+	{.name = "X23", .offset = offsetof(struct vm_cpu, X23), .size = 64},
+	{.name = "X24", .offset = offsetof(struct vm_cpu, X24), .size = 64},
+	{.name = "X25", .offset = offsetof(struct vm_cpu, X25), .size = 64},
+	{.name = "X26", .offset = offsetof(struct vm_cpu, X26), .size = 64},
+	{.name = "X27", .offset = offsetof(struct vm_cpu, X27), .size = 64},
+	{.name = "X28", .offset = offsetof(struct vm_cpu, X28), .size = 64},
+	{.name = "X29", .offset = offsetof(struct vm_cpu, X29), .size = 64},
+	{.name = "LR", .offset = offsetof(struct vm_cpu, LR), .size = 64},
+
+	{.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 64},
+	{.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 64},
+
+	{.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8},
+	{.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8},
+	{.name = "of", .offset = offsetof(struct vm_cpu, of), .size = 8},
+	{.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8},
+
+	{.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32},
+	{.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32},
+
+};
+
+/************************** JitCpu object **************************/
+
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(X0);
+    get_reg(X1);
+    get_reg(X2);
+    get_reg(X3);
+    get_reg(X4);
+    get_reg(X5);
+    get_reg(X6);
+    get_reg(X7);
+    get_reg(X8);
+    get_reg(X9);
+    get_reg(X10);
+    get_reg(X11);
+    get_reg(X12);
+    get_reg(X13);
+    get_reg(X14);
+    get_reg(X15);
+    get_reg(X16);
+    get_reg(X17);
+    get_reg(X18);
+    get_reg(X19);
+    get_reg(X20);
+    get_reg(X21);
+    get_reg(X22);
+    get_reg(X23);
+    get_reg(X24);
+    get_reg(X25);
+    get_reg(X26);
+    get_reg(X27);
+    get_reg(X28);
+    get_reg(X29);
+    get_reg(LR);
+    get_reg(SP);
+    get_reg(PC);
+
+    get_reg(zf);
+    get_reg(nf);
+    get_reg(of);
+    get_reg(cf);
+
+    return dict;
+}
+
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val32;
+    uint64_t val64;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    RAISE(PyExc_TypeError,"Cannot parse arguments");
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    PyGetStr(d_key_name, d_key);
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(d_key_name, gpreg_dict[i].name))
+			    continue;
+		    found = 1;
+		    switch (gpreg_dict[i].size) {
+			    default:
+				    RAISE(PyExc_TypeError, "Unsupported size");
+				    break;
+			    case 32:
+				    PyGetInt_uint32_t(d_value, val32);
+				    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val32;
+				    break;
+			    case 64:
+				    PyGetInt_uint64_t(d_value, val64);
+				    *((uint64_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val64;
+				    break;
+		    }
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unknown key: %s\n", d_key_name);
+	    RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+void dump_gpregs(struct vm_cpu* vmcpu)
+{
+	printf("X0  %.16"PRIX64" X1  %.16"PRIX64" X2  %.16"PRIX64" X3  %.16"PRIX64" "\
+	       "X4  %.16"PRIX64" X5  %.16"PRIX64" X6  %.16"PRIX64" X7  %.16"PRIX64"\n",
+	       vmcpu->X0, vmcpu->X1, vmcpu->X2, vmcpu->X3, vmcpu->X4, vmcpu->X5, vmcpu->X6, vmcpu->X7);
+	printf("X8  %.16"PRIX64" X9  %.16"PRIX64" X10 %.16"PRIX64" X11 %.16"PRIX64" "\
+	       "X12 %.16"PRIX64" X13 %.16"PRIX64" X14 %.16"PRIX64" X15 %.16"PRIX64"\n",
+	       vmcpu->X8, vmcpu->X9, vmcpu->X10, vmcpu->X11,
+	       vmcpu->X12, vmcpu->X13, vmcpu->X14, vmcpu->X15);
+	printf("X16 %.16"PRIX64" X17 %.16"PRIX64" X18 %.16"PRIX64" X19 %.16"PRIX64" "\
+	       "X20 %.16"PRIX64" X21 %.16"PRIX64" X22 %.16"PRIX64" X23 %.16"PRIX64"\n",
+	       vmcpu->X16, vmcpu->X17, vmcpu->X18, vmcpu->X19,
+	       vmcpu->X20, vmcpu->X21, vmcpu->X22, vmcpu->X23);
+	printf("X24 %.16"PRIX64" X25 %.16"PRIX64" X26 %.16"PRIX64" X27 %.16"PRIX64" "\
+	       "X28 %.16"PRIX64" X29 %.16"PRIX64" LR  %.16"PRIX64"\n",
+	       vmcpu->X24, vmcpu->X25, vmcpu->X26, vmcpu->X27,
+	       vmcpu->X28, vmcpu->X29, vmcpu->LR);
+
+
+	printf("SP  %.16"PRIX64" PC  %.16"PRIX64" "\
+	       "zf  %"PRIX32" nf  %"PRIX32" of  %"PRIX32" cf  %"PRIX32"\n",
+	       vmcpu->SP, vmcpu->PC,
+	       vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf);
+}
+
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(struct vm_cpu));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc struct vm_cpu\n");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+
+
+getset_reg_u64(X0);
+getset_reg_u64(X1);
+getset_reg_u64(X2);
+getset_reg_u64(X3);
+getset_reg_u64(X4);
+getset_reg_u64(X5);
+getset_reg_u64(X6);
+getset_reg_u64(X7);
+getset_reg_u64(X8);
+getset_reg_u64(X9);
+getset_reg_u64(X10);
+getset_reg_u64(X11);
+getset_reg_u64(X12);
+getset_reg_u64(X13);
+getset_reg_u64(X14);
+getset_reg_u64(X15);
+getset_reg_u64(X16);
+getset_reg_u64(X17);
+getset_reg_u64(X18);
+getset_reg_u64(X19);
+getset_reg_u64(X20);
+getset_reg_u64(X21);
+getset_reg_u64(X22);
+getset_reg_u64(X23);
+getset_reg_u64(X24);
+getset_reg_u64(X25);
+getset_reg_u64(X26);
+getset_reg_u64(X27);
+getset_reg_u64(X28);
+getset_reg_u64(X29);
+getset_reg_u64(LR);
+getset_reg_u64(SP);
+getset_reg_u64(PC);
+
+getset_reg_u32(zf);
+getset_reg_u32(nf);
+getset_reg_u32(of);
+getset_reg_u32(cf);
+
+
+getset_reg_u32(exception_flags);
+getset_reg_u32(interrupt_num);
+
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg_off(exception_flags);
+
+    get_reg_off(X0);
+    get_reg_off(X1);
+    get_reg_off(X2);
+    get_reg_off(X3);
+    get_reg_off(X4);
+    get_reg_off(X5);
+    get_reg_off(X6);
+    get_reg_off(X7);
+    get_reg_off(X8);
+    get_reg_off(X9);
+    get_reg_off(X10);
+    get_reg_off(X11);
+    get_reg_off(X12);
+    get_reg_off(X13);
+    get_reg_off(X14);
+    get_reg_off(X15);
+    get_reg_off(X16);
+    get_reg_off(X17);
+    get_reg_off(X18);
+    get_reg_off(X19);
+    get_reg_off(X20);
+    get_reg_off(X21);
+    get_reg_off(X22);
+    get_reg_off(X23);
+    get_reg_off(X24);
+    get_reg_off(X25);
+    get_reg_off(X26);
+    get_reg_off(X27);
+    get_reg_off(X28);
+    get_reg_off(X29);
+    get_reg_off(LR);
+    get_reg_off(SP);
+    get_reg_off(PC);
+
+    /* eflag */
+    get_reg_off(zf);
+    get_reg_off(nf);
+    get_reg_off(of);
+    get_reg_off(cf);
+
+    return dict;
+}
+
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+
+    {"X0" , (getter)JitCpu_get_X0 , (setter)JitCpu_set_X0 , "X0" , NULL},
+    {"X1" , (getter)JitCpu_get_X1 , (setter)JitCpu_set_X1 , "X1" , NULL},
+    {"X2" , (getter)JitCpu_get_X2 , (setter)JitCpu_set_X2 , "X2" , NULL},
+    {"X3" , (getter)JitCpu_get_X3 , (setter)JitCpu_set_X3 , "X3" , NULL},
+    {"X4" , (getter)JitCpu_get_X4 , (setter)JitCpu_set_X4 , "X4" , NULL},
+    {"X5" , (getter)JitCpu_get_X5 , (setter)JitCpu_set_X5 , "X5" , NULL},
+    {"X6" , (getter)JitCpu_get_X6 , (setter)JitCpu_set_X6 , "X6" , NULL},
+    {"X7" , (getter)JitCpu_get_X7 , (setter)JitCpu_set_X7 , "X7" , NULL},
+    {"X8" , (getter)JitCpu_get_X8 , (setter)JitCpu_set_X8 , "X8" , NULL},
+    {"X9" , (getter)JitCpu_get_X9 , (setter)JitCpu_set_X9 , "X9" , NULL},
+
+    {"X10" , (getter)JitCpu_get_X10 , (setter)JitCpu_set_X10 , "X10" , NULL},
+    {"X11" , (getter)JitCpu_get_X11 , (setter)JitCpu_set_X11 , "X11" , NULL},
+    {"X12" , (getter)JitCpu_get_X12 , (setter)JitCpu_set_X12 , "X12" , NULL},
+    {"X13" , (getter)JitCpu_get_X13 , (setter)JitCpu_set_X13 , "X13" , NULL},
+    {"X14" , (getter)JitCpu_get_X14 , (setter)JitCpu_set_X14 , "X14" , NULL},
+    {"X15" , (getter)JitCpu_get_X15 , (setter)JitCpu_set_X15 , "X15" , NULL},
+    {"X16" , (getter)JitCpu_get_X16 , (setter)JitCpu_set_X16 , "X16" , NULL},
+    {"X17" , (getter)JitCpu_get_X17 , (setter)JitCpu_set_X17 , "X17" , NULL},
+    {"X18" , (getter)JitCpu_get_X18 , (setter)JitCpu_set_X18 , "X18" , NULL},
+    {"X19" , (getter)JitCpu_get_X19 , (setter)JitCpu_set_X19 , "X19" , NULL},
+
+    {"X20" , (getter)JitCpu_get_X20 , (setter)JitCpu_set_X20 , "X20" , NULL},
+    {"X21" , (getter)JitCpu_get_X21 , (setter)JitCpu_set_X21 , "X21" , NULL},
+    {"X22" , (getter)JitCpu_get_X22 , (setter)JitCpu_set_X22 , "X22" , NULL},
+    {"X23" , (getter)JitCpu_get_X23 , (setter)JitCpu_set_X23 , "X23" , NULL},
+    {"X24" , (getter)JitCpu_get_X24 , (setter)JitCpu_set_X24 , "X24" , NULL},
+    {"X25" , (getter)JitCpu_get_X25 , (setter)JitCpu_set_X25 , "X25" , NULL},
+    {"X26" , (getter)JitCpu_get_X26 , (setter)JitCpu_set_X26 , "X26" , NULL},
+    {"X27" , (getter)JitCpu_get_X27 , (setter)JitCpu_set_X27 , "X27" , NULL},
+    {"X28" , (getter)JitCpu_get_X28 , (setter)JitCpu_set_X28 , "X28" , NULL},
+    {"X29" , (getter)JitCpu_get_X29 , (setter)JitCpu_set_X29 , "X29" , NULL},
+
+    {"LR" , (getter)JitCpu_get_LR , (setter)JitCpu_set_LR , "LR" , NULL},
+
+
+
+    {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL},
+    {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL},
+
+    {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL},
+    {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL},
+    {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL},
+    {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL},
+
+    {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL},
+    {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL},
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_aarch64.JitCpu",  /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_aarch64_Methods[] = {
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+
+MOD_INIT(JitCore_aarch64)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_aarch64", "JitCore_aarch64 module", JitCore_aarch64_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
+
diff --git a/src/miasm/jitter/arch/JitCore_aarch64.h b/src/miasm/jitter/arch/JitCore_aarch64.h
new file mode 100644
index 00000000..975a93ec
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_aarch64.h
@@ -0,0 +1,57 @@
+
+struct vm_cpu {
+	uint32_t exception_flags;
+	uint32_t interrupt_num;
+
+	/* gpregs */
+
+	uint64_t X0;
+	uint64_t X1;
+	uint64_t X2;
+	uint64_t X3;
+	uint64_t X4;
+	uint64_t X5;
+	uint64_t X6;
+	uint64_t X7;
+	uint64_t X8;
+	uint64_t X9;
+	uint64_t X10;
+	uint64_t X11;
+	uint64_t X12;
+	uint64_t X13;
+	uint64_t X14;
+	uint64_t X15;
+	uint64_t X16;
+	uint64_t X17;
+	uint64_t X18;
+	uint64_t X19;
+	uint64_t X20;
+	uint64_t X21;
+	uint64_t X22;
+	uint64_t X23;
+	uint64_t X24;
+	uint64_t X25;
+	uint64_t X26;
+	uint64_t X27;
+	uint64_t X28;
+	uint64_t X29;
+	uint64_t LR;
+	uint64_t SP;
+
+	uint64_t PC;
+
+	/* eflag */
+	uint32_t zf;
+	uint32_t nf;
+	uint32_t of;
+	uint32_t cf;
+};
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
+
+#define RETURN_PC return BlockDst;
diff --git a/src/miasm/jitter/arch/JitCore_arm.c b/src/miasm/jitter/arch/JitCore_arm.c
new file mode 100644
index 00000000..b39ae4d2
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_arm.c
@@ -0,0 +1,453 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "../op_semantics.h"
+#include "JitCore_arm.h"
+
+
+
+reg_dict gpreg_dict[] = {
+			 {.name = "R0", .offset = offsetof(struct vm_cpu, R0), .size = 32},
+			 {.name = "R1", .offset = offsetof(struct vm_cpu, R1), .size = 32},
+			 {.name = "R2", .offset = offsetof(struct vm_cpu, R2), .size = 32},
+			 {.name = "R3", .offset = offsetof(struct vm_cpu, R3), .size = 32},
+			 {.name = "R4", .offset = offsetof(struct vm_cpu, R4), .size = 32},
+			 {.name = "R5", .offset = offsetof(struct vm_cpu, R5), .size = 32},
+			 {.name = "R6", .offset = offsetof(struct vm_cpu, R6), .size = 32},
+			 {.name = "R7", .offset = offsetof(struct vm_cpu, R7), .size = 32},
+			 {.name = "R8", .offset = offsetof(struct vm_cpu, R8), .size = 32},
+			 {.name = "R9", .offset = offsetof(struct vm_cpu, R9), .size = 32},
+			 {.name = "R10", .offset = offsetof(struct vm_cpu, R10), .size = 32},
+			 {.name = "R11", .offset = offsetof(struct vm_cpu, R11), .size = 32},
+			 {.name = "R12", .offset = offsetof(struct vm_cpu, R12), .size = 32},
+			 {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32},
+			 {.name = "LR", .offset = offsetof(struct vm_cpu, LR), .size = 32},
+			 {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32},
+
+			 {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8},
+			 {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8},
+			 {.name = "of", .offset = offsetof(struct vm_cpu, of), .size = 8},
+			 {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8},
+
+			 {.name = "ge0", .offset = offsetof(struct vm_cpu, ge0), .size = 8},
+			 {.name = "ge1", .offset = offsetof(struct vm_cpu, ge1), .size = 8},
+			 {.name = "ge2", .offset = offsetof(struct vm_cpu, ge2), .size = 8},
+			 {.name = "ge3", .offset = offsetof(struct vm_cpu, ge3), .size = 8},
+
+			 {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32},
+			 {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32},
+};
+
+/************************** JitCpu object **************************/
+
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(R0);
+    get_reg(R1);
+    get_reg(R2);
+    get_reg(R3);
+    get_reg(R4);
+    get_reg(R5);
+    get_reg(R6);
+    get_reg(R7);
+    get_reg(R8);
+    get_reg(R9);
+    get_reg(R10);
+    get_reg(R11);
+    get_reg(R12);
+    get_reg(SP);
+    get_reg(LR);
+    get_reg(PC);
+
+    get_reg(zf);
+    get_reg(nf);
+    get_reg(of);
+    get_reg(cf);
+
+    get_reg(ge0);
+    get_reg(ge1);
+    get_reg(ge2);
+    get_reg(ge3);
+
+    return dict;
+}
+
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    RAISE(PyExc_TypeError,"Cannot parse arguments");
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    PyGetStr(d_key_name, d_key);
+	    PyGetInt_uint32_t(d_value, val);
+
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(d_key_name, gpreg_dict[i].name))
+			    continue;
+		    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+		    found = 1;
+		    break;
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unknown key: %s\n", d_key_name);
+	    RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+void dump_gpregs(struct vm_cpu* vmcpu)
+{
+	printf("R0  %.8"PRIX32" R1  %.8"PRIX32" R2  %.8"PRIX32" R3  %.8"PRIX32" ",
+	       vmcpu->R0, vmcpu->R1, vmcpu->R2, vmcpu->R3);
+	printf("R4  %.8"PRIX32" R5  %.8"PRIX32" R6  %.8"PRIX32" R7  %.8"PRIX32"\n",
+	       vmcpu->R4, vmcpu->R5, vmcpu->R6, vmcpu->R7);
+	printf("R8  %.8"PRIX32" R9  %.8"PRIX32" R10 %.8"PRIX32" R11 %.8"PRIX32" ",
+	       vmcpu->R8, vmcpu->R9, vmcpu->R10, vmcpu->R11);
+	printf("R12 %.8"PRIX32" SP  %.8"PRIX32" LR  %.8"PRIX32" PC  %.8"PRIX32" ",
+	       vmcpu->R12, vmcpu->SP, vmcpu->LR, vmcpu->PC);
+	printf("zf %"PRIX32" nf %"PRIX32" of %"PRIX32" cf %"PRIX32"\n",
+	       vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf);
+}
+
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num));
+}
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS,
+	 "X"},
+	{"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(struct vm_cpu));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc struct vm_cpu\n");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+getset_reg_u32(R0);
+getset_reg_u32(R1);
+getset_reg_u32(R2);
+getset_reg_u32(R3);
+getset_reg_u32(R4);
+getset_reg_u32(R5);
+getset_reg_u32(R6);
+getset_reg_u32(R7);
+getset_reg_u32(R8);
+getset_reg_u32(R9);
+getset_reg_u32(R10);
+getset_reg_u32(R11);
+getset_reg_u32(R12);
+getset_reg_u32(SP);
+getset_reg_u32(LR);
+getset_reg_u32(PC);
+
+getset_reg_u32(zf);
+getset_reg_u32(nf);
+getset_reg_u32(of);
+getset_reg_u32(cf);
+
+getset_reg_u32(ge0);
+getset_reg_u32(ge1);
+getset_reg_u32(ge2);
+getset_reg_u32(ge3);
+
+getset_reg_u32(exception_flags);
+getset_reg_u32(interrupt_num);
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg_off(exception_flags);
+    get_reg_off(interrupt_num);
+
+    get_reg_off(R0);
+    get_reg_off(R1);
+    get_reg_off(R2);
+    get_reg_off(R3);
+    get_reg_off(R4);
+    get_reg_off(R5);
+    get_reg_off(R6);
+    get_reg_off(R7);
+    get_reg_off(R8);
+    get_reg_off(R9);
+    get_reg_off(R10);
+    get_reg_off(R11);
+    get_reg_off(R12);
+    get_reg_off(SP);
+    get_reg_off(LR);
+    get_reg_off(PC);
+
+	/* eflag */
+    get_reg_off(zf);
+    get_reg_off(nf);
+    get_reg_off(of);
+    get_reg_off(cf);
+
+    get_reg_off(ge0);
+    get_reg_off(ge1);
+    get_reg_off(ge2);
+    get_reg_off(ge3);
+
+    return dict;
+}
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+
+    {"R0" , (getter)JitCpu_get_R0 , (setter)JitCpu_set_R0 , "R0" , NULL},
+    {"R1" , (getter)JitCpu_get_R1 , (setter)JitCpu_set_R1 , "R1" , NULL},
+    {"R2" , (getter)JitCpu_get_R2 , (setter)JitCpu_set_R2 , "R2" , NULL},
+    {"R3" , (getter)JitCpu_get_R3 , (setter)JitCpu_set_R3 , "R3" , NULL},
+    {"R4" , (getter)JitCpu_get_R4 , (setter)JitCpu_set_R4 , "R4" , NULL},
+    {"R5" , (getter)JitCpu_get_R5 , (setter)JitCpu_set_R5 , "R5" , NULL},
+    {"R6" , (getter)JitCpu_get_R6 , (setter)JitCpu_set_R6 , "R6" , NULL},
+    {"R7" , (getter)JitCpu_get_R7 , (setter)JitCpu_set_R7 , "R7" , NULL},
+    {"R8" , (getter)JitCpu_get_R8 , (setter)JitCpu_set_R8 , "R8" , NULL},
+    {"R9" , (getter)JitCpu_get_R9 , (setter)JitCpu_set_R9 , "R9" , NULL},
+    {"R10", (getter)JitCpu_get_R10, (setter)JitCpu_set_R10, "R10", NULL},
+    {"R11", (getter)JitCpu_get_R11, (setter)JitCpu_set_R11, "R11", NULL},
+    {"R12", (getter)JitCpu_get_R12, (setter)JitCpu_set_R12, "R12", NULL},
+    {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL},
+    {"LR" , (getter)JitCpu_get_LR , (setter)JitCpu_set_LR , "LR" , NULL},
+    {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL},
+
+    {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL},
+    {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL},
+    {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL},
+    {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL},
+
+    {"ge0", (getter)JitCpu_get_ge0, (setter)JitCpu_set_ge0, "ge0", NULL},
+    {"ge1", (getter)JitCpu_get_ge1, (setter)JitCpu_set_ge1, "ge1", NULL},
+    {"ge2", (getter)JitCpu_get_ge2, (setter)JitCpu_set_ge2, "ge2", NULL},
+    {"ge3", (getter)JitCpu_get_ge3, (setter)JitCpu_set_ge3, "ge3", NULL},
+
+    {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL},
+    {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL},
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_arm.JitCpu",      /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_arm_Methods[] = {
+
+	/*
+
+	*/
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+
+MOD_INIT(JitCore_arm)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_arm", "JitCore_arm module", JitCore_arm_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
+
diff --git a/src/miasm/jitter/arch/JitCore_arm.h b/src/miasm/jitter/arch/JitCore_arm.h
new file mode 100644
index 00000000..30a38344
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_arm.h
@@ -0,0 +1,47 @@
+
+struct vm_cpu {
+	uint32_t exception_flags;
+	uint32_t interrupt_num;
+
+	/* gpregs */
+	uint32_t R0;
+	uint32_t R1;
+	uint32_t R2;
+	uint32_t R3;
+	uint32_t R4;
+	uint32_t R5;
+	uint32_t R6;
+	uint32_t R7;
+	uint32_t R8;
+	uint32_t R9;
+	uint32_t R10;
+	uint32_t R11;
+	uint32_t R12;
+	uint32_t SP;
+	uint32_t LR;
+	uint32_t PC;
+
+	/* eflag */
+	uint32_t zf;
+	uint32_t nf;
+	uint32_t of;
+	uint32_t cf;
+
+	/* ge */
+	uint32_t ge0;
+	uint32_t ge1;
+	uint32_t ge2;
+	uint32_t ge3;
+
+	uint32_t bp_num;
+};
+
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
+
+#define RETURN_PC return BlockDst;
diff --git a/src/miasm/jitter/arch/JitCore_m68k.c b/src/miasm/jitter/arch/JitCore_m68k.c
new file mode 100644
index 00000000..0989fde1
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_m68k.c
@@ -0,0 +1,467 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "../op_semantics.h"
+#include "JitCore_m68k.h"
+
+
+
+reg_dict gpreg_dict[] = {
+			 {.name = "A0", .offset = offsetof(struct vm_cpu, A0), .size = 32},
+			 {.name = "A1", .offset = offsetof(struct vm_cpu, A1), .size = 32},
+			 {.name = "A2", .offset = offsetof(struct vm_cpu, A2), .size = 32},
+			 {.name = "A3", .offset = offsetof(struct vm_cpu, A3), .size = 32},
+			 {.name = "A4", .offset = offsetof(struct vm_cpu, A4), .size = 32},
+			 {.name = "A5", .offset = offsetof(struct vm_cpu, A5), .size = 32},
+			 {.name = "A6", .offset = offsetof(struct vm_cpu, A6), .size = 32},
+			 {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32},
+
+			 {.name = "D0", .offset = offsetof(struct vm_cpu, D0), .size = 32},
+			 {.name = "D1", .offset = offsetof(struct vm_cpu, D1), .size = 32},
+			 {.name = "D2", .offset = offsetof(struct vm_cpu, D2), .size = 32},
+			 {.name = "D3", .offset = offsetof(struct vm_cpu, D3), .size = 32},
+			 {.name = "D4", .offset = offsetof(struct vm_cpu, D4), .size = 32},
+			 {.name = "D5", .offset = offsetof(struct vm_cpu, D5), .size = 32},
+			 {.name = "D6", .offset = offsetof(struct vm_cpu, D6), .size = 32},
+			 {.name = "D7", .offset = offsetof(struct vm_cpu, D7), .size = 32},
+
+			 {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32},
+
+			 {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8},
+			 {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8},
+			 {.name = "vf", .offset = offsetof(struct vm_cpu, vf), .size = 8},
+			 {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8},
+			 {.name = "xf", .offset = offsetof(struct vm_cpu, xf), .size = 8},
+
+			 {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32},
+			 {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32},
+};
+
+/************************** JitCpu object **************************/
+
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(A0);
+    get_reg(A1);
+    get_reg(A2);
+    get_reg(A3);
+    get_reg(A4);
+    get_reg(A5);
+    get_reg(A6);
+    get_reg(SP);
+
+    get_reg(D0);
+    get_reg(D1);
+    get_reg(D2);
+    get_reg(D3);
+    get_reg(D4);
+    get_reg(D5);
+    get_reg(D6);
+    get_reg(D7);
+
+    get_reg(PC);
+
+    get_reg(zf);
+    get_reg(nf);
+    get_reg(vf);
+    get_reg(cf);
+    get_reg(xf);
+
+    return dict;
+}
+
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    RAISE(PyExc_TypeError,"Cannot parse arguments");
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    PyGetStr(d_key_name, d_key);
+	    PyGetInt_uint32_t(d_value, val);
+
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(d_key_name, gpreg_dict[i].name))
+			    continue;
+		    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+		    found = 1;
+		    break;
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unknown key: %s\n", d_key_name);
+	    RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr)
+{
+	return addr;
+}
+
+void dump_gpregs(struct vm_cpu* vmcpu)
+{
+	printf("A0  %.8"PRIX32" A1  %.8"PRIX32" A2  %.8"PRIX32" A3  %.8"PRIX32" ",
+	       vmcpu->A0, vmcpu->A1, vmcpu->A2, vmcpu->A3);
+	printf("R4  %.8"PRIX32" A5  %.8"PRIX32" A6  %.8"PRIX32" SP  %.8"PRIX32"\n",
+	       vmcpu->A4, vmcpu->A5, vmcpu->A6, vmcpu->SP);
+
+	printf("D0  %.8"PRIX32" D1  %.8"PRIX32" D2  %.8"PRIX32" D3  %.8"PRIX32" ",
+	       vmcpu->D0, vmcpu->D1, vmcpu->D2, vmcpu->D3);
+	printf("R4  %.8"PRIX32" D5  %.8"PRIX32" D6  %.8"PRIX32" D7  %.8"PRIX32"\n",
+	       vmcpu->D4, vmcpu->D5, vmcpu->D6, vmcpu->D7);
+
+
+	printf("PC  %.8"PRIX32" ",
+	       vmcpu->PC);
+	printf("zf %"PRIX32" nf %"PRIX32" vf %"PRIX32"  cf %"PRIX32" xf %"PRIX32"\n",
+	       vmcpu->zf, vmcpu->nf, vmcpu->vf, vmcpu->cf, vmcpu->xf);
+}
+
+void dump_gpregs_32(struct vm_cpu* vmcpu)
+{
+	dump_gpregs(vmcpu);
+}
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num));
+}
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS,
+	 "X"},
+	{"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(struct vm_cpu));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc struct vm_cpu\n");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+getset_reg_u32(A0);
+getset_reg_u32(A1);
+getset_reg_u32(A2);
+getset_reg_u32(A3);
+getset_reg_u32(A4);
+getset_reg_u32(A5);
+getset_reg_u32(A6);
+getset_reg_u32(SP);
+
+getset_reg_u32(D0);
+getset_reg_u32(D1);
+getset_reg_u32(D2);
+getset_reg_u32(D3);
+getset_reg_u32(D4);
+getset_reg_u32(D5);
+getset_reg_u32(D6);
+getset_reg_u32(D7);
+getset_reg_u32(PC);
+
+getset_reg_u32(zf);
+getset_reg_u32(nf);
+getset_reg_u32(vf);
+getset_reg_u32(cf);
+getset_reg_u32(xf);
+
+getset_reg_u32(exception_flags);
+getset_reg_u32(interrupt_num);
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg_off(exception_flags);
+    get_reg_off(interrupt_num);
+
+    get_reg_off(A0);
+    get_reg_off(A1);
+    get_reg_off(A2);
+    get_reg_off(A3);
+    get_reg_off(A4);
+    get_reg_off(A5);
+    get_reg_off(A6);
+    get_reg_off(SP);
+
+    get_reg_off(D0);
+    get_reg_off(D1);
+    get_reg_off(D2);
+    get_reg_off(D3);
+    get_reg_off(D4);
+    get_reg_off(D5);
+    get_reg_off(D6);
+    get_reg_off(D7);
+
+    get_reg_off(PC);
+
+	/* eflag */
+    get_reg_off(zf);
+    get_reg_off(nf);
+    get_reg_off(vf);
+    get_reg_off(cf);
+    get_reg_off(xf);
+
+    return dict;
+}
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"vmcpu",
+     (getter)JitCpu_get_vmcpu, (setter)JitCpu_set_vmcpu,
+     "vmcpu",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+
+    {"A0" , (getter)JitCpu_get_A0 , (setter)JitCpu_set_A0 , "A0" , NULL},
+    {"A1" , (getter)JitCpu_get_A1 , (setter)JitCpu_set_A1 , "A1" , NULL},
+    {"A2" , (getter)JitCpu_get_A2 , (setter)JitCpu_set_A2 , "A2" , NULL},
+    {"A3" , (getter)JitCpu_get_A3 , (setter)JitCpu_set_A3 , "A3" , NULL},
+    {"A4" , (getter)JitCpu_get_A4 , (setter)JitCpu_set_A4 , "A4" , NULL},
+    {"A5" , (getter)JitCpu_get_A5 , (setter)JitCpu_set_A5 , "A5" , NULL},
+    {"A6" , (getter)JitCpu_get_A6 , (setter)JitCpu_set_A6 , "A6" , NULL},
+    {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL},
+
+    {"D0" , (getter)JitCpu_get_D0 , (setter)JitCpu_set_D0 , "D0" , NULL},
+    {"D1" , (getter)JitCpu_get_D1 , (setter)JitCpu_set_D1 , "D1" , NULL},
+    {"D2" , (getter)JitCpu_get_D2 , (setter)JitCpu_set_D2 , "D2" , NULL},
+    {"D3" , (getter)JitCpu_get_D3 , (setter)JitCpu_set_D3 , "D3" , NULL},
+    {"D4" , (getter)JitCpu_get_D4 , (setter)JitCpu_set_D4 , "D4" , NULL},
+    {"D5" , (getter)JitCpu_get_D5 , (setter)JitCpu_set_D5 , "D5" , NULL},
+    {"D6" , (getter)JitCpu_get_D6 , (setter)JitCpu_set_D6 , "D6" , NULL},
+    {"D7" , (getter)JitCpu_get_D7 , (setter)JitCpu_set_D7 , "D7" , NULL},
+
+    {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL},
+
+    {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL},
+    {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL},
+    {"vf", (getter)JitCpu_get_vf, (setter)JitCpu_set_vf, "vf", NULL},
+    {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL},
+    {"xf", (getter)JitCpu_get_xf, (setter)JitCpu_set_xf, "xf", NULL},
+
+    {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL},
+    {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL},
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_m68k.JitCpu",      /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_m68k_Methods[] = {
+
+	/*
+
+	*/
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+
+MOD_INIT(JitCore_m68k)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_m68k", "JitCore_m68k module", JitCore_m68k_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
+
diff --git a/src/miasm/jitter/arch/JitCore_m68k.h b/src/miasm/jitter/arch/JitCore_m68k.h
new file mode 100644
index 00000000..6ff6b326
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_m68k.h
@@ -0,0 +1,55 @@
+
+struct vm_cpu {
+	uint32_t exception_flags;
+	uint32_t interrupt_num;
+
+	/* gpregs */
+	uint32_t A0;
+	uint32_t A1;
+	uint32_t A2;
+	uint32_t A3;
+	uint32_t A4;
+	uint32_t A5;
+	uint32_t A6;
+	uint32_t SP;
+
+	uint32_t D0;
+	uint32_t D1;
+	uint32_t D2;
+	uint32_t D3;
+	uint32_t D4;
+	uint32_t D5;
+	uint32_t D6;
+	uint32_t D7;
+
+
+	uint32_t PC;
+
+	/* eflag */
+	uint32_t zf;
+	uint32_t nf;
+	uint32_t vf;
+	uint32_t cf;
+	uint32_t xf;
+
+	uint64_t float_st0;
+	uint64_t float_st1;
+	uint64_t float_st2;
+	uint64_t float_st3;
+	uint64_t float_st4;
+	uint64_t float_st5;
+	uint64_t float_st6;
+	uint64_t float_st7;
+
+	uint32_t bp_num;
+};
+
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
+
+#define RETURN_PC return BlockDst;
diff --git a/src/miasm/jitter/arch/JitCore_mep.c b/src/miasm/jitter/arch/JitCore_mep.c
new file mode 100644
index 00000000..286a12ac
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_mep.c
@@ -0,0 +1,569 @@
+// Inspired from JitCore_mep.c
+
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "JitCore_mep.h"
+
+
+reg_dict gpreg_dict[] = {
+	{.name = "R0", .offset = offsetof(struct vm_cpu, R0), .size = 32},
+	{.name = "R1", .offset = offsetof(struct vm_cpu, R1), .size = 32},
+	{.name = "R2", .offset = offsetof(struct vm_cpu, R2), .size = 32},
+	{.name = "R3", .offset = offsetof(struct vm_cpu, R3), .size = 32},
+	{.name = "R4", .offset = offsetof(struct vm_cpu, R4), .size = 32},
+	{.name = "R5", .offset = offsetof(struct vm_cpu, R5), .size = 32},
+	{.name = "R6", .offset = offsetof(struct vm_cpu, R6), .size = 32},
+	{.name = "R7", .offset = offsetof(struct vm_cpu, R7), .size = 32},
+	{.name = "R8", .offset = offsetof(struct vm_cpu, R8), .size = 32},
+	{.name = "R9", .offset = offsetof(struct vm_cpu, R9), .size = 32},
+	{.name = "R10", .offset = offsetof(struct vm_cpu, R10), .size = 32},
+	{.name = "R11", .offset = offsetof(struct vm_cpu, R11), .size = 32},
+	{.name = "R12", .offset = offsetof(struct vm_cpu, R12), .size = 32},
+	{.name = "TP", .offset = offsetof(struct vm_cpu, TP), .size = 32},
+	{.name = "GP", .offset = offsetof(struct vm_cpu, GP), .size = 32},
+	{.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32},
+
+	{.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32},
+	{.name = "LP", .offset = offsetof(struct vm_cpu, LP), .size = 32},
+	{.name = "SAR", .offset = offsetof(struct vm_cpu, SAR), .size = 32},
+	{.name = "S3", .offset = offsetof(struct vm_cpu, S3), .size = 32},
+	{.name = "RPB", .offset = offsetof(struct vm_cpu, RPB), .size = 32},
+	{.name = "RPE", .offset = offsetof(struct vm_cpu, RPE), .size = 32},
+	{.name = "RPC", .offset = offsetof(struct vm_cpu, RPC), .size = 32},
+	{.name = "HI", .offset = offsetof(struct vm_cpu, HI), .size = 32},
+	{.name = "LO", .offset = offsetof(struct vm_cpu, LO), .size = 32},
+	{.name = "S9", .offset = offsetof(struct vm_cpu, S9), .size = 32},
+	{.name = "S10", .offset = offsetof(struct vm_cpu, S10), .size = 32},
+	{.name = "S11", .offset = offsetof(struct vm_cpu, S11), .size = 32},
+	{.name = "MB0", .offset = offsetof(struct vm_cpu, MB0), .size = 32},
+	{.name = "ME0", .offset = offsetof(struct vm_cpu, ME0), .size = 32},
+	{.name = "MB1", .offset = offsetof(struct vm_cpu, MB1), .size = 32},
+	{.name = "ME1", .offset = offsetof(struct vm_cpu, ME1), .size = 32},
+	{.name = "PSW", .offset = offsetof(struct vm_cpu, PSW), .size = 32},
+	{.name = "ID", .offset = offsetof(struct vm_cpu, ID), .size = 32},
+	{.name = "TMP", .offset = offsetof(struct vm_cpu, TMP), .size = 32},
+	{.name = "EPC", .offset = offsetof(struct vm_cpu, EPC), .size = 32},
+	{.name = "EXC", .offset = offsetof(struct vm_cpu, EXC), .size = 32},
+	{.name = "CFG", .offset = offsetof(struct vm_cpu, CFG), .size = 32},
+	{.name = "S22", .offset = offsetof(struct vm_cpu, S22), .size = 32},
+	{.name = "NPC", .offset = offsetof(struct vm_cpu, NPC), .size = 32},
+	{.name = "DBG", .offset = offsetof(struct vm_cpu, DBG), .size = 32},
+	{.name = "DEPC", .offset = offsetof(struct vm_cpu, DEPC), .size = 32},
+	{.name = "OPT", .offset = offsetof(struct vm_cpu, OPT), .size = 32},
+	{.name = "RCFG", .offset = offsetof(struct vm_cpu, RCFG), .size = 32},
+	{.name = "CCFG", .offset = offsetof(struct vm_cpu, CCFG), .size = 32},
+	{.name = "S29", .offset = offsetof(struct vm_cpu, S29), .size = 32},
+	{.name = "S30", .offset = offsetof(struct vm_cpu, S30), .size = 32},
+	{.name = "S31", .offset = offsetof(struct vm_cpu, S31), .size = 32},
+	{.name = "S32", .offset = offsetof(struct vm_cpu, S32), .size = 32},
+	{.name = "take_jmp", .offset = offsetof(struct vm_cpu, take_jmp), .size = 32},
+	{.name = "last_addr", .offset = offsetof(struct vm_cpu, last_addr), .size = 32},
+	{.name = "is_repeat_end", .offset = offsetof(struct vm_cpu, is_repeat_end), .size = 32},
+
+	{.name = "PC_end", .offset = offsetof(struct vm_cpu, PC_end), .size = 32},
+	{.name = "RPE_instr_count", .offset = offsetof(struct vm_cpu, RPE_instr_count), .size = 32},
+	{.name = "RPC_current", .offset = offsetof(struct vm_cpu, RPC_current), .size = 32},
+
+};
+
+/************************** JitCpu object **************************/
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(R0);
+    get_reg(R1);
+    get_reg(R2);
+    get_reg(R3);
+    get_reg(R4);
+    get_reg(R5);
+    get_reg(R6);
+    get_reg(R7);
+    get_reg(R8);
+    get_reg(R9);
+    get_reg(R10);
+    get_reg(R11);
+    get_reg(R12);
+    get_reg(TP);
+    get_reg(GP);
+    get_reg(SP);
+
+    get_reg(PC);
+    get_reg(LP);
+    get_reg(SAR);
+    get_reg(S3);
+    get_reg(RPB);
+    get_reg(RPE);
+    get_reg(RPC);
+    get_reg(HI);
+    get_reg(LO);
+    get_reg(S9);
+    get_reg(S10);
+    get_reg(S11);
+    get_reg(MB0);
+    get_reg(ME0);
+    get_reg(MB1);
+    get_reg(ME1);
+    get_reg(PSW);
+    get_reg(ID);
+    get_reg(TMP);
+    get_reg(EPC);
+    get_reg(EXC);
+    get_reg(CFG);
+    get_reg(S22);
+    get_reg(NPC);
+    get_reg(DBG);
+    get_reg(DEPC);
+    get_reg(OPT);
+    get_reg(RCFG);
+    get_reg(CCFG);
+    get_reg(S29);
+    get_reg(S30);
+    get_reg(S31);
+    get_reg(S32);
+
+    get_reg(PC_end);
+    get_reg(RPE_instr_count);
+    get_reg(RPC_current);
+
+
+    return dict;
+}
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	return NULL;
+    if(!PyDict_Check(dict))
+	RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	PyGetStr(d_key_name, d_key);
+	PyGetInt_uint32_t(d_value, val);
+
+	found = 0;
+	for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+	    if (strcmp(d_key_name, gpreg_dict[i].name))
+		continue;
+	    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+	    found = 1;
+	    break;
+	}
+
+	if (found)
+	    continue;
+	fprintf(stderr, "unknown key: %s\n", d_key_name);
+	RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+    memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+    Py_INCREF(Py_None);
+    return Py_None;
+
+}
+
+void dump_gpregs(struct vm_cpu* vmcpu)
+{
+	printf("R0  %.4"PRIX32" ", vmcpu->R0);
+	printf("R1  %.4"PRIX32" ", vmcpu->R1);
+	printf("R2  %.4"PRIX32" ", vmcpu->R2);
+	printf("R3  %.4"PRIX32" ", vmcpu->R3);
+	printf("R4  %.4"PRIX32" ", vmcpu->R4);
+	printf("R5  %.4"PRIX32" ", vmcpu->R5);
+	printf("R6  %.4"PRIX32" ", vmcpu->R6);
+	printf("R7  %.4"PRIX32" ", vmcpu->R7);
+	printf("R8  %.4"PRIX32" ", vmcpu->R8);
+	printf("R9  %.4"PRIX32" ", vmcpu->R9);
+	printf("R10  %.4"PRIX32" ", vmcpu->R10);
+	printf("R11  %.4"PRIX32" ", vmcpu->R11);
+	printf("R12  %.4"PRIX32" ", vmcpu->R12);
+	printf("TP  %.4"PRIX32" ", vmcpu->TP);
+	printf("GP  %.4"PRIX32" ", vmcpu->GP);
+	printf("SP  %.4"PRIX32" ", vmcpu->SP);
+	printf("\n");
+}
+
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+    struct vm_cpu* vmcpu;
+
+    vmcpu = self->cpu;
+    dump_gpregs(vmcpu);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+    PyObject *item1;
+    uint32_t exception_flags;
+
+    if (!PyArg_ParseTuple(args, "O", &item1))
+	return NULL;
+
+    PyGetInt_uint32_t(item1, exception_flags);
+
+    ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+    return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+    vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+    vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+    vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+    vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+    {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, "X"},
+    {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, "X"},
+    {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, "X"},
+    {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, "X"},
+    {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, "X"},
+    {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, "X"},
+    {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, "X"},
+    {NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+    self->cpu = malloc(sizeof(struct vm_cpu));
+    if (self->cpu == NULL) {
+	fprintf(stderr, "cannot alloc struct vm_cpu\n");
+	exit(0);
+    }
+    return 0;
+}
+
+getset_reg_u32(R0);
+getset_reg_u32(R1);
+getset_reg_u32(R2);
+getset_reg_u32(R3);
+getset_reg_u32(R4);
+getset_reg_u32(R5);
+getset_reg_u32(R6);
+getset_reg_u32(R7);
+getset_reg_u32(R8);
+getset_reg_u32(R9);
+getset_reg_u32(R10);
+getset_reg_u32(R11);
+getset_reg_u32(R12);
+getset_reg_u32(TP);
+getset_reg_u32(GP);
+getset_reg_u32(SP);
+
+getset_reg_u32(PC);
+getset_reg_u32(LP);
+getset_reg_u32(SAR);
+getset_reg_u32(S3);
+getset_reg_u32(RPB);
+getset_reg_u32(RPE);
+getset_reg_u32(RPC);
+getset_reg_u32(HI);
+getset_reg_u32(LO);
+getset_reg_u32(S9);
+getset_reg_u32(S10);
+getset_reg_u32(S11);
+getset_reg_u32(MB0);
+getset_reg_u32(ME0);
+getset_reg_u32(MB1);
+getset_reg_u32(ME1);
+getset_reg_u32(PSW);
+getset_reg_u32(ID);
+getset_reg_u32(TMP);
+getset_reg_u32(EPC);
+getset_reg_u32(EXC);
+getset_reg_u32(CFG);
+getset_reg_u32(S22);
+getset_reg_u32(NPC);
+getset_reg_u32(DBG);
+getset_reg_u32(DEPC);
+getset_reg_u32(OPT);
+getset_reg_u32(RCFG);
+getset_reg_u32(CCFG);
+getset_reg_u32(S29);
+getset_reg_u32(S30);
+getset_reg_u32(S31);
+getset_reg_u32(S32);
+
+getset_reg_u32(PC_end);
+getset_reg_u32(RPE_instr_count);
+getset_reg_u32(RPC_current);
+
+
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+    get_reg_off(exception_flags);
+
+    get_reg_off(R0);
+    get_reg_off(R1);
+    get_reg_off(R2);
+    get_reg_off(R3);
+    get_reg_off(R4);
+    get_reg_off(R5);
+    get_reg_off(R6);
+    get_reg_off(R7);
+    get_reg_off(R8);
+    get_reg_off(R9);
+    get_reg_off(R10);
+    get_reg_off(R11);
+    get_reg_off(R12);
+    get_reg_off(TP);
+    get_reg_off(GP);
+    get_reg_off(SP);
+
+    get_reg_off(PC);
+    get_reg_off(LP);
+    get_reg_off(SAR);
+    get_reg_off(S3);
+    get_reg_off(RPB);
+    get_reg_off(RPE);
+    get_reg_off(RPC);
+    get_reg_off(HI);
+    get_reg_off(LO);
+    get_reg_off(S9);
+    get_reg_off(S10);
+    get_reg_off(S11);
+    get_reg_off(MB0);
+    get_reg_off(ME0);
+    get_reg_off(MB1);
+    get_reg_off(ME1);
+    get_reg_off(PSW);
+    get_reg_off(ID);
+    get_reg_off(TMP);
+    get_reg_off(EPC);
+    get_reg_off(EXC);
+    get_reg_off(CFG);
+    get_reg_off(S22);
+    get_reg_off(NPC);
+    get_reg_off(DBG);
+    get_reg_off(DEPC);
+    get_reg_off(OPT);
+    get_reg_off(RCFG);
+    get_reg_off(CCFG);
+    get_reg_off(S29);
+    get_reg_off(S30);
+    get_reg_off(S31);
+    get_reg_off(S32);
+
+    get_reg_off(PC_end);
+    get_reg_off(RPE_instr_count);
+    get_reg_off(RPC_current);
+
+
+    return dict;
+}
+
+
+
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+    {"R0" , (getter)JitCpu_get_R0      , (setter)JitCpu_set_R0     , "R0" , NULL},
+    {"R1" , (getter)JitCpu_get_R1      , (setter)JitCpu_set_R1     , "R1" , NULL},
+    {"R2" , (getter)JitCpu_get_R2      , (setter)JitCpu_set_R2     , "R2" , NULL},
+    {"R3" , (getter)JitCpu_get_R3      , (setter)JitCpu_set_R3     , "R3" , NULL},
+    {"R4" , (getter)JitCpu_get_R4      , (setter)JitCpu_set_R4     , "R4" , NULL},
+    {"R5" , (getter)JitCpu_get_R5      , (setter)JitCpu_set_R5     , "R5" , NULL},
+    {"R6" , (getter)JitCpu_get_R6      , (setter)JitCpu_set_R6     , "R6" , NULL},
+    {"R7" , (getter)JitCpu_get_R7      , (setter)JitCpu_set_R7     , "R7" , NULL},
+    {"R8" , (getter)JitCpu_get_R8      , (setter)JitCpu_set_R8     , "R8" , NULL},
+    {"R9" , (getter)JitCpu_get_R9      , (setter)JitCpu_set_R9     , "R9" , NULL},
+    {"R10" , (getter)JitCpu_get_R10      , (setter)JitCpu_set_R10     , "R10" , NULL},
+    {"R11" , (getter)JitCpu_get_R11      , (setter)JitCpu_set_R11     , "R11" , NULL},
+    {"R12" , (getter)JitCpu_get_R12      , (setter)JitCpu_set_R12     , "R12" , NULL},
+    {"TP" , (getter)JitCpu_get_TP      , (setter)JitCpu_set_TP     , "TP" , NULL},
+    {"GP" , (getter)JitCpu_get_GP      , (setter)JitCpu_set_GP     , "GP" , NULL},
+    {"SP" , (getter)JitCpu_get_SP      , (setter)JitCpu_set_SP     , "SP" , NULL},
+
+    {"PC" , (getter)JitCpu_get_PC      , (setter)JitCpu_set_PC     , "PC" , NULL},
+    {"LP" , (getter)JitCpu_get_LP      , (setter)JitCpu_set_LP     , "LP" , NULL},
+    {"SAR" , (getter)JitCpu_get_SAR      , (setter)JitCpu_set_SAR     , "SAR" , NULL},
+    {"S3" , (getter)JitCpu_get_S3      , (setter)JitCpu_set_S3     , "S3" , NULL},
+    {"RPB" , (getter)JitCpu_get_RPB      , (setter)JitCpu_set_RPB     , "RPB" , NULL},
+    {"RPE" , (getter)JitCpu_get_RPE      , (setter)JitCpu_set_RPE     , "RPE" , NULL},
+    {"RPC" , (getter)JitCpu_get_RPC      , (setter)JitCpu_set_RPC     , "RPC" , NULL},
+    {"HI" , (getter)JitCpu_get_HI      , (setter)JitCpu_set_HI     , "HI" , NULL},
+    {"LO" , (getter)JitCpu_get_LO      , (setter)JitCpu_set_LO     , "LO" , NULL},
+    {"S9" , (getter)JitCpu_get_S9      , (setter)JitCpu_set_S9     , "S9" , NULL},
+    {"S10" , (getter)JitCpu_get_S10      , (setter)JitCpu_set_S10     , "S10" , NULL},
+    {"S11" , (getter)JitCpu_get_S11      , (setter)JitCpu_set_S11     , "S11" , NULL},
+    {"MB0" , (getter)JitCpu_get_MB0      , (setter)JitCpu_set_MB0     , "MB0" , NULL},
+    {"ME0" , (getter)JitCpu_get_ME0      , (setter)JitCpu_set_ME0     , "ME0" , NULL},
+    {"MB1" , (getter)JitCpu_get_MB1      , (setter)JitCpu_set_MB1     , "MB1" , NULL},
+    {"ME1" , (getter)JitCpu_get_ME1      , (setter)JitCpu_set_ME1     , "ME1" , NULL},
+    {"PSW" , (getter)JitCpu_get_PSW      , (setter)JitCpu_set_PSW     , "PSW" , NULL},
+    {"ID" , (getter)JitCpu_get_ID      , (setter)JitCpu_set_ID     , "ID" , NULL},
+    {"TMP" , (getter)JitCpu_get_TMP      , (setter)JitCpu_set_TMP     , "TMP" , NULL},
+    {"EPC" , (getter)JitCpu_get_EPC      , (setter)JitCpu_set_EPC     , "EPC" , NULL},
+    {"EXC" , (getter)JitCpu_get_EXC      , (setter)JitCpu_set_EXC     , "EXC" , NULL},
+    {"CFG" , (getter)JitCpu_get_CFG      , (setter)JitCpu_set_CFG     , "CFG" , NULL},
+    {"S22" , (getter)JitCpu_get_S22      , (setter)JitCpu_set_S22     , "S22" , NULL},
+    {"NPC" , (getter)JitCpu_get_NPC      , (setter)JitCpu_set_NPC     , "NPC" , NULL},
+    {"DBG" , (getter)JitCpu_get_DBG      , (setter)JitCpu_set_DBG     , "DBG" , NULL},
+    {"DEPC" , (getter)JitCpu_get_DEPC      , (setter)JitCpu_set_DEPC     , "DEPC" , NULL},
+    {"OPT" , (getter)JitCpu_get_OPT      , (setter)JitCpu_set_OPT     , "OPT" , NULL},
+    {"RCFG" , (getter)JitCpu_get_RCFG      , (setter)JitCpu_set_RCFG     , "RCFG" , NULL},
+    {"CCFG" , (getter)JitCpu_get_CCFG      , (setter)JitCpu_set_CCFG     , "CCFG" , NULL},
+    {"S29" , (getter)JitCpu_get_S29      , (setter)JitCpu_set_S29     , "S29" , NULL},
+    {"S30" , (getter)JitCpu_get_S30      , (setter)JitCpu_set_S30     , "S30" , NULL},
+    {"S31" , (getter)JitCpu_get_S31      , (setter)JitCpu_set_S31     , "S31" , NULL},
+    {"S32" , (getter)JitCpu_get_S32      , (setter)JitCpu_set_S32     , "S32" , NULL},
+
+    {"PC_end" , (getter)JitCpu_get_PC_end      , (setter)JitCpu_set_PC_end     , "PC_end" , NULL},
+    {"RPE_instr_count" , (getter)JitCpu_get_RPE_instr_count      , (setter)JitCpu_set_RPE_instr_count     , "RPE_instr_count" , NULL},
+    {"RPC_current" , (getter)JitCpu_get_RPC_current      , (setter)JitCpu_set_RPC_current     , "RPC_current" , NULL},
+
+
+
+    {NULL}  /* Sentinel */
+};
+
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_mep.JitCpu",   /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,                         /* tp_traverse */
+    0,                         /* tp_clear */
+    0,                         /* tp_richcompare */
+    0,                         /* tp_weaklistoffset */
+    0,                         /* tp_iter */
+    0,                         /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_mep_Methods[] = {
+
+    /*
+
+    */
+    {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+
+MOD_INIT(JitCore_mep)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_mep", "JitCore_mep module", JitCore_mep_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/arch/JitCore_mep.h b/src/miasm/jitter/arch/JitCore_mep.h
new file mode 100644
index 00000000..f656b3a0
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_mep.h
@@ -0,0 +1,82 @@
+// Inspired from JitCore_msp430.h
+
+struct vm_cpu {
+	/* miasm flags */
+	uint32_t exception_flags;
+
+	/* gpregs */
+	uint32_t R0;
+	uint32_t R1;
+	uint32_t R2;
+	uint32_t R3;
+	uint32_t R4;
+	uint32_t R5;
+	uint32_t R6;
+	uint32_t R7;
+	uint32_t R8;
+	uint32_t R9;
+	uint32_t R10;
+	uint32_t R11;
+	uint32_t R12;
+	uint32_t TP;
+	uint32_t GP;
+	uint32_t SP;
+
+	/* csregs */
+	uint32_t PC;
+	uint32_t LP;
+	uint32_t SAR;
+	uint32_t S3;
+	uint32_t RPB;
+	uint32_t RPE;
+	uint32_t RPC;
+	uint32_t HI;
+	uint32_t LO;
+	uint32_t S9;
+	uint32_t S10;
+	uint32_t S11;
+	uint32_t MB0;
+	uint32_t ME0;
+	uint32_t MB1;
+	uint32_t ME1;
+	uint32_t PSW;
+	uint32_t ID;
+	uint32_t TMP;
+	uint32_t EPC;
+	uint32_t EXC;
+	uint32_t CFG;
+	uint32_t S22;
+	uint32_t NPC;
+	uint32_t DBG;
+	uint32_t DEPC;
+	uint32_t OPT;
+	uint32_t RCFG;
+	uint32_t CCFG;
+	uint32_t S29;
+	uint32_t S30;
+	uint32_t S31;
+	uint32_t S32;
+
+	/* miasm specific regs */
+	uint32_t PC_end;
+	uint32_t RPE_instr_count;
+	uint32_t RPC_current;
+
+
+	uint32_t take_jmp;
+	uint32_t last_addr;
+	uint32_t is_repeat_end;
+	uint32_t in_erepeat;
+
+	/* flags */
+
+};
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
+
+#define RETURN_PC return BlockDst;
diff --git a/src/miasm/jitter/arch/JitCore_mips32.c b/src/miasm/jitter/arch/JitCore_mips32.c
new file mode 100644
index 00000000..1d7a762c
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_mips32.c
@@ -0,0 +1,484 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "../op_semantics.h"
+#include "JitCore_mips32.h"
+
+
+
+reg_dict gpreg_dict[] = { {.name = "ZERO", .offset = offsetof(struct vm_cpu, ZERO), .size = 32},
+			  {.name = "AT", .offset = offsetof(struct vm_cpu, AT), .size = 32},
+			  {.name = "V0", .offset = offsetof(struct vm_cpu, V0), .size = 32},
+			  {.name = "V1", .offset = offsetof(struct vm_cpu, V1), .size = 32},
+			  {.name = "A0", .offset = offsetof(struct vm_cpu, A0), .size = 32},
+			  {.name = "A1", .offset = offsetof(struct vm_cpu, A1), .size = 32},
+			  {.name = "A2", .offset = offsetof(struct vm_cpu, A2), .size = 32},
+			  {.name = "A3", .offset = offsetof(struct vm_cpu, A3), .size = 32},
+			  {.name = "T0", .offset = offsetof(struct vm_cpu, T0), .size = 32},
+			  {.name = "T1", .offset = offsetof(struct vm_cpu, T1), .size = 32},
+			  {.name = "T2", .offset = offsetof(struct vm_cpu, T2), .size = 32},
+			  {.name = "T3", .offset = offsetof(struct vm_cpu, T3), .size = 32},
+			  {.name = "T4", .offset = offsetof(struct vm_cpu, T4), .size = 32},
+			  {.name = "T5", .offset = offsetof(struct vm_cpu, T5), .size = 32},
+			  {.name = "T6", .offset = offsetof(struct vm_cpu, T6), .size = 32},
+			  {.name = "T7", .offset = offsetof(struct vm_cpu, T7), .size = 32},
+			  {.name = "S0", .offset = offsetof(struct vm_cpu, S0), .size = 32},
+			  {.name = "S1", .offset = offsetof(struct vm_cpu, S1), .size = 32},
+			  {.name = "S2", .offset = offsetof(struct vm_cpu, S2), .size = 32},
+			  {.name = "S3", .offset = offsetof(struct vm_cpu, S3), .size = 32},
+			  {.name = "S4", .offset = offsetof(struct vm_cpu, S4), .size = 32},
+			  {.name = "S5", .offset = offsetof(struct vm_cpu, S5), .size = 32},
+			  {.name = "S6", .offset = offsetof(struct vm_cpu, S6), .size = 32},
+			  {.name = "S7", .offset = offsetof(struct vm_cpu, S7), .size = 32},
+			  {.name = "T8", .offset = offsetof(struct vm_cpu, T8), .size = 32},
+			  {.name = "T9", .offset = offsetof(struct vm_cpu, T9), .size = 32},
+			  {.name = "K0", .offset = offsetof(struct vm_cpu, K0), .size = 32},
+			  {.name = "K1", .offset = offsetof(struct vm_cpu, K1), .size = 32},
+			  {.name = "GP", .offset = offsetof(struct vm_cpu, GP), .size = 32},
+			  {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32},
+			  {.name = "FP", .offset = offsetof(struct vm_cpu, FP), .size = 32},
+			  {.name = "RA", .offset = offsetof(struct vm_cpu, RA), .size = 32},
+			  {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32},
+			  {.name = "PC_FETCH", .offset = offsetof(struct vm_cpu, PC_FETCH), .size = 32},
+			  {.name = "R_LO", .offset = offsetof(struct vm_cpu, R_LO), .size = 32},
+			  {.name = "R_HI", .offset = offsetof(struct vm_cpu, R_HI), .size = 32},
+};
+
+/************************** JitCpu object **************************/
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(ZERO);
+    get_reg(AT);
+    get_reg(V0);
+    get_reg(V1);
+    get_reg(A0);
+    get_reg(A1);
+    get_reg(A2);
+    get_reg(A3);
+    get_reg(T0);
+    get_reg(T1);
+    get_reg(T2);
+    get_reg(T3);
+    get_reg(T4);
+    get_reg(T5);
+    get_reg(T6);
+    get_reg(T7);
+    get_reg(S0);
+    get_reg(S1);
+    get_reg(S2);
+    get_reg(S3);
+    get_reg(S4);
+    get_reg(S5);
+    get_reg(S6);
+    get_reg(S7);
+    get_reg(T8);
+    get_reg(T9);
+    get_reg(K0);
+    get_reg(K1);
+    get_reg(GP);
+    get_reg(SP);
+    get_reg(FP);
+    get_reg(RA);
+    get_reg(PC);
+    get_reg(PC_FETCH);
+    get_reg(R_LO);
+    get_reg(R_HI);
+
+    return dict;
+}
+
+
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    RAISE(PyExc_TypeError,"Cannot parse arguments");
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    PyGetStr(d_key_name, d_key);
+	    PyGetInt_uint32_t(d_value, val);
+
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(d_key_name, gpreg_dict[i].name))
+			    continue;
+		    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+		    found = 1;
+		    break;
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unknown key: %s\n", d_key_name);
+	    RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+
+void dump_gpregs(struct vm_cpu* vmcpu)
+{
+
+	printf("ZR %.8"PRIX32" AT %.8"PRIX32" V0 %.8"PRIX32" V1 %.8"PRIX32" ",
+	       vmcpu->ZERO, vmcpu->AT, vmcpu->V0, vmcpu->V1);
+	printf("A0 %.8"PRIX32" A1 %.8"PRIX32" A2 %.8"PRIX32" A3 %.8"PRIX32" ",
+	       vmcpu->A0, vmcpu->A1, vmcpu->A2, vmcpu->A3);
+	printf("T0 %.8"PRIX32" T1 %.8"PRIX32" T2 %.8"PRIX32" T3 %.8"PRIX32" ",
+	       vmcpu->T0, vmcpu->T1, vmcpu->T2, vmcpu->T3);
+	printf("T4 %.8"PRIX32" T5 %.8"PRIX32" T6 %.8"PRIX32" T7 %.8"PRIX32"\n",
+	       vmcpu->T4, vmcpu->T5, vmcpu->T6, vmcpu->T7);
+	printf("S0 %.8"PRIX32" S1 %.8"PRIX32" S2 %.8"PRIX32" S3 %.8"PRIX32" ",
+	       vmcpu->S0, vmcpu->S1, vmcpu->S2, vmcpu->S3);
+	printf("S4 %.8"PRIX32" S5 %.8"PRIX32" S6 %.8"PRIX32" S7 %.8"PRIX32" ",
+	       vmcpu->S4, vmcpu->S5, vmcpu->S6, vmcpu->S7);
+	printf("T8 %.8"PRIX32" T9 %.8"PRIX32" K0 %.8"PRIX32" K1 %.8"PRIX32" ",
+	       vmcpu->T8, vmcpu->T9, vmcpu->K0, vmcpu->K1);
+	printf("GP %.8"PRIX32" SP %.8"PRIX32" FP %.8"PRIX32" RA %.8"PRIX32"\n",
+	       vmcpu->GP, vmcpu->SP, vmcpu->FP, vmcpu->RA);
+	printf("PC %.8"PRIX32"\n",
+	       vmcpu->PC);
+}
+
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(struct vm_cpu));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc struct vm_cpu\n");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+getset_reg_u32(ZERO);
+getset_reg_u32(AT);
+getset_reg_u32(V0);
+getset_reg_u32(V1);
+getset_reg_u32(A0);
+getset_reg_u32(A1);
+getset_reg_u32(A2);
+getset_reg_u32(A3);
+getset_reg_u32(T0);
+getset_reg_u32(T1);
+getset_reg_u32(T2);
+getset_reg_u32(T3);
+getset_reg_u32(T4);
+getset_reg_u32(T5);
+getset_reg_u32(T6);
+getset_reg_u32(T7);
+getset_reg_u32(S0);
+getset_reg_u32(S1);
+getset_reg_u32(S2);
+getset_reg_u32(S3);
+getset_reg_u32(S4);
+getset_reg_u32(S5);
+getset_reg_u32(S6);
+getset_reg_u32(S7);
+getset_reg_u32(T8);
+getset_reg_u32(T9);
+getset_reg_u32(K0);
+getset_reg_u32(K1);
+getset_reg_u32(GP);
+getset_reg_u32(SP);
+getset_reg_u32(FP);
+getset_reg_u32(RA);
+getset_reg_u32(PC);
+getset_reg_u32(PC_FETCH);
+getset_reg_u32(R_LO);
+getset_reg_u32(R_HI);
+
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg_off(exception_flags);
+
+
+    get_reg_off(ZERO);
+    get_reg_off(AT);
+    get_reg_off(V0);
+    get_reg_off(V1);
+    get_reg_off(A0);
+    get_reg_off(A1);
+    get_reg_off(A2);
+    get_reg_off(A3);
+    get_reg_off(T0);
+    get_reg_off(T1);
+    get_reg_off(T2);
+    get_reg_off(T3);
+    get_reg_off(T4);
+    get_reg_off(T5);
+    get_reg_off(T6);
+    get_reg_off(T7);
+    get_reg_off(S0);
+    get_reg_off(S1);
+    get_reg_off(S2);
+    get_reg_off(S3);
+    get_reg_off(S4);
+    get_reg_off(S5);
+    get_reg_off(S6);
+    get_reg_off(S7);
+    get_reg_off(T8);
+    get_reg_off(T9);
+    get_reg_off(K0);
+    get_reg_off(K1);
+    get_reg_off(GP);
+    get_reg_off(SP);
+    get_reg_off(FP);
+    get_reg_off(RA);
+    get_reg_off(PC);
+    get_reg_off(PC_FETCH);
+    get_reg_off(R_LO);
+    get_reg_off(R_HI);
+
+    return dict;
+}
+
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+    {"ZERO" , (getter)JitCpu_get_ZERO , (setter)JitCpu_set_ZERO , "ZERO" , NULL},
+    {"AT" , (getter)JitCpu_get_AT , (setter)JitCpu_set_AT , "AT" , NULL},
+    {"V0" , (getter)JitCpu_get_V0 , (setter)JitCpu_set_V0 , "V0" , NULL},
+    {"V1" , (getter)JitCpu_get_V1 , (setter)JitCpu_set_V1 , "V1" , NULL},
+    {"A0" , (getter)JitCpu_get_A0 , (setter)JitCpu_set_A0 , "A0" , NULL},
+    {"A1" , (getter)JitCpu_get_A1 , (setter)JitCpu_set_A1 , "A1" , NULL},
+    {"A2" , (getter)JitCpu_get_A2 , (setter)JitCpu_set_A2 , "A2" , NULL},
+    {"A3" , (getter)JitCpu_get_A3 , (setter)JitCpu_set_A3 , "A3" , NULL},
+    {"T0" , (getter)JitCpu_get_T0 , (setter)JitCpu_set_T0 , "T0" , NULL},
+    {"T1" , (getter)JitCpu_get_T1 , (setter)JitCpu_set_T1 , "T1" , NULL},
+    {"T2" , (getter)JitCpu_get_T2 , (setter)JitCpu_set_T2 , "T2" , NULL},
+    {"T3" , (getter)JitCpu_get_T3 , (setter)JitCpu_set_T3 , "T3" , NULL},
+    {"T4" , (getter)JitCpu_get_T4 , (setter)JitCpu_set_T4 , "T4" , NULL},
+    {"T5" , (getter)JitCpu_get_T5 , (setter)JitCpu_set_T5 , "T5" , NULL},
+    {"T6" , (getter)JitCpu_get_T6 , (setter)JitCpu_set_T6 , "T6" , NULL},
+    {"T7" , (getter)JitCpu_get_T7 , (setter)JitCpu_set_T7 , "T7" , NULL},
+    {"S0" , (getter)JitCpu_get_S0 , (setter)JitCpu_set_S0 , "S0" , NULL},
+    {"S1" , (getter)JitCpu_get_S1 , (setter)JitCpu_set_S1 , "S1" , NULL},
+    {"S2" , (getter)JitCpu_get_S2 , (setter)JitCpu_set_S2 , "S2" , NULL},
+    {"S3" , (getter)JitCpu_get_S3 , (setter)JitCpu_set_S3 , "S3" , NULL},
+    {"S4" , (getter)JitCpu_get_S4 , (setter)JitCpu_set_S4 , "S4" , NULL},
+    {"S5" , (getter)JitCpu_get_S5 , (setter)JitCpu_set_S5 , "S5" , NULL},
+    {"S6" , (getter)JitCpu_get_S6 , (setter)JitCpu_set_S6 , "S6" , NULL},
+    {"S7" , (getter)JitCpu_get_S7 , (setter)JitCpu_set_S7 , "S7" , NULL},
+    {"T8" , (getter)JitCpu_get_T8 , (setter)JitCpu_set_T8 , "T8" , NULL},
+    {"T9" , (getter)JitCpu_get_T9 , (setter)JitCpu_set_T9 , "T9" , NULL},
+    {"K0" , (getter)JitCpu_get_K0 , (setter)JitCpu_set_K0 , "K0" , NULL},
+    {"K1" , (getter)JitCpu_get_K1 , (setter)JitCpu_set_K1 , "K1" , NULL},
+    {"GP" , (getter)JitCpu_get_GP , (setter)JitCpu_set_GP , "GP" , NULL},
+    {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL},
+    {"FP" , (getter)JitCpu_get_FP , (setter)JitCpu_set_FP , "FP" , NULL},
+    {"RA" , (getter)JitCpu_get_RA , (setter)JitCpu_set_RA , "RA" , NULL},
+    {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL},
+    {"PC_FETCH" , (getter)JitCpu_get_PC_FETCH , (setter)JitCpu_set_PC_FETCH , "PC_FETCH" , NULL},
+    {"R_LO" , (getter)JitCpu_get_R_LO , (setter)JitCpu_set_R_LO , "R_LO" , NULL},
+    {"R_HI" , (getter)JitCpu_get_R_HI , (setter)JitCpu_set_R_HI , "R_HI" , NULL},
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_mips32.JitCpu",   /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_mips32_Methods[] = {
+
+	/*
+
+	*/
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+
+
+
+MOD_INIT(JitCore_mips32)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_mips32", "JitCore_mips32 module", JitCore_mips32_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/arch/JitCore_mips32.h b/src/miasm/jitter/arch/JitCore_mips32.h
new file mode 100644
index 00000000..8478fb53
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_mips32.h
@@ -0,0 +1,343 @@
+
+struct vm_cpu {
+	uint32_t exception_flags;
+
+	/* gpregs */
+
+	uint32_t ZERO;
+	uint32_t AT;
+	uint32_t V0;
+	uint32_t V1;
+	uint32_t A0;
+	uint32_t A1;
+	uint32_t A2;
+	uint32_t A3;
+	uint32_t T0;
+	uint32_t T1;
+	uint32_t T2;
+	uint32_t T3;
+	uint32_t T4;
+	uint32_t T5;
+	uint32_t T6;
+	uint32_t T7;
+	uint32_t S0;
+	uint32_t S1;
+	uint32_t S2;
+	uint32_t S3;
+	uint32_t S4;
+	uint32_t S5;
+	uint32_t S6;
+	uint32_t S7;
+	uint32_t T8;
+	uint32_t T9;
+	uint32_t K0;
+	uint32_t K1;
+	uint32_t GP;
+	uint32_t SP;
+	uint32_t FP;
+	uint32_t RA;
+	uint32_t PC;
+	uint32_t PC_FETCH;
+	uint32_t R_LO;
+	uint32_t R_HI;
+
+
+	double F0;
+	double F1;
+	double F2;
+	double F3;
+	double F4;
+	double F5;
+	double F6;
+	double F7;
+	double F8;
+	double F9;
+	double F10;
+	double F11;
+	double F12;
+	double F13;
+	double F14;
+	double F15;
+	double F16;
+	double F17;
+	double F18;
+	double F19;
+	double F20;
+	double F21;
+	double F22;
+	double F23;
+	double F24;
+	double F25;
+	double F26;
+	double F27;
+	double F28;
+	double F29;
+	double F30;
+	double F31;
+
+	uint32_t INDEX;
+	uint32_t CPR0_1;
+	uint32_t CPR0_2;
+	uint32_t CPR0_3;
+	uint32_t CPR0_4;
+	uint32_t CPR0_5;
+	uint32_t CPR0_6;
+	uint32_t CPR0_7;
+	uint32_t RANDOM;
+	uint32_t CPR0_9;
+	uint32_t CPR0_10;
+	uint32_t CPR0_11;
+	uint32_t CPR0_12;
+	uint32_t CPR0_13;
+	uint32_t CPR0_14;
+	uint32_t CPR0_15;
+	uint32_t ENTRYLO0;
+	uint32_t CPR0_17;
+	uint32_t CPR0_18;
+	uint32_t CPR0_19;
+	uint32_t CPR0_20;
+	uint32_t CPR0_21;
+	uint32_t CPR0_22;
+	uint32_t CPR0_23;
+	uint32_t ENTRYLO1;
+	uint32_t CPR0_25;
+	uint32_t CPR0_26;
+	uint32_t CPR0_27;
+	uint32_t CPR0_28;
+	uint32_t CPR0_29;
+	uint32_t CPR0_30;
+	uint32_t CPR0_31;
+	uint32_t CONTEXT;
+	uint32_t CONTEXTCONFIG;
+	uint32_t CPR0_34;
+	uint32_t CPR0_35;
+	uint32_t CPR0_36;
+	uint32_t CPR0_37;
+	uint32_t CPR0_38;
+	uint32_t CPR0_39;
+	uint32_t PAGEMASK;
+	uint32_t PAGEGRAIN;
+	uint32_t SEGCTL0;
+	uint32_t SEGCTL1;
+	uint32_t SEGCTL2;
+	uint32_t PWBASE;
+	uint32_t PWFIELD;
+	uint32_t PWSIZE;
+	uint32_t WIRED;
+	uint32_t CPR0_49;
+	uint32_t CPR0_50;
+	uint32_t CPR0_51;
+	uint32_t CPR0_52;
+	uint32_t CPR0_53;
+	uint32_t PWCTL;
+	uint32_t CPR0_55;
+	uint32_t CPR0_56;
+	uint32_t CPR0_57;
+	uint32_t CPR0_58;
+	uint32_t CPR0_59;
+	uint32_t CPR0_60;
+	uint32_t CPR0_61;
+	uint32_t CPR0_62;
+	uint32_t CPR0_63;
+	uint32_t BADVADDR;
+	uint32_t BADINSTR;
+	uint32_t BADINSTRP;
+	uint32_t CPR0_67;
+	uint32_t CPR0_68;
+	uint32_t CPR0_69;
+	uint32_t CPR0_70;
+	uint32_t CPR0_71;
+	uint32_t COUNT;
+	uint32_t CPR0_73;
+	uint32_t CPR0_74;
+	uint32_t CPR0_75;
+	uint32_t CPR0_76;
+	uint32_t CPR0_77;
+	uint32_t CPR0_78;
+	uint32_t CPR0_79;
+	uint32_t ENTRYHI;
+	uint32_t CPR0_81;
+	uint32_t CPR0_82;
+	uint32_t CPR0_83;
+	uint32_t CPR0_84;
+	uint32_t CPR0_85;
+	uint32_t CPR0_86;
+	uint32_t CPR0_87;
+	uint32_t CPR0_88;
+	uint32_t CPR0_89;
+	uint32_t CPR0_90;
+	uint32_t CPR0_91;
+	uint32_t CPR0_92;
+	uint32_t CPR0_93;
+	uint32_t CPR0_94;
+	uint32_t CPR0_95;
+	uint32_t CPR0_96;
+	uint32_t CPR0_97;
+	uint32_t CPR0_98;
+	uint32_t CPR0_99;
+	uint32_t CPR0_100;
+	uint32_t CPR0_101;
+	uint32_t CPR0_102;
+	uint32_t CPR0_103;
+	uint32_t CAUSE;
+	uint32_t CPR0_105;
+	uint32_t CPR0_106;
+	uint32_t CPR0_107;
+	uint32_t CPR0_108;
+	uint32_t CPR0_109;
+	uint32_t CPR0_110;
+	uint32_t CPR0_111;
+	uint32_t EPC;
+	uint32_t CPR0_113;
+	uint32_t CPR0_114;
+	uint32_t CPR0_115;
+	uint32_t CPR0_116;
+	uint32_t CPR0_117;
+	uint32_t CPR0_118;
+	uint32_t CPR0_119;
+	uint32_t PRID;
+	uint32_t EBASE;
+	uint32_t CPR0_122;
+	uint32_t CPR0_123;
+	uint32_t CPR0_124;
+	uint32_t CPR0_125;
+	uint32_t CPR0_126;
+	uint32_t CPR0_127;
+	uint32_t CONFIG;
+	uint32_t CONFIG1;
+	uint32_t CONFIG2;
+	uint32_t CONFIG3;
+	uint32_t CONFIG4;
+	uint32_t CONFIG5;
+	uint32_t CPR0_134;
+	uint32_t CPR0_135;
+	uint32_t CPR0_136;
+	uint32_t CPR0_137;
+	uint32_t CPR0_138;
+	uint32_t CPR0_139;
+	uint32_t CPR0_140;
+	uint32_t CPR0_141;
+	uint32_t CPR0_142;
+	uint32_t CPR0_143;
+	uint32_t CPR0_144;
+	uint32_t CPR0_145;
+	uint32_t CPR0_146;
+	uint32_t CPR0_147;
+	uint32_t CPR0_148;
+	uint32_t CPR0_149;
+	uint32_t CPR0_150;
+	uint32_t CPR0_151;
+	uint32_t WATCHHI;
+	uint32_t CPR0_153;
+	uint32_t CPR0_154;
+	uint32_t CPR0_155;
+	uint32_t CPR0_156;
+	uint32_t CPR0_157;
+	uint32_t CPR0_158;
+	uint32_t CPR0_159;
+	uint32_t CPR0_160;
+	uint32_t CPR0_161;
+	uint32_t CPR0_162;
+	uint32_t CPR0_163;
+	uint32_t CPR0_164;
+	uint32_t CPR0_165;
+	uint32_t CPR0_166;
+	uint32_t CPR0_167;
+	uint32_t CPR0_168;
+	uint32_t CPR0_169;
+	uint32_t CPR0_170;
+	uint32_t CPR0_171;
+	uint32_t CPR0_172;
+	uint32_t CPR0_173;
+	uint32_t CPR0_174;
+	uint32_t CPR0_175;
+	uint32_t CPR0_176;
+	uint32_t CPR0_177;
+	uint32_t CPR0_178;
+	uint32_t CPR0_179;
+	uint32_t CPR0_180;
+	uint32_t CPR0_181;
+	uint32_t CPR0_182;
+	uint32_t CPR0_183;
+	uint32_t CPR0_184;
+	uint32_t CPR0_185;
+	uint32_t CPR0_186;
+	uint32_t CPR0_187;
+	uint32_t CPR0_188;
+	uint32_t CPR0_189;
+	uint32_t CPR0_190;
+	uint32_t CPR0_191;
+	uint32_t CPR0_192;
+	uint32_t CPR0_193;
+	uint32_t CPR0_194;
+	uint32_t CPR0_195;
+	uint32_t CPR0_196;
+	uint32_t CPR0_197;
+	uint32_t CPR0_198;
+	uint32_t CPR0_199;
+	uint32_t CPR0_200;
+	uint32_t CPR0_201;
+	uint32_t CPR0_202;
+	uint32_t CPR0_203;
+	uint32_t CPR0_204;
+	uint32_t CPR0_205;
+	uint32_t CPR0_206;
+	uint32_t CPR0_207;
+	uint32_t CPR0_208;
+	uint32_t CPR0_209;
+	uint32_t CPR0_210;
+	uint32_t CPR0_211;
+	uint32_t CPR0_212;
+	uint32_t CPR0_213;
+	uint32_t CPR0_214;
+	uint32_t CPR0_215;
+	uint32_t CPR0_216;
+	uint32_t CPR0_217;
+	uint32_t CPR0_218;
+	uint32_t CPR0_219;
+	uint32_t CPR0_220;
+	uint32_t CPR0_221;
+	uint32_t CPR0_222;
+	uint32_t CPR0_223;
+	uint32_t CPR0_224;
+	uint32_t CPR0_225;
+	uint32_t CPR0_226;
+	uint32_t CPR0_227;
+	uint32_t CPR0_228;
+	uint32_t CPR0_229;
+	uint32_t CPR0_230;
+	uint32_t CPR0_231;
+	uint32_t CPR0_232;
+	uint32_t CPR0_233;
+	uint32_t CPR0_234;
+	uint32_t CPR0_235;
+	uint32_t CPR0_236;
+	uint32_t CPR0_237;
+	uint32_t CPR0_238;
+	uint32_t CPR0_239;
+	uint32_t CPR0_240;
+	uint32_t CPR0_241;
+	uint32_t CPR0_242;
+	uint32_t CPR0_243;
+	uint32_t CPR0_244;
+	uint32_t CPR0_245;
+	uint32_t CPR0_246;
+	uint32_t CPR0_247;
+	uint32_t CPR0_248;
+	uint32_t CPR0_249;
+	uint32_t KSCRATCH0;
+	uint32_t KSCRATCH1;
+	uint32_t KSCRATCH2;
+	uint32_t KSCRATCH3;
+	uint32_t KSCRATCH4;
+	uint32_t KSCRATCH5;
+};
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
+
+#define RETURN_PC return BlockDst;
diff --git a/src/miasm/jitter/arch/JitCore_msp430.c b/src/miasm/jitter/arch/JitCore_msp430.c
new file mode 100644
index 00000000..86e082ad
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_msp430.c
@@ -0,0 +1,423 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "JitCore_msp430.h"
+
+
+reg_dict gpreg_dict[] = { {.name = "PC", .offset = offsetof(struct vm_cpu, PC)},
+			  {.name = "SP", .offset = offsetof(struct vm_cpu, SP)},
+			  //{.name = "SR", .offset = offsetof(struct vm_cpu, SR)},
+			  {.name = "R3", .offset = offsetof(struct vm_cpu, R3)},
+			  {.name = "R4", .offset = offsetof(struct vm_cpu, R4)},
+			  {.name = "R5", .offset = offsetof(struct vm_cpu, R5)},
+			  {.name = "R6", .offset = offsetof(struct vm_cpu, R6)},
+			  {.name = "R7", .offset = offsetof(struct vm_cpu, R7)},
+			  {.name = "R8", .offset = offsetof(struct vm_cpu, R8)},
+			  {.name = "R9", .offset = offsetof(struct vm_cpu, R9)},
+			  {.name = "R10", .offset = offsetof(struct vm_cpu, R10)},
+			  {.name = "R11", .offset = offsetof(struct vm_cpu, R11)},
+			  {.name = "R12", .offset = offsetof(struct vm_cpu, R12)},
+			  {.name = "R13", .offset = offsetof(struct vm_cpu, R13)},
+			  {.name = "R14", .offset = offsetof(struct vm_cpu, R14)},
+			  {.name = "R15", .offset = offsetof(struct vm_cpu, R15)},
+
+			  {.name = "zf", .offset = offsetof(struct vm_cpu, zf)},
+			  {.name = "nf", .offset = offsetof(struct vm_cpu, nf)},
+			  {.name = "of", .offset = offsetof(struct vm_cpu, of)},
+			  {.name = "cf", .offset = offsetof(struct vm_cpu, cf)},
+
+			  {.name = "cpuoff", .offset = offsetof(struct vm_cpu, cpuoff)},
+			  {.name = "gie", .offset = offsetof(struct vm_cpu, gie)},
+			  {.name = "osc", .offset = offsetof(struct vm_cpu, osc)},
+			  {.name = "scg0", .offset = offsetof(struct vm_cpu, scg0)},
+			  {.name = "scg1", .offset = offsetof(struct vm_cpu, scg1)},
+			  {.name = "res", .offset = offsetof(struct vm_cpu, res)},
+
+};
+
+/************************** JitCpu object **************************/
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(PC);
+    get_reg(SP);
+    //get_reg(SR);
+    get_reg(R3);
+    get_reg(R4);
+    get_reg(R5);
+    get_reg(R6);
+    get_reg(R7);
+    get_reg(R8);
+    get_reg(R9);
+    get_reg(R10);
+    get_reg(R11);
+    get_reg(R12);
+    get_reg(R13);
+    get_reg(R14);
+    get_reg(R15);
+
+    get_reg(zf);
+    get_reg(nf);
+    get_reg(of);
+    get_reg(cf);
+
+    get_reg(cpuoff);
+    get_reg(gie);
+    get_reg(osc);
+    get_reg(scg0);
+    get_reg(scg1);
+    get_reg(res);
+
+
+    return dict;
+}
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    RAISE(PyExc_TypeError,"Cannot parse arguments");
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    PyGetStr(d_key_name, d_key);
+	    PyGetInt_uint32_t(d_value, val);
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(d_key_name, gpreg_dict[i].name))
+			    continue;
+		    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+		    found = 1;
+		    break;
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unknown key: %s\n", d_key_name);
+	    RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+void dump_gpregs(struct vm_cpu* vmcpu)
+{
+
+	printf("PC  %.4"PRIX32" SP  %.4"PRIX32"  R3  %.4"PRIX32" ",
+	       vmcpu->PC, vmcpu->SP, vmcpu->R3);
+	printf("R4  %.4"PRIX32" R5  %.4"PRIX32" R6  %.4"PRIX32" R7  %.4"PRIX32"\n",
+	       vmcpu->R4, vmcpu->R5, vmcpu->R6, vmcpu->R7);
+	printf("R8  %.4"PRIX32" R9  %.4"PRIX32" R10 %.4"PRIX32" R11 %.4"PRIX32" ",
+	       vmcpu->R8, vmcpu->R9, vmcpu->R10, vmcpu->R11);
+	printf("R12 %.4"PRIX32" R13 %.4"PRIX32" R14 %.4"PRIX32" R15 %.4"PRIX32"\n",
+	       vmcpu->R12, vmcpu->R13, vmcpu->R14, vmcpu->R15);
+	printf("zf %"PRIX32" nf %"PRIX32" of %"PRIX32" cf %"PRIX32"\n",
+	       vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf);
+}
+
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(struct vm_cpu));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc struct vm_cpu\n");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+getset_reg_u16(PC);
+getset_reg_u16(SP);
+getset_reg_u16(R3);
+getset_reg_u16(R4);
+getset_reg_u16(R5);
+getset_reg_u16(R6);
+getset_reg_u16(R7);
+getset_reg_u16(R8);
+getset_reg_u16(R9);
+getset_reg_u16(R10);
+getset_reg_u16(R11);
+getset_reg_u16(R12);
+getset_reg_u16(R13);
+getset_reg_u16(R14);
+getset_reg_u16(R15);
+getset_reg_u16(zf);
+getset_reg_u16(nf);
+getset_reg_u16(of);
+getset_reg_u16(cf);
+getset_reg_u16(cpuoff);
+getset_reg_u16(gie);
+getset_reg_u16(osc);
+getset_reg_u16(scg0);
+getset_reg_u16(scg1);
+getset_reg_u16(res);
+
+
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+    get_reg_off(exception_flags);
+
+    get_reg_off(PC);
+    get_reg_off(SP);
+    get_reg_off(R3);
+    get_reg_off(R4);
+    get_reg_off(R5);
+    get_reg_off(R6);
+    get_reg_off(R7);
+    get_reg_off(R8);
+    get_reg_off(R9);
+    get_reg_off(R10);
+    get_reg_off(R11);
+    get_reg_off(R12);
+    get_reg_off(R13);
+    get_reg_off(R14);
+    get_reg_off(R15);
+
+    get_reg_off(zf);
+    get_reg_off(nf);
+    get_reg_off(of);
+    get_reg_off(cf);
+    get_reg_off(cpuoff);
+    get_reg_off(gie);
+    get_reg_off(osc);
+    get_reg_off(scg0);
+    get_reg_off(scg1);
+    get_reg_off(res);
+
+    return dict;
+}
+
+
+
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+    {"PC" , (getter)JitCpu_get_PC      , (setter)JitCpu_set_PC     , "PC" , NULL},
+    {"SP" , (getter)JitCpu_get_SP      , (setter)JitCpu_set_SP     , "SP" , NULL},
+    {"R3" , (getter)JitCpu_get_R3      , (setter)JitCpu_set_R3     , "R3" , NULL},
+    {"R4" , (getter)JitCpu_get_R4      , (setter)JitCpu_set_R4     , "R4" , NULL},
+    {"R5" , (getter)JitCpu_get_R5      , (setter)JitCpu_set_R5     , "R5" , NULL},
+    {"R6" , (getter)JitCpu_get_R6      , (setter)JitCpu_set_R6     , "R6" , NULL},
+    {"R7" , (getter)JitCpu_get_R7      , (setter)JitCpu_set_R7     , "R7" , NULL},
+    {"R8" , (getter)JitCpu_get_R8      , (setter)JitCpu_set_R8     , "R8" , NULL},
+    {"R9" , (getter)JitCpu_get_R9      , (setter)JitCpu_set_R9     , "R9" , NULL},
+    {"R10" , (getter)JitCpu_get_R10    , (setter)JitCpu_set_R10    , "R10" , NULL},
+    {"R11" , (getter)JitCpu_get_R11    , (setter)JitCpu_set_R11    , "R11" , NULL},
+    {"R12" , (getter)JitCpu_get_R12    , (setter)JitCpu_set_R12    , "R12" , NULL},
+    {"R13" , (getter)JitCpu_get_R13    , (setter)JitCpu_set_R13    , "R13" , NULL},
+    {"R14" , (getter)JitCpu_get_R14    , (setter)JitCpu_set_R14    , "R14" , NULL},
+    {"R15" , (getter)JitCpu_get_R15    , (setter)JitCpu_set_R15    , "R15" , NULL},
+    {"zf" , (getter)JitCpu_get_zf      , (setter)JitCpu_set_zf     , "zf" , NULL},
+    {"nf" , (getter)JitCpu_get_nf      , (setter)JitCpu_set_nf     , "nf" , NULL},
+    {"of" , (getter)JitCpu_get_of      , (setter)JitCpu_set_of     , "of" , NULL},
+    {"cf" , (getter)JitCpu_get_cf      , (setter)JitCpu_set_cf     , "cf" , NULL},
+    {"cpuoff" , (getter)JitCpu_get_cpuoff , (setter)JitCpu_set_cpuoff , "cpuoff" , NULL},
+    {"gie" , (getter)JitCpu_get_gie    , (setter)JitCpu_set_gie    , "gie" , NULL},
+    {"osc" , (getter)JitCpu_get_osc    , (setter)JitCpu_set_osc    , "osc" , NULL},
+    {"scg0" , (getter)JitCpu_get_scg0   , (setter)JitCpu_set_scg0   , "scg0" , NULL},
+    {"scg1" , (getter)JitCpu_get_scg1   , (setter)JitCpu_set_scg1   , "scg1" , NULL},
+    {"res" , (getter)JitCpu_get_res    , (setter)JitCpu_set_res    , "res" , NULL},
+
+    {NULL}  /* Sentinel */
+};
+
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_msp430.JitCpu",   /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_msp430_Methods[] = {
+
+	/*
+
+	*/
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+
+
+MOD_INIT(JitCore_msp430)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_msp430", "JitCore_msp430 module", JitCore_msp430_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/arch/JitCore_msp430.h b/src/miasm/jitter/arch/JitCore_msp430.h
new file mode 100644
index 00000000..d7b6a7b9
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_msp430.h
@@ -0,0 +1,44 @@
+
+struct vm_cpu {
+	uint32_t exception_flags;
+
+	/* gpregs */
+	uint32_t PC;
+	uint32_t SP;
+	uint32_t R3;
+	uint32_t R4;
+	uint32_t R5;
+	uint32_t R6;
+	uint32_t R7;
+	uint32_t R8;
+	uint32_t R9;
+	uint32_t R10;
+	uint32_t R11;
+	uint32_t R12;
+	uint32_t R13;
+	uint32_t R14;
+	uint32_t R15;
+
+	/* eflag */
+	uint32_t zf;
+	uint32_t nf;
+	uint32_t of;
+	uint32_t cf;
+
+	uint32_t cpuoff;
+	uint32_t gie;
+	uint32_t osc;
+	uint32_t scg0;
+	uint32_t scg1;
+	uint32_t res;
+
+};
+
+#define RETURN_PC return BlockDst;
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
diff --git a/src/miasm/jitter/arch/JitCore_ppc32.c b/src/miasm/jitter/arch/JitCore_ppc32.c
new file mode 100644
index 00000000..086b140f
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_ppc32.c
@@ -0,0 +1,297 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "JitCore_ppc32.h"
+
+reg_dict gpreg_dict[] = {
+#define JITCORE_PPC_REG_EXPAND(_name, _size)				\
+    { .name = #_name, .offset = offsetof(struct vm_cpu, _name), .size = _size },
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+};
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+#define JITCORE_PPC_REG_EXPAND(_name, _size) \
+    get_reg(_name);
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+
+    return dict;
+}
+
+
+
+PyObject *
+cpu_set_gpreg(JitCpu *self, PyObject *args) {
+    PyObject *dict;
+    PyObject *d_key, *d_value = NULL;
+    Py_ssize_t pos = 0;
+    const char *d_key_name;
+    uint32_t val;
+    unsigned int i;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	return NULL;
+    if(!PyDict_Check(dict))
+	RAISE(PyExc_TypeError, "arg must be dict");
+
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)) {
+	int found = 0;
+	PyGetStr(d_key_name, d_key);
+	PyGetInt_uint32_t(d_value, val);
+
+	for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+	    if (strcmp(d_key_name, gpreg_dict[i].name))
+		continue;
+	    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val;
+	    found = 1;
+	    break;
+	}
+
+	if (found)
+	    continue;
+	fprintf(stderr, "unknown key: %s\n", d_key_name);
+	RAISE(PyExc_ValueError, "unknown reg");
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+PyObject *
+cpu_init_regs(JitCpu *self) {
+    memset(self->cpu, 0, sizeof(struct vm_cpu));
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static void
+dump_gpreg(const char *name, uint32_t val, int *n) {
+    printf("%6s %.8" PRIX32"%c", name, val, (*n + 1) % 4 == 0? '\n':' ');
+    *n = (*n + 1) % 4;
+}
+
+void
+dump_gpregs(struct vm_cpu *vmcpu) {
+    int reg_num = 0;
+
+#define JITCORE_PPC_REG_EXPAND(_name, _size) \
+    dump_gpreg(#_name, vmcpu->_name, &reg_num);
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+
+    if ((reg_num % 4) != 0)
+      putchar('\n');
+}
+
+
+PyObject *
+cpu_dump_gpregs(JitCpu *self, PyObject *args) {
+
+    dump_gpregs(self->cpu);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject *
+cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	return cpu_dump_gpregs(self, args);
+}
+
+PyObject *
+cpu_set_exception(JitCpu *self, PyObject *args) {
+    PyObject *item1;
+    uint64_t exception_flags;
+
+    if (!PyArg_ParseTuple(args, "O", &item1))
+	return NULL;
+
+    PyGetInt_uint64_t(item1, exception_flags);
+
+    ((struct vm_cpu *)self->cpu)->exception_flags = exception_flags;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject *
+cpu_get_exception(JitCpu *self, PyObject *args) {
+    return PyLong_FromUnsignedLongLong(((struct vm_cpu *)self->cpu)->exception_flags);
+}
+
+static PyObject *
+cpu_get_spr_access(JitCpu *self, PyObject *args) {
+    return PyLong_FromUnsignedLongLong(((struct vm_cpu *) self->cpu)->spr_access);
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+    {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, "X"},
+    {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, "X"},
+    {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, "X"},
+    {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, "X"},
+    {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, "X"},
+    {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, "X"},
+    {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, "X"},
+    {"get_spr_access", (PyCFunction)cpu_get_spr_access, METH_VARARGS, "X"},
+    {NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) {
+    self->cpu = malloc(sizeof(struct vm_cpu));
+    if (self->cpu == NULL) {
+	fprintf(stderr, "cannot alloc struct vm_cpu\n");
+	exit(1);
+    }
+    return 0;
+}
+
+
+#define JITCORE_PPC_REG_EXPAND(_name, _size) \
+getset_reg_u32(_name);
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+
+PyObject *
+get_gpreg_offset_all(void) {
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+#define JITCORE_PPC_REG_EXPAND(_name, _size)				\
+    get_reg_off(_name);
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+
+    return dict;
+}
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+#define JITCORE_PPC_REG_EXPAND(_name, _size)				\
+    { #_name, (getter) JitCpu_get_ ## _name ,				\
+	(setter) JitCpu_set_ ## _name , #_name , NULL},
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_ppc.JitCpu",      /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_ppc32_Methods[] = {
+    {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+
+
+MOD_INIT(JitCore_ppc32)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_ppc32", "JitCore_ppc32 module", JitCore_ppc32_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/arch/JitCore_ppc32.h b/src/miasm/jitter/arch/JitCore_ppc32.h
new file mode 100644
index 00000000..abb04941
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_ppc32.h
@@ -0,0 +1,22 @@
+/*
+ * _size can't be used yet because all register accesses are homogeneously
+ * 32-bit
+ */
+struct vm_cpu {
+#define JITCORE_PPC_REG_EXPAND(_name, _size)				\
+    uint32_t _name;
+#include "JitCore_ppc32_regs.h"
+#undef JITCORE_PPC_REG_EXPAND
+
+    uint64_t exception_flags;
+    uint32_t spr_access;
+    uint32_t reserve;
+    uint32_t reserve_address;
+};
+
+_MIASM_EXPORT void dump_gpregs(struct vm_cpu *);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
diff --git a/src/miasm/jitter/arch/JitCore_ppc32_regs.h b/src/miasm/jitter/arch/JitCore_ppc32_regs.h
new file mode 100644
index 00000000..79191d32
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_ppc32_regs.h
@@ -0,0 +1,192 @@
+JITCORE_PPC_REG_EXPAND(R0, 32)
+JITCORE_PPC_REG_EXPAND(R1, 32)
+JITCORE_PPC_REG_EXPAND(R2, 32)
+JITCORE_PPC_REG_EXPAND(R3, 32)
+JITCORE_PPC_REG_EXPAND(R4, 32)
+JITCORE_PPC_REG_EXPAND(R5, 32)
+JITCORE_PPC_REG_EXPAND(R6, 32)
+JITCORE_PPC_REG_EXPAND(R7, 32)
+JITCORE_PPC_REG_EXPAND(R8, 32)
+JITCORE_PPC_REG_EXPAND(R9, 32)
+JITCORE_PPC_REG_EXPAND(R10, 32)
+JITCORE_PPC_REG_EXPAND(R11, 32)
+JITCORE_PPC_REG_EXPAND(R12, 32)
+JITCORE_PPC_REG_EXPAND(R13, 32)
+JITCORE_PPC_REG_EXPAND(R14, 32)
+JITCORE_PPC_REG_EXPAND(R15, 32)
+JITCORE_PPC_REG_EXPAND(R16, 32)
+JITCORE_PPC_REG_EXPAND(R17, 32)
+JITCORE_PPC_REG_EXPAND(R18, 32)
+JITCORE_PPC_REG_EXPAND(R19, 32)
+JITCORE_PPC_REG_EXPAND(R20, 32)
+JITCORE_PPC_REG_EXPAND(R21, 32)
+JITCORE_PPC_REG_EXPAND(R22, 32)
+JITCORE_PPC_REG_EXPAND(R23, 32)
+JITCORE_PPC_REG_EXPAND(R24, 32)
+JITCORE_PPC_REG_EXPAND(R25, 32)
+JITCORE_PPC_REG_EXPAND(R26, 32)
+JITCORE_PPC_REG_EXPAND(R27, 32)
+JITCORE_PPC_REG_EXPAND(R28, 32)
+JITCORE_PPC_REG_EXPAND(R29, 32)
+JITCORE_PPC_REG_EXPAND(R30, 32)
+JITCORE_PPC_REG_EXPAND(R31, 32)
+
+JITCORE_PPC_REG_EXPAND(PC, 32)
+JITCORE_PPC_REG_EXPAND(LR, 32)
+JITCORE_PPC_REG_EXPAND(CTR, 32)
+JITCORE_PPC_REG_EXPAND(MSR, 32)
+
+JITCORE_PPC_REG_EXPAND(XER_SO, 32)
+JITCORE_PPC_REG_EXPAND(XER_OV, 32)
+JITCORE_PPC_REG_EXPAND(XER_CA, 32)
+JITCORE_PPC_REG_EXPAND(XER_BC, 32)
+
+JITCORE_PPC_REG_EXPAND(CR0_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR0_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR0_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR0_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR1_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR1_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR1_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR1_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR2_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR2_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR2_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR2_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR3_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR3_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR3_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR3_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR4_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR4_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR4_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR4_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR5_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR5_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR5_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR5_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR6_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR6_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR6_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR6_SO, 8)
+JITCORE_PPC_REG_EXPAND(CR7_LT, 8)
+JITCORE_PPC_REG_EXPAND(CR7_GT, 8)
+JITCORE_PPC_REG_EXPAND(CR7_EQ, 8)
+JITCORE_PPC_REG_EXPAND(CR7_SO, 8)
+
+JITCORE_PPC_REG_EXPAND(SPRG0, 32)
+JITCORE_PPC_REG_EXPAND(SPRG1, 32)
+JITCORE_PPC_REG_EXPAND(SPRG2, 32)
+JITCORE_PPC_REG_EXPAND(SPRG3, 32)
+JITCORE_PPC_REG_EXPAND(SRR0, 32)
+JITCORE_PPC_REG_EXPAND(SRR1, 32)
+JITCORE_PPC_REG_EXPAND(DAR, 32)
+JITCORE_PPC_REG_EXPAND(DSISR, 32)
+JITCORE_PPC_REG_EXPAND(PIR, 32)
+JITCORE_PPC_REG_EXPAND(PVR, 32)
+JITCORE_PPC_REG_EXPAND(DEC, 32)
+JITCORE_PPC_REG_EXPAND(TBL, 32)
+JITCORE_PPC_REG_EXPAND(TBU, 32)
+
+JITCORE_PPC_REG_EXPAND(SR0, 32)
+JITCORE_PPC_REG_EXPAND(SR1, 32)
+JITCORE_PPC_REG_EXPAND(SR2, 32)
+JITCORE_PPC_REG_EXPAND(SR3, 32)
+JITCORE_PPC_REG_EXPAND(SR4, 32)
+JITCORE_PPC_REG_EXPAND(SR5, 32)
+JITCORE_PPC_REG_EXPAND(SR6, 32)
+JITCORE_PPC_REG_EXPAND(SR7, 32)
+JITCORE_PPC_REG_EXPAND(SR8, 32)
+JITCORE_PPC_REG_EXPAND(SR9, 32)
+JITCORE_PPC_REG_EXPAND(SR10, 32)
+JITCORE_PPC_REG_EXPAND(SR11, 32)
+JITCORE_PPC_REG_EXPAND(SR12, 32)
+JITCORE_PPC_REG_EXPAND(SR13, 32)
+JITCORE_PPC_REG_EXPAND(SR14, 32)
+JITCORE_PPC_REG_EXPAND(SR15, 32)
+JITCORE_PPC_REG_EXPAND(IBAT0U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT0L, 32)
+JITCORE_PPC_REG_EXPAND(IBAT1U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT1L, 32)
+JITCORE_PPC_REG_EXPAND(IBAT2U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT2L, 32)
+JITCORE_PPC_REG_EXPAND(IBAT3U, 32)
+JITCORE_PPC_REG_EXPAND(IBAT3L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT0U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT0L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT1U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT1L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT2U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT2L, 32)
+JITCORE_PPC_REG_EXPAND(DBAT3U, 32)
+JITCORE_PPC_REG_EXPAND(DBAT3L, 32)
+JITCORE_PPC_REG_EXPAND(SDR1, 32)
+
+JITCORE_PPC_REG_EXPAND(FPR0, 64)
+JITCORE_PPC_REG_EXPAND(FPR1, 64)
+JITCORE_PPC_REG_EXPAND(FPR2, 64)
+JITCORE_PPC_REG_EXPAND(FPR3, 64)
+JITCORE_PPC_REG_EXPAND(FPR4, 64)
+JITCORE_PPC_REG_EXPAND(FPR5, 64)
+JITCORE_PPC_REG_EXPAND(FPR6, 64)
+JITCORE_PPC_REG_EXPAND(FPR7, 64)
+JITCORE_PPC_REG_EXPAND(FPR8, 64)
+JITCORE_PPC_REG_EXPAND(FPR9, 64)
+JITCORE_PPC_REG_EXPAND(FPR10, 64)
+JITCORE_PPC_REG_EXPAND(FPR11, 64)
+JITCORE_PPC_REG_EXPAND(FPR12, 64)
+JITCORE_PPC_REG_EXPAND(FPR13, 64)
+JITCORE_PPC_REG_EXPAND(FPR14, 64)
+JITCORE_PPC_REG_EXPAND(FPR15, 64)
+JITCORE_PPC_REG_EXPAND(FPR16, 64)
+JITCORE_PPC_REG_EXPAND(FPR17, 64)
+JITCORE_PPC_REG_EXPAND(FPR18, 64)
+JITCORE_PPC_REG_EXPAND(FPR19, 64)
+JITCORE_PPC_REG_EXPAND(FPR20, 64)
+JITCORE_PPC_REG_EXPAND(FPR21, 64)
+JITCORE_PPC_REG_EXPAND(FPR22, 64)
+JITCORE_PPC_REG_EXPAND(FPR23, 64)
+JITCORE_PPC_REG_EXPAND(FPR24, 64)
+JITCORE_PPC_REG_EXPAND(FPR25, 64)
+JITCORE_PPC_REG_EXPAND(FPR26, 64)
+JITCORE_PPC_REG_EXPAND(FPR27, 64)
+JITCORE_PPC_REG_EXPAND(FPR28, 64)
+JITCORE_PPC_REG_EXPAND(FPR29, 64)
+JITCORE_PPC_REG_EXPAND(FPR30, 64)
+JITCORE_PPC_REG_EXPAND(FPR31, 64)
+JITCORE_PPC_REG_EXPAND(FPSCR, 32)
+
+JITCORE_PPC_REG_EXPAND(VR0, 128)
+JITCORE_PPC_REG_EXPAND(VR1, 128)
+JITCORE_PPC_REG_EXPAND(VR2, 128)
+JITCORE_PPC_REG_EXPAND(VR3, 128)
+JITCORE_PPC_REG_EXPAND(VR4, 128)
+JITCORE_PPC_REG_EXPAND(VR5, 128)
+JITCORE_PPC_REG_EXPAND(VR6, 128)
+JITCORE_PPC_REG_EXPAND(VR7, 128)
+JITCORE_PPC_REG_EXPAND(VR8, 128)
+JITCORE_PPC_REG_EXPAND(VR9, 128)
+JITCORE_PPC_REG_EXPAND(VR10, 128)
+JITCORE_PPC_REG_EXPAND(VR11, 128)
+JITCORE_PPC_REG_EXPAND(VR12, 128)
+JITCORE_PPC_REG_EXPAND(VR13, 128)
+JITCORE_PPC_REG_EXPAND(VR14, 128)
+JITCORE_PPC_REG_EXPAND(VR15, 128)
+JITCORE_PPC_REG_EXPAND(VR16, 128)
+JITCORE_PPC_REG_EXPAND(VR17, 128)
+JITCORE_PPC_REG_EXPAND(VR18, 128)
+JITCORE_PPC_REG_EXPAND(VR19, 128)
+JITCORE_PPC_REG_EXPAND(VR20, 128)
+JITCORE_PPC_REG_EXPAND(VR21, 128)
+JITCORE_PPC_REG_EXPAND(VR22, 128)
+JITCORE_PPC_REG_EXPAND(VR23, 128)
+JITCORE_PPC_REG_EXPAND(VR24, 128)
+JITCORE_PPC_REG_EXPAND(VR25, 128)
+JITCORE_PPC_REG_EXPAND(VR26, 128)
+JITCORE_PPC_REG_EXPAND(VR27, 128)
+JITCORE_PPC_REG_EXPAND(VR28, 128)
+JITCORE_PPC_REG_EXPAND(VR29, 128)
+JITCORE_PPC_REG_EXPAND(VR30, 128)
+JITCORE_PPC_REG_EXPAND(VR31, 128)
+JITCORE_PPC_REG_EXPAND(VRSAVE, 32)
+JITCORE_PPC_REG_EXPAND(VSCR, 32)
diff --git a/src/miasm/jitter/arch/JitCore_x86.c b/src/miasm/jitter/arch/JitCore_x86.c
new file mode 100644
index 00000000..9081f3d8
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_x86.c
@@ -0,0 +1,903 @@
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include "../compat_py23.h"
+#include "../queue.h"
+#include "../vm_mngr.h"
+#include "../bn.h"
+#include "../vm_mngr_py.h"
+#include "../JitCore.h"
+#include "../op_semantics.h"
+#include "JitCore_x86.h"
+
+
+struct vm_cpu ref_arch_regs;
+
+reg_dict gpreg_dict[] = {
+			 {.name = "RAX", .offset = offsetof(struct vm_cpu, RAX), .size = 64},
+			 {.name = "RBX", .offset = offsetof(struct vm_cpu, RBX), .size = 64},
+			 {.name = "RCX", .offset = offsetof(struct vm_cpu, RCX), .size = 64},
+			 {.name = "RDX", .offset = offsetof(struct vm_cpu, RDX), .size = 64},
+			 {.name = "RSI", .offset = offsetof(struct vm_cpu, RSI), .size = 64},
+			 {.name = "RDI", .offset = offsetof(struct vm_cpu, RDI), .size = 64},
+			 {.name = "RSP", .offset = offsetof(struct vm_cpu, RSP), .size = 64},
+			 {.name = "RBP", .offset = offsetof(struct vm_cpu, RBP), .size = 64},
+
+			 {.name = "R8", .offset = offsetof(struct vm_cpu, R8), .size = 64},
+			 {.name = "R9", .offset = offsetof(struct vm_cpu, R9), .size = 64},
+			 {.name = "R10", .offset = offsetof(struct vm_cpu, R10), .size = 64},
+			 {.name = "R11", .offset = offsetof(struct vm_cpu, R11), .size = 64},
+			 {.name = "R12", .offset = offsetof(struct vm_cpu, R12), .size = 64},
+			 {.name = "R13", .offset = offsetof(struct vm_cpu, R13), .size = 64},
+			 {.name = "R14", .offset = offsetof(struct vm_cpu, R14), .size = 64},
+			 {.name = "R15", .offset = offsetof(struct vm_cpu, R15), .size = 64},
+
+			 {.name = "RIP", .offset = offsetof(struct vm_cpu, RIP), .size = 64},
+
+			 {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8},
+			 {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8},
+			 {.name = "pf", .offset = offsetof(struct vm_cpu, pf), .size = 8},
+			 {.name = "of", .offset = offsetof(struct vm_cpu, of), .size = 8},
+			 {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8},
+			 {.name = "af", .offset = offsetof(struct vm_cpu, af), .size = 8},
+			 {.name = "df", .offset = offsetof(struct vm_cpu, df), .size = 8},
+
+			 {.name = "ES", .offset = offsetof(struct vm_cpu, ES), .size = 16},
+			 {.name = "CS", .offset = offsetof(struct vm_cpu, CS), .size = 16},
+			 {.name = "SS", .offset = offsetof(struct vm_cpu, SS), .size = 16},
+			 {.name = "DS", .offset = offsetof(struct vm_cpu, DS), .size = 16},
+			 {.name = "FS", .offset = offsetof(struct vm_cpu, FS), .size = 16},
+			 {.name = "GS", .offset = offsetof(struct vm_cpu, GS), .size = 16},
+
+			 {.name = "MM0", .offset = offsetof(struct vm_cpu, MM0), .size = 64},
+			 {.name = "MM1", .offset = offsetof(struct vm_cpu, MM1), .size = 64},
+			 {.name = "MM2", .offset = offsetof(struct vm_cpu, MM2), .size = 64},
+			 {.name = "MM3", .offset = offsetof(struct vm_cpu, MM3), .size = 64},
+			 {.name = "MM4", .offset = offsetof(struct vm_cpu, MM4), .size = 64},
+			 {.name = "MM5", .offset = offsetof(struct vm_cpu, MM5), .size = 64},
+			 {.name = "MM6", .offset = offsetof(struct vm_cpu, MM6), .size = 64},
+			 {.name = "MM7", .offset = offsetof(struct vm_cpu, MM7), .size = 64},
+
+			 {.name = "XMM0", .offset = offsetof(struct vm_cpu, XMM0), .size = 128},
+			 {.name = "XMM1", .offset = offsetof(struct vm_cpu, XMM1), .size = 128},
+			 {.name = "XMM2", .offset = offsetof(struct vm_cpu, XMM2), .size = 128},
+			 {.name = "XMM3", .offset = offsetof(struct vm_cpu, XMM3), .size = 128},
+			 {.name = "XMM4", .offset = offsetof(struct vm_cpu, XMM4), .size = 128},
+			 {.name = "XMM5", .offset = offsetof(struct vm_cpu, XMM5), .size = 128},
+			 {.name = "XMM6", .offset = offsetof(struct vm_cpu, XMM6), .size = 128},
+			 {.name = "XMM7", .offset = offsetof(struct vm_cpu, XMM7), .size = 128},
+			 {.name = "XMM8", .offset = offsetof(struct vm_cpu, XMM8), .size = 128},
+			 {.name = "XMM9", .offset = offsetof(struct vm_cpu, XMM9), .size = 128},
+			 {.name = "XMM10", .offset = offsetof(struct vm_cpu, XMM10), .size = 128},
+			 {.name = "XMM11", .offset = offsetof(struct vm_cpu, XMM11), .size = 128},
+			 {.name = "XMM12", .offset = offsetof(struct vm_cpu, XMM12), .size = 128},
+			 {.name = "XMM13", .offset = offsetof(struct vm_cpu, XMM13), .size = 128},
+			 {.name = "XMM14", .offset = offsetof(struct vm_cpu, XMM14), .size = 128},
+			 {.name = "XMM15", .offset = offsetof(struct vm_cpu, XMM15), .size = 128},
+
+			 {.name = "tsc", .offset = offsetof(struct vm_cpu, tsc), .size = 64},
+
+			 {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32},
+			 {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32},
+};
+
+
+
+/************************** JitCpu object **************************/
+
+
+
+
+
+PyObject* cpu_get_gpreg(JitCpu* self)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+
+    get_reg(RAX);
+    get_reg(RBX);
+    get_reg(RCX);
+    get_reg(RDX);
+    get_reg(RSI);
+    get_reg(RDI);
+    get_reg(RSP);
+    get_reg(RBP);
+
+    get_reg(R8);
+    get_reg(R9);
+    get_reg(R10);
+    get_reg(R11);
+    get_reg(R12);
+    get_reg(R13);
+    get_reg(R14);
+    get_reg(R15);
+
+    get_reg(RIP);
+
+    get_reg(zf);
+    get_reg(nf);
+    get_reg(pf);
+    get_reg(of);
+    get_reg(cf);
+    get_reg(af);
+    get_reg(df);
+
+
+    get_reg(ES);
+    get_reg(CS);
+    get_reg(SS);
+    get_reg(DS);
+    get_reg(FS);
+    get_reg(GS);
+
+    get_reg(MM0);
+    get_reg(MM1);
+    get_reg(MM2);
+    get_reg(MM3);
+    get_reg(MM4);
+    get_reg(MM5);
+    get_reg(MM6);
+    get_reg(MM7);
+
+    get_reg_bn(XMM0, 128);
+    get_reg_bn(XMM1, 128);
+    get_reg_bn(XMM2, 128);
+    get_reg_bn(XMM3, 128);
+    get_reg_bn(XMM4, 128);
+    get_reg_bn(XMM5, 128);
+    get_reg_bn(XMM6, 128);
+    get_reg_bn(XMM7, 128);
+    get_reg_bn(XMM8, 128);
+    get_reg_bn(XMM9, 128);
+    get_reg_bn(XMM10, 128);
+    get_reg_bn(XMM11, 128);
+    get_reg_bn(XMM12, 128);
+    get_reg_bn(XMM13, 128);
+    get_reg_bn(XMM14, 128);
+    get_reg_bn(XMM15, 128);
+
+    get_reg(tsc);
+
+    return dict;
+}
+
+
+PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args)
+{
+    PyObject* dict;
+    PyObject *d_key, *d_value = NULL;
+    const char *d_key_name;
+    Py_ssize_t pos = 0;
+    uint8_t val08;
+    uint16_t val16;
+    uint32_t val32;
+    uint64_t val64;
+    unsigned int i, found;
+
+    if (!PyArg_ParseTuple(args, "O", &dict))
+	    RAISE(PyExc_TypeError,"Cannot parse arguments");
+    if(!PyDict_Check(dict))
+	    RAISE(PyExc_TypeError, "arg must be dict");
+    while(PyDict_Next(dict, &pos, &d_key, &d_value)){
+	    PyGetStr(d_key_name, d_key);
+	    found = 0;
+	    for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){
+		    if (strcmp(d_key_name, gpreg_dict[i].name))
+			    continue;
+		    found = 1;
+		    switch (gpreg_dict[i].size) {
+			    default:
+				    RAISE(PyExc_TypeError, "Unsupported size");
+				    break;
+			    case 8:
+				    PyGetInt_uint8_t(d_value, val08);
+				    *((uint8_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val08;
+				    break;
+			    case 16:
+				    PyGetInt_uint16_t(d_value, val16);
+				    *((uint16_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val16;
+				    break;
+			    case 32:
+				    PyGetInt_uint32_t(d_value, val32);
+				    *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val32;
+				    break;
+			    case 64:
+				    PyGetInt_uint64_t(d_value, val64);
+				    *((uint64_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val64;
+				    break;
+			    case 128:
+				    {
+					    bn_t bn;
+					    PyObject* py_long = d_value;
+
+
+#if PY_MAJOR_VERSION >= 3
+					    if (PyLong_Check(py_long)){
+						    /* Already PyLong */
+						    /* Increment ref as we will decement it next */
+						    Py_INCREF(py_long);
+					    } else {
+						    RAISE(PyExc_TypeError,"arg must be int");
+					    }
+#else
+					    uint64_t tmp;
+
+					    if (PyInt_Check(py_long)){
+						    tmp = (uint64_t)PyInt_AsLong(py_long);
+						    py_long = PyLong_FromLong((long)tmp);
+					    } else if (PyLong_Check(py_long)){
+						    /* Already PyLong */
+						    /* Increment ref as we will decement it next */
+						    Py_INCREF(py_long);
+					    }
+					    else{
+						    RAISE(PyExc_TypeError,"arg must be int");
+					    }
+#endif
+
+					    bn = PyLong_to_bn(py_long);
+					    *(bn_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset) = bignum_mask(bn, 128);
+				    }
+				    break;
+		    }
+		    break;
+	    }
+
+	    if (found)
+		    continue;
+	    fprintf(stderr, "unknown key: %s\n", d_key_name);
+	    RAISE(PyExc_ValueError, "unknown reg");
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject * cpu_init_regs(JitCpu* self)
+{
+	memset(self->cpu, 0, sizeof(struct vm_cpu));
+	((struct vm_cpu*)self->cpu)->tsc = 0x1122334455667788ULL;
+	((struct vm_cpu*)self->cpu)->i_f = 1;
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+void dump_gpregs_16(struct vm_cpu* vmcpu)
+{
+	printf("EAX %.8"PRIX32" EBX %.8"PRIX32" ECX %.8"PRIX32" EDX %.8"PRIX32" ",
+	       (uint32_t)(vmcpu->RAX & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RBX & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RCX & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RDX & 0xFFFFFFFF));
+	printf("ESI %.8"PRIX32" EDI %.8"PRIX32" ESP %.8"PRIX32" EBP %.8"PRIX32" ",
+	       (uint32_t)(vmcpu->RSI & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RDI & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RSP & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RBP & 0xFFFFFFFF));
+	printf("EIP %.8"PRIX32" ",
+	       (uint32_t)(vmcpu->RIP & 0xFFFFFFFF));
+	printf("zf %.1d nf %.1d of %.1d cf %.1d\n",
+	       (uint32_t)(vmcpu->zf & 0x1),
+	       (uint32_t)(vmcpu->nf & 0x1),
+	       (uint32_t)(vmcpu->of & 0x1),
+	       (uint32_t)(vmcpu->cf & 0x1));
+}
+
+void dump_gpregs_32(struct vm_cpu* vmcpu)
+{
+
+	printf("EAX %.8"PRIX32" EBX %.8"PRIX32" ECX %.8"PRIX32" EDX %.8"PRIX32" ",
+	       (uint32_t)(vmcpu->RAX & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RBX & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RCX & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RDX & 0xFFFFFFFF));
+	printf("ESI %.8"PRIX32" EDI %.8"PRIX32" ESP %.8"PRIX32" EBP %.8"PRIX32" ",
+	       (uint32_t)(vmcpu->RSI & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RDI & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RSP & 0xFFFFFFFF),
+	       (uint32_t)(vmcpu->RBP & 0xFFFFFFFF));
+	printf("EIP %.8"PRIX32" ",
+	       (uint32_t)(vmcpu->RIP & 0xFFFFFFFF));
+	printf("zf %.1d nf %.1d of %.1d cf %.1d\n",
+	       (uint32_t)(vmcpu->zf & 0x1),
+	       (uint32_t)(vmcpu->nf & 0x1),
+	       (uint32_t)(vmcpu->of & 0x1),
+	       (uint32_t)(vmcpu->cf & 0x1));
+
+}
+
+void dump_gpregs_64(struct vm_cpu* vmcpu)
+{
+
+	printf("RAX %.16"PRIX64" RBX %.16"PRIX64" RCX %.16"PRIX64" RDX %.16"PRIX64" ",
+	       vmcpu->RAX, vmcpu->RBX, vmcpu->RCX, vmcpu->RDX);
+	printf("RSI %.16"PRIX64" RDI %.16"PRIX64" RSP %.16"PRIX64" RBP %.16"PRIX64" ",
+	       vmcpu->RSI, vmcpu->RDI, vmcpu->RSP, vmcpu->RBP);
+	printf("RIP %.16"PRIX64"\n",
+	       vmcpu->RIP);
+	printf("R8  %.16"PRIX64" R9  %.16"PRIX64" R10 %.16"PRIX64" R11 %.16"PRIX64" ",
+	       vmcpu->R8, vmcpu->R9, vmcpu->R10, vmcpu->R11);
+	printf("R12 %.16"PRIX64" R13 %.16"PRIX64" R14 %.16"PRIX64" R15 %.16"PRIX64" ",
+	       vmcpu->R12, vmcpu->R13, vmcpu->R14, vmcpu->R15);
+
+
+	printf("zf %.1d nf %.1d of %.1d cf %.1d\n",
+	       vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf);
+
+}
+
+PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+
+	vmcpu = self->cpu;
+	dump_gpregs_64(vmcpu);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args)
+{
+	struct vm_cpu* vmcpu;
+	PyObject *item1;
+	uint64_t attrib;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(item1, attrib);
+
+	vmcpu = self->cpu;
+	if (attrib == 16 || attrib == 32)
+		dump_gpregs_32(vmcpu);
+	else if (attrib == 64)
+		dump_gpregs_64(vmcpu);
+	else {
+		RAISE(PyExc_TypeError,"Bad attrib");
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+
+PyObject* cpu_set_exception(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_exception(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags));
+}
+
+PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint32_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint32_t(item1, exception_flags);
+
+	((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num));
+}
+
+PyObject* cpu_set_segm_base(JitCpu* self, PyObject* args)
+{
+	PyObject *item1, *item2;
+	uint64_t segm_num, segm_base;
+
+	if (!PyArg_ParseTuple(args, "OO", &item1, &item2))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(item1, segm_num);
+	PyGetInt_uint64_t(item2, segm_base);
+	((struct vm_cpu*)self->cpu)->segm_base[segm_num & 0xFFFF] = segm_base;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* cpu_get_segm_base(JitCpu* self, PyObject* args)
+{
+	PyObject *item1;
+	uint64_t segm_num;
+	PyObject* v;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+	PyGetInt_uint64_t(item1, segm_num);
+	v = PyLong_FromLong((long)(((struct vm_cpu*)self->cpu)->segm_base[segm_num & 0xFFFF]));
+	return v;
+}
+
+uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr)
+{
+	return addr + ((struct vm_cpu*)jitcpu->cpu)->segm_base[segm & 0xFFFF];
+}
+
+void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src)
+{
+	vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src)
+{
+	vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src)
+{
+	vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src)
+{
+	vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src);
+}
+
+
+
+static PyMemberDef JitCpu_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef JitCpu_methods[] = {
+	{"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS,
+	 "X"},
+	{"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS,
+	 "X"},
+	{"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS,
+	 "X"},
+	{"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS,
+	 "X"},
+	{"get_segm_base", (PyCFunction)cpu_get_segm_base, METH_VARARGS,
+	 "X"},
+	{"set_segm_base", (PyCFunction)cpu_set_segm_base, METH_VARARGS,
+	 "X"},
+	{"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS,
+	 "X"},
+	{"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS,
+	 "X"},
+	{"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS,
+	 "X"},
+	{"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS,
+	 "X"},
+	{NULL}  /* Sentinel */
+};
+
+static int
+JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds)
+{
+	self->cpu = malloc(sizeof(struct vm_cpu));
+	if (self->cpu == NULL) {
+		fprintf(stderr, "cannot alloc struct vm_cpu\n");
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+#define getset_reg_E_u32(regname)					\
+	static PyObject *JitCpu_get_E ## regname  (JitCpu *self, void *closure) \
+	{								\
+		return PyLong_FromUnsignedLongLong((uint32_t)(self->cpu->R ## regname & 0xFFFFFFFF  )); \
+	}								\
+	static int JitCpu_set_E ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		uint32_t val32;						\
+		uint64_t val64;						\
+		PyGetInt_uint32_t_retneg(value, val32);			\
+		val64 = val32;						\
+		val64 |= self->cpu->R ##regname & 0xFFFFFFFF00000000ULL; \
+		self->cpu->R ## regname = val64;			\
+		return 0;						\
+	}
+
+
+
+#define getset_reg_R_u16(regname)					\
+	static PyObject *JitCpu_get_ ## regname  (JitCpu *self, void *closure) \
+	{								\
+		return PyLong_FromUnsignedLongLong((uint16_t)(self->cpu->R ## regname & 0xFFFF  )); \
+	}								\
+	static int JitCpu_set_ ## regname  (JitCpu *self, PyObject *value, void *closure) \
+	{								\
+		uint16_t val16;						\
+		uint64_t val64;						\
+		PyGetInt_uint16_t_retneg(value, val16);			\
+		val64 = val16;						\
+		val64 |= self->cpu->R ##regname & 0xFFFFFFFFFFFF0000ULL; \
+		self->cpu->R ## regname = val64;			\
+		return 0;						\
+	}
+
+
+getset_reg_u64(RAX);
+getset_reg_u64(RBX);
+getset_reg_u64(RCX);
+getset_reg_u64(RDX);
+getset_reg_u64(RSI);
+getset_reg_u64(RDI);
+getset_reg_u64(RSP);
+getset_reg_u64(RBP);
+
+getset_reg_u64(R8);
+getset_reg_u64(R9);
+getset_reg_u64(R10);
+getset_reg_u64(R11);
+getset_reg_u64(R12);
+getset_reg_u64(R13);
+getset_reg_u64(R14);
+getset_reg_u64(R15);
+
+getset_reg_u64(RIP);
+
+getset_reg_u8(zf);
+getset_reg_u8(nf);
+getset_reg_u8(pf);
+getset_reg_u8(of);
+getset_reg_u8(cf);
+getset_reg_u8(af);
+getset_reg_u8(df);
+
+
+getset_reg_u16(ES);
+getset_reg_u16(CS);
+getset_reg_u16(SS);
+getset_reg_u16(DS);
+getset_reg_u16(FS);
+getset_reg_u16(GS);
+
+getset_reg_E_u32(AX);
+getset_reg_E_u32(BX);
+getset_reg_E_u32(CX);
+getset_reg_E_u32(DX);
+getset_reg_E_u32(SI);
+getset_reg_E_u32(DI);
+getset_reg_E_u32(SP);
+getset_reg_E_u32(BP);
+getset_reg_E_u32(IP);
+
+getset_reg_R_u16(AX);
+getset_reg_R_u16(BX);
+getset_reg_R_u16(CX);
+getset_reg_R_u16(DX);
+getset_reg_R_u16(SI);
+getset_reg_R_u16(DI);
+getset_reg_R_u16(SP);
+getset_reg_R_u16(BP);
+
+getset_reg_R_u16(IP);
+
+getset_reg_u64(MM0);
+getset_reg_u64(MM1);
+getset_reg_u64(MM2);
+getset_reg_u64(MM3);
+getset_reg_u64(MM4);
+getset_reg_u64(MM5);
+getset_reg_u64(MM6);
+getset_reg_u64(MM7);
+
+getset_reg_bn(XMM0, 128);
+getset_reg_bn(XMM1, 128);
+getset_reg_bn(XMM2, 128);
+getset_reg_bn(XMM3, 128);
+getset_reg_bn(XMM4, 128);
+getset_reg_bn(XMM5, 128);
+getset_reg_bn(XMM6, 128);
+getset_reg_bn(XMM7, 128);
+getset_reg_bn(XMM8, 128);
+getset_reg_bn(XMM9, 128);
+getset_reg_bn(XMM10, 128);
+getset_reg_bn(XMM11, 128);
+getset_reg_bn(XMM12, 128);
+getset_reg_bn(XMM13, 128);
+getset_reg_bn(XMM14, 128);
+getset_reg_bn(XMM15, 128);
+
+getset_reg_u64(tsc);
+
+getset_reg_u32(exception_flags);
+getset_reg_u32(interrupt_num);
+
+
+PyObject* get_gpreg_offset_all(void)
+{
+    PyObject *dict = PyDict_New();
+    PyObject *o;
+    get_reg_off(exception_flags);
+
+    get_reg_off(RAX);
+    get_reg_off(RBX);
+    get_reg_off(RCX);
+    get_reg_off(RDX);
+    get_reg_off(RSI);
+    get_reg_off(RDI);
+    get_reg_off(RSP);
+    get_reg_off(RBP);
+    get_reg_off(R8);
+    get_reg_off(R9);
+    get_reg_off(R10);
+    get_reg_off(R11);
+    get_reg_off(R12);
+    get_reg_off(R13);
+    get_reg_off(R14);
+    get_reg_off(R15);
+    get_reg_off(RIP);
+    get_reg_off(zf);
+    get_reg_off(nf);
+    get_reg_off(pf);
+    get_reg_off(of);
+    get_reg_off(cf);
+    get_reg_off(af);
+    get_reg_off(df);
+    get_reg_off(tf);
+    get_reg_off(i_f);
+    get_reg_off(iopl_f);
+    get_reg_off(nt);
+    get_reg_off(rf);
+    get_reg_off(vm);
+    get_reg_off(ac);
+    get_reg_off(vif);
+    get_reg_off(vip);
+    get_reg_off(i_d);
+    get_reg_off(my_tick);
+    get_reg_off(cond);
+
+    get_reg_off(float_st0);
+    get_reg_off(float_st1);
+    get_reg_off(float_st2);
+    get_reg_off(float_st3);
+    get_reg_off(float_st4);
+    get_reg_off(float_st5);
+    get_reg_off(float_st6);
+    get_reg_off(float_st7);
+
+    get_reg_off(ES);
+    get_reg_off(CS);
+    get_reg_off(SS);
+    get_reg_off(DS);
+    get_reg_off(FS);
+    get_reg_off(GS);
+
+    get_reg_off(MM0);
+    get_reg_off(MM1);
+    get_reg_off(MM2);
+    get_reg_off(MM3);
+    get_reg_off(MM4);
+    get_reg_off(MM5);
+    get_reg_off(MM6);
+    get_reg_off(MM7);
+
+    get_reg_off(XMM0);
+    get_reg_off(XMM1);
+    get_reg_off(XMM2);
+    get_reg_off(XMM3);
+    get_reg_off(XMM4);
+    get_reg_off(XMM5);
+    get_reg_off(XMM6);
+    get_reg_off(XMM7);
+    get_reg_off(XMM8);
+    get_reg_off(XMM9);
+    get_reg_off(XMM10);
+    get_reg_off(XMM11);
+    get_reg_off(XMM12);
+    get_reg_off(XMM13);
+    get_reg_off(XMM14);
+    get_reg_off(XMM15);
+
+    get_reg_off(tsc);
+
+    get_reg_off(interrupt_num);
+    get_reg_off(exception_flags);
+
+    get_reg_off(float_stack_ptr);
+    get_reg_off(reg_float_cs);
+    get_reg_off(reg_float_eip);
+    get_reg_off(reg_float_control);
+
+    return dict;
+}
+
+
+static PyGetSetDef JitCpu_getseters[] = {
+    {"vmmngr",
+     (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr,
+     "vmmngr",
+     NULL},
+
+    {"vmcpu",
+     (getter)JitCpu_get_vmcpu, (setter)JitCpu_set_vmcpu,
+     "vmcpu",
+     NULL},
+
+    {"jitter",
+     (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter,
+     "jitter",
+     NULL},
+
+
+    {"RAX", (getter)JitCpu_get_RAX, (setter)JitCpu_set_RAX, "RAX", NULL},
+    {"RBX", (getter)JitCpu_get_RBX, (setter)JitCpu_set_RBX, "RBX", NULL},
+    {"RCX", (getter)JitCpu_get_RCX, (setter)JitCpu_set_RCX, "RCX", NULL},
+    {"RDX", (getter)JitCpu_get_RDX, (setter)JitCpu_set_RDX, "RDX", NULL},
+    {"RSI", (getter)JitCpu_get_RSI, (setter)JitCpu_set_RSI, "RSI", NULL},
+    {"RDI", (getter)JitCpu_get_RDI, (setter)JitCpu_set_RDI, "RDI", NULL},
+    {"RSP", (getter)JitCpu_get_RSP, (setter)JitCpu_set_RSP, "RSP", NULL},
+    {"RBP", (getter)JitCpu_get_RBP, (setter)JitCpu_set_RBP, "RBP", NULL},
+    {"R8",  (getter)JitCpu_get_R8,  (setter)JitCpu_set_R8,  "R8",  NULL},
+    {"R9",  (getter)JitCpu_get_R9,  (setter)JitCpu_set_R9,  "R9",  NULL},
+    {"R10", (getter)JitCpu_get_R10, (setter)JitCpu_set_R10, "R10", NULL},
+    {"R11", (getter)JitCpu_get_R11, (setter)JitCpu_set_R11, "R11", NULL},
+    {"R12", (getter)JitCpu_get_R12, (setter)JitCpu_set_R12, "R12", NULL},
+    {"R13", (getter)JitCpu_get_R13, (setter)JitCpu_set_R13, "R13", NULL},
+    {"R14", (getter)JitCpu_get_R14, (setter)JitCpu_set_R14, "R14", NULL},
+    {"R15", (getter)JitCpu_get_R15, (setter)JitCpu_set_R15, "R15", NULL},
+    {"RIP", (getter)JitCpu_get_RIP, (setter)JitCpu_set_RIP, "RIP", NULL},
+    {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL},
+    {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL},
+    {"pf", (getter)JitCpu_get_pf, (setter)JitCpu_set_pf, "pf", NULL},
+    {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL},
+    {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL},
+    {"af", (getter)JitCpu_get_af, (setter)JitCpu_set_af, "af", NULL},
+    {"df", (getter)JitCpu_get_df, (setter)JitCpu_set_df, "df", NULL},
+    {"ES", (getter)JitCpu_get_ES, (setter)JitCpu_set_ES, "ES", NULL},
+    {"CS", (getter)JitCpu_get_CS, (setter)JitCpu_set_CS, "CS", NULL},
+    {"SS", (getter)JitCpu_get_SS, (setter)JitCpu_set_SS, "SS", NULL},
+    {"DS", (getter)JitCpu_get_DS, (setter)JitCpu_set_DS, "DS", NULL},
+    {"FS", (getter)JitCpu_get_FS, (setter)JitCpu_set_FS, "FS", NULL},
+    {"GS", (getter)JitCpu_get_GS, (setter)JitCpu_set_GS, "GS", NULL},
+
+    {"EAX", (getter)JitCpu_get_EAX, (setter)JitCpu_set_EAX, "EAX", NULL},
+    {"EBX", (getter)JitCpu_get_EBX, (setter)JitCpu_set_EBX, "EBX", NULL},
+    {"ECX", (getter)JitCpu_get_ECX, (setter)JitCpu_set_ECX, "ECX", NULL},
+    {"EDX", (getter)JitCpu_get_EDX, (setter)JitCpu_set_EDX, "EDX", NULL},
+    {"ESI", (getter)JitCpu_get_ESI, (setter)JitCpu_set_ESI, "ESI", NULL},
+    {"EDI", (getter)JitCpu_get_EDI, (setter)JitCpu_set_EDI, "EDI", NULL},
+    {"ESP", (getter)JitCpu_get_ESP, (setter)JitCpu_set_ESP, "ESP", NULL},
+    {"EBP", (getter)JitCpu_get_EBP, (setter)JitCpu_set_EBP, "EBP", NULL},
+    {"EIP", (getter)JitCpu_get_EIP, (setter)JitCpu_set_EIP, "EIP", NULL},
+
+    {"AX", (getter)JitCpu_get_AX, (setter)JitCpu_set_AX, "AX", NULL},
+    {"BX", (getter)JitCpu_get_BX, (setter)JitCpu_set_BX, "BX", NULL},
+    {"CX", (getter)JitCpu_get_CX, (setter)JitCpu_set_CX, "CX", NULL},
+    {"DX", (getter)JitCpu_get_DX, (setter)JitCpu_set_DX, "DX", NULL},
+    {"SI", (getter)JitCpu_get_SI, (setter)JitCpu_set_SI, "SI", NULL},
+    {"DI", (getter)JitCpu_get_DI, (setter)JitCpu_set_DI, "DI", NULL},
+    {"SP", (getter)JitCpu_get_SP, (setter)JitCpu_set_SP, "SP", NULL},
+    {"BP", (getter)JitCpu_get_BP, (setter)JitCpu_set_BP, "BP", NULL},
+
+    {"IP", (getter)JitCpu_get_IP, (setter)JitCpu_set_IP, "IP", NULL},
+
+    {"MM0", (getter)JitCpu_get_MM0, (setter)JitCpu_set_MM0, "MM0", NULL},
+    {"MM1", (getter)JitCpu_get_MM1, (setter)JitCpu_set_MM1, "MM1", NULL},
+    {"MM2", (getter)JitCpu_get_MM2, (setter)JitCpu_set_MM2, "MM2", NULL},
+    {"MM3", (getter)JitCpu_get_MM3, (setter)JitCpu_set_MM3, "MM3", NULL},
+    {"MM4", (getter)JitCpu_get_MM4, (setter)JitCpu_set_MM4, "MM4", NULL},
+    {"MM5", (getter)JitCpu_get_MM5, (setter)JitCpu_set_MM5, "MM5", NULL},
+    {"MM6", (getter)JitCpu_get_MM6, (setter)JitCpu_set_MM6, "MM6", NULL},
+    {"MM7", (getter)JitCpu_get_MM7, (setter)JitCpu_set_MM7, "MM7", NULL},
+
+    {"XMM0", (getter)JitCpu_get_XMM0, (setter)JitCpu_set_XMM0, "XMM0", NULL},
+    {"XMM1", (getter)JitCpu_get_XMM1, (setter)JitCpu_set_XMM1, "XMM1", NULL},
+    {"XMM2", (getter)JitCpu_get_XMM2, (setter)JitCpu_set_XMM2, "XMM2", NULL},
+    {"XMM3", (getter)JitCpu_get_XMM3, (setter)JitCpu_set_XMM3, "XMM3", NULL},
+    {"XMM4", (getter)JitCpu_get_XMM4, (setter)JitCpu_set_XMM4, "XMM4", NULL},
+    {"XMM5", (getter)JitCpu_get_XMM5, (setter)JitCpu_set_XMM5, "XMM5", NULL},
+    {"XMM6", (getter)JitCpu_get_XMM6, (setter)JitCpu_set_XMM6, "XMM6", NULL},
+    {"XMM7", (getter)JitCpu_get_XMM7, (setter)JitCpu_set_XMM7, "XMM7", NULL},
+    {"XMM8", (getter)JitCpu_get_XMM8, (setter)JitCpu_set_XMM8, "XMM8", NULL},
+    {"XMM9", (getter)JitCpu_get_XMM9, (setter)JitCpu_set_XMM9, "XMM9", NULL},
+    {"XMM10", (getter)JitCpu_get_XMM10, (setter)JitCpu_set_XMM10, "XMM10", NULL},
+    {"XMM11", (getter)JitCpu_get_XMM11, (setter)JitCpu_set_XMM11, "XMM11", NULL},
+    {"XMM12", (getter)JitCpu_get_XMM12, (setter)JitCpu_set_XMM12, "XMM12", NULL},
+    {"XMM13", (getter)JitCpu_get_XMM13, (setter)JitCpu_set_XMM13, "XMM13", NULL},
+    {"XMM14", (getter)JitCpu_get_XMM14, (setter)JitCpu_set_XMM14, "XMM14", NULL},
+    {"XMM15", (getter)JitCpu_get_XMM15, (setter)JitCpu_set_XMM15, "XMM15", NULL},
+
+    {"tsc", (getter)JitCpu_get_tsc, (setter)JitCpu_set_tsc, "tsc", NULL},
+
+    {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL},
+    {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL},
+
+
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject JitCpuType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "JitCore_x86.JitCpu",      /*tp_name*/
+    sizeof(JitCpu),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)JitCpu_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "JitCpu objects",          /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    JitCpu_methods,            /* tp_methods */
+    JitCpu_members,            /* tp_members */
+    JitCpu_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)JitCpu_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    JitCpu_new,                /* tp_new */
+};
+
+
+
+static PyMethodDef JitCore_x86_Methods[] = {
+
+	/*
+
+	*/
+	{"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS},
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+
+MOD_INIT(JitCore_x86)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "JitCore_x86", "JitCore_x86 module", JitCore_x86_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&JitCpuType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&JitCpuType);
+	if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
diff --git a/src/miasm/jitter/arch/JitCore_x86.h b/src/miasm/jitter/arch/JitCore_x86.h
new file mode 100644
index 00000000..5c005e86
--- /dev/null
+++ b/src/miasm/jitter/arch/JitCore_x86.h
@@ -0,0 +1,136 @@
+#include "../bn.h"
+
+#if _WIN32
+#define _MIASM_EXPORT __declspec(dllexport)
+#else
+#define _MIASM_EXPORT
+#endif
+
+struct vm_cpu {
+	uint32_t exception_flags;
+	uint32_t interrupt_num;
+
+
+	/* gpregs */
+	uint64_t RAX;
+	uint64_t RBX;
+	uint64_t RCX;
+	uint64_t RDX;
+	uint64_t RSI;
+	uint64_t RDI;
+	uint64_t RSP;
+	uint64_t RBP;
+	uint64_t R8;
+	uint64_t R9;
+	uint64_t R10;
+	uint64_t R11;
+	uint64_t R12;
+	uint64_t R13;
+	uint64_t R14;
+	uint64_t R15;
+
+	uint64_t RIP;
+
+	/* eflag */
+	uint8_t zf;
+	uint8_t nf;
+	uint8_t pf;
+	uint8_t of;
+	uint8_t cf;
+	uint8_t af;
+	uint8_t df;
+
+	uint8_t tf;
+	uint8_t i_f;
+	uint8_t iopl_f;
+	uint8_t nt;
+	uint8_t rf;
+	uint8_t vm;
+	uint8_t ac;
+	uint8_t vif;
+	uint8_t vip;
+	uint8_t i_d;
+
+	bn_t my_tick;
+
+	bn_t cond;
+
+	uint64_t float_st0;
+	uint64_t float_st1;
+	uint64_t float_st2;
+	uint64_t float_st3;
+	uint64_t float_st4;
+	uint64_t float_st5;
+	uint64_t float_st6;
+	uint64_t float_st7;
+
+	unsigned int float_c0;
+	unsigned int float_c1;
+	unsigned int float_c2;
+	unsigned int float_c3;
+
+
+	unsigned int float_stack_ptr;
+
+	unsigned int reg_float_control;
+
+	unsigned int reg_float_eip;
+	unsigned int reg_float_cs;
+	unsigned int reg_float_address;
+	unsigned int reg_float_ds;
+
+
+	uint64_t tsc;
+
+
+	uint16_t ES;
+	uint16_t CS;
+	uint16_t SS;
+	uint16_t DS;
+	uint16_t FS;
+	uint16_t GS;
+
+	unsigned int cr0;
+	unsigned int cr3;
+
+	uint64_t MM0;
+	uint64_t MM1;
+	uint64_t MM2;
+	uint64_t MM3;
+	uint64_t MM4;
+	uint64_t MM5;
+	uint64_t MM6;
+	uint64_t MM7;
+
+	/* SSE */
+	bn_t XMM0;
+	bn_t XMM1;
+	bn_t XMM2;
+	bn_t XMM3;
+	bn_t XMM4;
+	bn_t XMM5;
+	bn_t XMM6;
+	bn_t XMM7;
+	bn_t XMM8;
+	bn_t XMM9;
+	bn_t XMM10;
+	bn_t XMM11;
+	bn_t XMM12;
+	bn_t XMM13;
+	bn_t XMM14;
+	bn_t XMM15;
+
+	uint64_t segm_base[0x10000];
+
+};
+
+_MIASM_EXPORT void dump_gpregs_32(struct vm_cpu* vmcpu);
+_MIASM_EXPORT void dump_gpregs_64(struct vm_cpu* vmcpu);
+_MIASM_EXPORT uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr);
+
+_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src);
+_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src);
+_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src);
+_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src);
+
+#define RETURN_PC return BlockDst;
diff --git a/src/miasm/jitter/arch/__init__.py b/src/miasm/jitter/arch/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/miasm/jitter/arch/__init__.py
diff --git a/src/miasm/jitter/bn.c b/src/miasm/jitter/bn.c
new file mode 100644
index 00000000..43e552a4
--- /dev/null
+++ b/src/miasm/jitter/bn.c
@@ -0,0 +1,933 @@
+/*
+
+Big number library - arithmetic on multiple-precision unsigned integers.
+
+This library is an implementation of arithmetic on arbitrarily large integers.
+
+The difference between this and other implementations, is that the data structure
+has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM),
+and all memory is allocated statically: no dynamic allocation for better or worse.
+
+Primary goals are correctness, clarity of code and clean, portable implementation.
+Secondary goal is a memory footprint small enough to make it suitable for use in
+embedded applications.
+
+
+The current state is correct functionality and adequate performance.
+There may well be room for performance-optimizations and improvements.
+
+Source: https://github.com/kokke/tiny-bignum-c
+
+Code slightly modified to support ast generation calculus style from Expr.
+
+*/
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <assert.h>
+#include "bn.h"
+
+/* Functions for shifting number in-place. */
+static bn_t _lshift_one_bit(bn_t a);
+static bn_t _rshift_one_bit(bn_t a);
+static bn_t _lshift_word(bn_t a, int nwords);
+static bn_t _rshift_word(bn_t a, int nwords);
+
+
+
+
+/* Public / Exported functions. */
+bn_t bignum_init(void)
+{
+	int i;
+	bn_t n;
+
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		n.array[i] = 0;
+	}
+
+	return n;
+}
+
+
+bn_t bignum_from_int(DTYPE_TMP i)
+{
+	bn_t n;
+
+	n = bignum_init();
+  /* Endianness issue if machine is not little-endian? */
+#ifdef WORD_SIZE
+ #if (WORD_SIZE == 1)
+	n.array[0] = (i & 0x000000ff);
+	n.array[1] = (i & 0x0000ff00) >> 8;
+	n.array[2] = (i & 0x00ff0000) >> 16;
+	n.array[3] = (i & 0xff000000) >> 24;
+ #elif (WORD_SIZE == 2)
+	n.array[0] = (i & 0x0000ffff);
+	n.array[1] = (i & 0xffff0000) >> 16;
+ #elif (WORD_SIZE == 4)
+	n.array[0] = (DTYPE)i;
+	DTYPE_TMP num_32 = 32;
+	DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */
+	n.array[1] = (DTYPE)tmp;
+ #endif
+#endif
+
+	return n;
+}
+
+
+
+bn_t bignum_from_uint64(uint64_t i)
+{
+	bn_t n;
+	n = bignum_init();
+  /* Endianness issue if machine is not little-endian? */
+#ifdef WORD_SIZE
+ #if (WORD_SIZE == 1)
+	n.array[0] = (i & 0x000000ff);
+	n.array[1] = (i & 0x0000ff00) >> 8;
+	n.array[2] = (i & 0x00ff0000) >> 16;
+	n.array[3] = (i & 0xff000000) >> 24;
+ #elif (WORD_SIZE == 2)
+	n.array[0] = (i & 0x0000ffff);
+	n.array[1] = (i & 0xffff0000) >> 16;
+ #elif (WORD_SIZE == 4)
+	n.array[0] = (DTYPE)i;
+	DTYPE_TMP num_32 = 32;
+	DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */
+	n.array[1] = (DTYPE)tmp;
+ #endif
+#endif
+
+	return n;
+}
+
+
+
+
+
+int bignum_to_int(bn_t n)
+{
+
+	int ret = 0;
+
+	/* Endianness issue if machine is not little-endian? */
+#if (WORD_SIZE == 1)
+	ret += n.array[0];
+	ret += n.array[1] << 8;
+	ret += n.array[2] << 16;
+	ret += n.array[3] << 24;
+#elif (WORD_SIZE == 2)
+	ret += n.array[0];
+	ret += n.array[1] << 16;
+#elif (WORD_SIZE == 4)
+	ret += n.array[0];
+#endif
+
+
+	return ret;
+}
+
+
+uint64_t bignum_to_uint64(bn_t n)
+{
+
+	uint64_t ret = 0;
+
+	/* Endianness issue if machine is not little-endian? */
+#if (WORD_SIZE == 1)
+	ret += (uint64_t)(n.array[0]);
+	ret += (uint64_t)(n.array[1]) << 8;
+	ret += (uint64_t)(n.array[2]) << 16;
+	ret += (uint64_t)(n.array[3]) << 24;
+
+	ret += (uint64_t)(n.array[4]) << 32;
+	ret += (uint64_t)(n.array[5]) << 40;
+	ret += (uint64_t)(n.array[6]) << 48;
+	ret += (uint64_t)(n.array[7]) << 56;
+
+
+#elif (WORD_SIZE == 2)
+	ret += (uint64_t)(n.array[0]);
+	ret += (uint64_t)(n.array[1]) << 16;
+	ret += (uint64_t)(n.array[2]) << 32;
+	ret += (uint64_t)(n.array[3]) << 48;
+#elif (WORD_SIZE == 4)
+	ret += n.array[0];
+	ret += (uint64_t)(n.array[1]) << 32;
+#endif
+
+	return ret;
+}
+
+
+
+
+bn_t bignum_from_string(char* str, int nbytes)
+{
+
+	require(str, "str is null");
+	require(nbytes > 0, "nbytes must be positive");
+	require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
+
+	bn_t n;
+
+	n = bignum_init();
+
+	DTYPE tmp;                        /* DTYPE is defined in bn.h - uint{8,16,32,64}_t */
+	int i = nbytes - (2 * WORD_SIZE); /* index into string */
+	int j = 0;                        /* index into array */
+
+	/* reading last hex-byte "MSB" from string first -> big endian */
+	/* MSB ~= most significant byte / block ? :) */
+	while (i >= 0) {
+		tmp = 0;
+		sscanf(&str[i], SSCANF_FORMAT_STR, &tmp);
+		n.array[j] = tmp;
+		i -= (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) back in the string. */
+		j += 1;               /* step one element forward in the array. */
+	}
+
+	return n;
+}
+
+void bignum_to_string(bn_t n, char* str, int nbytes)
+{
+	require(str, "str is null");
+	require(nbytes > 0, "nbytes must be positive");
+	require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
+
+	int j = BN_ARRAY_SIZE - 1; /* index into array - reading "MSB" first -> big-endian */
+	int i = 0;                 /* index into string representation. */
+
+	/* reading last array-element "MSB" first -> big endian */
+	while ((j >= 0) && (nbytes > (i + 1))) {
+		sprintf(&str[i], SPRINTF_FORMAT_STR, n.array[j]);
+		i += (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) forward in the string. */
+		j -= 1;               /* step one element back in the array. */
+	}
+
+	/* Zero-terminate string */
+	str[i] = 0;
+}
+
+
+
+bn_t bignum_dec(bn_t n)
+{
+	//require(n, "n is null");
+
+	DTYPE tmp; /* copy of n */
+	DTYPE res;
+
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		tmp = n.array[i];
+		res = tmp - 1;
+		n.array[i] = res;
+
+		if (!(res > tmp)) {
+			break;
+		}
+	}
+
+	return n;
+}
+
+
+bn_t bignum_inc(bn_t n)
+{
+	//require(n, "n is null");
+
+	DTYPE res;
+	DTYPE tmp; /* copy of n */
+
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		tmp = n.array[i];
+		res = tmp + 1;
+		n.array[i] = res;
+
+		if (res > tmp) {
+			break;
+		}
+	}
+
+	return n;
+}
+
+
+
+bn_t bignum_add(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+	bn_t c;
+
+	DTYPE_TMP tmp;
+	int carry = 0;
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		tmp = (DTYPE_TMP)a.array[i] + b.array[i] + carry;
+		carry = (tmp > MAX_VAL);
+		c.array[i] = (tmp & MAX_VAL);
+	}
+
+	return c;
+}
+
+
+bn_t bignum_sub(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+	bn_t c;
+
+	DTYPE_TMP res;
+	DTYPE_TMP tmp1;
+	DTYPE_TMP tmp2;
+	int borrow = 0;
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		tmp1 = (DTYPE_TMP)a.array[i] + (MAX_VAL + 1); /* + number_base */
+		tmp2 = (DTYPE_TMP)b.array[i] + borrow;;
+		res = (tmp1 - tmp2);
+		c.array[i] = (DTYPE)(res & MAX_VAL); /* "modulo number_base" == "% (number_base - 1)" if number_base is 2^N */
+		borrow = (res <= MAX_VAL);
+	}
+
+	return c;
+}
+
+
+
+
+bn_t bignum_mul(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+
+	bn_t c;
+	bn_t row;
+	bn_t tmp;
+	int i, j;
+
+	c = bignum_init();
+
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		row = bignum_init();
+
+		for (j = 0; j < BN_ARRAY_SIZE; ++j) {
+			if (i + j < BN_ARRAY_SIZE) {
+				tmp = bignum_init();
+				DTYPE_TMP intermediate = ((DTYPE_TMP)a.array[i] * (DTYPE_TMP)b.array[j]);
+				tmp = bignum_from_int(intermediate);
+				tmp = _lshift_word(tmp, i + j);
+				row = bignum_add(tmp, row);
+			}
+		}
+		c = bignum_add(c, row);
+	}
+
+	return c;
+}
+
+
+bn_t bignum_udiv(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+
+	bn_t c;
+	bn_t current;
+	bn_t denom;
+	bn_t tmp;
+
+	current = bignum_from_int(1);               // int current = 1;
+	denom = bignum_assign(b);                   // denom = b
+	tmp = bignum_assign(a);                     // tmp   = a
+
+	const DTYPE_TMP half_max = 1 + (DTYPE_TMP)(MAX_VAL / 2);
+	bool overflow = false;
+
+	while (bignum_cmp(denom, a) != LARGER) {    // while (denom <= a) {
+		if (denom.array[BN_ARRAY_SIZE - 1] >= half_max) {
+			overflow = true;
+			break;
+		}
+		current = _lshift_one_bit(current);                //   current <<= 1;
+		denom = _lshift_one_bit(denom);                  //   denom <<= 1;
+	}
+	if (!overflow) {
+		denom = _rshift_one_bit(denom);                  // denom >>= 1;
+		current = _rshift_one_bit(current);                // current >>= 1;
+	}
+	c = bignum_init();                             // int answer = 0;
+
+	while (!bignum_is_zero(current)) {           // while (current != 0)
+		if (bignum_cmp(tmp, denom) != SMALLER) {  //   if (dividend >= denom)
+			tmp = bignum_sub(tmp, denom);         //     dividend -= denom;
+			c = bignum_or(c, current);              //     answer |= current;
+		}
+		current = _rshift_one_bit(current);                //   current >>= 1;
+		denom = _rshift_one_bit(denom);                  //   denom >>= 1;
+	}                                           // return answer;
+
+	return c;
+}
+
+
+
+bn_t bignum_lshift(bn_t a, int nbits)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	require(nbits >= 0, "no negative shifts");
+
+	bn_t b;
+
+	b = bignum_assign(a);
+	/* Handle shift in multiples of word-size */
+	const int nbits_pr_word = (WORD_SIZE * 8);
+	int nwords = nbits / nbits_pr_word;
+	if (nwords != 0) {
+		b = _lshift_word(b, nwords);
+		nbits -= (nwords * nbits_pr_word);
+	}
+
+	if (nbits != 0) {
+		int i;
+		for (i = (BN_ARRAY_SIZE - 1); i > 0; --i) {
+			b.array[i] = (b.array[i] << nbits) | (b.array[i - 1] >> ((8 * WORD_SIZE) - nbits));
+		}
+		b.array[i] <<= nbits;
+	}
+
+	return b;
+}
+
+
+bn_t bignum_rshift(bn_t a, int nbits)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	require(nbits >= 0, "no negative shifts");
+
+	bn_t b;
+
+	b = bignum_assign(a);
+	/* Handle shift in multiples of word-size */
+	const int nbits_pr_word = (WORD_SIZE * 8);
+	int nwords = nbits / nbits_pr_word;
+
+	if (nwords != 0) {
+		b = _rshift_word(b, nwords);
+		nbits -= (nwords * nbits_pr_word);
+	}
+	if (nbits != 0) {
+		int i;
+		for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i) {
+			b.array[i] = (b.array[i] >> nbits) | (b.array[i + 1] << ((8 * WORD_SIZE) - nbits));
+		}
+		b.array[i] >>= nbits;
+	}
+
+	return b;
+}
+
+
+
+bn_t bignum_a_rshift(bn_t a, int size, int nbits)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	require(nbits >= 0, "no negative shifts");
+	require(size > 0, "no negative shifts");
+
+	bn_t b;
+	bn_t tmp, mask;
+
+	b = bignum_rshift(a, nbits);
+
+	/* get sign bit */
+	tmp = bignum_rshift(a, size - 1);
+	tmp = bignum_mask(tmp, 1);
+
+	if (!bignum_is_zero(tmp)) {
+		/* generate sign propag */
+		tmp = bignum_from_int(1);
+		tmp = bignum_lshift(tmp, size);
+		tmp = bignum_dec(tmp);
+
+		mask = bignum_from_int(1);
+		mask = bignum_lshift(mask, size - nbits);
+		mask = bignum_dec(mask);
+
+		tmp = bignum_xor(tmp, mask);
+		b = bignum_or(b, tmp);
+	}
+
+	return b;
+}
+
+bn_t bignum_not(bn_t a)
+{
+	int i;
+	bn_t b;
+
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		b.array[i] = ~a.array[i];
+	}
+
+	return b;
+}
+
+
+
+bn_t bignum_umod(bn_t a, bn_t b)
+{
+	/*
+	  Take divmod and throw away div part
+	*/
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+
+	bn_t c, d;
+	bn_t tmp;
+
+	/* c = (a / b) */
+	c = bignum_udiv(a, b);
+	/* tmp = (c * b) */
+	tmp = bignum_mul(c, b);
+	/* c = a - tmp */
+	d = bignum_sub(a, tmp);
+	return d;
+}
+
+
+bn_t bignum_and(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+	bn_t c;
+
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		c.array[i] = (a.array[i] & b.array[i]);
+	}
+
+	return c;
+}
+
+
+bn_t bignum_or(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+	bn_t c;
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		c.array[i] = (a.array[i] | b.array[i]);
+	}
+
+	return c;
+}
+
+
+bn_t bignum_xor(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+	//require(c, "c is null");
+
+	bn_t c;
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		c.array[i] = (a.array[i] ^ b.array[i]);
+	}
+	return c;
+}
+
+
+int bignum_cmp(bn_t a, bn_t b)
+{
+	//require(a, "a is null");
+	//require(b, "b is null");
+
+	int i = BN_ARRAY_SIZE;
+	do {
+		i -= 1; /* Decrement first, to start with last array element */
+		if (a.array[i] > b.array[i]) {
+			return LARGER;
+		}
+		else if (a.array[i] < b.array[i]) {
+			return SMALLER;
+		}
+	}
+	while (i != 0);
+
+	return EQUAL;
+}
+
+
+/* Signed compare bn */
+int bignum_cmp_signed(bn_t a, bn_t b)
+{
+	int i = BN_ARRAY_SIZE;
+	do {
+		i -= 1; /* Decrement first, to start with last array element */
+		if ((DTYPE_SIGNED)a.array[i] > (DTYPE_SIGNED)b.array[i]) {
+			return LARGER;
+		}
+		else if ((DTYPE_SIGNED)a.array[i] < (DTYPE_SIGNED)b.array[i]) {
+			return SMALLER;
+		}
+	}
+	while (i != 0);
+
+	return EQUAL;
+}
+
+
+/* Unsigned compare bn */
+int bignum_cmp_unsigned(bn_t a, bn_t b)
+{
+	return bignum_cmp(a, b);
+}
+
+
+/* Return 1 if a == b else 0 */
+int bignum_is_equal(bn_t a, bn_t b)
+{
+	int ret;
+	ret = bignum_cmp_unsigned(a, b);
+	if (ret == EQUAL)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* Return 1 if a <u b else 0 */
+int bignum_is_inf_unsigned(bn_t a, bn_t b)
+{
+	int ret;
+	ret = bignum_cmp_unsigned(a, b);
+	if (ret == SMALLER)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* Return 1 if a <=u b else 0 */
+int bignum_is_inf_equal_unsigned(bn_t a, bn_t b)
+{
+	int ret;
+	ret = bignum_cmp_unsigned(a, b);
+	if (ret == EQUAL || ret == SMALLER)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* Return 1 if a <s b else 0 */
+int bignum_is_inf_signed(bn_t a, bn_t b)
+{
+	int ret;
+	ret = bignum_cmp_signed(a, b);
+	if (ret == SMALLER)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* Return 1 if a <=s b else 0 */
+int bignum_is_inf_equal_signed(bn_t a, bn_t b)
+{
+	int ret;
+	ret = bignum_cmp_signed(a, b);
+	if (ret == EQUAL || ret == SMALLER)
+		return 1;
+	else
+		return 0;
+}
+
+
+int bignum_is_zero(bn_t n)
+{
+	//require(n, "n is null");
+
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		if (n.array[i]) {
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+
+
+bn_t bignum_assign(bn_t src)
+{
+	//require(dst, "dst is null");
+	//require(src, "src is null");
+	bn_t dst;
+
+	int i;
+	for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+		dst.array[i] = src.array[i];
+	}
+
+	return dst;
+}
+
+
+bn_t bignum_mask(bn_t src, int bits)
+{
+	bn_t dst;
+	bn_t mask;
+
+	mask = bignum_from_int(0);
+	mask = bignum_dec(mask);
+	mask = bignum_rshift(mask, BN_BIT_SIZE - bits);
+	dst = bignum_and(src, mask);
+	return dst;
+}
+
+/* Private / Static functions. */
+static bn_t _rshift_word(bn_t a, int nwords)
+{
+	/* Naive method: */
+	//require(a, "a is null");
+	int i;
+
+	require(nwords >= 0, "no negative shifts");
+
+	if (nwords >= BN_ARRAY_SIZE) {
+		for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+			a.array[i] = 0;
+		}
+		return a;
+	}
+
+	for (i = 0; i < BN_ARRAY_SIZE - nwords; ++i) {
+		a.array[i] = a.array[i + nwords];
+	}
+
+	for (; i < BN_ARRAY_SIZE; ++i) {
+		a.array[i] = 0;
+	}
+
+	return a;
+}
+
+
+static bn_t _lshift_word(bn_t a, int nwords)
+{
+	//require(a, "a is null");
+	require(nwords >= 0, "no negative shifts");
+
+	int i;
+
+	if (nwords >= BN_ARRAY_SIZE) {
+		for (i = 0; i < BN_ARRAY_SIZE; ++i) {
+			a.array[i] = 0;
+		}
+		return a;
+	}
+
+	/* Shift whole words */
+	for (i = (BN_ARRAY_SIZE - 1); i >= nwords; --i) {
+		a.array[i] = a.array[i - nwords];
+	}
+	/* Zero pad shifted words. */
+	for (; i >= 0; --i) {
+		a.array[i] = 0;
+	}
+
+	return a;
+}
+
+
+static bn_t _lshift_one_bit(bn_t a)
+{
+	//require(a, "a is null");
+
+	int i;
+	for (i = (BN_ARRAY_SIZE - 1); i > 0; --i) {
+		a.array[i] = (a.array[i] << 1) | (a.array[i - 1] >> ((8 * WORD_SIZE) - 1));
+	}
+	a.array[0] <<= 1;
+
+	return a;
+}
+
+
+static bn_t _rshift_one_bit(bn_t a)
+{
+	//require(a, "a is null");
+
+	int i;
+	for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i) {
+		a.array[i] = (a.array[i] >> 1) | (a.array[i + 1] << ((8 * WORD_SIZE) - 1));
+	}
+	a.array[BN_ARRAY_SIZE - 1] >>= 1;
+
+	return a;
+}
+
+
+bn_t bignum_rol(bn_t a, int size, int nbits)
+{
+	bn_t c;
+
+	c = bignum_or(
+		      bignum_lshift(a, nbits),
+		      bignum_rshift(a, size - nbits)
+		      );
+	c = bignum_mask(c, size);
+	return c;
+}
+
+
+bn_t bignum_ror(bn_t a, int size, int nbits)
+{
+	bn_t c;
+
+	c = bignum_or(
+		      bignum_rshift(a, nbits),
+		      bignum_lshift(a, size - nbits)
+		      );
+	c = bignum_mask(c, size);
+	return c;
+}
+
+
+int bignum_getbit(bn_t a, int pos)
+{
+	int d_pos, bit_pos;
+
+	require(pos < BN_BIT_SIZE, "size must be below bignum max size");
+
+	d_pos = pos / (sizeof(DTYPE) * 8);
+	bit_pos = pos % (sizeof(DTYPE) * 8);
+	return !!(a.array[d_pos] & (1 << bit_pos));
+
+}
+
+
+
+/*
+ * Count leading zeros - count the number of zero starting at the most
+ * significant bit
+ *
+ * Example:
+ * - cntleadzeros(size=32, src=2): 30
+ * - cntleadzeros(size=32, src=0): 32
+ */
+int bignum_cntleadzeros(bn_t n, int size)
+{
+	int i;
+
+	require(size, "size must be greater than 0");
+	require(size <= BN_BIT_SIZE, "size must be below bignum max size");
+
+	for (i = 0; i < size; i++) {
+		if (bignum_getbit(n, size - i - 1))
+			break;
+	}
+
+	return i;
+}
+
+
+
+/*
+ * Count trailing zeros - count the number of zero starting at the least
+ * significant bit
+ *
+ * Example:
+ * - cnttrailzeros(size=32, src=2): 1
+ * - cnttrailzeros(size=32, src=0): 32
+ */
+int bignum_cnttrailzeros(bn_t n, int size)
+{
+	int i;
+
+	require(size, "size must be greater than 0");
+	require(size <= BN_BIT_SIZE, "size must be below bignum max size");
+
+	for (i = 0; i < size; i++) {
+		if (bignum_getbit(n, i))
+			break;
+	}
+
+	return i;
+}
+
+
+
+
+bn_t bignum_sdiv(bn_t a, bn_t b, int size)
+{
+	require(size, "size must be greater than 0");
+	require(size <= BN_BIT_SIZE, "size must be below bignum max size");
+
+	int a_sign, b_sign;
+	bn_t c;
+
+	a_sign = bignum_getbit(a, size - 1);
+	b_sign = bignum_getbit(b, size - 1);
+
+	if (a_sign) {
+		/* neg a */
+		printf("a neg\n");
+		a = bignum_sub(bignum_from_int(0), a);
+		a = bignum_mask(a, size - 1);
+	}
+
+	if (b_sign) {
+		/* neg b */
+		printf("b neg\n");
+		b = bignum_sub(bignum_from_int(0), b);
+		b = bignum_mask(b, size - 1);
+	}
+
+	c = bignum_udiv(a, b);
+	if (a_sign ^ b_sign) {
+		c = bignum_sub(bignum_from_int(0), c);
+	}
+
+	c = bignum_mask(c, size);
+	return c;
+}
+
+
+
+bn_t bignum_smod(bn_t a, bn_t b, int size)
+{
+	require(size, "size must be greater than 0");
+	require(size <= BN_BIT_SIZE, "size must be below bignum max size");
+
+	bn_t c;
+
+	c = bignum_sdiv(a, b, size);
+	c = bignum_mul(c, b);
+	c = bignum_sub(a, c);
+	c = bignum_mask(c, size);
+	return c;
+}
diff --git a/src/miasm/jitter/bn.h b/src/miasm/jitter/bn.h
new file mode 100644
index 00000000..8c4a8ba1
--- /dev/null
+++ b/src/miasm/jitter/bn.h
@@ -0,0 +1,163 @@
+#ifndef __BIGNUM_H__
+#define __BIGNUM_H__
+
+#if _WIN32
+#define _MIASM_EXPORT __declspec(dllexport)
+#else
+#define _MIASM_EXPORT
+#endif
+
+/*
+
+Big number library - arithmetic on multiple-precision unsigned integers.
+
+This library is an implementation of arithmetic on arbitrarily large integers.
+
+The difference between this and other implementations, is that the data structure
+has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM),
+and all memory is allocated statically: no dynamic allocation for better or worse.
+
+Primary goals are correctness, clarity of code and clean, portable implementation.
+Secondary goal is a memory footprint small enough to make it suitable for use in
+embedded applications.
+
+
+The current state is correct functionality and adequate performance.
+There may well be room for performance-optimizations and improvements.
+
+Source: https://github.com/kokke/tiny-bignum-c
+
+Code slightly modified to support ast generation calculus style from Expr.
+
+*/
+
+#include <stdint.h>
+#include <assert.h>
+
+
+/* This macro defines the word size in bytes of the array that constitutes the big-number data structure. */
+#ifndef WORD_SIZE
+  #define WORD_SIZE 4
+#endif
+
+#define BN_BYTE_SIZE 32
+
+#define BN_BIT_SIZE ((BN_BYTE_SIZE) * 8)
+
+/* Size of big-numbers in bytes */
+//#define BN_ARRAY_SIZE    (128 / WORD_SIZE)
+#define BN_ARRAY_SIZE    (BN_BYTE_SIZE / WORD_SIZE)
+
+
+/* Here comes the compile-time specialization for how large the underlying array size should be. */
+/* The choices are 1, 2 and 4 bytes in size with uint32, uint64 for WORD_SIZE==4, as temporary. */
+#ifndef WORD_SIZE
+  #error Must define WORD_SIZE to be 1, 2, 4
+#elif (WORD_SIZE == 1)
+  /* Data type of array in structure */
+  #define DTYPE                    uint8_t
+  #define DTYPE_SIGNED             int8_t
+  /* bitmask for getting MSB */
+  #define DTYPE_MSB                ((DTYPE_TMP)(0x80))
+  /* Data-type larger than DTYPE, for holding intermediate results of calculations */
+  #define DTYPE_TMP                uint32_t
+  /* sprintf format string */
+  #define SPRINTF_FORMAT_STR       "%.02x"
+  #define SSCANF_FORMAT_STR        "%2hhx"
+  /* Max value of integer type */
+  #define MAX_VAL                  ((DTYPE_TMP)0xFF)
+#elif (WORD_SIZE == 2)
+  #define DTYPE                    uint16_t
+  #define DTYPE_SIGNED             int16_t
+  #define DTYPE_TMP                uint32_t
+  #define DTYPE_MSB                ((DTYPE_TMP)(0x8000))
+  #define SPRINTF_FORMAT_STR       "%.04x"
+  #define SSCANF_FORMAT_STR        "%4hx"
+  #define MAX_VAL                  ((DTYPE_TMP)0xFFFF)
+#elif (WORD_SIZE == 4)
+  #define DTYPE                    uint32_t
+  #define DTYPE_SIGNED             int32_t
+  #define DTYPE_TMP                uint64_t
+  #define DTYPE_MSB                ((DTYPE_TMP)(0x80000000))
+  #define SPRINTF_FORMAT_STR       "%.08x"
+  #define SSCANF_FORMAT_STR        "%8x"
+  #define MAX_VAL                  ((DTYPE_TMP)0xFFFFFFFF)
+#endif
+#ifndef DTYPE
+  #error DTYPE must be defined to uint8_t, uint16_t uint32_t or whatever
+#endif
+
+
+/* Custom assert macro - easy to disable */
+#define require(p, msg) assert(p && #msg)
+
+
+/* Data-holding structure: array of DTYPEs */
+typedef struct bn
+{
+  DTYPE array[BN_ARRAY_SIZE];
+} bn_t;
+
+
+
+/* Tokens returned by bignum_cmp() for value comparison */
+enum { SMALLER = -1, EQUAL = 0, LARGER = 1 };
+
+/* Initialization functions: */
+_MIASM_EXPORT bn_t bignum_init(void);
+_MIASM_EXPORT bn_t bignum_from_int(DTYPE_TMP i);
+_MIASM_EXPORT bn_t bignum_from_uint64(uint64_t i);
+_MIASM_EXPORT int  bignum_to_int(bn_t n);
+_MIASM_EXPORT uint64_t bignum_to_uint64(bn_t n);
+_MIASM_EXPORT bn_t bignum_from_string(char* str, int nbytes);
+_MIASM_EXPORT void bignum_to_string(bn_t n, char* str, int maxsize);
+
+
+/* Basic arithmetic operations: */
+_MIASM_EXPORT bn_t bignum_add(bn_t a, bn_t b); /* c = a + b */
+_MIASM_EXPORT bn_t bignum_sub(bn_t a, bn_t b); /* c = a - b */
+_MIASM_EXPORT bn_t bignum_mul(bn_t a, bn_t b); /* c = a * b */
+_MIASM_EXPORT bn_t bignum_udiv(bn_t a, bn_t b); /* c = a / b */
+_MIASM_EXPORT bn_t bignum_umod(bn_t a, bn_t b); /* c = a % b */
+_MIASM_EXPORT bn_t bignum_sdiv(bn_t a, bn_t b, int size);
+_MIASM_EXPORT bn_t bignum_smod(bn_t a, bn_t b, int size);
+//void bignum_udivmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */
+
+
+
+/* Bitwise operations: */
+_MIASM_EXPORT bn_t bignum_and(bn_t a, bn_t b); /* c = a & b */
+_MIASM_EXPORT bn_t bignum_or(bn_t a, bn_t b);  /* c = a | b */
+_MIASM_EXPORT bn_t bignum_xor(bn_t a, bn_t b); /* c = a ^ b */
+_MIASM_EXPORT bn_t bignum_lshift(bn_t a, int nbits); /* b = a << nbits */
+_MIASM_EXPORT bn_t bignum_rshift(bn_t a, int nbits); /* b = a >> nbits */
+_MIASM_EXPORT bn_t bignum_a_rshift(bn_t a, int size, int nbits); /* b = a a>> nbits */
+_MIASM_EXPORT bn_t bignum_not(bn_t a); /* c = ~a */
+
+/* Special operators and comparison */
+_MIASM_EXPORT int bignum_cmp(bn_t a, bn_t b);                      /* Compare: returns LARGER, EQUAL or SMALLER */
+_MIASM_EXPORT int bignum_is_equal(bn_t a, bn_t b);                 /* Return 1 if a == b else 0 */
+_MIASM_EXPORT int bignum_is_inf_unsigned(bn_t a, bn_t b);          /* Return 1 if a <u b else 0 */
+_MIASM_EXPORT int bignum_is_inf_equal_unsigned(bn_t a, bn_t b);    /* Return 1 if a <=u b else 0 */
+_MIASM_EXPORT int bignum_is_inf_signed(bn_t a, bn_t b);            /* Return 1 if a <s b else 0 */
+_MIASM_EXPORT int bignum_is_inf_equal_signed(bn_t a, bn_t b);      /* Return 1 if a <=s b else 0 */
+
+
+
+_MIASM_EXPORT int  bignum_is_zero(bn_t n);                         /* For comparison with zero */
+_MIASM_EXPORT bn_t bignum_inc(bn_t n);                             /* Increment: add one to n */
+_MIASM_EXPORT bn_t bignum_dec(bn_t n);                             /* Decrement: subtract one from n */
+//bn_t bignum_pow(bn_t a, bn_t b, bn_t c); /* Calculate a^b -- e.g. 2^10 => 1024 */
+//bn_t bignum_isqrt(bn_t a, bn_t b);             /* Integer square root -- e.g. isqrt(5) => 2*/
+_MIASM_EXPORT int bignum_cntleadzeros(bn_t n, int size);
+_MIASM_EXPORT int bignum_cnttrailzeros(bn_t n, int size);
+_MIASM_EXPORT bn_t bignum_assign(bn_t src);        /* Copy src into dst -- dst := src */
+_MIASM_EXPORT bn_t bignum_mask(bn_t src, int bits);  /*  c = src & ((1<<bits) -1) */
+
+_MIASM_EXPORT bn_t bignum_rol(bn_t a, int size, int nbits);
+_MIASM_EXPORT bn_t bignum_ror(bn_t a, int size, int nbits);
+_MIASM_EXPORT int bignum_getbit(bn_t a, int pos);
+
+#endif /* #ifndef __BIGNUM_H__ */
+
+
diff --git a/src/miasm/jitter/codegen.py b/src/miasm/jitter/codegen.py
new file mode 100644
index 00000000..305d6c36
--- /dev/null
+++ b/src/miasm/jitter/codegen.py
@@ -0,0 +1,656 @@
+"""
+Module to generate C code for a given native @block
+"""
+
+from builtins import zip
+import warnings
+
+from future.utils import viewitems, viewvalues
+
+from miasm.expression.expression import ExprId, ExprLoc, ExprInt, \
+    ExprMem, ExprCond, LocKey, is_expr
+from miasm.ir.ir import IRBlock, AssignBlock
+
+from miasm.ir.translators.C import TranslatorC
+from miasm.core.asmblock import AsmBlockBad
+from miasm.expression.simplifications import expr_simp_high_to_explicit
+
+TRANSLATOR_NO_SYMBOL = TranslatorC(loc_db=None)
+
+SIZE_TO_MASK = {size: TRANSLATOR_NO_SYMBOL.from_expr(ExprInt(0, size).mask)
+                for size in (1, 2, 3, 7, 8, 16, 32, 64)}
+
+
+
+
+
+
+class Attributes(object):
+
+    """
+    Store an irblock attributes
+    """
+
+    def __init__(self, log_mn=False, log_regs=False):
+        self.mem_read = False
+        self.mem_write = False
+        self.set_exception = False
+        self.log_mn = log_mn
+        self.log_regs = log_regs
+        self.instr = None
+
+
+class CGen(object):
+    """
+    Helper to generate C code for a given AsmBlock
+    """
+
+    """
+    Translate native assembly block to C
+    """
+
+    CODE_EXCEPTION_MEM_AT_INSTR = r"""
+    // except fetch mem at instr noauto
+    if ((VM_exception_flag & ~EXCEPT_CODE_AUTOMOD) & EXCEPT_DO_NOT_UPDATE_PC) {
+        %s = %s;
+        BlockDst->address = %s;
+        return JIT_RET_EXCEPTION;
+    }
+    """
+
+    CODE_EXCEPTION_AT_INSTR = r"""
+    if (CPU_exception_flag_at_instr) {
+        %s = %s;
+        BlockDst->address = %s;
+        return JIT_RET_EXCEPTION;
+    }
+    """
+
+    CODE_RETURN_EXCEPTION = r"""
+    return JIT_RET_EXCEPTION;
+    """
+
+    CODE_RETURN_NO_EXCEPTION = r"""
+    %s:
+    %s = %s;
+    BlockDst->address = %s;
+    return JIT_RET_NO_EXCEPTION;
+    """
+
+    CODE_CPU_EXCEPTION_POST_INSTR = r"""
+    if (CPU_exception_flag) {
+        %s = DST_value;
+        BlockDst->address = DST_value;
+        return JIT_RET_EXCEPTION;
+    }
+    """
+
+    CODE_VM_EXCEPTION_POST_INSTR = r"""
+    check_memory_breakpoint(&(jitcpu->pyvm->vm_mngr));
+    check_invalid_code_blocs(&(jitcpu->pyvm->vm_mngr));
+    if (VM_exception_flag) {
+        %s = DST_value;
+        BlockDst->address = DST_value;
+        return JIT_RET_EXCEPTION;
+    }
+    """
+
+    CODE_INIT = r"""
+    int DST_case;
+    uint64_t DST_value;
+    struct vm_cpu *mycpu = jitcpu->cpu;
+
+    goto %s;
+    """
+
+    CODE_BAD_BLOCK = r"""
+    // Unknown mnemonic
+    CPU_exception_flag = EXCEPT_UNK_MNEMO;
+    """ + CODE_RETURN_EXCEPTION
+
+    def __init__(self, lifter):
+        self.lifter = lifter
+        self.PC = self.lifter.pc
+        self.translator = TranslatorC(self.lifter.loc_db)
+        self.init_arch_C()
+
+    @property
+    def ir_arch(self):
+        warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"')
+        return self.lifter
+
+    def init_arch_C(self):
+        """Iinitialize jitter internals"""
+        self.id_to_c_id = {}
+        for reg in self.lifter.arch.regs.all_regs_ids:
+            self.id_to_c_id[reg] = ExprId('mycpu->%s' % reg, reg.size)
+
+        self.C_PC = self.id_to_c(self.PC)
+
+    def dst_to_c(self, src):
+        """Translate Expr @src into C code"""
+        if not is_expr(src):
+            src = ExprInt(src, self.PC.size)
+        return self.id_to_c(src)
+
+    def patch_c_id(self, expr):
+        """Replace ExprId in @expr with corresponding C variables"""
+        return expr.replace_expr(self.id_to_c_id)
+
+    def id_to_c(self, expr):
+        """Translate Expr @expr into corresponding C code"""
+        return self.translator.from_expr(self.patch_c_id(expr))
+
+    def add_label_index(self, dst2index, loc_key):
+        """Insert @lbl to the dictionary @dst2index with a uniq value
+        @dst2index: LocKey -> uniq value
+        @loc_key: LocKey instance"""
+
+        if loc_key not in dst2index:
+            dst2index[loc_key] = len(dst2index)
+
+    def assignblk_to_irbloc(self, instr, assignblk):
+        """
+        Ensure IRDst is always set in the head @assignblk of the @instr
+        @instr: an instruction instance
+        @assignblk: Assignblk instance
+        """
+        new_assignblk = dict(assignblk)
+        if self.lifter.IRDst not in assignblk:
+            offset = instr.offset + instr.l
+            loc_key = self.lifter.loc_db.get_or_create_offset_location(offset)
+            dst = ExprLoc(loc_key, self.lifter.IRDst.size)
+            new_assignblk[self.lifter.IRDst] = dst
+        irs = [AssignBlock(new_assignblk, instr)]
+        return IRBlock(self.lifter.loc_db, self.lifter.get_loc_key_for_instr(instr), irs)
+
+    def block2assignblks(self, block):
+        """
+        Return the list of irblocks for a native @block
+        @block: AsmBlock
+        """
+        irblocks_list = []
+        for instr in block.lines:
+            assignblk_head, assignblks_extra = self.lifter.instr2ir(instr)
+            # Keep result in ordered list as first element is the assignblk head
+            # The remainings order is not really important
+            irblock_head = self.assignblk_to_irbloc(instr, assignblk_head)
+            irblocks = [irblock_head] + assignblks_extra
+
+            # Simplify high level operators
+            out = []
+            for irblock in irblocks:
+                new_irblock = self.lifter.irbloc_fix_regs_for_mode(irblock, self.lifter.attrib)
+                new_irblock = new_irblock.simplify(expr_simp_high_to_explicit)[1]
+                out.append(new_irblock)
+            irblocks = out
+
+            for irblock in irblocks:
+                assert irblock.dst is not None
+            irblocks_list.append(irblocks)
+
+        return irblocks_list
+
+    def add_local_var(self, dst_var, dst_index, expr):
+        """
+        Add local variable used to store temporary result
+        @dst_var: dictionary of Expr -> local_var_expr
+        @dst_index : dictionary of size -> local var count
+        @expr: Expression source
+        """
+        size = expr.size
+        if size < 8:
+            size = 8
+        if size not in dst_index:
+            raise RuntimeError("Unsupported operand size %s", size)
+        var_num = dst_index[size]
+        dst = ExprId("var_%.2d_%.2d" % (size, var_num), size)
+        dst_index[size] += 1
+        dst_var[expr] = dst
+        return dst
+
+    def get_mem_prefetch(self, assignblk):
+        """
+        Generate temporary variables used to fetch memory used in the @assignblk
+        Return a dictionary: ExprMem -> temporary variable
+        @assignblk: AssignBlock instance
+        """
+        mem_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0}
+        mem_var = {}
+
+        # Prefetch memory read
+        for expr in assignblk.get_r(mem_read=True):
+            if not isinstance(expr, ExprMem):
+                continue
+            var_num = mem_index[expr.size]
+            mem_index[expr.size] += 1
+            var = ExprId(
+                "prefetch_%.2d_%.2d" % (expr.size, var_num), expr.size
+            )
+            mem_var[expr] = var
+
+        # Generate memory prefetch
+        return mem_var
+
+    def gen_c_assignments(self, assignblk):
+        """
+        Return C information used to generate the C code of the @assignblk
+        @assignblk: an AssignBlock instance
+        """
+        c_var = []
+        c_main = []
+        c_mem = []
+        c_updt = []
+        c_prefetch = []
+
+        dst_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0}
+        dst_var = {}
+
+        prefetchers = self.get_mem_prefetch(assignblk)
+
+        for expr, prefetcher in viewitems(prefetchers):
+            str_src = self.id_to_c(expr)
+            str_dst = self.id_to_c(prefetcher)
+            c_prefetch.append('%s = %s;' % (str_dst, str_src))
+
+        for var in viewvalues(prefetchers):
+            if var.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                c_var.append("uint%d_t %s;" % (var.size, var))
+            else:
+                c_var.append("bn_t %s; // %d" % (var, var.size))
+
+        for dst, src in viewitems(assignblk):
+            src = src.replace_expr(prefetchers)
+            if dst == self.lifter.IRDst:
+                pass
+            elif isinstance(dst, ExprId):
+                new_dst = self.add_local_var(dst_var, dst_index, dst)
+                if dst in self.lifter.arch.regs.regs_flt_expr:
+                    # Don't mask float assignment
+                    c_main.append(
+                        '%s = (%s);' % (self.id_to_c(new_dst), self.id_to_c(src)))
+                elif new_dst.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                    c_main.append(
+                        '%s = (%s)&%s;' % (self.id_to_c(new_dst),
+                                           self.id_to_c(src),
+                                           SIZE_TO_MASK[src.size]))
+                else:
+                    c_main.append(
+                        '%s = bignum_mask(%s, %d);' % (
+                            self.id_to_c(new_dst),
+                            self.id_to_c(src),
+                            src.size
+                        )
+                    )
+            elif isinstance(dst, ExprMem):
+                ptr = dst.ptr.replace_expr(prefetchers)
+                if ptr.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                    new_dst = ExprMem(ptr, dst.size)
+                    str_dst = self.id_to_c(new_dst).replace('MEM_LOOKUP', 'MEM_WRITE')
+                    c_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src)))
+                else:
+                    ptr_str = self.id_to_c(ptr)
+                    if ptr.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                        c_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src)))
+                    else:
+                        if src.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                            c_mem.append('MEM_WRITE_BN_INT(jitcpu, %d, %s, %s);' % (
+                                src.size, ptr_str, self.id_to_c(src))
+                            )
+                        else:
+                            c_mem.append('MEM_WRITE_BN_BN(jitcpu, %d, %s, %s);' % (
+                                src.size, ptr_str, self.id_to_c(src))
+                            )
+            else:
+                raise ValueError("Unknown dst")
+
+        for dst, new_dst in viewitems(dst_var):
+            if dst == self.lifter.IRDst:
+                continue
+
+            c_updt.append('%s = %s;' % (self.id_to_c(dst), self.id_to_c(new_dst)))
+            if dst.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                c_var.append("uint%d_t %s;" % (new_dst.size, new_dst))
+            else:
+                c_var.append("bn_t %s; // %d" % (new_dst, new_dst.size))
+
+        return c_prefetch, c_var, c_main, c_mem, c_updt
+
+    def gen_check_memory_exception(self, address):
+        """Generate C code to check memory exceptions
+        @address: address of the faulty instruction"""
+        dst = self.dst_to_c(address)
+        return (self.CODE_EXCEPTION_MEM_AT_INSTR % (self.C_PC, dst, dst)).split('\n')
+
+    def gen_check_cpu_exception(self, address):
+        """Generate C code to check cpu exceptions
+        @address: address of the faulty instruction"""
+        dst = self.dst_to_c(address)
+        return (self.CODE_EXCEPTION_AT_INSTR % (self.C_PC, dst, dst)).split('\n')
+
+    def traverse_expr_dst(self, expr, dst2index):
+        """
+        Generate the index of the destination label for the @expr
+        @dst2index: dictionary to link label to its index
+        """
+
+        if isinstance(expr, ExprCond):
+            src1, src1b = self.traverse_expr_dst(expr.src1, dst2index)
+            src2, src2b = self.traverse_expr_dst(expr.src2, dst2index)
+            cond = self.id_to_c(expr.cond)
+            if not expr.cond.size <= self.translator.NATIVE_INT_MAX_SIZE:
+                cond = "(!bignum_is_zero(%s))" % cond
+
+            return ("((%s)?(%s):(%s))" % (cond, src1, src2),
+                    "((%s)?(%s):(%s))" % (cond, src1b, src2b))
+        if isinstance(expr, ExprInt):
+            offset = int(expr)
+            loc_key = self.lifter.loc_db.get_or_create_offset_location(offset)
+            self.add_label_index(dst2index, loc_key)
+            out = hex(offset)
+            return ("%s" % dst2index[loc_key], out)
+        if expr.is_loc():
+            loc_key = expr.loc_key
+            offset = self.lifter.loc_db.get_location_offset(expr.loc_key)
+            if offset is not None:
+                self.add_label_index(dst2index, loc_key)
+                out = hex(offset)
+                return ("%s" % dst2index[loc_key], out)
+            self.add_label_index(dst2index, loc_key)
+            out = hex(0)
+            return ("%s" % dst2index[loc_key], out)
+        dst2index[expr] = -1
+        return ("-1", self.id_to_c(expr))
+
+    def gen_assignblk_dst(self, dst):
+        """Generate C code to handle instruction destination
+        @dst: instruction destination Expr"""
+        dst2index = {}
+        (ret, retb) = self.traverse_expr_dst(dst, dst2index)
+        ret = "DST_case = %s;" % ret
+        retb = 'DST_value = %s;' % retb
+        return ['// %s' % dst2index,
+                '%s' % ret,
+                '%s' % retb], dst2index
+
+    def gen_post_instr_checks(self, attrib):
+        """Generate C code for handling potential exceptions
+        @attrib: Attributes instance"""
+        out = []
+        if attrib.mem_read | attrib.mem_write:
+            out += (self.CODE_VM_EXCEPTION_POST_INSTR % (self.C_PC)).split('\n')
+        if attrib.set_exception:
+            out += (self.CODE_CPU_EXCEPTION_POST_INSTR % (self.C_PC)).split('\n')
+
+        if attrib.mem_read | attrib.mem_write:
+            out.append("reset_memory_access(&(jitcpu->pyvm->vm_mngr));")
+
+        return out
+
+    def gen_pre_code(self, instr_attrib):
+        """Callback to generate code BEFORE the instruction execution
+        @instr_attrib: Attributes instance"""
+
+        out = []
+
+        if instr_attrib.log_mn:
+            out.append(
+                'printf("%.8X %s\\n");' % (
+                    instr_attrib.instr.offset,
+                    instr_attrib.instr.to_string(self.lifter.loc_db)
+                )
+            )
+        return out
+
+    def gen_post_code(self, attrib, pc_value):
+        """Callback to generate code AFTER the instruction execution
+        @attrib: Attributes instance"""
+        out = []
+        if attrib.log_regs:
+            # Update PC for dump_gpregs
+            out.append("%s = %s;" % (self.C_PC, pc_value))
+            out.append('dump_gpregs(jitcpu->cpu);')
+        return out
+
+    def gen_goto_code(self, attrib, instr_offsets, dst):
+        """Generate C code for a potential destination @dst
+        @attrib: instruction Attributes
+        @instr_offsets: instructions offsets list
+        @dst: potential instruction destination"""
+
+        out = []
+        if is_expr(dst):
+            out += self.gen_post_code(attrib, "DST_value")
+            out.append('BlockDst->address = DST_value;')
+            out += self.gen_post_instr_checks(attrib)
+            out.append('\t\treturn JIT_RET_NO_EXCEPTION;')
+            return out
+
+        assert isinstance(dst, LocKey)
+        offset = self.lifter.loc_db.get_location_offset(dst)
+        if offset is None:
+            # Generate goto for local labels
+            return ['goto %s;' % dst]
+        if (offset > attrib.instr.offset and
+            offset in instr_offsets):
+            # Only generate goto for next instructions.
+            # (consecutive instructions)
+            out += self.gen_post_code(attrib, "0x%x" % offset)
+            out += self.gen_post_instr_checks(attrib)
+            out.append('goto %s;' % dst)
+        else:
+            out += self.gen_post_code(attrib, "0x%x" % offset)
+            out.append('BlockDst->address = DST_value;')
+            out += self.gen_post_instr_checks(attrib)
+            out.append('\t\treturn JIT_RET_NO_EXCEPTION;')
+        return out
+
+    def gen_dst_goto(self, attrib, instr_offsets, dst2index):
+        """
+        Generate code for possible @dst2index.
+
+        @attrib: an Attributes instance
+        @instr_offsets: list of instructions offsets
+        @dst2index: link from destination to index
+        """
+
+        if not dst2index:
+            return []
+        out = []
+        out.append('switch(DST_case) {')
+
+        stopcase = False
+        for dst, index in sorted(viewitems(dst2index), key=lambda lblindex: lblindex[1]):
+            if index == -1:
+                # Handle '-1' case only once
+                if not stopcase:
+                    stopcase = True
+                else:
+                    continue
+
+            out.append('\tcase %d:' % index)
+
+            out += self.gen_goto_code(attrib, instr_offsets, dst)
+            out.append('\t\tbreak;')
+        out.append('};')
+        return out
+
+    def gen_c_code(self, attrib, c_dst, c_assignmnts):
+        """
+        Generate the C code for assignblk.
+        @attrib: Attributes instance
+        @c_dst: irdst C code
+        """
+
+        c_prefetch, c_var, c_main, c_mem, c_updt = c_assignmnts
+        out = []
+        out.append("{")
+        out.append("// var")
+        out += c_var
+        out.append("// Prefetch")
+        out += c_prefetch
+        out.append("// Dst")
+        out += c_dst
+        out.append("// Main")
+        out += c_main
+
+        out.append("// Check op/mem exceptions")
+
+        # Check memory access if assignblk has memory read
+        if c_prefetch:
+            out += self.gen_check_memory_exception(attrib.instr.offset)
+
+        out.append("// Mem updt")
+        out += c_mem
+
+        out.append("// Check exception Mem write")
+        # Check memory write exceptions
+        if attrib.mem_write:
+            out += self.gen_check_memory_exception(attrib.instr.offset)
+
+        out.append("// Updt")
+        out += c_updt
+
+        out.append("// Checks exception")
+
+        # Check post assignblk exception flags
+        if attrib.set_exception:
+            out += self.gen_check_cpu_exception(attrib.instr.offset)
+
+        out.append("}")
+
+        return out
+
+    def get_caracteristics(self, assignblk, attrib):
+        """
+        Set the carateristics in @attrib according to the @assignblk
+        @assignblk: an AssignBlock instance
+        @attrib: an Attributes instance
+        """
+
+        # Check explicit exception raising
+        attrib.set_exception = self.lifter.arch.regs.exception_flags in assignblk
+
+        element_read = assignblk.get_r(mem_read=True)
+        # Check mem read
+        attrib.mem_read = any(isinstance(expr, ExprMem)
+                              for expr in element_read)
+        # Check mem write
+        attrib.mem_write = any(isinstance(dst, ExprMem)
+                               for dst in assignblk)
+
+    def get_attributes(self, instr, irblocks, log_mn=False, log_regs=False):
+        """
+        Get the carateristics of each @irblocks. Returns the corresponding
+        attributes object.
+        @irblock: a list of irbloc instance
+        @log_mn: generate code to log instructions
+        @log_regs: generate code to log registers states
+        """
+
+        instr_attrib = Attributes(log_mn, log_regs)
+        instr_attrib.instr = instr
+        irblocks_attributes = []
+
+        for irblock in irblocks:
+            attributes = []
+            irblocks_attributes.append(attributes)
+            for assignblk in irblock:
+                attrib = Attributes(log_mn, log_regs)
+                attributes.append(attrib)
+                self.get_caracteristics(assignblk, attrib)
+                attrib.instr = instr
+                instr_attrib.mem_read |= attrib.mem_read
+                instr_attrib.mem_write |= attrib.mem_write
+                instr_attrib.set_exception |= attrib.set_exception
+
+        return instr_attrib, irblocks_attributes
+
+    def gen_bad_block(self):
+        """
+        Generate the C code for a bad_block instance
+        """
+        return self.CODE_BAD_BLOCK.split("\n")
+
+    def get_block_post_label(self, block):
+        """Get label next to the @block
+        @block: AsmBlock instance"""
+
+        last_instr = block.lines[-1]
+        offset = last_instr.offset + last_instr.l
+        return self.lifter.loc_db.get_or_create_offset_location(offset)
+
+    def gen_init(self, block):
+        """
+        Generate the init C code for a @block
+        @block: an asm_bloc instance
+        """
+
+        instr_offsets = [line.offset for line in block.lines]
+        post_label = self.get_block_post_label(block)
+        post_offset = self.lifter.loc_db.get_location_offset(post_label)
+        instr_offsets.append(post_offset)
+        lbl_start = block.loc_key
+        return (self.CODE_INIT % lbl_start).split("\n"), instr_offsets
+
+    def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock):
+        """
+        Generate the C code for an @irblock
+        @irblock: an irbloc instance
+        @attributes: an Attributes instance list
+        """
+
+        out = []
+        dst2index = None
+        for index, assignblk in enumerate(irblock):
+            if index == irblock.dst_linenb:
+                c_dst, dst2index = self.gen_assignblk_dst(irblock.dst)
+            else:
+                c_dst = []
+
+            c_assignmnts = self.gen_c_assignments(assignblk)
+            out += self.gen_c_code(attributes[index], c_dst, c_assignmnts)
+
+        if dst2index:
+            out.append("// Set irdst")
+            # Gen goto on irdst set
+            out += self.gen_dst_goto(instr_attrib, instr_offsets, dst2index)
+
+        return out
+
+    def gen_finalize(self, block):
+        """
+        Generate the C code for the final block instruction
+        """
+
+        loc_key = self.get_block_post_label(block)
+        offset = self.lifter.loc_db.get_location_offset(loc_key)
+        dst = self.dst_to_c(offset)
+        code = self.CODE_RETURN_NO_EXCEPTION % (loc_key, self.C_PC, dst, dst)
+        return code.split('\n')
+
+    def gen_c(self, block, log_mn=False, log_regs=False):
+        """
+        Generate the C code for the @block and return it as a list of lines
+        @log_mn: log mnemonics
+        @log_regs: log registers
+        """
+
+        if isinstance(block, AsmBlockBad):
+            return self.gen_bad_block()
+        irblocks_list = self.block2assignblks(block)
+        out, instr_offsets = self.gen_init(block)
+        assert len(block.lines) == len(irblocks_list)
+        for instr, irblocks in zip(block.lines, irblocks_list):
+            instr_attrib, irblocks_attributes = self.get_attributes(instr, irblocks, log_mn, log_regs)
+            for index, irblock in enumerate(irblocks):
+                label = str(irblock.loc_key)
+                out.append("%-40s // %.16X %s" %
+                           (label + ":", instr.offset, instr))
+                if index == 0:
+                    out += self.gen_pre_code(instr_attrib)
+                out += self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, irblock)
+
+        out += self.gen_finalize(block)
+
+        return ['\t' + line for line in out]
diff --git a/src/miasm/jitter/compat_py23.h b/src/miasm/jitter/compat_py23.h
new file mode 100644
index 00000000..6dce7818
--- /dev/null
+++ b/src/miasm/jitter/compat_py23.h
@@ -0,0 +1,228 @@
+#ifndef __COMPAT_PY23_H__
+#define __COMPAT_PY23_H__
+
+
+#include "bn.h"
+
+#if PY_MAJOR_VERSION >= 3
+#define PyGetInt_uint_t(size_type, item, value)				\
+	if (PyLong_Check(item)) {					\
+		Py_INCREF(item);					\
+		PyObject* py_long = item;				\
+		PyObject* py_long_new;					\
+		bn_t bn;						\
+		uint64_t tmp;						\
+		int neg = 0;    					\
+									\
+		if (Py_SIZE(py_long) < 0) {				\
+			neg = 1;					\
+			py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \
+			Py_DECREF(py_long);				\
+			py_long = py_long_new;				\
+		}							\
+									\
+		bn = PyLong_to_bn(py_long);				\
+									\
+		bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \
+		if (bignum_is_inf_equal_unsigned(mask_bn, bn)) {		\
+			RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \
+		}	 						\
+		if (neg) {						\
+			bn = bignum_sub(mask_bn, bn);			\
+		}							\
+		tmp = bignum_to_uint64(bn);				\
+		value = (size_type) tmp;				\
+	}								\
+	else{								\
+		RAISE(PyExc_TypeError, "Arg must be int");		\
+	}
+
+
+#define PyGetInt_uint_t_retneg(size_type, item, value)			\
+	if (PyLong_Check(item)) {					\
+		Py_INCREF(item);					\
+		PyObject* py_long = item;				\
+		PyObject* py_long_new;					\
+		bn_t bn;						\
+		uint64_t tmp;						\
+		int neg = 0;    					\
+									\
+		if (Py_SIZE(py_long) < 0) {				\
+			neg = 1;					\
+			py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \
+			Py_DECREF(py_long);				\
+			py_long = py_long_new;				\
+		}							\
+									\
+		bn = PyLong_to_bn(py_long);				\
+									\
+		bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \
+		if (bignum_is_inf_equal_unsigned(mask_bn, bn)) {		\
+			PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \
+			return -1;					\
+		}	 						\
+		if (neg) {						\
+			bn = bignum_sub(mask_bn, bn);			\
+		}							\
+		tmp = bignum_to_uint64(bn);				\
+		value = (size_type) tmp;				\
+	}								\
+	else{								\
+		PyErr_SetString(PyExc_TypeError, "Arg must be int");	\
+		return -1;						\
+	}
+
+#define PyGetStr(dest, name)						\
+	if (!PyUnicode_Check((name)))					\
+		RAISE(PyExc_TypeError,"Page name must be bytes");	\
+	(dest) = PyUnicode_AsUTF8((name))
+
+
+
+#else
+#define PyGetInt_uint_t(size_type, item, value)				\
+	if (PyInt_Check(item)) {					\
+		long tmp;						\
+		tmp = PyInt_AsLong(item);				\
+									\
+		if (Py_SIZE(item) < 0) {				\
+			if (-tmp > ((size_type) -1)) {			\
+				RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \
+			}						\
+		}							\
+		else if (tmp > (size_type) -1) {			\
+			RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \
+		}							\
+		value = (size_type) tmp;				\
+	}								\
+	else if (PyLong_Check(item)){					\
+		Py_INCREF(item);					\
+		PyObject* py_long = item;				\
+		PyObject* py_long_new;					\
+		bn_t bn;						\
+		uint64_t tmp;						\
+		int neg = 0;    					\
+									\
+		if (Py_SIZE(py_long) < 0) {				\
+			neg = 1;					\
+			py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \
+			Py_DECREF(py_long);				\
+			py_long = py_long_new;				\
+		}							\
+									\
+		bn = PyLong_to_bn(py_long);				\
+									\
+		bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \
+		if (bignum_is_inf_equal_unsigned(mask_bn, bn)) {		\
+			RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \
+		}	 						\
+		if (neg) {						\
+			bn = bignum_sub(mask_bn, bn);			\
+		}							\
+		tmp = bignum_to_uint64(bn);				\
+		value = (size_type) tmp;				\
+	}								\
+	else{								\
+		RAISE(PyExc_TypeError, "Arg must be int");		\
+	}
+
+
+#define PyGetInt_uint_t_retneg(size_type, item, value)			\
+	if (PyInt_Check(item)) {					\
+		long tmp;						\
+		tmp = PyInt_AsLong(item);				\
+									\
+		if (Py_SIZE(item) < 0) {				\
+			if (-tmp > ((size_type) -1)) {			\
+				PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \
+				return -1;				\
+			}						\
+		}							\
+		else if (tmp > (size_type) -1) {			\
+			PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \
+			return -1;					\
+		}							\
+		value = (size_type) tmp;				\
+	}								\
+	else if (PyLong_Check(item)){					\
+		Py_INCREF(item);					\
+		PyObject* py_long = item;				\
+		PyObject* py_long_new;					\
+		bn_t bn;						\
+		uint64_t tmp;						\
+		int neg = 0;    					\
+									\
+		if (Py_SIZE(py_long) < 0) {				\
+			neg = 1;					\
+			py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \
+			Py_DECREF(py_long);				\
+			py_long = py_long_new;				\
+		}							\
+									\
+		bn = PyLong_to_bn(py_long);				\
+									\
+		bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \
+		if (bignum_is_inf_equal_unsigned(mask_bn, bn)) {	\
+			PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \
+			return -1;					\
+		}	 						\
+		if (neg) {						\
+			bn = bignum_sub(mask_bn, bn);			\
+		}							\
+		tmp = bignum_to_uint64(bn);				\
+		value = (size_type) tmp;				\
+	}								\
+	else{								\
+		PyErr_SetString(PyExc_TypeError, "Arg must be int");	\
+		return -1;						\
+	}								\
+
+
+#define PyGetStr(dest, name)						\
+	if (!PyString_Check((name)))					\
+		RAISE(PyExc_TypeError,"Page name must be bytes");	\
+	(dest) = PyString_AsString((name))
+
+#endif
+
+
+
+#define PyGetInt_size_t(item, value) PyGetInt_uint_t(size_t, item, value)
+
+#define PyGetInt_uint8_t(item, value) PyGetInt_uint_t(uint8_t, item, value)
+#define PyGetInt_uint16_t(item, value) PyGetInt_uint_t(uint16_t, item, value)
+#define PyGetInt_uint32_t(item, value) PyGetInt_uint_t(uint32_t, item, value)
+#define PyGetInt_uint64_t(item, value) PyGetInt_uint_t(uint64_t, item, value)
+
+#define PyGetInt_uint8_t_retneg(item, value) PyGetInt_uint_t_retneg(uint8_t, item, value)
+#define PyGetInt_uint16_t_retneg(item, value) PyGetInt_uint_t_retneg(uint16_t, item, value)
+#define PyGetInt_uint32_t_retneg(item, value) PyGetInt_uint_t_retneg(uint32_t, item, value)
+#define PyGetInt_uint64_t_retneg(item, value) PyGetInt_uint_t_retneg(uint64_t, item, value)
+
+
+
+#if PY_MAJOR_VERSION >= 3
+
+#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+
+#define MOD_DEF(ob, name, doc, methods)		  \
+	static struct PyModuleDef moduledef = {				\
+					       PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \
+	ob = PyModule_Create(&moduledef);
+#define RET_MODULE return module
+
+#else
+
+#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
+
+#define MOD_DEF(ob, name, doc, methods)			\
+	ob = Py_InitModule3(name, methods, doc);
+
+#define RET_MODULE return
+#endif
+
+
+
+
+
+#endif
diff --git a/src/miasm/jitter/csts.py b/src/miasm/jitter/csts.py
new file mode 100644
index 00000000..f40cbe74
--- /dev/null
+++ b/src/miasm/jitter/csts.py
@@ -0,0 +1,50 @@
+#-*- coding:utf-8 -*-
+
+
+# VM Mngr Exceptions
+EXCEPT_DO_NOT_UPDATE_PC = 1 << 25
+EXCEPT_NUM_UPDT_EIP = (1<<11)
+
+EXCEPT_CODE_AUTOMOD = (1 << 0)
+EXCEPT_SOFT_BP = (1 << 1)
+EXCEPT_INT_XX = (1 << 2)
+EXCEPT_SPR_ACCESS = (1 << 3)
+EXCEPT_SYSCALL = (1 << 4)
+EXCEPT_BREAKPOINT_MEMORY = (1 << 10)
+# Deprecated
+EXCEPT_BREAKPOINT_INTERN = EXCEPT_BREAKPOINT_MEMORY
+
+EXCEPT_ACCESS_VIOL = ((1 << 14) | EXCEPT_DO_NOT_UPDATE_PC)
+EXCEPT_DIV_BY_ZERO = ((1 << 16) | EXCEPT_DO_NOT_UPDATE_PC)
+EXCEPT_PRIV_INSN = ((1 << 17) | EXCEPT_DO_NOT_UPDATE_PC)
+EXCEPT_ILLEGAL_INSN = ((1 << 18) | EXCEPT_DO_NOT_UPDATE_PC)
+EXCEPT_UNK_MNEMO = ((1 << 19) | EXCEPT_DO_NOT_UPDATE_PC)
+EXCEPT_INT_1 = ((1 << 20) | EXCEPT_DO_NOT_UPDATE_PC)
+
+JitterExceptions = {
+    "DO_NOT_UPDATE_PC": EXCEPT_DO_NOT_UPDATE_PC,
+    "NUM_UPDT_EIP": EXCEPT_NUM_UPDT_EIP,
+    "CODE_AUTOMOD": EXCEPT_CODE_AUTOMOD,
+    "SOFT_BP": EXCEPT_SOFT_BP,
+    "INT_XX": EXCEPT_INT_XX,
+    "SPR_ACCESS": EXCEPT_SPR_ACCESS,
+    "SYSCALL": EXCEPT_SYSCALL,
+    "BREAKPOINT_MEMORY": EXCEPT_BREAKPOINT_MEMORY,
+    "BREAKPOINT_INTERN": EXCEPT_BREAKPOINT_INTERN,
+    "ACCESS_VIOL": EXCEPT_ACCESS_VIOL,
+    "DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO,
+    "PRIV_INSN": EXCEPT_PRIV_INSN,
+    "ILLEGAL_INSN": EXCEPT_ILLEGAL_INSN,
+    "UNK_MNEMO": EXCEPT_UNK_MNEMO,
+    "INT_1": EXCEPT_INT_1,
+}
+
+# VM Mngr constants
+
+PAGE_READ = 1
+PAGE_WRITE = 2
+PAGE_EXEC = 4
+
+BREAKPOINT_READ = 1
+BREAKPOINT_WRITE = 2
+
diff --git a/src/miasm/jitter/emulatedsymbexec.py b/src/miasm/jitter/emulatedsymbexec.py
new file mode 100644
index 00000000..1c3100ae
--- /dev/null
+++ b/src/miasm/jitter/emulatedsymbexec.py
@@ -0,0 +1,170 @@
+from miasm.core.utils import decode_hex, encode_hex
+import miasm.expression.expression as m2_expr
+from miasm.ir.symbexec import SymbolicExecutionEngine
+from miasm.arch.x86.arch import is_op_segm
+
+
+class EmulatedSymbExec(SymbolicExecutionEngine):
+    """Symbolic exec instance linked with a jitter"""
+
+    x86_cpuid = {
+        0: {
+            0: 0xa,
+            1: 0x756E6547,
+            2: 0x6C65746E,
+            3: 0x49656E69,
+        },
+        1: {
+            0: 0x00020652,
+            1: 0x00000800,
+            2: 0x00000209,
+            3: 0x078bf9ff
+        },
+        2: {
+            0: 0,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        4: {
+            0: 0,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        7: {
+            0: 0,
+            1: (1 << 0) | (1 << 3),
+            2: 0,
+            3: 0
+        },
+        0x80000000: {
+            0: 0x80000008,
+            1: 0,
+            2: 0,
+            3: 0
+        },
+        0x80000001: {
+            0: 0,
+            1: 0,
+            2: (1 << 0) | (1 << 8),
+            3: (1 << 11) | (1 << 29),
+        },
+    }
+
+    def __init__(self, cpu, vm, *args, **kwargs):
+        """Instantiate an EmulatedSymbExec, associated to CPU @cpu and bind
+        memory accesses.
+        @cpu: JitCpu instance
+        """
+        super(EmulatedSymbExec, self).__init__(*args, **kwargs)
+        self.cpu = cpu
+        self.vm = vm
+
+    def reset_regs(self):
+        """Set registers value to 0. Ignore register aliases"""
+        for reg in self.lifter.arch.regs.all_regs_ids_no_alias:
+            self.symbols.symbols_id[reg] = m2_expr.ExprInt(0, size=reg.size)
+
+    # Memory management
+    def mem_read(self, expr_mem):
+        """Memory read wrapper for symbolic execution
+        @expr_mem: ExprMem"""
+
+        addr = expr_mem.ptr
+        if not addr.is_int():
+            return super(EmulatedSymbExec, self).mem_read(expr_mem)
+        addr = int(addr)
+        size = expr_mem.size // 8
+        value = self.vm.get_mem(addr, size)
+        if self.vm.is_little_endian():
+            value = value[::-1]
+        self.vm.add_mem_read(addr, size)
+
+        return m2_expr.ExprInt(
+            int(encode_hex(value), 16),
+            expr_mem.size
+        )
+
+    def mem_write(self, dest, data):
+        """Memory read wrapper for symbolic execution
+        @dest: ExprMem instance
+        @data: Expr instance"""
+
+        # Get the content to write
+        data = self.expr_simp(data)
+        if not isinstance(data, m2_expr.ExprInt):
+            raise RuntimeError("A simplification is missing: %s" % data)
+        to_write = int(data)
+
+        # Format information
+        addr = int(dest.ptr)
+        size = data.size // 8
+        content = hex(to_write).replace("0x", "").replace("L", "")
+        content = "0" * (size * 2 - len(content)) + content
+        content = decode_hex(content)
+
+        if self.vm.is_little_endian():
+            content = content[::-1]
+
+        # Write in VmMngr context
+        self.vm.set_mem(addr, content)
+
+    # Interaction symbexec <-> jitter
+    def update_cpu_from_engine(self):
+        """Updates @cpu instance according to new CPU values"""
+
+        for symbol in self.symbols:
+            if isinstance(symbol, m2_expr.ExprId):
+                if hasattr(self.cpu, symbol.name):
+                    value = self.symbols.symbols_id[symbol]
+                    if not isinstance(value, m2_expr.ExprInt):
+                        raise ValueError("A simplification is missing: %s" % value)
+
+                    setattr(self.cpu, symbol.name, int(value))
+            else:
+                raise NotImplementedError("Type not handled: %s" % symbol)
+
+
+    def update_engine_from_cpu(self):
+        """Updates CPU values according to @cpu instance"""
+
+        for symbol in self.symbols:
+            if isinstance(symbol, m2_expr.ExprId):
+                if hasattr(self.cpu, symbol.name):
+                    value = m2_expr.ExprInt(getattr(self.cpu, symbol.name),
+                                            symbol.size)
+                    self.symbols.symbols_id[symbol] = value
+            else:
+                raise NotImplementedError("Type not handled: %s" % symbol)
+
+    # CPU specific simplifications
+    def _simp_handle_segm(self, e_s, expr):
+        """Handle 'segm' operation"""
+        if not is_op_segm(expr):
+            return expr
+        if not expr.args[0].is_int():
+            return expr
+        segm_nb = int(expr.args[0])
+        segmaddr = self.cpu.get_segm_base(segm_nb)
+        return e_s(m2_expr.ExprInt(segmaddr, expr.size) + expr.args[1])
+
+    def _simp_handle_x86_cpuid(self, e_s, expr):
+        """From miasm/jitter/op_semantics.h: x86_cpuid"""
+        if expr.op != "x86_cpuid":
+            return expr
+
+        if any(not arg.is_int() for arg in expr.args):
+            return expr
+        a, reg_num = (int(arg) for arg in expr.args)
+
+        # Not found error is keeped on purpose
+        return m2_expr.ExprInt(self.x86_cpuid[a][reg_num], expr.size)
+
+    def enable_emulated_simplifications(self):
+        """Enable simplifications needing a CPU instance on associated
+        ExpressionSimplifier
+        """
+        self.expr_simp.enable_passes({
+            m2_expr.ExprOp: [self._simp_handle_segm, self._simp_handle_x86_cpuid],
+        })
diff --git a/src/miasm/jitter/jitcore.py b/src/miasm/jitter/jitcore.py
new file mode 100644
index 00000000..434854ca
--- /dev/null
+++ b/src/miasm/jitter/jitcore.py
@@ -0,0 +1,308 @@
+from __future__ import print_function
+#
+# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+from hashlib import md5
+import warnings
+
+from future.utils import viewvalues
+
+from miasm.core.asmblock import disasmEngine, AsmBlockBad
+from miasm.core.interval import interval
+from miasm.core.utils import BoundedDict
+from miasm.expression.expression import LocKey
+from miasm.jitter.csts import *
+
+class JitCore(object):
+
+    "JiT management. This is an abstract class"
+
+    # Jitted function's name
+    FUNCNAME = "block_entry"
+
+    jitted_block_delete_cb = None
+    jitted_block_max_size = 10000
+
+    def __init__(self, lifter, bin_stream):
+        """Initialise a JitCore instance.
+        @lifter: Lifter instance for current architecture
+        @bin_stream: bin_stream instance
+        """
+        # Arch related
+        self.lifter = lifter
+        self.ircfg = self.lifter.new_ircfg()
+        self.arch_name = "%s%s" % (self.lifter.arch.name, self.lifter.attrib)
+
+        # Structures for block tracking
+        self.offset_to_jitted_func = BoundedDict(self.jitted_block_max_size,
+                                       delete_cb=self.jitted_block_delete_cb)
+        self.loc_key_to_block = {}
+        self.blocks_mem_interval = interval()
+
+        # Logging & options
+        self.log_mn = False
+        self.log_regs = False
+        self.log_newbloc = False
+        self.options = {"jit_maxline": 50,  # Maximum number of line jitted
+                        "max_exec_per_call": 0 # 0 means no limit
+                        }
+
+        # Disassembly Engine
+        self.split_dis = set()
+        self.mdis = disasmEngine(
+            lifter.arch, lifter.attrib, bin_stream,
+            lines_wd=self.options["jit_maxline"],
+            loc_db=lifter.loc_db,
+            follow_call=False,
+            dontdis_retcall=False,
+            split_dis=self.split_dis,
+        )
+
+    @property
+    def ir_arch(self):
+        warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"')
+        return self.lifter
+
+
+    def set_options(self, **kwargs):
+        "Set options relative to the backend"
+        self.options.update(kwargs)
+
+    def clear_jitted_blocks(self):
+        "Reset all jitted blocks"
+        self.offset_to_jitted_func.clear()
+        self.loc_key_to_block.clear()
+        self.blocks_mem_interval = interval()
+
+    def add_disassembly_splits(self, *args):
+        """The disassembly engine will stop on address in args if they
+        are not at the block beginning"""
+        self.split_dis.update(set(args))
+
+    def remove_disassembly_splits(self, *args):
+        """The disassembly engine will no longer stop on address in args"""
+        self.split_dis.difference_update(set(args))
+
+    def load(self):
+        "Initialise the Jitter"
+        raise NotImplementedError("Abstract class")
+
+    def set_block_min_max(self, cur_block):
+        "Update cur_block to set min/max address"
+
+        if cur_block.lines:
+            cur_block.ad_min = cur_block.lines[0].offset
+            cur_block.ad_max = cur_block.lines[-1].offset + cur_block.lines[-1].l
+        else:
+            # 1 byte block for unknown mnemonic
+            offset = self.lifter.loc_db.get_location_offset(cur_block.loc_key)
+            cur_block.ad_min = offset
+            cur_block.ad_max = offset+1
+
+
+    def add_block_to_mem_interval(self, vm, block):
+        "Update vm to include block addresses in its memory range"
+        self.blocks_mem_interval += interval([(block.ad_min, block.ad_max - 1)])
+
+        vm.reset_code_bloc_pool()
+        for a, b in self.blocks_mem_interval:
+            vm.add_code_bloc(a, b + 1)
+
+    def add_block(self, block):
+        """Add a block to JiT and JiT it.
+        @block: asm_bloc to add
+        """
+        raise NotImplementedError("Abstract class")
+
+    def disasm_and_jit_block(self, addr, vm):
+        """Disassemble a new block and JiT it
+        @addr: address of the block to disassemble (LocKey or int)
+        @vm: VmMngr instance
+        """
+
+        # Get the block
+        if isinstance(addr, LocKey):
+            addr = self.lifter.loc_db.get_location_offset(addr)
+            if addr is None:
+                raise RuntimeError("Unknown offset for LocKey")
+
+        # Prepare disassembler
+        self.mdis.lines_wd = self.options["jit_maxline"]
+
+        # Disassemble it
+        cur_block = self.mdis.dis_block(addr)
+        if isinstance(cur_block, AsmBlockBad):
+            return cur_block
+        # Logging
+        if self.log_newbloc:
+            print(cur_block)
+
+        # Update label -> block
+        self.loc_key_to_block[cur_block.loc_key] = cur_block
+
+        # Store min/max block address needed in jit automod code
+        self.set_block_min_max(cur_block)
+
+        # JiT it
+        self.add_block(cur_block)
+
+        # Update jitcode mem range
+        self.add_block_to_mem_interval(vm, cur_block)
+        return cur_block
+
+    def run_at(self, cpu, offset, stop_offsets):
+        """Run from the starting address @offset.
+        Execution will stop if:
+        - max_exec_per_call option is reached
+        - a new, yet unknown, block is reached after the execution of block at
+          address @offset
+        - an address in @stop_offsets is reached
+        @cpu: JitCpu instance
+        @offset: starting address (int)
+        @stop_offsets: set of address on which the jitter must stop
+        """
+
+        if offset is None:
+            offset = getattr(cpu, self.lifter.pc.name)
+
+        if offset not in self.offset_to_jitted_func:
+            # Need to JiT the block
+            cur_block = self.disasm_and_jit_block(offset, cpu.vmmngr)
+            if isinstance(cur_block, AsmBlockBad):
+                errno = cur_block.errno
+                if errno == AsmBlockBad.ERROR_IO:
+                    cpu.vmmngr.set_exception(EXCEPT_ACCESS_VIOL)
+                elif errno == AsmBlockBad.ERROR_CANNOT_DISASM:
+                    cpu.set_exception(EXCEPT_UNK_MNEMO)
+                else:
+                    raise RuntimeError("Unhandled disasm result %r" % errno)
+                return offset
+
+        # Run the block and update cpu/vmmngr state
+        return self.exec_wrapper(offset, cpu, self.offset_to_jitted_func.data,
+                                 stop_offsets,
+                                 self.options["max_exec_per_call"])
+
+    def blocks_to_memrange(self, blocks):
+        """Return an interval instance standing for blocks addresses
+        @blocks: list of AsmBlock instances
+        """
+
+        mem_range = interval()
+        mem_range = interval([(block.ad_min, block.ad_max - 1) for block in blocks])
+        return mem_range
+
+    def __updt_jitcode_mem_range(self, vm):
+        """Rebuild the VM blocks address memory range
+        @vm: VmMngr instance
+        """
+
+        # Reset the current pool
+        vm.reset_code_bloc_pool()
+
+        # Add blocks in the pool
+        for start, stop in self.blocks_mem_interval:
+            vm.add_code_bloc(start, stop + 1)
+
+    def del_block_in_range(self, ad1, ad2):
+        """Find and remove jitted block in range [ad1, ad2].
+        Return the list of block removed.
+        @ad1: First address
+        @ad2: Last address
+        """
+
+        # Find concerned blocks
+        modified_blocks = set()
+        for block in viewvalues(self.loc_key_to_block):
+            if not block.lines:
+                continue
+            if block.ad_max <= ad1 or block.ad_min >= ad2:
+                # Block not modified
+                pass
+            else:
+                # Modified blocks
+                modified_blocks.add(block)
+
+        # Remove modified blocks
+        for block in modified_blocks:
+            try:
+                for irblock in block.blocks:
+                    # Remove offset -> jitted block link
+                    offset = self.lifter.loc_db.get_location_offset(irblock.loc_key)
+                    if offset in self.offset_to_jitted_func:
+                        del(self.offset_to_jitted_func[offset])
+
+            except AttributeError:
+                # The block has never been translated in IR
+                offset = self.lifter.loc_db.get_location_offset(block.loc_key)
+                if offset in self.offset_to_jitted_func:
+                    del(self.offset_to_jitted_func[offset])
+
+            # Remove label -> block link
+            del(self.loc_key_to_block[block.loc_key])
+
+        # Re generate blocks intervals
+        self.blocks_mem_interval = self.blocks_to_memrange(self.loc_key_to_block.values())
+
+        return modified_blocks
+
+    def updt_automod_code_range(self, vm, mem_range):
+        """Remove jitted code in range @mem_range
+        @vm: VmMngr instance
+        @mem_range: list of start/stop addresses
+        """
+        for addr_start, addr_stop in mem_range:
+            self.del_block_in_range(addr_start, addr_stop)
+        self.__updt_jitcode_mem_range(vm)
+        vm.reset_memory_access()
+
+    def updt_automod_code(self, vm):
+        """Remove jitted code updated by memory write
+        @vm: VmMngr instance
+        """
+        mem_range = []
+        for addr_start, addr_stop in vm.get_memory_write():
+            mem_range.append((addr_start, addr_stop))
+        self.updt_automod_code_range(vm, mem_range)
+
+    def hash_block(self, block):
+        """
+        Build a hash of the block @block
+        @block: asmblock
+        """
+        block_raw = b"".join(line.b for line in block.lines)
+        offset = self.lifter.loc_db.get_location_offset(block.loc_key)
+        block_hash = md5(
+            b"%X_%s_%s_%s_%s" % (
+                offset,
+                self.arch_name.encode(),
+                b'\x01' if self.log_mn else b'\x00',
+                b'\x01' if self.log_regs else b'\x00',
+                block_raw
+            )
+        ).hexdigest()
+        return block_hash
+
+    @property
+    def disasm_cb(self):
+        warnings.warn("Deprecated API: use .mdis.dis_block_callback")
+        return self.mdis.dis_block_callback
+
+    @disasm_cb.setter
+    def disasm_cb(self, value):
+        warnings.warn("Deprecated API: use .mdis.dis_block_callback")
+        self.mdis.dis_block_callback = value
diff --git a/src/miasm/jitter/jitcore_cc_base.py b/src/miasm/jitter/jitcore_cc_base.py
new file mode 100644
index 00000000..c5819d1f
--- /dev/null
+++ b/src/miasm/jitter/jitcore_cc_base.py
@@ -0,0 +1,127 @@
+#-*- coding:utf-8 -*-
+
+import glob
+import os
+import tempfile
+import platform
+import sysconfig
+
+from miasm.jitter.jitcore import JitCore
+from miasm.core.utils import keydefaultdict
+
+is_win = platform.system() == "Windows"
+
+def gen_core(arch, attrib):
+    lib_dir = os.path.dirname(os.path.realpath(__file__))
+
+    txt = ""
+    txt += '#include "%s/queue.h"\n' % lib_dir
+    txt += '#include "%s/op_semantics.h"\n' % lib_dir
+    txt += '#include "%s/vm_mngr.h"\n' % lib_dir
+    txt += '#include "%s/bn.h"\n' % lib_dir
+    txt += '#include "%s/vm_mngr_py.h"\n' % lib_dir
+    txt += '#include "%s/JitCore.h"\n' % lib_dir
+    txt += '#include "%s/arch/JitCore_%s.h"\n' % (lib_dir, arch.name)
+
+    txt += r'''
+#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;}
+'''
+    return txt
+
+
+class myresolver(object):
+
+    def __init__(self, offset):
+        self.offset = offset
+
+    def ret(self):
+        return "return PyLong_FromUnsignedLongLong(0x%X);" % self.offset
+
+
+class resolver(object):
+
+    def __init__(self):
+        self.resolvers = keydefaultdict(myresolver)
+
+    def get_resolver(self, offset):
+        return self.resolvers[offset]
+
+
+class JitCore_Cc_Base(JitCore):
+    "JiT management, abstract class using a C compiler as backend"
+
+    def __init__(self, lifter, bin_stream):
+        self.jitted_block_delete_cb = self.deleteCB
+        super(JitCore_Cc_Base, self).__init__(lifter, bin_stream)
+        self.resolver = resolver()
+        self.lifter = lifter
+        self.states = {}
+        self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_cache")
+        try:
+            os.mkdir(self.tempdir, 0o755)
+        except OSError:
+            pass
+        if not os.access(self.tempdir, os.R_OK | os.W_OK):
+            raise RuntimeError(
+                'Cannot access cache directory %s ' % self.tempdir)
+        self.exec_wrapper = None
+        self.libs = None
+        self.include_files = None
+
+    def deleteCB(self, offset):
+        raise NotImplementedError()
+
+    def load(self):
+        lib_dir = os.path.dirname(os.path.realpath(__file__))
+        ext = sysconfig.get_config_var('EXT_SUFFIX')
+        if ext is None:
+            ext = ".so" if not is_win else ".lib"
+        if is_win:
+            # sysconfig.get_config_var('EXT_SUFFIX') is .pyd on Windows and need to be forced to .lib
+            # Additionally windows built libraries may have a name like VmMngr.cp38-win_amd64.lib
+            ext_files = glob.glob(os.path.join(lib_dir, "VmMngr.*lib"))
+            if len(ext_files) == 1:
+                ext = os.path.basename(ext_files[0]).replace("VmMngr", "")
+
+        libs = [
+            os.path.join(lib_dir, "VmMngr" + ext),
+            os.path.join(
+                lib_dir,
+                "arch",
+                "JitCore_%s%s" % (self.lifter.arch.name, ext)
+            )
+        ]
+
+        include_files = [
+            os.path.dirname(__file__),
+            sysconfig.get_paths()['include'],
+        ]
+        self.include_files = include_files
+        self.libs = libs
+
+    def init_codegen(self, codegen):
+        """
+        Get the code generator @codegen
+        @codegen: an CGen instance
+        """
+        self.codegen = codegen
+
+    def gen_c_code(self, block):
+        """
+        Return the C code corresponding to the @irblocks
+        @irblocks: list of irblocks
+        """
+        f_declaration = '_MIASM_EXPORT int %s(block_id * BlockDst, JitCpu* jitcpu)' % self.FUNCNAME
+        out = self.codegen.gen_c(
+            block,
+            log_mn=self.log_mn,
+            log_regs=self.log_regs
+        )
+        out = [f_declaration + '{'] + out + ['}\n']
+        c_code = out
+
+        return self.gen_C_source(self.lifter, c_code)
+
+    @staticmethod
+    def gen_C_source(lifter, func_code):
+        raise NotImplementedError()
diff --git a/src/miasm/jitter/jitcore_gcc.py b/src/miasm/jitter/jitcore_gcc.py
new file mode 100644
index 00000000..958c9d13
--- /dev/null
+++ b/src/miasm/jitter/jitcore_gcc.py
@@ -0,0 +1,141 @@
+#-*- coding:utf-8 -*-
+
+import sys
+import os
+import tempfile
+import ctypes
+import _ctypes
+import platform
+import sysconfig
+from subprocess import check_call
+from miasm.jitter import Jitgcc
+from miasm.jitter.jitcore_cc_base import JitCore_Cc_Base, gen_core
+
+is_win = platform.system() == "Windows"
+
+class JitCore_Gcc(JitCore_Cc_Base):
+    "JiT management, using a C compiler as backend"
+
+    def __init__(self, lifter, bin_stream):
+        super(JitCore_Gcc, self).__init__(lifter, bin_stream)
+        self.exec_wrapper = Jitgcc.gcc_exec_block
+
+    def deleteCB(self, offset):
+        """Free the state associated to @offset and delete it
+        @offset: gcc state offset
+        """
+        flib = None
+        if is_win:
+            flib = _ctypes.FreeLibrary
+        else:
+            flib = _ctypes.dlclose
+        flib(self.states[offset]._handle)
+        del self.states[offset]
+
+    def load_code(self, label, fname_so):
+        lib = ctypes.cdll.LoadLibrary(fname_so)
+        func = getattr(lib, self.FUNCNAME)
+        addr = ctypes.cast(func, ctypes.c_void_p).value
+        offset = self.lifter.loc_db.get_location_offset(label)
+        self.offset_to_jitted_func[offset] = addr
+        self.states[offset] = lib
+
+    def add_block(self, block):
+        """Add a block to JiT and JiT it.
+        @block: block to jit
+        """
+        block_hash = self.hash_block(block)
+        ext = sysconfig.get_config_var('EXT_SUFFIX')
+        if ext is None:
+            ext = ".so" if not is_win else ".pyd"
+        fname_out = os.path.join(self.tempdir, "%s%s" % (block_hash, ext))
+
+        if not os.access(fname_out, os.R_OK | os.X_OK):
+            func_code = self.gen_c_code(block)
+
+            # Create unique C file
+            fdesc, fname_in = tempfile.mkstemp(suffix=".c")
+            os.write(fdesc, func_code.encode())
+            os.close(fdesc)
+
+            # Create unique SO file
+            fdesc, fname_tmp = tempfile.mkstemp(suffix=ext)
+            os.close(fdesc)
+
+            inc_dir = ["-I%s" % inc for inc in self.include_files]
+            libs = ["%s" % lib for lib in self.libs]
+            if is_win:
+                libs.append(
+                    os.path.join(
+                        sysconfig.get_paths()['include'],
+                        "..",
+                        "libs",
+                        "python%d%d.lib" % (sys.version_info.major, sys.version_info.minor)
+                    )
+                )
+                cl = [
+                    "cl", "/nologo", "/W3", "/MP",
+                    "/Od", "/DNDEBUG", "/D_WINDOWS", "/Gm-", "/EHsc",
+                    "/RTC1", "/MD", "/GS",
+                    fname_in
+                ] + inc_dir + libs
+                cl += ["/link", "/DLL", "/OUT:" + fname_tmp]
+                out_dir, _ = os.path.split(fname_tmp)
+                check_call(cl, cwd = out_dir)
+                basename_out, _ = os.path.splitext(fname_tmp)
+                basename_in, _ = os.path.splitext(os.path.basename(fname_in))
+                for ext in ('.obj', '.exp', '.lib'):
+                    artifact_out_path = os.path.join(
+                        out_dir,
+                        basename_out + ext
+                    )
+                    if os.path.isfile(artifact_out_path):
+                        os.remove(artifact_out_path)
+                    artifact_in_path = os.path.join(
+                        out_dir,
+                        basename_in + ext
+                    )
+                    if os.path.isfile(artifact_in_path):
+                        os.remove(artifact_in_path)
+            else:
+                args = [
+                    "cc",
+                    "-O3",
+                    "-shared",
+                    "-fPIC",
+                    fname_in,
+                    "-o",
+                    fname_tmp
+                ] + inc_dir + libs
+                check_call(args)
+
+            # Move temporary file to final file
+            try:
+                os.rename(fname_tmp, fname_out)
+            except WindowsError as e:
+                # On Windows, os.rename works slightly differently than on
+                # Linux; quoting the documentation:
+                # "On Unix, if dst exists and is a file, it will be replaced
+                # silently if the user has permission.  The operation may fail
+                # on some Unix flavors if src and dst are on different
+                # filesystems.  If successful, the renaming will be an atomic
+                # operation (this is a POSIX requirement).  On Windows, if dst
+                # already exists, OSError will be raised even if it is a file;
+                # there may be no way to implement an atomic rename when dst
+                # names an existing file."
+                # [Error 183] Cannot create a file when that file already exists
+                if e.winerror != 183:
+                    raise
+                os.remove(fname_tmp)
+            os.remove(fname_in)
+
+        self.load_code(block.loc_key, fname_out)
+
+    @staticmethod
+    def gen_C_source(lifter, func_code):
+        c_source = ""
+        c_source += "\n".join(func_code)
+
+        c_source = gen_core(lifter.arch, lifter.attrib) + c_source
+        c_source = "#define PARITY_IMPORT\n#include <Python.h>\n" + c_source
+        return c_source
diff --git a/src/miasm/jitter/jitcore_llvm.py b/src/miasm/jitter/jitcore_llvm.py
new file mode 100644
index 00000000..4f1871b2
--- /dev/null
+++ b/src/miasm/jitter/jitcore_llvm.py
@@ -0,0 +1,144 @@
+from __future__ import print_function
+import os
+import glob
+import importlib
+import tempfile
+import sysconfig
+
+from miasm.jitter.llvmconvert import *
+import miasm.jitter.jitcore as jitcore
+from miasm.jitter import Jitllvm
+import platform
+
+import llvmlite
+llvmlite.binding.load_library_permanently(Jitllvm.__file__)
+
+is_win = platform.system() == "Windows"
+
+class JitCore_LLVM(jitcore.JitCore):
+    "JiT management, using LLVM as backend"
+
+    # Architecture dependent libraries
+    arch_dependent_libs = {
+        "x86": "JitCore_x86",
+        "arm": "JitCore_arm",
+        "msp430": "JitCore_msp430",
+        "mips32": "JitCore_mips32",
+        "aarch64": "JitCore_aarch64",
+        "ppc32": "JitCore_ppc32",
+    }
+
+    def __init__(self, lifter, bin_stream):
+        super(JitCore_LLVM, self).__init__(lifter, bin_stream)
+
+        self.options.update(
+            {
+                "safe_mode": True,   # Verify each function
+                "optimise": True,     # Optimise functions
+                "log_func": False,    # Print LLVM functions
+                "log_assembly": False,  # Print assembly executed
+            }
+        )
+
+        self.exec_wrapper = Jitllvm.llvm_exec_block
+        self.lifter = lifter
+
+        # Cache temporary dir
+        self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_cache")
+        try:
+            os.mkdir(self.tempdir, 0o755)
+        except OSError:
+            pass
+        if not os.access(self.tempdir, os.R_OK | os.W_OK):
+            raise RuntimeError(
+                'Cannot access cache directory %s ' % self.tempdir)
+
+    def load(self):
+
+        # Library to load within Jit context
+        libs_to_load = []
+
+        # Get architecture dependent Jitcore library (if any)
+        lib_dir = os.path.dirname(os.path.realpath(__file__))
+        ext = sysconfig.get_config_var('EXT_SUFFIX')
+        if ext is None:
+            ext = ".so" if not is_win else ".pyd"
+        if is_win:
+            # sysconfig.get_config_var('EXT_SUFFIX') is .pyd on Windows and need to be forced to .lib
+            # Additionally windows built libraries may have a name like VmMngr.cp38-win_amd64.lib
+            ext_files = glob.glob(os.path.join(lib_dir, "VmMngr.*pyd"))
+            if len(ext_files) == 1:
+                ext = os.path.basename(ext_files[0]).replace("VmMngr", "")
+        lib_dir = os.path.join(lib_dir, 'arch')
+        try:
+            jit_lib = os.path.join(
+                lib_dir, self.arch_dependent_libs[self.lifter.arch.name] + ext
+            )
+            libs_to_load.append(jit_lib)
+        except KeyError:
+            pass
+
+        # Create a context
+        self.context = LLVMContext_JIT(libs_to_load, self.lifter)
+
+        # Set the optimisation level
+        self.context.optimise_level()
+
+        # Save the current architecture parameters
+        self.arch = self.lifter.arch
+
+        # Get the correspondence between registers and vmcpu struct
+        mod_name = "miasm.jitter.arch.JitCore_%s" % (self.lifter.arch.name)
+        mod = importlib.import_module(mod_name)
+        self.context.set_vmcpu(mod.get_gpreg_offset_all())
+
+        # Enable caching
+        self.context.enable_cache()
+
+    def add_block(self, block):
+        """Add a block to JiT and JiT it.
+        @block: the block to add
+        """
+
+        block_hash = self.hash_block(block)
+        fname_out = os.path.join(self.tempdir, "%s.bc" % block_hash)
+
+        if not os.access(fname_out, os.R_OK):
+            # Build a function in the context
+            func = LLVMFunction(self.context, self.FUNCNAME)
+
+            # Set log level
+            func.log_regs = self.log_regs
+            func.log_mn = self.log_mn
+
+            # Import asm block
+            func.from_asmblock(block)
+
+            # Verify
+            if self.options["safe_mode"] is True:
+                func.verify()
+
+            # Optimise
+            if self.options["optimise"] is True:
+                func.optimise()
+
+            # Log
+            if self.options["log_func"] is True:
+                print(func)
+            if self.options["log_assembly"] is True:
+                print(func.get_assembly())
+
+            # Use propagate the cache filename
+            self.context.set_cache_filename(func, fname_out)
+
+            # Get a pointer on the function for JiT
+            ptr = func.get_function_pointer()
+
+        else:
+            # The cache file exists: function can be loaded from cache
+            ptr = self.context.get_ptr_from_cache(fname_out, self.FUNCNAME)
+
+        # Store a pointer on the function jitted code
+        loc_key = block.loc_key
+        offset = self.lifter.loc_db.get_location_offset(loc_key)
+        self.offset_to_jitted_func[offset] = ptr
diff --git a/src/miasm/jitter/jitcore_python.py b/src/miasm/jitter/jitcore_python.py
new file mode 100644
index 00000000..269df973
--- /dev/null
+++ b/src/miasm/jitter/jitcore_python.py
@@ -0,0 +1,219 @@
+from __future__ import print_function
+from builtins import zip
+import miasm.jitter.jitcore as jitcore
+from miasm.expression.expression import ExprInt, ExprLoc
+import miasm.jitter.csts as csts
+from miasm.expression.simplifications import expr_simp_explicit
+from miasm.jitter.emulatedsymbexec import EmulatedSymbExec
+
+################################################################################
+#                              Python jitter Core                              #
+################################################################################
+
+
+class JitCore_Python(jitcore.JitCore):
+    "JiT management, using Miasm2 Symbol Execution engine as backend"
+
+    SymbExecClass = EmulatedSymbExec
+
+    def __init__(self, lifter, bin_stream):
+        super(JitCore_Python, self).__init__(lifter, bin_stream)
+        self.lifter = lifter
+        self.ircfg = self.lifter.new_ircfg()
+
+        # CPU & VM (None for now) will be set later
+
+        self.symbexec = self.SymbExecClass(
+            None, None,
+            self.lifter, {},
+            sb_expr_simp=expr_simp_explicit
+        )
+        self.symbexec.enable_emulated_simplifications()
+
+    def set_cpu_vm(self, cpu, vm):
+        self.symbexec.cpu = cpu
+        self.symbexec.vm = vm
+
+    def load(self):
+        "Preload symbols according to current architecture"
+        self.symbexec.reset_regs()
+
+    def arch_specific(self):
+        """Return arch specific information for the current architecture"""
+        arch = self.lifter.arch
+        has_delayslot = False
+        if arch.name == "mips32":
+            from miasm.arch.mips32.jit import mipsCGen
+            cgen_class = mipsCGen
+            has_delayslot = True
+        elif arch.name == "arm":
+            from miasm.arch.arm.jit import arm_CGen
+            cgen_class = arm_CGen
+        else:
+            from miasm.jitter.codegen import CGen
+            cgen_class = CGen
+        return cgen_class(self.lifter), has_delayslot
+
+    def add_block(self, asmblock):
+        """Create a python function corresponding to an AsmBlock
+        @asmblock: AsmBlock
+        """
+
+        # TODO: merge duplicate code with CGen, llvmconvert
+        codegen, has_delayslot = self.arch_specific()
+        irblocks_list = codegen.block2assignblks(asmblock)
+        instr_offsets = [line.offset for line in asmblock.lines]
+
+        loc_db = self.lifter.loc_db
+        local_loc_keys = []
+        for irblocks in irblocks_list:
+            for irblock in irblocks:
+                local_loc_keys.append(irblock.loc_key)
+
+        def myfunc(cpu):
+            """Execute the function according to cpu and vmmngr states
+            @cpu: JitCpu instance
+            """
+            # Get virtual memory handler
+            vmmngr = cpu.vmmngr
+
+            # Get execution engine (EmulatedSymbExec instance)
+            exec_engine = self.symbexec
+
+            # Refresh CPU values according to @cpu instance
+            exec_engine.update_engine_from_cpu()
+
+            # Get initial loc_key
+            cur_loc_key = asmblock.loc_key
+
+            # Update PC helper
+            update_pc = lambda value: setattr(cpu, self.lifter.pc.name, value)
+
+            while True:
+                # Retrieve the expected irblock
+                for instr, irblocks in zip(asmblock.lines, irblocks_list):
+                    for index, irblock in enumerate(irblocks):
+                        if irblock.loc_key == cur_loc_key:
+                            break
+                    else:
+                        continue
+                    break
+                else:
+                    raise RuntimeError("Unable to find the block for %r" % cur_loc_key)
+
+                instr_attrib, irblocks_attributes = codegen.get_attributes(
+                    instr, irblocks, self.log_mn, self.log_regs
+                )
+                irblock_attributes = irblocks_attributes[index]
+
+                # Do IRBlock
+                new_irblock = self.lifter.irbloc_fix_regs_for_mode(
+                    irblock, self.lifter.attrib
+                )
+                if index == 0:
+                    # Pre code
+                    if instr_attrib.log_mn:
+                        print("%.8X %s" % (
+                            instr_attrib.instr.offset,
+                            instr_attrib.instr.to_string(loc_db)
+                        ))
+
+                # Exec IRBlock
+                instr = instr_attrib.instr
+
+                for index, assignblk in enumerate(irblock):
+                    attributes = irblock_attributes[index]
+
+                    # Eval current instruction (in IR)
+                    exec_engine.eval_updt_assignblk(assignblk)
+
+                    # Check memory access / write exception
+                    # TODO: insert a check between memory reads and writes
+                    if attributes.mem_read or attributes.mem_write:
+                        # Restricted exception
+                        flag = ~csts.EXCEPT_CODE_AUTOMOD & csts.EXCEPT_DO_NOT_UPDATE_PC
+                        if (vmmngr.get_exception() & flag != 0):
+                            # Do not update registers
+                            update_pc(instr.offset)
+                            return instr.offset
+
+                    # Update registers values
+                    exec_engine.update_cpu_from_engine()
+
+                    # Check post assignblk exception flags
+                    if attributes.set_exception:
+                        # Restricted exception
+                        if cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP:
+                            # Update PC
+                            update_pc(instr.offset)
+                            return instr.offset
+
+                dst = exec_engine.eval_expr(self.lifter.IRDst)
+                if dst.is_int():
+                    loc_key = loc_db.get_or_create_offset_location(int(dst))
+                    dst = ExprLoc(loc_key, dst.size)
+
+                assert dst.is_loc()
+                loc_key = dst.loc_key
+                offset = loc_db.get_location_offset(loc_key)
+                if offset is None:
+                    # Avoid checks on generated label
+                    cur_loc_key = loc_key
+                    continue
+
+                if instr_attrib.log_regs:
+                    update_pc(offset)
+                    cpu.dump_gpregs_with_attrib(self.lifter.attrib)
+
+                # Post-instr checks
+                if instr_attrib.mem_read | instr_attrib.mem_write:
+                    vmmngr.check_memory_breakpoint()
+                    vmmngr.check_invalid_code_blocs()
+                    if vmmngr.get_exception():
+                        update_pc(offset)
+                        return offset
+
+                if instr_attrib.set_exception:
+                    if cpu.get_exception():
+                        update_pc(offset)
+                        return offset
+
+                if instr_attrib.mem_read | instr_attrib.mem_write:
+                    vmmngr.reset_memory_access()
+
+                # Manage resulting address
+                if (loc_key in local_loc_keys and
+                    offset > instr.offset):
+                    # Forward local jump
+                    # Note: a backward local jump has to be promoted to extern,
+                    # for max_exec_per_call support
+                    cur_loc_key = loc_key
+                    continue
+
+                # Delay slot
+                if has_delayslot:
+                    delay_slot_set = exec_engine.eval_expr(codegen.delay_slot_set)
+                    if delay_slot_set.is_int() and int(delay_slot_set) != 0:
+                        return int(exec_engine.eval_expr(codegen.delay_slot_dst))
+
+                # Extern of asmblock, must have an offset
+                assert offset is not None
+                return offset
+
+        # Associate myfunc with current loc_key
+        offset = loc_db.get_location_offset(asmblock.loc_key)
+        assert offset is not None
+        self.offset_to_jitted_func[offset] = myfunc
+
+    def exec_wrapper(self, loc_key, cpu, _offset_to_jitted_func, _stop_offsets,
+                     _max_exec_per_call):
+        """Call the function @loc_key with @cpu
+        @loc_key: function's loc_key
+        @cpu: JitCpu instance
+        """
+
+        # Get Python function corresponding to @loc_key
+        fc_ptr = self.offset_to_jitted_func[loc_key]
+
+        # Execute the function
+        return fc_ptr(cpu)
diff --git a/src/miasm/jitter/jitload.py b/src/miasm/jitter/jitload.py
new file mode 100644
index 00000000..99e4429d
--- /dev/null
+++ b/src/miasm/jitter/jitload.py
@@ -0,0 +1,585 @@
+import logging
+import warnings
+from functools import wraps
+from collections import namedtuple
+try:
+    from collections.abc import Sequence, Iterator
+except ImportError:
+    from collections import Sequence, Iterator
+
+from future.utils import viewitems
+
+from miasm.jitter.csts import *
+from miasm.core.utils import *
+from miasm.core.bin_stream import bin_stream_vm
+from miasm.jitter.emulatedsymbexec import EmulatedSymbExec
+from miasm.jitter.codegen import CGen
+from miasm.jitter.jitcore_cc_base import JitCore_Cc_Base
+
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log = logging.getLogger('jitload.py')
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+log_func = logging.getLogger('jit function call')
+log_func.addHandler(hnd)
+log_func.setLevel(logging.CRITICAL)
+
+try:
+    from miasm.jitter import VmMngr
+except ImportError:
+    log.error('cannot import VmMngr')
+
+
+def named_arguments(func):
+    """Function decorator to allow the use of .func_args_*() methods
+    with either the number of arguments or the list of the argument
+    names.
+
+    The wrapper is also used to log the argument values.
+
+    @func: function
+
+    """
+    @wraps(func)
+    def newfunc(self, args):
+        if isinstance(args, Sequence):
+            ret_ad, arg_vals = func(self, len(args))
+            arg_vals = namedtuple("args", args)(*arg_vals)
+            # func_name(arguments) return address
+            log_func.info(
+                '%s(%s) ret addr: %s',
+                get_caller_name(1),
+                ', '.join(
+                    "%s=0x%x" % (field, value)
+                    for field, value in viewitems(arg_vals._asdict())
+                ),
+                hex(ret_ad)
+            )
+            return ret_ad, namedtuple("args", args)(*arg_vals)
+        else:
+            ret_ad, arg_vals = func(self, args)
+            # func_name(arguments) return address
+            log_func.info('%s(%s) ret addr: %s',
+                get_caller_name(1),
+                ', '.join(hex(arg) for arg in arg_vals),
+                hex(ret_ad))
+            return ret_ad, arg_vals
+    return newfunc
+
+
+class CallbackHandler(object):
+
+    "Handle a list of callback"
+
+    def __init__(self):
+        self.callbacks = {}  # Key -> [callback list]
+
+    def add_callback(self, key, callback):
+        """Add a callback to the key @key, iff the @callback isn't already
+        assigned to it"""
+        if callback not in self.callbacks.get(key, []):
+            self.callbacks[key] = self.callbacks.get(key, []) + [callback]
+
+    def set_callback(self, key, *args):
+        "Set the list of callback for key 'key'"
+        self.callbacks[key] = list(args)
+
+    def get_callbacks(self, key):
+        "Return the list of callbacks associated to key 'key'"
+        return self.callbacks.get(key, [])
+
+    def remove_callback(self, callback):
+        """Remove the callback from the list.
+        Return the list of empty keys (removed)"""
+
+        to_check = set()
+        for key, cb_list in viewitems(self.callbacks):
+            try:
+                cb_list.remove(callback)
+                to_check.add(key)
+            except ValueError:
+                pass
+
+        empty_keys = []
+        for key in to_check:
+            if len(self.callbacks[key]) == 0:
+                empty_keys.append(key)
+                del(self.callbacks[key])
+
+        return empty_keys
+
+    def has_callbacks(self, key):
+        return key in self.callbacks
+
+    def remove_key(self, key):
+        """Remove and return all callbacks associated to @key"""
+        callbacks = self.callbacks.get(key, [])
+        del self.callbacks[key]
+        return callbacks
+
+    def call_callbacks(self, key, *args):
+        """Call callbacks associated to key 'key' with arguments args. While
+        callbacks return True, continue with next callback.
+        Iterator on other results."""
+
+        res = True
+
+        for c in self.get_callbacks(key):
+            res = c(*args)
+            if res is not True:
+                yield res
+
+    def __call__(self, key, *args):
+        "Wrapper for call_callbacks"
+        return self.call_callbacks(key, *args)
+
+
+class CallbackHandlerBitflag(CallbackHandler):
+
+    "Handle a list of callback with conditions on bitflag"
+
+    def call_callbacks(self, bitflag, *args):
+        """Call each callbacks associated with bit set in bitflag. While
+        callbacks return True, continue with next callback.
+        Iterator on other results"""
+
+        for bitflag_expected in self.callbacks:
+            if bitflag_expected & bitflag == bitflag_expected:
+                # If the flag matched
+                for res in super(CallbackHandlerBitflag,
+                                 self).call_callbacks(bitflag_expected, *args):
+                    if res is not True:
+                        yield res
+
+
+class ExceptionHandle(object):
+
+    "Return type for exception handler"
+
+    def __init__(self, except_flag):
+        self.except_flag = except_flag
+
+    @classmethod
+    def memoryBreakpoint(cls):
+        return cls(EXCEPT_BREAKPOINT_MEMORY)
+
+    def __eq__(self, to_cmp):
+        if not isinstance(to_cmp, ExceptionHandle):
+            return False
+        return (self.except_flag == to_cmp.except_flag)
+
+    def __ne__(self, to_cmp):
+        return not self.__eq__(to_cmp)
+
+
+class JitterException(Exception):
+
+    "Raised when any unhandled exception occurs (in jitter.vm or jitter.cpu)"
+
+    def __init__(self, exception_flag):
+        super(JitterException, self).__init__()
+        self.exception_flag = exception_flag
+
+    def __str__(self):
+        return "A jitter exception occurred: %s (0x%x)" % (
+            self.exception_flag_to_str(), self.exception_flag
+        )
+
+    def exception_flag_to_str(self):
+        exception_flag_list = []
+        for name, value in JitterExceptions.items():
+            if value & self.exception_flag == value:
+                exception_flag_list.append(name)
+        return ' & '.join(exception_flag_list)
+
+
+class Jitter(object):
+
+    "Main class for JIT handling"
+
+    C_Gen = CGen
+
+    def __init__(self, lifter, jit_type="gcc"):
+        """Init an instance of jitter.
+        @lifter: Lifter instance for this architecture
+        @jit_type: JiT backend to use. Available options are:
+            - "gcc"
+            - "llvm"
+            - "python"
+        """
+
+        self.arch = lifter.arch
+        self.attrib = lifter.attrib
+        arch_name = lifter.arch.name  # (lifter.arch.name, lifter.attrib)
+        self.running = False
+
+        try:
+            if arch_name == "x86":
+                from miasm.jitter.arch import JitCore_x86 as jcore
+            elif arch_name == "arm":
+                from miasm.jitter.arch import JitCore_arm as jcore
+            elif arch_name == "armt":
+                from miasm.jitter.arch import JitCore_arm as jcore
+                lifter.arch.name = 'arm'
+            elif arch_name == "aarch64":
+                from miasm.jitter.arch import JitCore_aarch64 as jcore
+            elif arch_name == "msp430":
+                from miasm.jitter.arch import JitCore_msp430 as jcore
+            elif arch_name == "mips32":
+                from miasm.jitter.arch import JitCore_mips32 as jcore
+            elif arch_name == "ppc32":
+                from miasm.jitter.arch import JitCore_ppc32 as jcore
+            elif arch_name == "mep":
+                from miasm.jitter.arch import JitCore_mep as jcore
+            else:
+                raise ValueError("unknown jit arch: %s" % arch_name)
+        except ImportError:
+            raise RuntimeError('Unsupported jit arch: %s' % arch_name)
+
+        self.vm = VmMngr.Vm()
+        self.cpu = jcore.JitCpu()
+        self.lifter = lifter
+        self.bs = bin_stream_vm(self.vm)
+        self.ircfg = self.lifter.new_ircfg()
+
+        self.symbexec = EmulatedSymbExec(
+            self.cpu, self.vm, self.lifter, {}
+        )
+        self.symbexec.reset_regs()
+
+        try:
+            if jit_type == "llvm":
+                from miasm.jitter.jitcore_llvm import JitCore_LLVM as JitCore
+            elif jit_type == "python":
+                from miasm.jitter.jitcore_python import JitCore_Python as JitCore
+            elif jit_type == "gcc":
+                from miasm.jitter.jitcore_gcc import JitCore_Gcc as JitCore
+            else:
+                raise ValueError("Unknown jitter %s" % jit_type)
+        except ImportError:
+            raise RuntimeError('Unsupported jitter: %s' % jit_type)
+
+        self.jit = JitCore(self.lifter, self.bs)
+        if isinstance(self.jit, JitCore_Cc_Base):
+            self.jit.init_codegen(self.C_Gen(self.lifter))
+        elif jit_type == "python":
+            self.jit.set_cpu_vm(self.cpu, self.vm)
+
+        self.cpu.init_regs()
+        self.vm.init_memory_page_pool()
+        self.vm.init_code_bloc_pool()
+        self.vm.init_memory_breakpoint()
+
+        self.jit.load()
+        self.cpu.vmmngr = self.vm
+        self.cpu.jitter = self.jit
+        self.stack_size = 0x10000
+        self.stack_base = 0x1230000
+
+        # Init callback handler
+        self.breakpoints_handler = CallbackHandler()
+        self.exceptions_handler = CallbackHandlerBitflag()
+        self.init_exceptions_handler()
+        self.exec_cb = None
+
+    def init_exceptions_handler(self):
+        "Add common exceptions handlers"
+
+        def exception_automod(jitter):
+            "Tell the JiT backend to update blocks modified"
+
+            self.jit.updt_automod_code(jitter.vm)
+            self.vm.set_exception(0)
+
+            return True
+
+        self.add_exception_handler(EXCEPT_CODE_AUTOMOD, exception_automod)
+
+    def add_breakpoint(self, addr, callback):
+        """Add a callback associated with addr.
+        @addr: breakpoint address
+        @callback: function with definition (jitter instance)
+        """
+        self.breakpoints_handler.add_callback(addr, callback)
+        self.jit.add_disassembly_splits(addr)
+        # De-jit previously jitted blocks
+        self.jit.updt_automod_code_range(self.vm, [(addr, addr)])
+
+    def set_breakpoint(self, addr, *args):
+        """Set callbacks associated with addr.
+        @addr: breakpoint address
+        @args: functions with definition (jitter instance)
+        """
+        self.breakpoints_handler.set_callback(addr, *args)
+        self.jit.add_disassembly_splits(addr)
+
+    def get_breakpoint(self, addr):
+        """
+        Return breakpoints handlers for address @addr
+        @addr: integer
+        """
+        return self.breakpoints_handler.get_callbacks(addr)
+
+    def remove_breakpoints_by_callback(self, callback):
+        """Remove callbacks associated with breakpoint.
+        @callback: callback to remove
+        """
+        empty_keys = self.breakpoints_handler.remove_callback(callback)
+        for key in empty_keys:
+            self.jit.remove_disassembly_splits(key)
+
+    def remove_breakpoints_by_address(self, address):
+        """Remove all breakpoints associated with @address.
+        @address: address of breakpoints to remove
+        """
+        callbacks = self.breakpoints_handler.remove_key(address)
+        if callbacks:
+            self.jit.remove_disassembly_splits(address)
+
+    def add_exception_handler(self, flag, callback):
+        """Add a callback associated with an exception flag.
+        @flag: bitflag
+        @callback: function with definition (jitter instance)
+        """
+        self.exceptions_handler.add_callback(flag, callback)
+
+    def run_at(self, pc):
+        """Wrapper on JiT backend. Run the code at PC and return the next PC.
+        @pc: address of code to run"""
+
+        return self.jit.run_at(
+            self.cpu, pc,
+            set(self.breakpoints_handler.callbacks)
+        )
+
+    def runiter_once(self, pc):
+        """Iterator on callbacks results on code running from PC.
+        Check exceptions before breakpoints."""
+
+        self.pc = pc
+        # Callback called before exec
+        if self.exec_cb is not None:
+            res = self.exec_cb(self)
+            if res is not True:
+                yield res
+
+        # Check breakpoints
+        old_pc = self.pc
+        for res in self.breakpoints_handler.call_callbacks(self.pc, self):
+            if res is not True:
+                if isinstance(res, Iterator):
+                    # If the breakpoint is a generator, yield it step by step
+                    for tmp in res:
+                        yield tmp
+                else:
+                    yield res
+
+        # Check exceptions (raised by breakpoints)
+        exception_flag = self.get_exception()
+        for res in self.exceptions_handler(exception_flag, self):
+            if res is not True:
+                if isinstance(res, Iterator):
+                    for tmp in res:
+                        yield tmp
+                else:
+                    yield res
+
+        # If a callback changed pc, re call every callback
+        if old_pc != self.pc:
+            return
+
+        # Exceptions should never be activated before run
+        exception_flag = self.get_exception()
+        if exception_flag:
+            raise JitterException(exception_flag)
+
+        # Run the block at PC
+        self.pc = self.run_at(self.pc)
+
+        # Check exceptions (raised by the execution of the block)
+        exception_flag = self.get_exception()
+        for res in self.exceptions_handler(exception_flag, self):
+            if res is not True:
+                if isinstance(res, Iterator):
+                    for tmp in res:
+                        yield tmp
+                else:
+                    yield res
+
+    def init_run(self, pc):
+        """Create an iterator on pc with runiter.
+        @pc: address of code to run
+        """
+        self.run_iterator = self.runiter_once(pc)
+        self.pc = pc
+        self.running = True
+
+    def continue_run(self, step=False, trace=False):
+        """PRE: init_run.
+        Continue the run of the current session until iterator returns or run is
+        set to False.
+        If step is True, run only one time.
+        If trace is True, activate trace log option until execution stops
+        Return the iterator value"""
+
+        if trace:
+            self.set_trace_log()
+        while self.running:
+            try:
+                return next(self.run_iterator)
+            except StopIteration:
+                pass
+
+            self.run_iterator = self.runiter_once(self.pc)
+
+            if step is True:
+                break
+        if trace:
+            self.set_trace_log(False, False, False)
+        return None
+
+
+    def run(self, addr):
+        """
+        Launch emulation
+        @addr: (int) start address
+        """
+        self.init_run(addr)
+        return self.continue_run()
+
+    def run_until(self, addr, trace=False):
+        """PRE: init_run.
+        Continue the run of the current session until iterator returns, run is
+        set to False or addr is reached.
+        If trace is True, activate trace log option until execution stops
+        Return the iterator value"""
+
+        def stop_exec(jitter):
+            jitter.remove_breakpoints_by_callback(stop_exec)
+            return False
+        self.add_breakpoint(addr, stop_exec)
+        return self.continue_run(trace=trace)
+
+    def init_stack(self):
+        self.vm.add_memory_page(
+            self.stack_base,
+            PAGE_READ | PAGE_WRITE,
+            b"\x00" * self.stack_size,
+            "Stack")
+        sp = self.arch.getsp(self.attrib)
+        setattr(self.cpu, sp.name, self.stack_base + self.stack_size)
+        # regs = self.cpu.get_gpreg()
+        # regs[sp.name] = self.stack_base+self.stack_size
+        # self.cpu.set_gpreg(regs)
+
+    def get_exception(self):
+        return self.cpu.get_exception() | self.vm.get_exception()
+
+    # common functions
+    def get_c_str(self, addr, max_char=None):
+        """Get C str from vm.
+        @addr: address in memory
+        @max_char: maximum len"""
+        l = 0
+        tmp = addr
+        while ((max_char is None or l < max_char) and
+               self.vm.get_mem(tmp, 1) != b"\x00"):
+            tmp += 1
+            l += 1
+        value = self.vm.get_mem(addr, l)
+        value = force_str(value)
+        return value
+
+    def set_c_str(self, addr, value):
+        """Set C str str from vm.
+        @addr: address in memory
+        @value: str"""
+        value = force_bytes(value)
+        self.vm.set_mem(addr, value + b'\x00')
+
+    def get_str_ansi(self, addr, max_char=None):
+        raise NotImplementedError("Deprecated: use os_dep.win_api_x86_32.get_win_str_a")
+
+    def get_str_unic(self, addr, max_char=None):
+        raise NotImplementedError("Deprecated: use os_dep.win_api_x86_32.get_win_str_a")
+
+    @staticmethod
+    def handle_lib(jitter):
+        """Resolve the name of the function which cause the handler call. Then
+        call the corresponding handler from users callback.
+        """
+        fname = jitter.libs.fad2cname[jitter.pc]
+        if fname in jitter.user_globals:
+            func = jitter.user_globals[fname]
+        else:
+            log.debug('%r', fname)
+            raise ValueError('unknown api', hex(jitter.pc), repr(fname))
+        ret = func(jitter)
+        jitter.pc = getattr(jitter.cpu, jitter.lifter.pc.name)
+
+        # Don't break on a None return
+        if ret is None:
+            return True
+        else:
+            return ret
+
+    def handle_function(self, f_addr):
+        """Add a breakpoint which will trigger the function handler"""
+        self.add_breakpoint(f_addr, self.handle_lib)
+
+    def add_lib_handler(self, libs, user_globals=None):
+        """Add a function to handle libs call with breakpoints
+        @libs: libimp instance
+        @user_globals: dictionary for defined user function
+        """
+        if user_globals is None:
+            user_globals = {}
+
+        self.libs = libs
+        out = {}
+        for name, func in viewitems(user_globals):
+            out[name] = func
+        self.user_globals = out
+
+        for f_addr in libs.fad2cname:
+            self.handle_function(f_addr)
+
+    def eval_expr(self, expr):
+        """Eval expression @expr in the context of the current instance. Side
+        effects are passed on it"""
+        self.symbexec.update_engine_from_cpu()
+        ret = self.symbexec.eval_updt_expr(expr)
+        self.symbexec.update_cpu_from_engine()
+
+        return ret
+
+    def set_trace_log(self,
+                      trace_instr=True, trace_regs=True,
+                      trace_new_blocks=False):
+        """
+        Activate/Deactivate trace log options
+
+        @trace_instr: activate instructions tracing log
+        @trace_regs: activate registers tracing log
+        @trace_new_blocks: dump new code blocks log
+        """
+
+        # As trace state changes, clear already jitted blocks
+        self.jit.clear_jitted_blocks()
+
+        self.jit.log_mn = trace_instr
+        self.jit.log_regs = trace_regs
+        self.jit.log_newbloc = trace_new_blocks
+
+
+class jitter(Jitter):
+    """
+    DEPRECATED object
+    Use Jitter instead of jitter
+    """
+
+
+    def __init__(self, *args, **kwargs):
+        warnings.warn("Deprecated API: use Jitter")
+        super(jitter, self).__init__(*args, **kwargs)
diff --git a/src/miasm/jitter/llvmconvert.py b/src/miasm/jitter/llvmconvert.py
new file mode 100644
index 00000000..2430d884
--- /dev/null
+++ b/src/miasm/jitter/llvmconvert.py
@@ -0,0 +1,1935 @@
+#
+#
+# Miasm2 Extension:                                                            #
+# - Miasm2 IR to LLVM IR                                                       #
+# - JiT                                                                        #
+#
+# Requires:                                                                    #
+# - llvmlite (tested on v0.15)                                                 #
+#
+# Authors : Fabrice DESCLAUX (CEA/DAM), Camille MOUGEY (CEA/DAM)               #
+#
+#
+
+from builtins import zip
+from builtins import range
+import os
+from llvmlite import binding as llvm
+from llvmlite import ir as llvm_ir
+from builtins import int as int_types
+import warnings
+
+from future.utils import viewitems, viewvalues
+
+from miasm.expression.expression import ExprId, ExprInt, ExprMem, ExprSlice, \
+    ExprCond, ExprLoc, ExprOp, ExprCompose, LocKey, Expr, \
+    TOK_EQUAL, \
+    TOK_INF_SIGNED, TOK_INF_UNSIGNED, \
+    TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED
+
+import miasm.jitter.csts as m2_csts
+import miasm.core.asmblock as m2_asmblock
+from miasm.core.utils import size2mask
+from miasm.jitter.codegen import CGen, Attributes
+from miasm.expression.expression_helper import possible_values
+
+
+class LLVMType(llvm_ir.Type):
+
+    "Handle LLVM Type"
+
+    int_cache = {}
+
+    @classmethod
+    def IntType(cls, size=32):
+        try:
+            return cls.int_cache[size]
+        except KeyError:
+            cls.int_cache[size] = llvm_ir.IntType(size)
+            return cls.int_cache[size]
+
+    @classmethod
+    def pointer(cls, addr):
+        "Generic pointer for execution"
+        return llvm_e.GenericValue.pointer(addr)
+
+    @classmethod
+    def generic(cls, e):
+        "Generic value for execution"
+        if isinstance(e, ExprInt):
+            return llvm_e.GenericValue.int(LLVMType.IntType(e.size), int(e.arg))
+        elif isinstance(e, llvm_e.GenericValue):
+            return e
+        else:
+            raise ValueError()
+
+    @classmethod
+    def fptype(cls, size):
+        """Return the floating type corresponding to precision @size"""
+        if size == 32:
+            precision = llvm_ir.FloatType()
+        elif size == 64:
+            precision = llvm_ir.DoubleType()
+        else:
+            raise RuntimeError("Unsupported precision: %x", size)
+        return precision
+
+
+class LLVMContext(object):
+
+    "Context for llvm binding. Stand for a LLVM Module"
+
+    known_fc = {}
+
+    def __init__(self, name="mod"):
+        "Initialize a context with a module named 'name'"
+        # Initialize llvm
+        llvm.initialize()
+        llvm.initialize_native_target()
+        llvm.initialize_native_asmprinter()
+
+        # Initialize target for compilation
+        target = llvm.Target.from_default_triple()
+        self.target_machine = target.create_target_machine()
+        self.init_exec_engine()
+
+    def canonize_label_name(self, label):
+        """Canonize @label names to a common form.
+        @label: str or asmlabel instance"""
+        if isinstance(label, str):
+            return label
+        elif isinstance(label, LocKey):
+            return str(label)
+        else:
+            raise ValueError("label must either be str or LocKey")
+
+    def optimise_level(self, level=2):
+        """Set the optimisation level to @level from 0 to 2
+        0: non-optimized
+        2: optimized
+        """
+
+        # Set up the optimiser pipeline
+        pmb = llvm.create_pass_manager_builder()
+        pmb.opt_level = level
+        pm = llvm.create_module_pass_manager()
+        pmb.populate(pm)
+        self.pass_manager = pm
+
+    def init_exec_engine(self):
+        mod = llvm.parse_assembly("")
+        engine = llvm.create_mcjit_compiler(mod,
+                                            self.target_machine)
+        self.exec_engine = engine
+
+    def new_module(self, name="mod"):
+        """Create a module, with needed functions"""
+        self.mod = llvm_ir.Module(name=name)
+        self.add_fc(self.known_fc)
+        self.add_op()
+
+    def get_execengine(self):
+        "Return the Execution Engine associated with this context"
+        return self.exec_engine
+
+    def get_passmanager(self):
+        "Return the Pass Manager associated with this context"
+        return self.pass_manager
+
+    def get_module(self):
+        "Return the module associated with this context"
+        return self.mod
+
+    def add_shared_library(self, filename):
+        "Load the shared library 'filename'"
+        return llvm.load_library_permanently(filename)
+
+    def add_fc(self, fc, readonly=False):
+        "Add function into known_fc"
+
+        for name, detail in viewitems(fc):
+            fnty = llvm_ir.FunctionType(detail["ret"], detail["args"])
+            fn = llvm_ir.Function(self.mod, fnty, name=name)
+            if readonly:
+                fn.attributes.add("readonly")
+
+    def add_op(self):
+        "Add operations functions"
+
+        i8 = LLVMType.IntType(8)
+        p8 = llvm_ir.PointerType(i8)
+        itype = LLVMType.IntType(64)
+        ftype = llvm_ir.FloatType()
+        dtype = llvm_ir.DoubleType()
+        fc = {"llvm.ctpop.i8": {"ret": i8,
+                                "args": [i8]},
+              "llvm.nearbyint.f32": {"ret": ftype,
+                                     "args": [ftype]},
+              "llvm.nearbyint.f64": {"ret": dtype,
+                                     "args": [dtype]},
+              "llvm.trunc.f32": {"ret": ftype,
+                                 "args": [ftype]},
+              "segm2addr": {"ret": itype,
+                            "args": [p8,
+                                     itype,
+                                     itype]},
+              "x86_cpuid": {"ret": itype,
+                        "args": [itype,
+                                 itype]},
+              "fpu_fcom_c0": {"ret": itype,
+                          "args": [dtype,
+                                   dtype]},
+              "fpu_fcom_c1": {"ret": itype,
+                          "args": [dtype,
+                                   dtype]},
+              "fpu_fcom_c2": {"ret": itype,
+                          "args": [dtype,
+                                   dtype]},
+              "fpu_fcom_c3": {"ret": itype,
+                          "args": [dtype,
+                                   dtype]},
+              "llvm.sqrt.f32": {"ret": ftype,
+                                "args": [ftype]},
+              "llvm.sqrt.f64": {"ret": dtype,
+                                "args": [dtype]},
+              "llvm.fabs.f32": {"ret": ftype,
+                                "args": [ftype]},
+              "llvm.fabs.f64": {"ret": dtype,
+                                "args": [dtype]},
+        }
+
+        for k in [8, 16]:
+            fc["bcdadd_%s" % k] = {"ret": LLVMType.IntType(k),
+                                   "args": [LLVMType.IntType(k),
+                                            LLVMType.IntType(k)]}
+            fc["bcdadd_cf_%s" % k] = {"ret": LLVMType.IntType(k),
+                                      "args": [LLVMType.IntType(k),
+                                               LLVMType.IntType(k)]}
+        self.add_fc(fc, readonly=True)
+
+
+    def memory_lookup(self, func, addr, size):
+        """Perform a memory lookup at @addr of size @size (in bit)"""
+        raise NotImplementedError("Abstract method")
+
+    def memory_write(self, func, addr, size, value):
+        """Perform a memory write at @addr of size @size (in bit) with LLVM IR @value"""
+        raise NotImplementedError("Abstract method")
+
+
+class LLVMContext_JIT(LLVMContext):
+
+    """Extend LLVMContext_JIT in order to handle memory management and custom
+    operations"""
+
+    def __init__(self, library_filenames, lifter, name="mod"):
+        "Init a LLVMContext object, and load the mem management shared library"
+        self.library_filenames = library_filenames
+        self.lifter = lifter
+        self.arch_specific()
+        self.load_libraries()
+        LLVMContext.__init__(self, name)
+        self.vmcpu = {}
+
+    @property
+    def ir_arch(self):
+        warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"')
+        return self.lifter
+
+    def load_libraries(self):
+        # Get LLVM specific functions
+        name = "libLLVM-%d.%d" % (llvm.llvm_version_info[0],
+                                  llvm.llvm_version_info[1],
+        )
+        try:
+            # On Windows, no need to add ".dll"
+            self.add_shared_library(name)
+        except RuntimeError:
+            try:
+                # On Linux, ".so" is needed
+                self.add_shared_library("%s.so" % name)
+            except RuntimeError:
+                pass
+
+        # Load additional libraries
+        for lib_fname in self.library_filenames:
+            self.add_shared_library(lib_fname)
+
+    def new_module(self, name="mod"):
+        LLVMContext.new_module(self, name)
+        self.add_memlookups()
+        self.add_get_exceptionflag()
+        self.add_log_functions()
+
+    def arch_specific(self):
+        arch = self.lifter.arch
+        if arch.name == "x86":
+            self.PC = arch.regs.RIP
+            self.logging_func = "dump_gpregs_%d" % self.lifter.attrib
+        else:
+            self.PC = self.lifter.pc
+            self.logging_func = "dump_gpregs"
+        if arch.name == "mips32":
+            from miasm.arch.mips32.jit import mipsCGen
+            self.cgen_class = mipsCGen
+            self.has_delayslot = True
+        elif arch.name == "arm":
+            from miasm.arch.arm.jit import arm_CGen
+            self.cgen_class = arm_CGen
+            self.has_delayslot = False
+        else:
+            self.cgen_class = CGen
+            self.has_delayslot = False
+
+    def add_memlookups(self):
+        "Add MEM_LOOKUP functions"
+
+        fc = {}
+        p8 = llvm_ir.PointerType(LLVMType.IntType(8))
+        for i in [8, 16, 32, 64]:
+            fc["MEM_LOOKUP_%02d" % i] = {"ret": LLVMType.IntType(i),
+                                         "args": [p8,
+                                                  LLVMType.IntType(64)]}
+
+            fc["MEM_WRITE_%02d" % i] = {"ret": llvm_ir.VoidType(),
+                                        "args": [p8,
+                                                 LLVMType.IntType(64),
+                                                 LLVMType.IntType(i)]}
+
+        fc["MEM_LOOKUP_INT_BN_TO_PTR"] = {"ret": llvm_ir.VoidType(),
+                                          "args": [
+                                              p8,
+                                              LLVMType.IntType(32),
+                                              LLVMType.IntType(64),
+                                              p8
+                                          ]}
+        fc["MEM_WRITE_INT_BN_FROM_PTR"] = {"ret": llvm_ir.VoidType(),
+                                           "args": [
+                                               p8,
+                                               LLVMType.IntType(32),
+                                               LLVMType.IntType(64),
+                                               p8,
+                                           ]}
+
+        fc["reset_memory_access"] = {"ret": llvm_ir.VoidType(),
+                                     "args": [p8,
+                                     ]}
+        fc["check_memory_breakpoint"] = {"ret": llvm_ir.VoidType(),
+                                         "args": [p8,
+                                         ]}
+        fc["check_invalid_code_blocs"] = {"ret": llvm_ir.VoidType(),
+                                          "args": [p8,
+                                          ]}
+        self.add_fc(fc)
+
+    def add_get_exceptionflag(self):
+        "Add 'get_exception_flag' function"
+        p8 = llvm_ir.PointerType(LLVMType.IntType(8))
+        self.add_fc({"get_exception_flag": {"ret": LLVMType.IntType(64),
+                                            "args": [p8]}}, readonly=True)
+
+    def add_log_functions(self):
+        "Add functions for state logging"
+
+        p8 = llvm_ir.PointerType(LLVMType.IntType(8))
+        self.add_fc({self.logging_func: {"ret": llvm_ir.VoidType(),
+                                         "args": [p8]}},
+                    readonly=True)
+
+    def set_vmcpu(self, lookup_table):
+        "Set the correspondence between register name and vmcpu offset"
+
+        self.vmcpu = lookup_table
+
+    def memory_lookup(self, func, addr, size):
+        """Perform a memory lookup at @addr of size @size (in bit)"""
+        builder = func.builder
+        if size <= 64:
+            fc_name = "MEM_LOOKUP_%02d" % size
+            fc_ptr = self.mod.get_global(fc_name)
+            addr_casted = builder.zext(addr, LLVMType.IntType(64))
+            ret = builder.call(
+                fc_ptr, [func.local_vars["jitcpu"],addr_casted]
+            )
+        else:
+            # Miasm uses a memory lookup function which returns a bn_t for its
+            # result. We cannot simply translate this into IntType. The trick
+            # here is to use the function MEM_LOOKUP_INT_BN_TO_PTR which has a
+            # different interface: the resulting bn_t is passed through a char*
+            # argument.
+            #
+            # WARNING: Here, we use the fact that the serialisation of LLVM
+            # IntType is the *same* as the bn_t structure.
+
+            fc_name = "MEM_LOOKUP_INT_BN_TO_PTR"
+            fc_ptr = self.mod.get_global(fc_name)
+            addr_casted = builder.zext(addr, LLVMType.IntType(64))
+            size_cst = llvm_ir.Constant(LLVMType.IntType(32), size)
+
+            value_ptr = builder.alloca(llvm_ir.IntType(size))
+            value_ptr_u8 = builder.bitcast(
+                value_ptr,
+                LLVMType.IntType(8).as_pointer()
+            )
+
+
+            builder.call(
+                fc_ptr,
+                [
+                    func.local_vars["jitcpu"],
+                    size_cst,
+                    addr_casted,
+                    value_ptr_u8
+                ]
+            )
+            ret = builder.load(value_ptr)
+
+        return ret
+
+    def memory_write(self, func, addr, size, value):
+        """Perform a memory write at @addr of size @size (in bit) with LLVM IR @value"""
+        # Function call
+        builder = func.builder
+        if size <= 64:
+            fc_name = "MEM_WRITE_%02d" % size
+            fc_ptr = self.mod.get_global(fc_name)
+            dst_casted = builder.zext(addr, LLVMType.IntType(64))
+            builder.call(
+                fc_ptr,
+                [
+                    func.local_vars["jitcpu"],
+                    dst_casted,
+                    value
+                ]
+            )
+        else:
+            # The same trick as described in MEM_LOOKUP_INT_BN_TO_PTR is used
+            # here.
+
+            fc_name = "MEM_WRITE_INT_BN_FROM_PTR"
+            fc_ptr = self.mod.get_global(fc_name)
+            addr_casted = builder.zext(addr, LLVMType.IntType(64))
+            size_cst = llvm_ir.Constant(LLVMType.IntType(32), size)
+
+            ret = builder.alloca(value.type)
+            builder.store(value, ret)
+            value_ptr = builder.bitcast(ret, llvm_ir.IntType(8).as_pointer())
+
+            builder.call(
+                fc_ptr,
+                [
+                    func.local_vars["jitcpu"],
+                    size_cst,
+                    addr_casted,
+                    value_ptr,
+                ]
+            )
+
+
+    @staticmethod
+    def cache_notify(module, buffer):
+        """Called when @module has been compiled to @buffer"""
+        if not hasattr(module, "fname_out"):
+            return
+        fname_out = module.fname_out
+
+        if os.access(fname_out, os.R_OK):
+            # No need to overwrite
+            return
+
+        open(fname_out, "wb").write(buffer)
+
+    @staticmethod
+    def cache_getbuffer(module):
+        """Return a compiled buffer for @module if available"""
+        if not hasattr(module, "fname_out"):
+            return None
+
+        fname_out = module.fname_out
+        if os.access(fname_out, os.R_OK):
+            return open(fname_out, "rb").read()
+        return None
+
+    def enable_cache(self):
+        "Enable cache of compiled object"
+        # Load shared libraries
+        for lib_fname in self.library_filenames:
+            self.add_shared_library(lib_fname)
+
+        # Activate cache
+        self.exec_engine.set_object_cache(
+            self.cache_notify,
+            self.cache_getbuffer
+        )
+
+    def set_cache_filename(self, func, fname_out):
+        "Set the filename @fname_out to use for cache for @func"
+        # Use a custom attribute to propagate the cache filename
+        func.as_llvm_mod().fname_out = fname_out
+
+    def get_ptr_from_cache(self, file_name, func_name):
+        "Load @file_name and return a pointer on the jitter @func_name"
+        # We use an empty module to avoid losing time on function building
+        empty_module = llvm.parse_assembly("")
+        empty_module.fname_out = file_name
+
+        engine = self.exec_engine
+        engine.add_module(empty_module)
+        engine.finalize_object()
+        return engine.get_function_address(func_name)
+
+
+class LLVMContext_IRCompilation(LLVMContext):
+
+    """Extend LLVMContext in order to handle memory management and custom
+    operations for Miasm IR compilation"""
+
+    def memory_lookup(self, func, addr, size):
+        """Perform a memory lookup at @addr of size @size (in bit)"""
+        builder = func.builder
+        int_size = LLVMType.IntType(size)
+        ptr_casted = builder.inttoptr(
+            addr,
+            llvm_ir.PointerType(int_size)
+        )
+        return builder.load(ptr_casted)
+
+    def memory_write(self, func, addr, size, value):
+        """Perform a memory write at @addr of size @size (in bit) with LLVM IR @value"""
+        builder = func.builder
+        int_size = LLVMType.IntType(size)
+        ptr_casted = builder.inttoptr(
+            addr,
+            llvm_ir.PointerType(int_size)
+        )
+        return builder.store(value, ptr_casted)
+
+
+class LLVMFunction(object):
+    """Represent a LLVM function
+
+    Implementation note:
+    A new module is created each time to avoid cumulative lag (if @new_module)
+    """
+
+    # Default logging values
+    log_mn = False
+    log_regs = True
+
+    # Operation translation
+    ## Basics
+    op_translate = {'x86_cpuid': 'x86_cpuid',
+    }
+    ## Add the size as first argument
+    op_translate_with_size = {}
+    ## Add the size as suffix
+    op_translate_with_suffix_size = {
+        'bcdadd': 'bcdadd',
+        'bcdadd_cf': 'bcdadd_cf',
+    }
+
+    def __init__(self, llvm_context, name="fc", new_module=True):
+        "Create a new function with name @name"
+        self.llvm_context = llvm_context
+        if new_module:
+            self.llvm_context.new_module()
+        self.mod = self.llvm_context.get_module()
+
+        self.my_args = []  # (Expr, LLVMType, Name)
+        self.ret_type = None
+        self.builder = None
+        self.entry_bbl = None
+
+        self.branch_counter = 0
+        self.name = name
+        self._llvm_mod = None
+
+    # Constructor utils
+
+    def new_branch_name(self):
+        "Return a new branch name"
+        self.branch_counter += 1
+        return str(self.branch_counter)
+
+    def append_basic_block(self, label, overwrite=True):
+        """Add a new basic block to the current function.
+        @label: str or asmlabel
+        @overwrite: if False, do nothing if a bbl with the same name already exists
+        Return the corresponding LLVM Basic Block"""
+        name = self.llvm_context.canonize_label_name(label)
+        bbl = self.name2bbl.get(name, None)
+        if not overwrite and bbl is not None:
+            return bbl
+        bbl = self.fc.append_basic_block(name)
+        self.name2bbl[name] = bbl
+
+        return bbl
+
+    def CreateEntryBlockAlloca(self, var_type, default_value=None):
+        """Create an alloca instruction at the beginning of the current fc
+        @default_value: if set, store the default_value just after the allocation
+        """
+        builder = self.builder
+        current_bbl = builder.basic_block
+        builder.position_at_start(self.entry_bbl)
+
+        ret = builder.alloca(var_type)
+        if default_value is not None:
+            builder.store(default_value, ret)
+        builder.position_at_end(current_bbl)
+        return ret
+
+    def get_ptr_by_expr(self, expr):
+        """"Return a pointer casted corresponding to ExprId expr. If it is not
+        already computed, compute it at the end of entry_bloc"""
+
+        name = expr.name
+
+        ptr_casted = self.local_vars_pointers.get(name, None)
+        if ptr_casted is not None:
+            # If the pointer has already been computed
+            return ptr_casted
+
+        # Get current objects
+        builder = self.builder
+        current_bbl = builder.basic_block
+
+        # Go at the right position
+        entry_bloc_bbl = self.entry_bbl
+        builder.position_at_end(entry_bloc_bbl)
+
+        # Compute the pointer address
+        offset = self.llvm_context.vmcpu[name]
+
+        # Pointer cast
+        ptr = builder.gep(
+            self.local_vars["vmcpu"],
+            [
+                llvm_ir.Constant(
+                    LLVMType.IntType(),
+                    offset
+                )
+            ]
+        )
+        pointee_type = LLVMType.IntType(expr.size)
+        ptr_casted = builder.bitcast(
+            ptr,
+            llvm_ir.PointerType(pointee_type)
+        )
+        # Store in cache
+        self.local_vars_pointers[name] = ptr_casted
+
+        # Reset builder
+        builder.position_at_end(current_bbl)
+
+        return ptr_casted
+
+    def update_cache(self, name, value):
+        "Add 'name' = 'value' to the cache iff main_stream = True"
+
+        if self.main_stream is True:
+            self.expr_cache[name] = value
+
+    def set_ret(self, var):
+        "Cast @var and return it at the end of current bbl"
+        if var.type.width < 64:
+            var_casted = self.builder.zext(var, LLVMType.IntType(64))
+        else:
+            var_casted = var
+        self.builder.ret(var_casted)
+
+    def get_basic_block_by_loc_key(self, loc_key):
+        "Return the bbl corresponding to label, None otherwise"
+        return self.name2bbl.get(
+            self.llvm_context.canonize_label_name(loc_key),
+            None
+        )
+
+    def global_constant(self, name, value):
+        """
+        Inspired from numba/cgutils.py
+
+        Get or create a (LLVM module-)global constant with *name* or *value*.
+        """
+        if name in self.mod.globals:
+            return self.mod.globals[name]
+        data = llvm_ir.GlobalVariable(self.mod, value.type, name=name)
+        data.global_constant = True
+        data.initializer = value
+        return data
+
+    def make_bytearray(self, buf):
+        """
+        Inspired from numba/cgutils.py
+
+        Make a byte array constant from *buf*.
+        """
+        b = bytearray(buf)
+        n = len(b)
+        return llvm_ir.Constant(llvm_ir.ArrayType(llvm_ir.IntType(8), n), b)
+
+    def printf(self, format, *args):
+        """
+        Inspired from numba/cgutils.py
+
+        Calls printf().
+        Argument `format` is expected to be a Python string.
+        Values to be printed are listed in `args`.
+
+        Note: There is no checking to ensure there is correct number of values
+        in `args` and there type matches the declaration in the format string.
+        """
+        assert isinstance(format, str)
+        mod = self.mod
+        # Make global constant for format string
+        cstring = llvm_ir.IntType(8).as_pointer()
+        fmt_bytes = self.make_bytearray((format + '\00').encode('ascii'))
+
+        base_name = "printf_format"
+        count = 0
+        while "%s_%d" % (base_name, count) in self.mod.globals:
+            count += 1
+        global_fmt = self.global_constant(
+            "%s_%d" % (base_name, count),
+            fmt_bytes
+        )
+        fnty = llvm_ir.FunctionType(
+            llvm_ir.IntType(32),
+            [cstring],
+            var_arg=True
+        )
+        # Insert printf()
+        fn = mod.globals.get('printf', None)
+        if fn is None:
+            fn = llvm_ir.Function(mod, fnty, name="printf")
+        # Call
+        ptr_fmt = self.builder.bitcast(global_fmt, cstring)
+        return self.builder.call(fn, [ptr_fmt] + list(args))
+
+    # Effective constructors
+
+    def assign(self, src, dst):
+        "Assign from LLVM src to M2 dst"
+
+        # Destination
+        builder = self.builder
+
+        if isinstance(dst, ExprId):
+            ptr_casted = self.get_ptr_by_expr(dst)
+            builder.store(src, ptr_casted)
+
+        elif isinstance(dst, ExprMem):
+            addr = self.add_ir(dst.ptr)
+            self.llvm_context.memory_write(self, addr, dst.size, src)
+        else:
+            raise Exception("UnknownAssignmentType")
+
+    def init_fc(self):
+        "Init the function"
+
+        # Build type for fc signature
+        fc_type = llvm_ir.FunctionType(
+            self.ret_type,
+            [k[1] for k in self.my_args]
+        )
+
+        # Add fc in module
+        try:
+            fc = llvm_ir.Function(self.mod, fc_type, name=self.name)
+        except llvm.LLVMException:
+            # Overwrite the previous function
+            previous_fc = self.mod.get_global(self.name)
+            previous_fc.delete()
+            fc = self.mod.add_function(fc_type, self.name)
+
+        # Name args
+        for i, a in enumerate(self.my_args):
+            fc.args[i].name = a[2]
+
+        # Initialize local variable pool
+        self.local_vars = {}
+        self.local_vars_pointers = {}
+        for i, a in enumerate(self.my_args):
+            self.local_vars[a[2]] = fc.args[i]
+
+        # Init cache
+        self.expr_cache = {}
+        self.main_stream = True
+        self.name2bbl = {}
+
+        # Function link
+        self.fc = fc
+
+        # Add a first BasicBlock
+        self.entry_bbl = self.append_basic_block("entry")
+
+        # Instruction builder
+        self.builder = llvm_ir.IRBuilder(self.entry_bbl)
+
+    def add_ir(self, expr):
+        "Add a Miasm2 IR to the last bbl. Return the var created"
+
+        if self.main_stream is True and expr in self.expr_cache:
+            return self.expr_cache[expr]
+
+        builder = self.builder
+
+        if isinstance(expr, ExprInt):
+            ret = llvm_ir.Constant(LLVMType.IntType(expr.size), int(expr))
+            self.update_cache(expr, ret)
+            return ret
+
+        if expr.is_loc():
+            offset = self.llvm_context.lifter.loc_db.get_location_offset(
+                expr.loc_key
+            )
+            ret = llvm_ir.Constant(LLVMType.IntType(expr.size), offset)
+            self.update_cache(expr, ret)
+            return ret
+
+        if isinstance(expr, ExprId):
+            name = expr.name
+            try:
+                # If expr.name is already known (args)
+                return self.local_vars[name]
+            except KeyError:
+                pass
+
+            ptr_casted = self.get_ptr_by_expr(expr)
+
+            var = builder.load(ptr_casted, name)
+            self.update_cache(expr, var)
+            return var
+
+        if isinstance(expr, ExprOp):
+            op = expr.op
+
+            if (op in self.op_translate or
+                op in self.op_translate_with_size or
+                op in self.op_translate_with_suffix_size):
+                args = [self.add_ir(arg) for arg in expr.args]
+                arg_size = expr.args[0].size
+
+                if op in self.op_translate_with_size:
+                    fc_name = self.op_translate_with_size[op]
+                    arg_size_cst = llvm_ir.Constant(LLVMType.IntType(64),
+                                                    arg_size)
+                    args = [arg_size_cst] + args
+                elif op in self.op_translate:
+                    fc_name = self.op_translate[op]
+                elif op in self.op_translate_with_suffix_size:
+                    fc_name = "%s_%s" % (self.op_translate[op], arg_size)
+
+                fc_ptr = self.mod.get_global(fc_name)
+
+                # Cast args if needed
+                casted_args = []
+                for i, arg in enumerate(args):
+                    if arg.type.width < fc_ptr.args[i].type.width:
+                        casted_args.append(
+                            builder.zext(
+                                arg,
+                                fc_ptr.args[i].type
+                            )
+                        )
+                    else:
+                        casted_args.append(arg)
+                ret = builder.call(fc_ptr, casted_args)
+
+                # Cast ret if needed
+                ret_size = fc_ptr.return_value.type.width
+                if ret_size > expr.size:
+                    ret = builder.trunc(ret, LLVMType.IntType(expr.size))
+
+                self.update_cache(expr, ret)
+                return ret
+
+            if op == "-":
+                # Unsupported op '-' with more than 1 arg
+                assert len(expr.args) == 1
+                zero = LLVMType.IntType(expr.size)(0)
+                ret = builder.sub(zero, self.add_ir(expr.args[0]))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op == "parity":
+                assert len(expr.args) == 1
+                arg = self.add_ir(expr.args[0])
+                truncated = builder.trunc(arg, LLVMType.IntType(8))
+                bitcount = builder.call(
+                    self.mod.get_global("llvm.ctpop.i8"),
+                    [truncated]
+                )
+                ret = builder.not_(builder.trunc(bitcount, LLVMType.IntType(1)))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in ["cntleadzeros", "cnttrailzeros"]:
+                assert len(expr.args) == 1
+                arg = self.add_ir(expr.args[0])
+                func_name = {
+                    "cntleadzeros": "ctlz",
+                    "cnttrailzeros": "cttz",
+                }[op]
+                func_llvm_name = "llvm.%s.i%d" % (func_name, expr.size)
+                func_sig = {
+                    func_llvm_name: {
+                        "ret": LLVMType.IntType(expr.size),
+                        "args": [LLVMType.IntType(expr.args[0].size)]
+                    }
+                }
+                try:
+                    self.mod.get_global(func_llvm_name)
+                except KeyError:
+                    self.llvm_context.add_fc(func_sig, readonly=True)
+                ret = builder.call(
+                    self.mod.get_global(func_llvm_name),
+                    [arg]
+                )
+                self.update_cache(expr, ret)
+                return ret
+
+
+            if op.startswith('zeroExt_'):
+                arg = expr.args[0]
+                if expr.size == arg.size:
+                    return arg
+                new_expr = ExprCompose(arg, ExprInt(0, expr.size - arg.size))
+                return self.add_ir(new_expr)
+
+            if op.startswith("signExt_"):
+                arg = expr.args[0]
+                add_size = expr.size - arg.size
+                new_expr = ExprCompose(
+                    arg,
+                    ExprCond(
+                        arg.msb(),
+                        ExprInt(size2mask(add_size), add_size),
+                        ExprInt(0, add_size)
+                    )
+                )
+                return self.add_ir(new_expr)
+
+
+            if op == "segm":
+                fc_ptr = self.mod.get_global("segm2addr")
+
+                # Cast args if needed
+                args = [self.add_ir(arg) for arg in expr.args]
+                casted_args = []
+                for i, arg in enumerate(args, 1):
+                    if arg.type.width < fc_ptr.args[i].type.width:
+                        casted_args.append(
+                            builder.zext(
+                                arg,
+                                fc_ptr.args[i].type
+                            )
+                        )
+                    else:
+                        casted_args.append(arg)
+
+                ret = builder.call(
+                    fc_ptr,
+                    [self.local_vars["jitcpu"]] + casted_args
+                )
+                if ret.type.width > expr.size:
+                    ret = builder.trunc(ret, LLVMType.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in ["smod", "sdiv", "umod", "udiv"]:
+                assert len(expr.args) == 2
+
+                arg_b = self.add_ir(expr.args[1])
+                arg_a = self.add_ir(expr.args[0])
+
+                if op == "smod":
+                    callback = builder.srem
+                elif op == "sdiv":
+                    callback = builder.sdiv
+                elif op == "umod":
+                    callback = builder.urem
+                elif op == "udiv":
+                    callback = builder.udiv
+
+                ret = callback(arg_a, arg_b)
+                self.update_cache(expr, ret)
+                return ret
+
+            unsigned_cmps = {
+                "==": "==",
+                "<u": "<",
+                "<=u": "<="
+            }
+            if op in unsigned_cmps:
+                op = unsigned_cmps[op]
+                args = [self.add_ir(arg) for arg in expr.args]
+                ret = builder.select(
+                    builder.icmp_unsigned(op,
+                                          args[0],
+                                          args[1]
+                    ),
+                    llvm_ir.IntType(expr.size)(1),
+                    llvm_ir.IntType(expr.size)(0)
+                )
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in [">>", "<<", "a>>"]:
+                assert len(expr.args) == 2
+                # Undefined behavior must be enforced to 0
+                count = self.add_ir(expr.args[1])
+                value = self.add_ir(expr.args[0])
+                itype = LLVMType.IntType(expr.size)
+                cond_ok = self.builder.icmp_unsigned(
+                    "<",
+                    count,
+                    itype(expr.size)
+                )
+                zero = itype(0)
+                if op == ">>":
+                    callback = builder.lshr
+                elif op == "<<":
+                    callback = builder.shl
+                elif op == "a>>":
+                    callback = builder.ashr
+                    # x a>> size is 0 or -1, depending on x sign
+                    cond_neg = self.builder.icmp_signed("<", value, zero)
+                    zero = self.builder.select(cond_neg, itype(-1), zero)
+
+                ret = self.builder.select(
+                    cond_ok,
+                    callback(value, count),
+                    zero
+                )
+                self.update_cache(expr, ret)
+                return ret
+
+
+            if op in ['<<<', '>>>']:
+                assert len(expr.args) == 2
+                # First compute rotation modulus size
+                count = self.add_ir(expr.args[1])
+                value = self.add_ir(expr.args[0])
+                itype = LLVMType.IntType(expr.size)
+                expr_size = itype(expr.size)
+
+                # As shift of expr_size is undefined, we urem the shifters
+                shift = builder.urem(count, expr_size)
+                shift_inv = builder.urem(
+                    builder.sub(expr_size, shift),
+                    expr_size
+                )
+
+                if op == '<<<':
+                    part_a = builder.shl(value, shift)
+                    part_b = builder.lshr(value, shift_inv)
+                else:
+                    part_a = builder.lshr(value, shift)
+                    part_b = builder.shl(value, shift_inv)
+                ret = builder.or_(part_a, part_b)
+                self.update_cache(expr, ret)
+                return ret
+
+            if op == "sint_to_fp":
+                fptype = LLVMType.fptype(expr.size)
+                arg = self.add_ir(expr.args[0])
+                ret = builder.sitofp(arg, fptype)
+                ret = builder.bitcast(ret, llvm_ir.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op.startswith("fp_to_sint"):
+                size_arg = expr.args[0].size
+                fptype_orig = LLVMType.fptype(size_arg)
+                arg = self.add_ir(expr.args[0])
+                arg = builder.bitcast(arg, fptype_orig)
+                # Enforce IEEE-754 behavior. This could be enhanced with
+                # 'llvm.experimental.constrained.nearbyint'
+                if size_arg == 32:
+                    func = self.mod.get_global("llvm.nearbyint.f32")
+                elif size_arg == 64:
+                    func = self.mod.get_global("llvm.nearbyint.f64")
+                else:
+                    raise RuntimeError("Unsupported size")
+                rounded = builder.call(func, [arg])
+                ret = builder.fptoui(rounded, llvm_ir.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op.startswith("fpconvert_fp"):
+                assert len(expr.args) == 1
+                size_arg = expr.args[0].size
+                fptype = LLVMType.fptype(expr.size)
+                fptype_orig = LLVMType.fptype(size_arg)
+                arg = self.add_ir(expr.args[0])
+                arg = builder.bitcast(arg, fptype_orig)
+                if expr.size > size_arg:
+                    fc = builder.fpext
+                elif expr.size < size_arg:
+                    fc = builder.fptrunc
+                else:
+                    raise RuntimeError("Not supported, same size")
+                ret = fc(arg, fptype)
+                ret = builder.bitcast(ret, llvm_ir.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op.startswith("fpround_"):
+                assert len(expr.args) == 1
+                fptype = LLVMType.fptype(expr.size)
+                arg = self.add_ir(expr.args[0])
+                arg = builder.bitcast(arg, fptype)
+                if op == "fpround_towardszero" and expr.size == 32:
+                    fc = self.mod.get_global("llvm.trunc.f32")
+                else:
+                    raise RuntimeError("Not supported, same size")
+                rounded = builder.call(fc, [arg])
+                ret = builder.bitcast(rounded, llvm_ir.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in ["fcom_c0", "fcom_c1", "fcom_c2", "fcom_c3"]:
+                arg1 = self.add_ir(expr.args[0])
+                arg2 = self.add_ir(expr.args[0])
+                fc_name = "fpu_%s" % op
+                fc_ptr = self.mod.get_global(fc_name)
+                casted_args = [
+                    builder.bitcast(arg1, llvm_ir.DoubleType()),
+                    builder.bitcast(arg2, llvm_ir.DoubleType()),
+                ]
+                ret = builder.call(fc_ptr, casted_args)
+
+                # Cast ret if needed
+                ret_size = fc_ptr.return_value.type.width
+                if ret_size > expr.size:
+                    ret = builder.trunc(ret, LLVMType.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in ["fsqrt", "fabs"]:
+                arg = self.add_ir(expr.args[0])
+                if op == "fsqrt":
+                    op = "sqrt"
+
+                # Apply the correct func
+                if expr.size == 32:
+                    arg = builder.bitcast(arg, llvm_ir.FloatType())
+                    ret = builder.call(
+                        self.mod.get_global("llvm.%s.f32" % op),
+                        [arg]
+                    )
+                elif expr.size == 64:
+                    arg = builder.bitcast(arg, llvm_ir.DoubleType())
+                    ret = builder.call(
+                        self.mod.get_global("llvm.%s.f64" % op),
+                        [arg]
+                    )
+                else:
+                    raise RuntimeError("Unsupported precision: %x", expr.size)
+
+                ret = builder.bitcast(ret, llvm_ir.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in ["fadd", "fmul", "fsub", "fdiv"]:
+                # More than 2 args not yet supported
+                assert len(expr.args) == 2
+                arg1 = self.add_ir(expr.args[0])
+                arg2 = self.add_ir(expr.args[1])
+                precision = LLVMType.fptype(expr.size)
+                arg1 = builder.bitcast(arg1, precision)
+                arg2 = builder.bitcast(arg2, precision)
+                if op == "fadd":
+                    ret = builder.fadd(arg1, arg2)
+                elif op == "fmul":
+                    ret = builder.fmul(arg1, arg2)
+                elif op == "fsub":
+                    ret = builder.fsub(arg1, arg2)
+                elif op == "fdiv":
+                    ret = builder.fdiv(arg1, arg2)
+                ret = builder.bitcast(ret, llvm_ir.IntType(expr.size))
+                self.update_cache(expr, ret)
+                return ret
+
+            if op in [
+                    TOK_EQUAL,
+                    TOK_INF_SIGNED,
+                    TOK_INF_EQUAL_SIGNED,
+                    TOK_INF_UNSIGNED,
+                    TOK_INF_EQUAL_UNSIGNED,
+            ]:
+                if op == TOK_EQUAL:
+                    opname = "=="
+                    callback = builder.icmp_unsigned
+                elif op == TOK_INF_SIGNED:
+                    opname = "<"
+                    callback = builder.icmp_signed
+                elif op == TOK_INF_UNSIGNED:
+                    opname = "<"
+                    callback = builder.icmp_unsigned
+                elif op == TOK_INF_EQUAL_SIGNED:
+                    opname = "<="
+                    callback = builder.icmp_signed
+                elif op == TOK_INF_EQUAL_UNSIGNED:
+                    opname = "<"
+                    callback = builder.icmp_unsigned
+
+                left = self.add_ir(expr.args[0])
+                right = self.add_ir(expr.args[1])
+
+                ret = callback(opname, left, right)
+                self.update_cache(expr, ret)
+
+                return ret
+
+            if len(expr.args) > 1:
+
+                if op == "*":
+                    callback = builder.mul
+                elif op == "+":
+                    callback = builder.add
+                elif op == "&":
+                    callback = builder.and_
+                elif op == "^":
+                    callback = builder.xor
+                elif op == "|":
+                    callback = builder.or_
+                elif op == "%":
+                    callback = builder.urem
+                elif op == "/":
+                    callback = builder.udiv
+                else:
+                    raise NotImplementedError('Unknown op: %s' % op)
+
+                last = self.add_ir(expr.args[0])
+
+                for i in range(1, len(expr.args)):
+                    last = callback(last,
+                                    self.add_ir(expr.args[i]))
+
+                self.update_cache(expr, last)
+
+                return last
+
+            raise NotImplementedError()
+
+        if isinstance(expr, ExprMem):
+
+            addr = self.add_ir(expr.ptr)
+            ret = self.llvm_context.memory_lookup(self, addr, expr.size)
+            self.update_cache(expr, ret)
+            return ret
+
+        if isinstance(expr, ExprCond):
+            # Compute cond
+            cond = self.add_ir(expr.cond)
+            zero_casted = LLVMType.IntType(expr.cond.size)(0)
+            condition_bool = builder.icmp_unsigned("!=", cond,
+                                                   zero_casted)
+            then_value = self.add_ir(expr.src1)
+            else_value = self.add_ir(expr.src2)
+            ret = builder.select(condition_bool, then_value, else_value)
+
+            self.update_cache(expr, ret)
+            return ret
+
+        if isinstance(expr, ExprSlice):
+
+            src = self.add_ir(expr.arg)
+
+            # Remove trailing bits
+            if expr.start != 0:
+                to_shr = llvm_ir.Constant(
+                    LLVMType.IntType(expr.arg.size),
+                    expr.start
+                )
+                shred = builder.lshr(src, to_shr)
+            else:
+                shred = src
+
+            # Remove leading bits
+            to_and = llvm_ir.Constant(
+                LLVMType.IntType(expr.arg.size),
+                (1 << (expr.stop - expr.start)) - 1
+            )
+            anded = builder.and_(shred,
+                                 to_and)
+
+            # Cast into e.size
+            ret = builder.trunc(
+                anded,
+                LLVMType.IntType(expr.size)
+            )
+
+            self.update_cache(expr, ret)
+            return ret
+
+        if isinstance(expr, ExprCompose):
+
+            args = []
+
+            # Build each part
+            for start, src in expr.iter_args():
+                # src & size
+                src = self.add_ir(src)
+                src_casted = builder.zext(
+                    src,
+                    LLVMType.IntType(expr.size)
+                )
+                to_and = llvm_ir.Constant(
+                    LLVMType.IntType(expr.size),
+                    (1 << src.type.width) - 1
+                )
+                anded = builder.and_(src_casted,
+                                     to_and)
+
+                if (start != 0):
+                    # result << start
+                    to_shl = llvm_ir.Constant(
+                        LLVMType.IntType(expr.size),
+                        start
+                    )
+                    shled = builder.shl(anded, to_shl)
+                    final = shled
+                else:
+                    # Optimisation
+                    final = anded
+
+                args.append(final)
+
+            # result = part1 | part2 | ...
+            last = args[0]
+            for i in range(1, len(expr.args)):
+                last = builder.or_(last, args[i])
+
+            self.update_cache(expr, last)
+            return last
+
+        raise Exception("UnkownExpression", expr.__class__.__name__)
+
+    # JiT specifics
+
+    def check_memory_exception(self, offset, restricted_exception=False):
+        """Add a check for memory errors.
+        @offset: offset of the current exception (int or Instruction)
+        If restricted_exception, check only for exception which do not
+        require a pc update, and do not consider automod exception"""
+
+        # VmMngr "get_exception_flag" return's size
+        size = 64
+        t_size = LLVMType.IntType(size)
+
+        # Get exception flag value
+        # TODO: avoid costly call using a structure deref
+        builder = self.builder
+        fc_ptr = self.mod.get_global("get_exception_flag")
+        exceptionflag = builder.call(fc_ptr, [self.local_vars["vmmngr"]])
+
+        if restricted_exception is True:
+            flag = ~m2_csts.EXCEPT_CODE_AUTOMOD & m2_csts.EXCEPT_DO_NOT_UPDATE_PC
+            m2_flag = llvm_ir.Constant(t_size, flag)
+            exceptionflag = builder.and_(exceptionflag, m2_flag)
+
+        # Compute cond
+        zero_casted = llvm_ir.Constant(t_size, 0)
+        condition_bool = builder.icmp_unsigned(
+            "!=",
+            exceptionflag,
+            zero_casted
+        )
+
+        # Create bbls
+        branch_id = self.new_branch_name()
+        then_block = self.append_basic_block('then%s' % branch_id)
+        merge_block = self.append_basic_block('ifcond%s' % branch_id)
+
+        builder.cbranch(condition_bool, then_block, merge_block)
+
+        # Deactivate object caching
+        current_main_stream = self.main_stream
+        self.main_stream = False
+
+        # Then Block
+        builder.position_at_end(then_block)
+        PC = self.llvm_context.PC
+        if isinstance(offset, int_types):
+            offset = self.add_ir(ExprInt(offset, PC.size))
+        self.assign(offset, PC)
+        self.assign(self.add_ir(ExprInt(1, 8)), ExprId("status", 32))
+        self.set_ret(offset)
+
+        builder.position_at_end(merge_block)
+        # Reactivate object caching
+        self.main_stream = current_main_stream
+
+    def check_cpu_exception(self, offset, restricted_exception=False):
+        """Add a check for CPU errors.
+        @offset: offset of the current exception (int or Instruction)
+        If restricted_exception, check only for exception which do not
+        require a pc update"""
+
+        # Get exception flag value
+        builder = self.builder
+        m2_exception_flag = self.llvm_context.lifter.arch.regs.exception_flags
+        t_size = LLVMType.IntType(m2_exception_flag.size)
+        exceptionflag = self.add_ir(m2_exception_flag)
+
+        # Compute cond
+        if restricted_exception is True:
+            flag = m2_csts.EXCEPT_NUM_UPDT_EIP
+            condition_bool = builder.icmp_unsigned(
+                ">",
+                exceptionflag,
+                llvm_ir.Constant(t_size, flag)
+            )
+        else:
+            zero_casted = llvm_ir.Constant(t_size, 0)
+            condition_bool = builder.icmp_unsigned(
+                "!=",
+                exceptionflag,
+                zero_casted
+            )
+
+        # Create bbls
+        branch_id = self.new_branch_name()
+        then_block = self.append_basic_block('then%s' % branch_id)
+        merge_block = self.append_basic_block('ifcond%s' % branch_id)
+
+        builder.cbranch(condition_bool, then_block, merge_block)
+
+        # Deactivate object caching
+        current_main_stream = self.main_stream
+        self.main_stream = False
+
+        # Then Block
+        builder.position_at_end(then_block)
+        PC = self.llvm_context.PC
+        if isinstance(offset, int_types):
+            offset = self.add_ir(ExprInt(offset, PC.size))
+        self.assign(offset, PC)
+        self.assign(self.add_ir(ExprInt(1, 8)), ExprId("status", 32))
+        self.set_ret(offset)
+
+        builder.position_at_end(merge_block)
+        # Reactivate object caching
+        self.main_stream = current_main_stream
+
+    def gen_pre_code(self, instr_attrib):
+        if instr_attrib.log_mn:
+            loc_db = self.llvm_context.lifter.loc_db
+            self.printf(
+                "%.8X %s\n" % (
+                    instr_attrib.instr.offset,
+                    instr_attrib.instr.to_string(loc_db)
+                )
+            )
+
+    def gen_post_code(self, attributes, pc_value):
+        if attributes.log_regs:
+            # Update PC for dump_gpregs
+            PC = self.llvm_context.PC
+            t_size = LLVMType.IntType(PC.size)
+            dst = self.builder.zext(t_size(pc_value), t_size)
+            self.assign(dst, PC)
+
+            fc_ptr = self.mod.get_global(self.llvm_context.logging_func)
+            self.builder.call(fc_ptr, [self.local_vars["vmcpu"]])
+
+    def gen_post_instr_checks(self, attrib, next_instr):
+        if attrib.mem_read | attrib.mem_write:
+            fc_ptr = self.mod.get_global("check_memory_breakpoint")
+            self.builder.call(fc_ptr, [self.local_vars["vmmngr"]])
+            fc_ptr = self.mod.get_global("check_invalid_code_blocs")
+            self.builder.call(fc_ptr, [self.local_vars["vmmngr"]])
+            self.check_memory_exception(next_instr, restricted_exception=False)
+
+        if attrib.set_exception:
+            self.check_cpu_exception(next_instr, restricted_exception=False)
+
+        if attrib.mem_read | attrib.mem_write:
+            fc_ptr = self.mod.get_global("reset_memory_access")
+            self.builder.call(fc_ptr, [self.local_vars["vmmngr"]])
+
+    def expr2cases(self, expr):
+        """
+        Evaluate @expr and return:
+        - switch value -> dst
+        - evaluation of the switch value (if any)
+        """
+
+        to_eval = expr
+        dst2case = {}
+        case2dst = {}
+        for i, solution in enumerate(possible_values(expr)):
+            value = solution.value
+            index = dst2case.get(value, i)
+            to_eval = to_eval.replace_expr({value: ExprInt(index, value.size)})
+            dst2case[value] = index
+            if value.is_int() or value.is_loc():
+                case2dst[i] = value
+            else:
+                case2dst[i] = self.add_ir(value)
+
+
+        evaluated = self.add_ir(to_eval)
+        return case2dst, evaluated
+
+    def gen_jump2dst(self, attrib, instr_offsets, dst):
+        """Generate the code for a jump to @dst with final check for error
+
+        Several cases have to be considered:
+         - jump to an offset out of the current ASM BBL (JMP 0x11223344)
+         - jump to an offset inside the current ASM BBL (Go to next instruction)
+         - jump to an offset back in the current ASM BBL (For max_exec jit
+           option on self loops)
+         - jump to a generated IR label, which must be jitted in this same
+           function (REP MOVSB)
+         - jump to a computed offset (CALL @32[0x11223344])
+
+        """
+        PC = self.llvm_context.PC
+        # We are no longer in the main stream, deactivate cache
+        self.main_stream = False
+
+        offset = None
+        if isinstance(dst, ExprInt):
+            offset = int(dst)
+            loc_key = self.llvm_context.lifter.loc_db.get_or_create_offset_location(offset)
+            dst = ExprLoc(loc_key, dst.size)
+
+        if isinstance(dst, ExprLoc):
+            loc_key = dst.loc_key
+            bbl = self.get_basic_block_by_loc_key(loc_key)
+            offset = self.llvm_context.lifter.loc_db.get_location_offset(loc_key)
+            if bbl is not None:
+                # "local" jump, inside this function
+                if offset is None:
+                    # Avoid checks on generated label
+                    self.builder.branch(bbl)
+                    return
+
+                if (offset in instr_offsets and
+                    offset > attrib.instr.offset):
+                    # forward local jump (ie. next instruction)
+                    self.gen_post_code(attrib, offset)
+                    self.gen_post_instr_checks(attrib, offset)
+                    self.builder.branch(bbl)
+                    return
+
+                # reaching this point means a backward local jump, promote it to
+                # extern
+
+            # "extern" jump on a defined offset, return to the caller
+            dst = self.add_ir(ExprInt(offset, PC.size))
+
+        # "extern" jump with a computed value, return to the caller
+        assert isinstance(dst, (llvm_ir.Instruction, llvm_ir.Value))
+        # Cast @dst, if needed
+        # for instance, x86_32: IRDst is 32 bits, so is @dst; PC is 64 bits
+        if dst.type.width != PC.size:
+            dst = self.builder.zext(dst, LLVMType.IntType(PC.size))
+
+        self.gen_post_code(attrib, offset)
+        self.assign(dst, PC)
+        self.gen_post_instr_checks(attrib, dst)
+        self.assign(self.add_ir(ExprInt(0, 8)), ExprId("status", 32))
+        self.set_ret(dst)
+
+
+    def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock):
+        """
+        Generate the code for an @irblock
+        @instr_attrib: an Attributes instance or the instruction to translate
+        @attributes: list of Attributes corresponding to irblock assignments
+        @instr_offsets: offset of all asmblock's instructions
+        @irblock: an irblock instance
+        """
+
+        case2dst = None
+        case_value = None
+        instr = instr_attrib.instr
+
+        for index, assignblk in enumerate(irblock):
+            # Enable cache
+            self.main_stream = True
+            self.expr_cache = {}
+
+            # Prefetch memory
+            for element in assignblk.get_r(mem_read=True):
+                if isinstance(element, ExprMem):
+                    self.add_ir(element)
+
+            # Evaluate expressions
+            values = {}
+            for dst, src in viewitems(assignblk):
+                if dst == self.llvm_context.lifter.IRDst:
+                    case2dst, case_value = self.expr2cases(src)
+                else:
+                    values[dst] = self.add_ir(src)
+
+            # Check memory access exception
+            if attributes[index].mem_read:
+                self.check_memory_exception(
+                    instr.offset,
+                    restricted_exception=True
+                )
+
+            # Update the memory
+            for dst, src in viewitems(values):
+                if isinstance(dst, ExprMem):
+                    self.assign(src, dst)
+
+            # Check memory write exception
+            if attributes[index].mem_write:
+                self.check_memory_exception(
+                    instr.offset,
+                    restricted_exception=True
+                )
+
+            # Update registers values
+            for dst, src in viewitems(values):
+                if not isinstance(dst, ExprMem):
+                    self.assign(src, dst)
+
+            # Check post assignblk exception flags
+            if attributes[index].set_exception:
+                self.check_cpu_exception(
+                    instr.offset,
+                    restricted_exception=True
+                )
+
+        # Destination
+        assert case2dst is not None
+        if len(case2dst) == 1:
+            # Avoid switch in this common case
+            self.gen_jump2dst(
+                instr_attrib,
+                instr_offsets,
+                next(iter(viewvalues(case2dst)))
+            )
+        else:
+            current_bbl = self.builder.basic_block
+
+            # Gen the out cases
+            branch_id = self.new_branch_name()
+            case2bbl = {}
+            for case, dst in list(viewitems(case2dst)):
+                name = "switch_%s_%d" % (branch_id, case)
+                bbl = self.append_basic_block(name)
+                case2bbl[case] = bbl
+                self.builder.position_at_start(bbl)
+                self.gen_jump2dst(instr_attrib, instr_offsets, dst)
+
+            # Jump on the correct output
+            self.builder.position_at_end(current_bbl)
+            switch = self.builder.switch(case_value, case2bbl[0])
+            for i, bbl in viewitems(case2bbl):
+                if i == 0:
+                    # Default case is case 0, arbitrary
+                    continue
+                switch.add_case(i, bbl)
+
+    def gen_bad_block(self, asmblock):
+        """
+        Translate an asm_bad_block into a CPU exception
+        """
+        builder = self.builder
+        m2_exception_flag = self.llvm_context.lifter.arch.regs.exception_flags
+        t_size = LLVMType.IntType(m2_exception_flag.size)
+        self.assign(
+            self.add_ir(ExprInt(1, 8)),
+            ExprId("status", 32)
+        )
+        self.assign(
+            t_size(m2_csts.EXCEPT_UNK_MNEMO),
+            m2_exception_flag
+        )
+        offset = self.llvm_context.lifter.loc_db.get_location_offset(
+            asmblock.loc_key
+        )
+        self.set_ret(LLVMType.IntType(64)(offset))
+
+    def gen_finalize(self, asmblock, codegen):
+        """
+        In case of delayslot, generate a dummy BBL which return on the computed
+        IRDst or on next_label
+        """
+        if self.llvm_context.has_delayslot:
+            next_label = codegen.get_block_post_label(asmblock)
+            builder = self.builder
+
+            builder.position_at_end(self.get_basic_block_by_loc_key(next_label))
+
+            # Common code
+            self.assign(self.add_ir(ExprInt(0, 8)),
+                        ExprId("status", 32))
+
+            # Check if IRDst has been set
+            zero_casted = LLVMType.IntType(codegen.delay_slot_set.size)(0)
+            condition_bool = builder.icmp_unsigned(
+                "!=",
+                self.add_ir(codegen.delay_slot_set),
+                zero_casted
+            )
+
+            # Create bbls
+            branch_id = self.new_branch_name()
+            then_block = self.append_basic_block('then%s' % branch_id)
+            else_block = self.append_basic_block('else%s' % branch_id)
+
+            builder.cbranch(condition_bool, then_block, else_block)
+
+            # Deactivate object caching
+            self.main_stream = False
+
+            # Then Block
+            builder.position_at_end(then_block)
+            PC = self.llvm_context.PC
+            to_ret = self.add_ir(codegen.delay_slot_dst)
+            self.assign(to_ret, PC)
+            self.assign(self.add_ir(ExprInt(0, 8)),
+                        ExprId("status", 32))
+            self.set_ret(to_ret)
+
+            # Else Block
+            builder.position_at_end(else_block)
+            PC = self.llvm_context.PC
+            next_label_offset = self.llvm_context.lifter.loc_db.get_location_offset(next_label)
+            to_ret = LLVMType.IntType(PC.size)(next_label_offset)
+            self.assign(to_ret, PC)
+            self.set_ret(to_ret)
+
+    def from_asmblock(self, asmblock):
+        """Build the function from an asmblock (asm_block instance).
+        Prototype : f(i8* jitcpu, i8* vmcpu, i8* vmmngr, i8* status)"""
+
+        # Build function signature
+        self.my_args.append((ExprId("jitcpu", 32),
+                             llvm_ir.PointerType(LLVMType.IntType(8)),
+                             "jitcpu"))
+        self.my_args.append((ExprId("vmcpu", 32),
+                             llvm_ir.PointerType(LLVMType.IntType(8)),
+                             "vmcpu"))
+        self.my_args.append((ExprId("vmmngr", 32),
+                             llvm_ir.PointerType(LLVMType.IntType(8)),
+                             "vmmngr"))
+        self.my_args.append((ExprId("status", 32),
+                             llvm_ir.PointerType(LLVMType.IntType(8)),
+                             "status"))
+        ret_size = 64
+
+        self.ret_type = LLVMType.IntType(ret_size)
+
+        # Initialise the function
+        self.init_fc()
+        self.local_vars_pointers["status"] = self.local_vars["status"]
+
+        if isinstance(asmblock, m2_asmblock.AsmBlockBad):
+            self.gen_bad_block(asmblock)
+            return
+
+        # Create basic blocks (for label branches)
+        entry_bbl, builder = self.entry_bbl, self.builder
+        for instr in asmblock.lines:
+            lbl = self.llvm_context.lifter.loc_db.get_or_create_offset_location(instr.offset)
+            self.append_basic_block(lbl)
+
+        # TODO: merge duplicate code with CGen
+        codegen = self.llvm_context.cgen_class(self.llvm_context.lifter)
+        irblocks_list = codegen.block2assignblks(asmblock)
+        instr_offsets = [line.offset for line in asmblock.lines]
+
+        # Prepare for delayslot
+        if self.llvm_context.has_delayslot:
+            for element in (codegen.delay_slot_dst, codegen.delay_slot_set):
+                eltype = LLVMType.IntType(element.size)
+                ptr = self.CreateEntryBlockAlloca(
+                    eltype,
+                    default_value=eltype(0)
+                )
+                self.local_vars_pointers[element.name] = ptr
+            loc_key = codegen.get_block_post_label(asmblock)
+            offset = self.llvm_context.lifter.loc_db.get_location_offset(loc_key)
+            instr_offsets.append(offset)
+            self.append_basic_block(loc_key)
+
+        # Add content
+        builder.position_at_end(entry_bbl)
+
+
+        for instr, irblocks in zip(asmblock.lines, irblocks_list):
+            instr_attrib, irblocks_attributes = codegen.get_attributes(
+                instr,
+                irblocks,
+                self.log_mn,
+                self.log_regs
+            )
+
+            # Pre-create basic blocks
+            for irblock in irblocks:
+                self.append_basic_block(irblock.loc_key, overwrite=False)
+
+            # Generate the corresponding code
+            for index, irblock in enumerate(irblocks):
+                new_irblock = self.llvm_context.lifter.irbloc_fix_regs_for_mode(
+                    irblock, self.llvm_context.lifter.attrib)
+
+                # Set the builder at the beginning of the correct bbl
+                self.builder.position_at_end(self.get_basic_block_by_loc_key(new_irblock.loc_key))
+
+                if index == 0:
+                    self.gen_pre_code(instr_attrib)
+                self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, new_irblock)
+
+        # Gen finalize (see codegen::CGen) is unrecheable, except with delayslot
+        self.gen_finalize(asmblock, codegen)
+
+        # Branch entry_bbl on first label
+        builder.position_at_end(entry_bbl)
+        first_label_bbl = self.get_basic_block_by_loc_key(asmblock.loc_key)
+        builder.branch(first_label_bbl)
+
+
+    # LLVMFunction manipulation
+
+    def __str__(self):
+        "Print the llvm IR corresponding to the current module"
+        return str(self.mod)
+
+    def dot(self):
+        "Return the CFG of the current function"
+        return llvm.get_function_cfg(self.fc)
+
+    def as_llvm_mod(self):
+        """Return a ModuleRef standing for the current function"""
+        if self._llvm_mod is None:
+            self._llvm_mod = llvm.parse_assembly(str(self.mod))
+        return self._llvm_mod
+
+    def verify(self):
+        "Verify the module syntax"
+        return self.as_llvm_mod().verify()
+
+    def get_bytecode(self):
+        "Return LLVM bitcode corresponding to the current module"
+        return self.as_llvm_mod().as_bitcode()
+
+    def get_assembly(self):
+        "Return native assembly corresponding to the current module"
+        return self.llvm_context.target_machine.emit_assembly(self.as_llvm_mod())
+
+    def optimise(self):
+        "Optimise the function in place"
+        return self.llvm_context.pass_manager.run(self.as_llvm_mod())
+
+    def __call__(self, *args):
+        "Eval the function with arguments args"
+
+        e = self.llvm_context.get_execengine()
+
+        genargs = [LLVMType.generic(a) for a in args]
+        ret = e.run_function(self.fc, genargs)
+
+        return ret.as_int()
+
+    def get_function_pointer(self):
+        "Return a pointer on the Jitted function"
+        engine = self.llvm_context.get_execengine()
+
+        # Add the module and make sure it is ready for execution
+        engine.add_module(self.as_llvm_mod())
+        engine.finalize_object()
+
+        return engine.get_function_address(self.fc.name)
+
+
+class LLVMFunction_IRCompilation(LLVMFunction):
+    """LLVMFunction made for IR export, in conjunction with
+    LLVMContext_IRCompilation.
+
+    This class offers only the basics, and decision must be made by the class
+    user on how actual registers, ABI, etc. are reflected
+
+
+    Example of use:
+    >>> context = LLVMContext_IRCompilation()
+    >>> context.lifter = lifter
+    >>>
+    >>> func = LLVMFunction_IRCompilation(context, name="test")
+    >>> func.ret_type = llvm_ir.VoidType()
+    >>> func.init_fc()
+    >>>
+    >>> # Insert here function additional inits
+    >>> XX = func.builder.alloca(...)
+    >>> func.local_vars_pointers["EAX"] = XX
+    >>> #
+    >>>
+    >>> func.from_ircfg(ircfg)
+    """
+
+    def init_fc(self):
+        super(LLVMFunction_IRCompilation, self).init_fc()
+
+        # Create a global IRDst if not any
+        IRDst = self.llvm_context.lifter.IRDst
+        if str(IRDst) not in self.mod.globals:
+            llvm_ir.GlobalVariable(self.mod, LLVMType.IntType(IRDst.size),
+                                   name=str(IRDst))
+
+        # Create an 'exit' basic block, the final leave
+        self.exit_bbl = self.append_basic_block("exit")
+
+    def gen_jump2dst(self, _attrib, _instr_offsets, dst):
+        self.main_stream = False
+
+        if isinstance(dst, Expr):
+            if dst.is_int():
+                loc = self.llvm_context.lifter.loc_db.getby_offset_create(int(dst))
+                dst = ExprLoc(loc, dst.size)
+            assert dst.is_loc()
+            bbl = self.get_basic_block_by_loc_key(dst.loc_key)
+            if bbl is not None:
+                # "local" jump, inside this function
+                self.builder.branch(bbl)
+                return
+
+            # extern jump
+            dst = self.add_ir(dst)
+
+        # Emulate indirect jump with:
+        #   @IRDst = dst
+        #   goto exit
+        self.builder.store(dst, self.mod.get_global("IRDst"))
+        self.builder.branch(self.exit_bbl)
+
+    def gen_irblock(self, irblock):
+        instr_attrib = Attributes()
+        attributes = [Attributes() for _ in range(len(irblock.assignblks))]
+        instr_offsets = None
+        return super(LLVMFunction_IRCompilation, self).gen_irblock(
+            instr_attrib, attributes, instr_offsets, irblock
+        )
+
+    def from_ircfg(self, ircfg, append_ret=True):
+        # Create basic blocks
+        for loc_key, irblock in viewitems(ircfg.blocks):
+            self.append_basic_block(loc_key)
+
+        # Add IRBlocks
+        for label, irblock in viewitems(ircfg.blocks):
+            self.builder.position_at_end(self.get_basic_block_by_loc_key(label))
+            self.gen_irblock(irblock)
+
+        # Branch the entry BBL on the IRCFG head
+        self.builder.position_at_end(self.entry_bbl)
+        heads = ircfg.heads()
+        assert len(heads) == 1
+        starting_label = list(heads).pop()
+        self.builder.branch(self.get_basic_block_by_loc_key(starting_label))
+
+        # Returns with the builder on the exit block
+        self.builder.position_at_end(self.exit_bbl)
+
+        if append_ret:
+            self.builder.ret_void()
diff --git a/src/miasm/jitter/loader/__init__.py b/src/miasm/jitter/loader/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/miasm/jitter/loader/__init__.py
diff --git a/src/miasm/jitter/loader/elf.py b/src/miasm/jitter/loader/elf.py
new file mode 100644
index 00000000..91d1c18b
--- /dev/null
+++ b/src/miasm/jitter/loader/elf.py
@@ -0,0 +1,339 @@
+import struct
+from collections import defaultdict
+
+from future.utils import viewitems
+
+from miasm.loader import cstruct
+from miasm.loader import *
+import miasm.loader.elf as elf_csts
+
+from miasm.jitter.csts import *
+from miasm.jitter.loader.utils import canon_libname_libfunc, libimp
+from miasm.core.utils import force_str
+from miasm.core.interval import interval
+
+import logging
+
+log = logging.getLogger('loader_elf')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.CRITICAL)
+
+
+def get_import_address_elf(e):
+    import2addr = defaultdict(set)
+    for sh in e.sh:
+        if not hasattr(sh, 'rel'):
+            continue
+        for k, v in viewitems(sh.rel):
+            k = force_str(k)
+            import2addr[('xxx', k)].add(v.offset)
+    return import2addr
+
+
+def preload_elf(vm, e, runtime_lib, patch_vm_imp=True, loc_db=None):
+    # XXX quick hack
+    fa = get_import_address_elf(e)
+    dyn_funcs = {}
+    for (libname, libfunc), ads in viewitems(fa):
+        # Quick hack - if a symbol is already known, do not stub it
+        if loc_db and loc_db.get_name_location(libfunc) is not None:
+            continue
+        for ad in ads:
+            ad_base_lib = runtime_lib.lib_get_add_base(libname)
+            ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad)
+
+            libname_s = canon_libname_libfunc(libname, libfunc)
+            dyn_funcs[libname_s] = ad_libfunc
+            if patch_vm_imp:
+                log.debug('patch 0x%x 0x%x %s', ad, ad_libfunc, libfunc)
+                set_endianness = { elf_csts.ELFDATA2MSB: ">",
+                                   elf_csts.ELFDATA2LSB: "<",
+                                   elf_csts.ELFDATANONE: "" }[e.sex]
+                vm.set_mem(ad,
+                           struct.pack(set_endianness +
+                                       cstruct.size2type[e.size],
+                                       ad_libfunc))
+    return runtime_lib, dyn_funcs
+
+def fill_loc_db_with_symbols(elf, loc_db, base_addr=0):
+    """Parse the miasm.loader's ELF @elf to extract symbols, and fill the LocationDB
+    instance @loc_db with parsed symbols.
+
+    The ELF is considered mapped at @base_addr
+    @elf: miasm.loader's ELF instance
+    @loc_db: LocationDB used to retrieve symbols'offset
+    @base_addr: addr to reloc to (if any)
+    """
+    # Get symbol sections
+    symbol_sections = []
+    for section_header in elf.sh:
+        if hasattr(section_header, 'symbols'):
+            for name, sym in viewitems(section_header.symbols):
+                if not name or sym.value == 0:
+                    continue
+                name = loc_db.find_free_name(force_str(name))
+                loc_db.add_location(name, sym.value, strict=False)
+
+        if hasattr(section_header, 'reltab'):
+            for rel in section_header.reltab:
+                if not rel.sym or rel.offset == 0:
+                    continue
+                name = loc_db.find_free_name(force_str(rel.sym))
+                loc_db.add_location(name, rel.offset, strict=False)
+
+        if hasattr(section_header, 'symtab'):
+            log.debug("Find %d symbols in %r", len(section_header.symtab),
+                      section_header)
+            symbol_sections.append(section_header)
+        elif isinstance(section_header, (
+                elf_init.GNUVerDef, elf_init.GNUVerSym, elf_init.GNUVerNeed
+        )):
+            log.debug("Find GNU version related section, unsupported for now")
+
+    for section in symbol_sections:
+        for symbol_entry in section.symtab:
+            # Here, the computation of vaddr assumes 'elf' is an executable or a
+            # shared object file
+
+            # For relocatable file, symbol_entry.value is an offset from the section
+            # base -> not handled here
+            st_bind = symbol_entry.info >> 4
+            st_type = symbol_entry.info & 0xF
+
+            if st_type not in [
+                    elf_csts.STT_NOTYPE,
+                    elf_csts.STT_OBJECT,
+                    elf_csts.STT_FUNC,
+                    elf_csts.STT_COMMON,
+                    elf_csts.STT_GNU_IFUNC,
+            ]:
+                # Ignore symbols useless in linking
+                continue
+
+            if st_bind == elf_csts.STB_GLOBAL:
+                # Global symbol
+                weak = False
+            elif st_bind == elf_csts.STB_WEAK:
+                # Weak symbol
+                weak = True
+            else:
+                # Ignore local & others symbols
+                continue
+
+            absolute = False
+            if symbol_entry.shndx == 0:
+                # SHN_UNDEF
+                continue
+            elif symbol_entry.shndx == 0xfff1:
+                # SHN_ABS
+                absolute = True
+                log.debug("Absolute symbol %r - %x", symbol_entry.name,
+                          symbol_entry.value)
+            elif 0xff00 <= symbol_entry.shndx <= 0xffff:
+                # Reserved index (between SHN_LORESERV and SHN_HIRESERVE)
+                raise RuntimeError("Unsupported reserved index: %r" % symbol_entry)
+
+            name = force_str(symbol_entry.name)
+            if name == "":
+                # Ignore empty symbol
+                log.debug("Empty symbol %r", symbol_entry)
+                continue
+
+            if absolute:
+                vaddr = symbol_entry.value
+            else:
+                vaddr = symbol_entry.value + base_addr
+
+            # 'weak' information is only used to force global symbols for now
+            already_existing_loc = loc_db.get_name_location(name)
+            if already_existing_loc is not None:
+                if weak:
+                    # Weak symbol, this is ok to already exists, skip it
+                    continue
+                else:
+                    # Global symbol, force it
+                    loc_db.remove_location_name(already_existing_loc,
+                                                name)
+            already_existing_off = loc_db.get_offset_location(vaddr)
+            if already_existing_off is not None:
+                loc_db.add_location_name(already_existing_off, name)
+            else:
+                loc_db.add_location(name=name, offset=vaddr)
+
+
+def apply_reloc_x86(elf, vm, section, base_addr, loc_db):
+    """Apply relocation for x86 ELF contained in the section @section
+    @elf: miasm.loader's ELF instance
+    @vm: VmMngr instance
+    @section: elf's section containing relocation to perform
+    @base_addr: addr to reloc to
+    @loc_db: LocationDB used to retrieve symbols'offset
+    """
+    if elf.size == 64:
+        addr_writer = lambda vaddr, addr: vm.set_mem(vaddr,
+                                                     struct.pack("<Q", addr))
+    elif elf.size == 32:
+        addr_writer = lambda vaddr, addr: vm.set_mem(vaddr,
+                                                     struct.pack("<I", addr))
+    else:
+        raise ValueError("Unsupported elf size %d" % elf.size)
+
+    symb_section = section.linksection
+    for reloc in section.reltab:
+
+        # Parse relocation info
+        r_info = reloc.info
+        if elf.size == 64:
+            r_info_sym = (r_info >> 32) & 0xFFFFFFFF
+            r_info_type = r_info & 0xFFFFFFFF
+        elif elf.size == 32:
+            r_info_sym = (r_info >> 8) & 0xFFFFFF
+            r_info_type = r_info & 0xFF
+
+        is_ifunc = False
+        symbol_entry = None
+        if r_info_sym > 0:
+            symbol_entry = symb_section.symtab[r_info_sym]
+
+        r_offset = reloc.offset
+        r_addend = reloc.cstr.sym
+
+        if (elf.size, reloc.type) in [
+                (64, elf_csts.R_X86_64_RELATIVE),
+                (64, elf_csts.R_X86_64_IRELATIVE),
+                (32, elf_csts.R_386_RELATIVE),
+                (32, elf_csts.R_386_IRELATIVE),
+        ]:
+            # B + A
+            addr = base_addr + r_addend
+            where = base_addr + r_offset
+        elif reloc.type == elf_csts.R_X86_64_64:
+            # S + A
+            addr_symb = loc_db.get_name_offset(symbol_entry.name)
+            if addr_symb is None:
+                log.warning("Unable to find symbol %r" % symbol_entry.name)
+                continue
+            addr = addr_symb + r_addend
+            where = base_addr + r_offset
+        elif (elf.size, reloc.type) in [
+                (64, elf_csts.R_X86_64_TPOFF64),
+                (64, elf_csts.R_X86_64_DTPMOD64),
+                (32, elf_csts.R_386_TLS_TPOFF),
+        ]:
+            # Thread dependent, ignore for now
+            log.debug("Skip relocation TPOFF64 %r", reloc)
+            continue
+        elif (elf.size, reloc.type) in [
+                (64, elf_csts.R_X86_64_GLOB_DAT),
+                (64, elf_csts.R_X86_64_JUMP_SLOT),
+                (32, elf_csts.R_386_JMP_SLOT),
+                (32, elf_csts.R_386_GLOB_DAT),
+        ]:
+            # S
+            addr = loc_db.get_name_offset(symbol_entry.name)
+            if addr is None:
+                log.warning("Unable to find symbol %r" % symbol_entry.name)
+                continue
+            is_ifunc = symbol_entry.info & 0xF == elf_csts.STT_GNU_IFUNC
+            where = base_addr + r_offset
+        else:
+            raise ValueError(
+                "Unknown relocation type: %d (%r)" % (reloc.type,
+                                                      reloc)
+            )
+        if is_ifunc:
+            # Resolve at runtime - not implemented for now
+            log.warning("Relocation for %r (at %x, currently pointing on %x) "
+                        "has to be resolved at runtime",
+                        name, where, sym_addr)
+            continue
+
+        log.debug("Write %x at %x", addr, where)
+        addr_writer(where, addr)
+
+
+def vm_load_elf(vm, fdata, name="", base_addr=0, loc_db=None, apply_reloc=False,
+                **kargs):
+    """
+    Very dirty elf loader
+    TODO XXX: implement real loader
+    """
+    elf = elf_init.ELF(fdata, **kargs)
+    i = interval()
+    all_data = {}
+
+    for p in elf.ph.phlist:
+        if p.ph.type != elf_csts.PT_LOAD:
+            continue
+        log.debug(
+            '0x%x 0x%x 0x%x 0x%x 0x%x', p.ph.vaddr, p.ph.memsz, p.ph.offset,
+                  p.ph.filesz, p.ph.type)
+        data_o = elf._content[p.ph.offset:p.ph.offset + p.ph.filesz]
+        addr_o = p.ph.vaddr + base_addr
+        a_addr = addr_o & ~0xFFF
+        b_addr = addr_o + max(p.ph.memsz, p.ph.filesz)
+        b_addr = (b_addr + 0xFFF) & ~0xFFF
+        all_data[addr_o] = data_o
+        # -2: Trick to avoid merging 2 consecutive pages
+        i += [(a_addr, b_addr - 2)]
+    for a, b in i.intervals:
+        vm.add_memory_page(
+            a,
+            PAGE_READ | PAGE_WRITE,
+            b"\x00" * (b + 2 - a),
+            repr(name)
+        )
+
+    for r_vaddr, data in viewitems(all_data):
+        vm.set_mem(r_vaddr, data)
+
+    if loc_db is not None:
+        fill_loc_db_with_symbols(elf, loc_db, base_addr)
+
+    if apply_reloc:
+        arch = guess_arch(elf)
+        sections = []
+        for section in elf.sh:
+            if not hasattr(section, 'reltab'):
+                continue
+            if isinstance(section, elf_init.RelATable):
+                pass
+            elif isinstance(section, elf_init.RelTable):
+                if arch == "x86_64":
+                    log.warning("REL section should not happen in x86_64")
+            else:
+                raise RuntimeError("Unknown relocation section type: %r" % section)
+            sections.append(section)
+        for section in sections:
+            if arch in ["x86_64", "x86_32"]:
+                apply_reloc_x86(elf, vm, section, base_addr, loc_db)
+            else:
+                log.debug("Unsupported relocation for arch %r" % arch)
+
+    return elf
+
+
+class libimp_elf(libimp):
+    pass
+
+
+# machine, size, sex -> arch_name
+ELF_machine = {(elf_csts.EM_ARM, 32, elf_csts.ELFDATA2LSB): "arml",
+               (elf_csts.EM_ARM, 32, elf_csts.ELFDATA2MSB): "armb",
+               (elf_csts.EM_AARCH64, 64, elf_csts.ELFDATA2LSB): "aarch64l",
+               (elf_csts.EM_AARCH64, 64, elf_csts.ELFDATA2MSB): "aarch64b",
+               (elf_csts.EM_MIPS, 32, elf_csts.ELFDATA2MSB): "mips32b",
+               (elf_csts.EM_MIPS, 32, elf_csts.ELFDATA2LSB): "mips32l",
+               (elf_csts.EM_386, 32, elf_csts.ELFDATA2LSB): "x86_32",
+               (elf_csts.EM_X86_64, 64, elf_csts.ELFDATA2LSB): "x86_64",
+               (elf_csts.EM_SH, 32, elf_csts.ELFDATA2LSB): "sh4",
+               (elf_csts.EM_PPC, 32, elf_csts.ELFDATA2MSB): "ppc32b",
+               }
+
+
+def guess_arch(elf):
+    """Return the architecture specified by the ELF container @elf.
+    If unknown, return None"""
+    return ELF_machine.get((elf.Ehdr.machine, elf.size, elf.sex), None)
diff --git a/src/miasm/jitter/loader/pe.py b/src/miasm/jitter/loader/pe.py
new file mode 100644
index 00000000..9af068e4
--- /dev/null
+++ b/src/miasm/jitter/loader/pe.py
@@ -0,0 +1,834 @@
+from builtins import map
+import os
+import struct
+import logging
+from collections import defaultdict
+
+from future.utils import viewitems, viewvalues
+
+from miasm.loader import pe
+from miasm.loader import cstruct
+from miasm.loader import *
+
+from miasm.jitter.csts import *
+from miasm.jitter.loader.utils import canon_libname_libfunc, libimp
+from miasm.core.utils import force_str
+
+log = logging.getLogger('loader_pe')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.INFO)
+
+
+def get_pe_dependencies(pe_obj):
+    """Collect the shared libraries upon which this PE depends.
+
+    @pe_obj: pe object
+    Returns a set of strings of DLL names.
+
+    Example:
+
+        pe = miasm.analysis.binary.Container.from_string(buf)
+        deps = miasm.jitter.loader.pe.get_pe_dependencies(pe.executable)
+        assert sorted(deps)[0] == 'api-ms-win-core-appcompat-l1-1-0.dll'
+    """
+
+    if pe_obj.DirImport.impdesc is None:
+        return set()
+    out = set()
+    for dependency in pe_obj.DirImport.impdesc:
+        libname = dependency.dlldescname.name.lower()
+        # transform bytes to str
+        libname = force_str(libname)
+        out.add(libname)
+
+    # If binary has redirected export, add dependencies
+    if pe_obj.DirExport.expdesc != None:
+        addrs = get_export_name_addr_list(pe_obj)
+        for imp_ord_or_name, ad in addrs:
+            # if export is a redirection, search redirected dll
+            # and get function real addr
+            ret = is_redirected_export(pe_obj, ad)
+            if ret is False:
+                continue
+            dllname, func_info = ret
+            dllname = dllname + '.dll'
+            out.add(dllname)
+
+    return out
+
+
+def get_import_address_pe(e):
+    """Compute the addresses of imported symbols.
+    @e: pe object
+    Returns a dict mapping from tuple (dll name string, symbol name string) to set of virtual addresses.
+
+    Example:
+
+        pe = miasm.analysis.binary.Container.from_string(buf)
+        imports = miasm.jitter.loader.pe.get_import_address_pe(pe.executable)
+        assert imports[('api-ms-win-core-rtlsupport-l1-1-0.dll', 'RtlCaptureStackBackTrace')] == {0x6b88a6d0}
+    """
+    import2addr = defaultdict(set)
+    if e.DirImport.impdesc is None:
+        return import2addr
+    for s in e.DirImport.impdesc:
+        # fthunk = e.rva2virt(s.firstthunk)
+        # l = "%2d %-25s %s" % (i, repr(s.dlldescname), repr(s))
+        libname = force_str(s.dlldescname.name.lower())
+
+        for ii, imp in enumerate(s.impbynames):
+            if isinstance(imp, pe.ImportByName):
+                funcname = force_str(imp.name)
+            else:
+                funcname = imp
+            # l = "    %2d %-16s" % (ii, repr(funcname))
+            import2addr[(libname, funcname)].add(
+                e.rva2virt(s.firstthunk + (e._wsize * ii) // 8)
+            )
+    return import2addr
+
+
+def preload_pe(vm, e, runtime_lib, patch_vm_imp=True):
+    fa = get_import_address_pe(e)
+    dyn_funcs = {}
+    # log.debug('imported funcs: %s' % fa)
+    for (libname, libfunc), ads in viewitems(fa):
+        for ad in ads:
+            libname = force_str(libname)
+            ad_base_lib = runtime_lib.lib_get_add_base(libname)
+            ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad)
+
+            libname_s = canon_libname_libfunc(libname, libfunc)
+            dyn_funcs[libname_s] = ad_libfunc
+            if patch_vm_imp:
+                vm.set_mem(
+                    ad, struct.pack(cstruct.size2type[e._wsize], ad_libfunc))
+    return dyn_funcs
+
+
+def is_redirected_export(pe_obj, addr):
+    """Test if the @addr is a forwarded export address. If so, return
+    dllname/function name couple. If not, return False.
+
+    An export address is a forwarded export if the rva is in the export
+    directory of the pe.
+
+    @pe_obj: PE instance
+    @addr: virtual address of the function to test
+    """
+
+    export_dir = pe_obj.NThdr.optentries[pe.DIRECTORY_ENTRY_EXPORT]
+    addr_rva = pe_obj.virt2rva(addr)
+    if not (export_dir.rva <= addr_rva < export_dir.rva + export_dir.size):
+        return False
+    addr_end = pe_obj.virt.find(b'\x00', addr)
+    data = pe_obj.virt.get(addr, addr_end)
+
+    data = force_str(data)
+    dllname, func_info = data.split('.', 1)
+    dllname = dllname.lower()
+
+    # Test if function is forwarded using ordinal
+    if func_info.startswith('#'):
+        func_info = int(func_info[1:])
+    return dllname, func_info
+
+
+def get_export_name_addr_list(e):
+    """Collect names/ordinals and addresses of symbols exported by the given PE.
+    @e: PE instance
+    Returns a list of tuples:
+        (symbol name string, virtual address)
+        (ordinal number, virtual address)
+
+    Example:
+
+        pe = miasm.analysis.binary.Container.from_string(buf)
+        exports = miasm.jitter.loader.pe.get_export_name_addr_list(pe.executable)
+        assert exports[0] == ('AcquireSRWLockExclusive', 0x6b89b22a)
+    """
+    out = []
+    if e.DirExport.expdesc is None:
+        return out
+
+    # add func name
+    for i, n in enumerate(e.DirExport.f_names):
+        addr = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal]
+        f_name = force_str(n.name.name)
+        # log.debug('%s %s' % (f_name, hex(e.rva2virt(addr.rva))))
+        out.append((f_name, e.rva2virt(addr.rva)))
+
+    # add func ordinal
+    for i, s in enumerate(e.DirExport.f_address):
+        if not s.rva:
+            continue
+        out.append((i + e.DirExport.expdesc.base, e.rva2virt(s.rva)))
+
+    return out
+
+
+def vm_load_pe(vm, fdata, align_s=True, load_hdr=True, name="", winobjs=None, **kargs):
+    """Load a PE in memory (@vm) from a data buffer @fdata
+    @vm: VmMngr instance
+    @fdata: data buffer to parse
+    @align_s: (optional) If False, keep gaps between section
+    @load_hdr: (optional) If False, do not load the NThdr in memory
+    Return the corresponding PE instance.
+
+    Extra arguments are passed to PE instantiation.
+    If all sections are aligned, they will be mapped on several different pages
+    Otherwise, a big page is created, containing all sections
+    """
+
+    # Parse and build a PE instance
+    pe = pe_init.PE(fdata, **kargs)
+
+    # Check if all section are aligned
+    aligned = True
+    for section in pe.SHList:
+        if section.addr & 0xFFF:
+            aligned = False
+            break
+
+    if aligned:
+        # Loader NT header
+        if load_hdr:
+            # Header length
+            hdr_len = max(0x200, pe.NThdr.sizeofheaders)
+            # Page minimum size
+            min_len = min(pe.SHList[0].addr, 0x1000)
+
+            # Get and pad the pe_hdr
+            pe_hdr = (
+                pe.content[:hdr_len] +
+                max(0, (min_len - hdr_len)) * b"\x00"
+            )
+
+            if winobjs:
+                winobjs.allocated_pages[pe.NThdr.ImageBase] = (pe.NThdr.ImageBase, len(pe_hdr))
+            vm.add_memory_page(
+                pe.NThdr.ImageBase,
+                PAGE_READ | PAGE_WRITE,
+                pe_hdr,
+                "%r: PE Header" % name
+            )
+
+        # Align sections size
+        if align_s:
+            # Use the next section address to compute the new size
+            for i, section in enumerate(pe.SHList[:-1]):
+                new_size = pe.SHList[i + 1].addr - section.addr
+                section.size = new_size
+                section.rawsize = new_size
+                section.data = strpatchwork.StrPatchwork(
+                    section.data[:new_size]
+                )
+                section.offset = section.addr
+
+            # Last section alignment
+            last_section = pe.SHList[-1]
+            last_section.size = (last_section.size + 0xfff) & 0xfffff000
+
+        # Pad sections with null bytes and map them
+        for section in pe.SHList:
+            data = bytes(section.data)
+            data += b"\x00" * (section.size - len(data))
+            attrib = PAGE_READ
+            if section.flags & 0x80000000:
+                attrib |= PAGE_WRITE
+
+            section_addr = pe.rva2virt(section.addr)
+            if winobjs:
+                winobjs.allocated_pages[section_addr] = (section_addr, len(data))
+            vm.add_memory_page(
+                section_addr,
+                attrib,
+                data,
+                "%r: %r" % (name, section.name)
+            )
+
+        return pe
+
+    # At least one section is not aligned
+    log.warning('PE is not aligned, creating big section')
+    min_addr = 0 if load_hdr else None
+    max_addr = None
+    data = ""
+
+    for i, section in enumerate(pe.SHList):
+        if i < len(pe.SHList) - 1:
+            # If it is not the last section, use next section address
+            section.size = pe.SHList[i + 1].addr - section.addr
+        section.rawsize = section.size
+        section.offset = section.addr
+
+        # Update min and max addresses
+        if min_addr is None or section.addr < min_addr:
+            min_addr = section.addr
+        max_section_len = max(section.size, len(section.data))
+        if max_addr is None or section.addr + max_section_len > max_addr:
+            max_addr = section.addr + max_section_len
+
+    min_addr = pe.rva2virt(min_addr)
+    max_addr = pe.rva2virt(max_addr)
+    log.debug('Min: 0x%x, Max: 0x%x, Size: 0x%x', min_addr, max_addr,
+              (max_addr - min_addr))
+
+    # Create only one big section containing the whole PE
+    vm.add_memory_page(
+        min_addr,
+        PAGE_READ | PAGE_WRITE,
+        (max_addr - min_addr) * b"\x00"
+    )
+
+    # Copy each sections content in memory
+    for section in pe.SHList:
+        log.debug('Map 0x%x bytes to 0x%x', len(section.data),
+                  pe.rva2virt(section.addr))
+        vm.set_mem(pe.rva2virt(section.addr), bytes(section.data))
+
+    return pe
+
+
+def vm_load_pe_lib(vm, fname_in, libs, lib_path_base, **kargs):
+    """Call vm_load_pe on @fname_in and update @libs accordingly
+    @vm: VmMngr instance
+    @fname_in: library name
+    @libs: libimp_pe instance
+    @lib_path_base: DLLs relative path
+    Return the corresponding PE instance
+    Extra arguments are passed to vm_load_pe
+    """
+
+    log.info('Loading module %r', fname_in)
+
+    fname = os.path.join(lib_path_base, fname_in)
+    with open(fname, "rb") as fstream:
+        pe = vm_load_pe(vm, fstream.read(), name=fname_in, **kargs)
+    libs.add_export_lib(pe, fname_in)
+    return pe
+
+
+def vm_load_pe_libs(vm, libs_name, libs, lib_path_base, **kargs):
+    """Call vm_load_pe_lib on each @libs_name filename
+    @vm: VmMngr instance
+    @libs_name: list of str
+    @libs: libimp_pe instance
+    @lib_path_base: (optional) DLLs relative path
+    Return a dictionary Filename -> PE instances
+    Extra arguments are passed to vm_load_pe_lib
+    """
+    out = {}
+    for fname in libs_name:
+        assert isinstance(fname, str)
+        out[fname] = vm_load_pe_lib(vm, fname, libs, lib_path_base, **kargs)
+    return out
+
+
+def vm_fix_imports_pe_libs(lib_imgs, libs, lib_path_base,
+                           patch_vm_imp=True, **kargs):
+    for e in viewvalues(lib_imgs):
+        preload_pe(e, libs, patch_vm_imp)
+
+
+def vm2pe(myjit, fname, libs=None, e_orig=None,
+          min_addr=None, max_addr=None,
+          min_section_offset=0x1000, img_base=None,
+          added_funcs=None, **kwargs):
+    if e_orig:
+        size = e_orig._wsize
+    else:
+        size = 32
+    mye = pe_init.PE(wsize=size)
+
+    if min_addr is None and e_orig is not None:
+        min_addr = min([e_orig.rva2virt(s.addr) for s in e_orig.SHList])
+    if max_addr is None and e_orig is not None:
+        max_addr = max([e_orig.rva2virt(s.addr + s.size)
+                       for s in e_orig.SHList])
+
+    if img_base is None:
+        img_base = e_orig.NThdr.ImageBase
+
+    mye.NThdr.ImageBase = img_base
+    all_mem = myjit.vm.get_all_memory()
+    addrs = list(all_mem)
+    addrs.sort()
+    entry_point = mye.virt2rva(myjit.pc)
+    if entry_point is None or not 0 < entry_point < 0xFFFFFFFF:
+        raise ValueError(
+            "Current pc (0x%x) used as entry point seems to be out of the binary" %
+            myjit.pc
+        )
+
+    mye.Opthdr.AddressOfEntryPoint = entry_point
+    first = True
+    for ad in addrs:
+        if not min_addr <= ad < max_addr:
+            continue
+        log.debug("0x%x", ad)
+        if first:
+            mye.SHList.add_section(
+                "%.8X" % ad,
+                addr=ad - mye.NThdr.ImageBase,
+                data=all_mem[ad]['data'],
+                offset=min_section_offset)
+        else:
+            mye.SHList.add_section(
+                "%.8X" % ad,
+                addr=ad - mye.NThdr.ImageBase,
+                data=all_mem[ad]['data'])
+        first = False
+    if libs:
+        if added_funcs is not None:
+            for addr, funcaddr in added_funcs:
+                libbase, dllname = libs.fad2info[funcaddr]
+                libs.lib_get_add_func(libbase, dllname, addr)
+
+        filter_import = kwargs.get(
+            'filter_import', lambda _, ad: mye.virt.is_addr_in(ad))
+        new_dll = libs.gen_new_lib(mye, filter_import)
+    else:
+        new_dll = {}
+
+    log.debug('%s', new_dll)
+
+    mye.DirImport.add_dlldesc(new_dll)
+    s_imp = mye.SHList.add_section("import", rawsize=len(mye.DirImport))
+    mye.DirImport.set_rva(s_imp.addr)
+    log.debug('%r', mye.SHList)
+    if e_orig:
+        # resource
+        xx = bytes(mye)
+        mye.content = xx
+        ad = e_orig.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].rva
+        size = e_orig.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].size
+        log.debug('dirres 0x%x', ad)
+        if ad != 0:
+            mye.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].rva = ad
+            mye.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].size = size
+            mye.DirRes = pe.DirRes.unpack(mye.img_rva, ad, mye)
+            log.debug('%r', mye.DirRes)
+            s_res = mye.SHList.add_section(
+                name="myres",
+                rawsize=len(mye.DirRes)
+            )
+            mye.DirRes.set_rva(s_res.addr)
+    # generation
+    open(fname, 'wb').write(bytes(mye))
+    return mye
+
+
+class libimp_pe(libimp):
+
+    def __init__(self, *args, **kwargs):
+        super(libimp_pe, self).__init__(*args, **kwargs)
+        # dependency -> redirector
+        self.created_redirected_imports = {}
+
+
+    def add_function(self, dllname, imp_ord_or_name, addr):
+        assert isinstance(dllname, str)
+        assert isinstance(imp_ord_or_name, (int, str))
+        libad = self.name2off[dllname]
+        c_name = canon_libname_libfunc(
+            dllname, imp_ord_or_name
+        )
+        update_entry = True
+        if addr in self.fad2info:
+            known_libad, known_imp_ord_or_name = self.fad2info[addr]
+            if isinstance(imp_ord_or_name, int):
+                update_entry = False
+        self.cname2addr[c_name] = addr
+        log.debug("Add func %s %s", hex(addr), c_name)
+        if update_entry:
+            log.debug("Real Add func %s %s", hex(addr), c_name)
+            self.fad2cname[addr] = c_name
+            self.fad2info[addr] = libad, imp_ord_or_name
+
+
+    def add_export_lib(self, e, name):
+        if name in self.created_redirected_imports:
+            log.error("%r has previously been created due to redirect\
+            imports due to %r. Change the loading order.",
+                      name, self.created_redirected_imports[name])
+            raise RuntimeError('Bad import: loading previously created import')
+
+        self.all_exported_lib.append(e)
+        # will add real lib addresses to database
+        if name in self.name2off:
+            ad = self.name2off[name]
+            if e is not None and name in self.fake_libs:
+                log.error(
+                    "You are trying to load %r but it has been faked previously. Try loading this module earlier.", name)
+                raise RuntimeError("Bad import")
+        else:
+            log.debug('new lib %s', name)
+            ad = e.NThdr.ImageBase
+            libad = ad
+            self.name2off[name] = ad
+            self.libbase2lastad[ad] = ad + 0x1
+            self.lib_imp2ad[ad] = {}
+            self.lib_imp2dstad[ad] = {}
+            self.libbase_ad += 0x1000
+
+            ads = get_export_name_addr_list(e)
+            todo = list(ads)
+            # done = []
+            while todo:
+                # for imp_ord_or_name, ad in ads:
+                imp_ord_or_name, ad = todo.pop()
+
+                # if export is a redirection, search redirected dll
+                # and get function real addr
+                ret = is_redirected_export(e, ad)
+                if ret:
+                    exp_dname, exp_fname = ret
+                    exp_dname = exp_dname + '.dll'
+                    exp_dname = exp_dname.lower()
+                    # if dll auto refes in redirection
+                    if exp_dname == name:
+                        libad_tmp = self.name2off[exp_dname]
+                        if isinstance(exp_fname, str):
+                            exp_fname = bytes(ord(c) for c in exp_fname)
+                        found = None
+                        for tmp_func, tmp_addr in ads:
+                            if tmp_func == exp_fname:
+                                found = tmp_addr
+                        assert found is not None
+                        ad = found
+                    else:
+                        # import redirected lib from non loaded dll
+                        if not exp_dname in self.name2off:
+                            self.created_redirected_imports.setdefault(
+                                exp_dname, set()).add(name)
+
+                        # Ensure import entry is created
+                        new_lib_base = self.lib_get_add_base(exp_dname)
+                        # Ensure function entry is created
+                        _ = self.lib_get_add_func(new_lib_base, exp_fname)
+
+                        libad_tmp = self.name2off[exp_dname]
+                        ad = self.lib_imp2ad[libad_tmp][exp_fname]
+
+                self.lib_imp2ad[libad][imp_ord_or_name] = ad
+                name_inv = dict(
+                    (value, key) for key, value in viewitems(self.name2off)
+                )
+                c_name = canon_libname_libfunc(
+                    name_inv[libad], imp_ord_or_name)
+                self.fad2cname[ad] = c_name
+                self.cname2addr[c_name] = ad
+                log.debug("Add func %s %s", hex(ad), c_name)
+                self.fad2info[ad] = libad, imp_ord_or_name
+
+    def gen_new_lib(self, target_pe, filter_import=lambda peobj, ad: True, **kwargs):
+        """Gen a new DirImport description
+        @target_pe: PE instance
+        @filter_import: (boolean f(pe, address)) restrict addresses to keep
+        """
+
+        new_lib = []
+        for lib_name, ad in viewitems(self.name2off):
+            # Build an IMAGE_IMPORT_DESCRIPTOR
+
+            # Get fixed addresses
+            out_ads = dict()  # addr -> func_name
+            for func_name, dst_addresses in viewitems(self.lib_imp2dstad[ad]):
+                out_ads.update({addr: func_name for addr in dst_addresses})
+
+            # Filter available addresses according to @filter_import
+            all_ads = [
+                addr for addr in list(out_ads) if filter_import(target_pe, addr)
+            ]
+
+            if not all_ads:
+                continue
+
+            # Keep non-NULL elements
+            all_ads.sort(key=str)
+            for i, x in enumerate(all_ads):
+                if x not in [0,  None]:
+                    break
+            all_ads = all_ads[i:]
+            log.debug('ads: %s', list(map(hex, all_ads)))
+
+            while all_ads:
+                # Find libname's Import Address Table
+                othunk = all_ads[0]
+                i = 0
+                while (i + 1 < len(all_ads) and
+                       all_ads[i] + target_pe._wsize // 8 == all_ads[i + 1]):
+                    i += 1
+                # 'i + 1' is IAT's length
+
+                # Effectively build an IMAGE_IMPORT_DESCRIPTOR
+                funcs = [out_ads[addr] for addr in all_ads[:i + 1]]
+                try:
+                    rva = target_pe.virt2rva(othunk)
+                except pe.InvalidOffset:
+                    pass
+                else:
+                    new_lib.append(({"name": lib_name,
+                                     "firstthunk": rva},
+                                    funcs)
+                                   )
+
+                # Update elements to handle
+                all_ads = all_ads[i + 1:]
+
+        return new_lib
+
+
+def vm_load_pe_and_dependencies(vm, fname, name2module, runtime_lib,
+                                lib_path_base, **kwargs):
+    """Load a binary and all its dependencies. Returns a dictionary containing
+    the association between binaries names and it's pe object
+
+    @vm: virtual memory manager instance
+    @fname: full path of the binary
+    @name2module: dict containing association between name and pe
+    object. Updated.
+    @runtime_lib: libimp instance
+    @lib_path_base: directory of the libraries containing dependencies
+
+    """
+
+    todo = [(fname, fname, 0)]
+    weight2name = {}
+    done = set()
+
+    # Walk dependencies recursively
+    while todo:
+        name, fname, weight = todo.pop()
+        if name in done:
+            continue
+        done.add(name)
+        weight2name.setdefault(weight, set()).add(name)
+        if name in name2module:
+            pe_obj = name2module[name]
+        else:
+            try:
+                with open(fname, "rb") as fstream:
+                    log.info('Loading module name %r', fname)
+                    pe_obj = vm_load_pe(
+                        vm, fstream.read(), name=fname, **kwargs)
+            except IOError:
+                log.error('Cannot open %s' % fname)
+                name2module[name] = None
+                continue
+            name2module[name] = pe_obj
+
+        new_dependencies = get_pe_dependencies(pe_obj)
+        todo += [(name, os.path.join(lib_path_base, name), weight - 1)
+                 for name in new_dependencies]
+
+    known_export_addresses = {}
+    to_resolve = {}
+    for name, pe_obj in name2module.items():
+        print(name)
+        if pe_obj is None:
+            continue
+        if pe_obj.DirExport.expdesc == None:
+            continue
+        addrs = get_export_name_addr_list(pe_obj)
+        for imp_ord_or_name, ad in addrs:
+            # if export is a redirection, search redirected dll
+            # and get function real addr
+            ret = is_redirected_export(pe_obj, ad)
+            if ret is False:
+                known_export_addresses[(name, imp_ord_or_name)] = ad
+            else:
+                dllname, func_info = ret
+                dllname = dllname + '.dll'
+                to_resolve[(name, imp_ord_or_name)] = (dllname, func_info)
+
+    modified = True
+    while modified:
+        modified = False
+        out = {}
+        for target, dependency in to_resolve.items():
+            dllname, funcname = dependency
+            if dependency in known_export_addresses:
+                known_export_addresses[target] = known_export_addresses[dependency]
+                modified = True
+            else:
+                log.error("Cannot resolve redirection %r %r", dllname, dependency)
+                raise RuntimeError('Cannot resolve redirection')
+        to_resolve = out
+
+    for dllname, pe_obj in name2module.items():
+        if pe_obj is None:
+            continue
+        ad = pe_obj.NThdr.ImageBase
+        libad = ad
+        runtime_lib.name2off[dllname] = ad
+        runtime_lib.libbase2lastad[ad] = ad + 0x1
+        runtime_lib.lib_imp2ad[ad] = {}
+        runtime_lib.lib_imp2dstad[ad] = {}
+        runtime_lib.libbase_ad += 0x1000
+
+    for (dllname, imp_ord_or_name), addr in known_export_addresses.items():
+        runtime_lib.add_function(dllname, imp_ord_or_name, addr)
+        libad = runtime_lib.name2off[dllname]
+        runtime_lib.lib_imp2ad[libad][imp_ord_or_name] = addr
+
+    assert not to_resolve
+
+    for dllname, pe_obj in name2module.items():
+        if pe_obj is None:
+            continue
+        preload_pe(vm, pe_obj, runtime_lib, patch_vm_imp=True)
+
+    return name2module
+
+# machine -> arch
+PE_machine = {
+    0x14c: "x86_32",
+    0x8664: "x86_64",
+}
+
+
+def guess_arch(pe):
+    """Return the architecture specified by the PE container @pe.
+    If unknown, return None"""
+    return PE_machine.get(pe.Coffhdr.machine, None)
+
+
+class ImpRecStateMachine(object):
+    """
+    Finite State Machine used for internal purpose only.
+    See `ImpRecStrategy` for more details.
+    """
+
+    # Looking for a function pointer
+    STATE_SEARCH = 0
+    # Candidate function list
+    STATE_FUNC_FOUND = 1
+    # Function list found, terminated by a NULL entry
+    STATE_END_FUNC_LIST = 2
+
+    def __init__(self, libs, ptrtype):
+        self.ptrtype = ptrtype
+        self.libs = libs
+        self.func_addrs = set(struct.pack(self.ptrtype, address) for address in self.libs.cname2addr.values())
+        self.off2name = {v:k for k,v in self.libs.name2off.items()}
+        self.state = self.STATE_SEARCH
+
+        # STATE_FUNC_FOUND
+        self.cur_list = []
+        self.cur_list_lib = None
+
+        # STATE_END_FUNC_LIST
+        self.seen = []
+
+    def format_func_info(self, func_info, func_addr):
+        return {
+            "lib_addr": func_info[0],
+            "lib_name": self.off2name[func_info[0]],
+            "entry_name": func_info[1],
+            "entry_module_addr": func_addr,
+            "entry_memory_addr": self.cur_address,
+        }
+
+    def transition(self, data):
+        if self.state == self.STATE_SEARCH:
+            if data in self.func_addrs:
+                self.state = self.STATE_FUNC_FOUND
+                func_addr = struct.unpack(self.ptrtype, data)[0]
+                func_info = self.libs.fad2info[func_addr]
+                self.cur_list = [self.format_func_info(func_info, func_addr)]
+                self.cur_list_lib = func_info[0]
+        elif self.state == self.STATE_FUNC_FOUND:
+            if data == (b"\x00" * len(data)):
+                self.state = self.STATE_END_FUNC_LIST
+            elif data in self.func_addrs:
+                func_addr = struct.unpack(self.ptrtype, data)[0]
+                func_info = self.libs.fad2info[func_addr]
+                if func_info[0] != self.cur_list_lib:
+                    # The list must belong to the same library
+                    self.state = self.STATE_SEARCH
+                    return
+                self.cur_list.append(self.format_func_info(func_info, func_addr))
+            else:
+                self.state == self.STATE_SEARCH
+        elif self.state == self.STATE_END_FUNC_LIST:
+            self.seen.append(self.cur_list)
+            self.state = self.STATE_SEARCH
+            self.transition(data)
+        else:
+            raise ValueError()
+
+    def run(self):
+        while True:
+            data, address = yield
+            self.cur_address = address
+            self.transition(data)
+
+
+class ImpRecStrategy(object):
+    """
+    Naive import reconstruction, similar to ImpRec
+
+    It looks for a continuation of module export addresses, ended by a NULL entry, ie:
+    [...]
+    &Kernel32::LoadLibraryA
+    &Kernel32::HeapCreate
+    00 00 00 00
+    [...]
+
+    Usage:
+    >>> sb = Sandbox[...]
+    >>> sb.run()
+    >>> imprec = ImpRecStrategy(sb.jitter, sb.libs, size=32)
+    >>> imprec.recover_import()
+    List<List<Recovered functions>>
+
+    -> sb.libs has also been updated, ready to be passed to `vm2pe`
+    """
+    def __init__(self, jitter, libs, size):
+        self._jitter = jitter
+        self._libs = libs
+        if size == 32:
+            self._ptrtype = "<I"
+        elif size == 64:
+            self._ptrtype = "<Q"
+        else:
+            ValueError("Unsupported size: %d" % size)
+
+    def recover_import(self, update_libs=True, align_hypothesis=False):
+        """
+        Launch the import recovery routine.
+        @update_libs: if set (default), update `libs` object with founded addresses
+        @align_hypothesis: if not set (default), do not consider import
+            addresses are written on aligned addresses
+
+        Return the list of candidates
+        """
+        candidates = []
+
+        alignments = [0]
+        if not align_hypothesis:
+            alignments = list(range(0, struct.calcsize(self._ptrtype)))
+
+        for starting_offset in alignments:
+            # Search for several addresses from `func_addrs` ending with a `\x00`
+            fsm_obj = ImpRecStateMachine(self._libs, self._ptrtype)
+            fsm = fsm_obj.run()
+            fsm.send(None)
+            for addr_start, page_info in self._jitter.vm.get_all_memory().items():
+                data = page_info["data"]
+                for i in range(starting_offset, page_info["size"], struct.calcsize(self._ptrtype)):
+                    fsm.send((data[i:i+4], addr_start + i))
+
+            candidates.extend(fsm_obj.seen)
+
+        # Apply to libs
+        if update_libs:
+            for entry_list in candidates:
+                for func_info in entry_list:
+                    self._libs.lib_imp2dstad[func_info["lib_addr"]][func_info["entry_name"]].add(func_info["entry_memory_addr"])
+
+        return candidates
diff --git a/src/miasm/jitter/loader/utils.py b/src/miasm/jitter/loader/utils.py
new file mode 100644
index 00000000..7f913d76
--- /dev/null
+++ b/src/miasm/jitter/loader/utils.py
@@ -0,0 +1,100 @@
+from builtins import int as int_types
+import logging
+
+from future.utils import viewitems, viewvalues
+from past.builtins import basestring
+
+log = logging.getLogger('loader_common')
+hnd = logging.StreamHandler()
+hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
+log.addHandler(hnd)
+log.setLevel(logging.INFO)
+
+
+def canon_libname_libfunc(libname, libfunc):
+    assert isinstance(libname, basestring)
+    assert isinstance(libfunc, basestring) or isinstance(libfunc, int_types)
+    dn = libname.split('.')[0]
+    if isinstance(libfunc, int_types):
+        return str(dn), libfunc
+    else:
+        return "%s_%s" % (dn, libfunc)
+
+
+class libimp(object):
+
+    def __init__(self, lib_base_ad=0x71111000, **kargs):
+        self.name2off = {}
+        self.libbase2lastad = {}
+        self.libbase_ad = lib_base_ad
+        self.lib_imp2ad = {}
+        self.lib_imp2dstad = {}
+        self.fad2cname = {}
+        self.cname2addr = {}
+        self.fad2info = {}
+        self.all_exported_lib = []
+        self.fake_libs = set()
+
+    def lib_get_add_base(self, name):
+        assert isinstance(name, basestring)
+        name = name.lower().strip(' ')
+        if not "." in name:
+            log.warning('warning adding .dll to modulename')
+            name += '.dll'
+            log.warning(name)
+
+        if name in self.name2off:
+            ad = self.name2off[name]
+        else:
+            ad = self.libbase_ad
+            log.warning("Create dummy entry for %r", name)
+            self.fake_libs.add(name)
+            self.name2off[name] = ad
+            self.libbase2lastad[ad] = ad + 0x4
+            self.lib_imp2ad[ad] = {}
+            self.lib_imp2dstad[ad] = {}
+            self.libbase_ad += 0x1000
+        return ad
+
+    def lib_get_add_func(self, libad, imp_ord_or_name, dst_ad=None):
+        if not libad in viewvalues(self.name2off):
+            raise ValueError('unknown lib base!', hex(libad))
+
+        # test if not ordinatl
+        # if imp_ord_or_name >0x10000:
+        #    imp_ord_or_name = vm_get_str(imp_ord_or_name, 0x100)
+        #    imp_ord_or_name = imp_ord_or_name[:imp_ord_or_name.find('\x00')]
+
+        #[!] can have multiple dst ad
+        if not imp_ord_or_name in self.lib_imp2dstad[libad]:
+            self.lib_imp2dstad[libad][imp_ord_or_name] = set()
+        if dst_ad is not None:
+            self.lib_imp2dstad[libad][imp_ord_or_name].add(dst_ad)
+
+        if imp_ord_or_name in self.lib_imp2ad[libad]:
+            return self.lib_imp2ad[libad][imp_ord_or_name]
+        log.debug('new imp %s %s' % (imp_ord_or_name, dst_ad))
+        ad = self.libbase2lastad[libad]
+        self.libbase2lastad[libad] += 0x10  # arbitrary
+        self.lib_imp2ad[libad][imp_ord_or_name] = ad
+
+        name_inv = dict(
+            (value, key) for key, value in viewitems(self.name2off)
+        )
+        c_name = canon_libname_libfunc(name_inv[libad], imp_ord_or_name)
+        self.fad2cname[ad] = c_name
+        self.cname2addr[c_name] = ad
+        self.fad2info[ad] = libad, imp_ord_or_name
+        return ad
+
+    def check_dst_ad(self):
+        for ad in self.lib_imp2dstad:
+            all_ads = sorted(viewvalues(self.lib_imp2dstad[ad]))
+            for i, x in enumerate(all_ads[:-1]):
+                if x is None or all_ads[i + 1] is None:
+                    return False
+                if x + 4 != all_ads[i + 1]:
+                    return False
+        return True
+
+
diff --git a/src/miasm/jitter/op_semantics.c b/src/miasm/jitter/op_semantics.c
new file mode 100644
index 00000000..6725ae64
--- /dev/null
+++ b/src/miasm/jitter/op_semantics.c
@@ -0,0 +1,853 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <math.h>
+#include "op_semantics.h"
+
+const uint8_t parity_table[256] = {
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+};
+
+uint16_t bcdadd_16(uint16_t a, uint16_t b)
+{
+	int carry = 0;
+	int i,j = 0;
+	uint16_t res = 0;
+	int nib_a, nib_b;
+	for (i = 0; i < 16; i += 4) {
+		nib_a = (a  >> i) & (0xF);
+		nib_b = (b >> i) & (0xF);
+
+		j = (carry + nib_a + nib_b);
+		if (j >= 10) {
+			carry = 1;
+			j -= 10;
+			j &=0xf;
+		}
+		else {
+			carry = 0;
+		}
+		res += j << i;
+	}
+	return res;
+}
+
+uint16_t bcdadd_cf_16(uint16_t a, uint16_t b)
+{
+	int carry = 0;
+	int i,j = 0;
+	int nib_a, nib_b;
+	for (i = 0; i < 16; i += 4) {
+		nib_a = (a >> i) & (0xF);
+		nib_b = (b >> i) & (0xF);
+
+		j = (carry + nib_a + nib_b);
+		if (j >= 10) {
+			carry = 1;
+			j -= 10;
+			j &=0xf;
+		}
+		else {
+			carry = 0;
+		}
+	}
+	return carry;
+}
+
+unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b)
+{
+	unsigned int mask;
+
+	switch (size) {
+		case 8: mask = 0xff; break;
+		case 16: mask = 0xffff; break;
+		case 32: mask = 0xffffffff; break;
+		default: fprintf(stderr, "inv size in mul %d\n", size); exit(EXIT_FAILURE);
+	}
+
+	a &= mask;
+	b &= mask;
+	return ((int64_t)a * (int64_t) b) & mask;
+}
+
+unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b)
+{
+	uint64_t res = 0;
+	unsigned int mask;
+
+	switch (size) {
+		case 8: mask = 0xff; break;
+		case 16: mask = 0xffff; break;
+		case 32: mask = 0xffffffff; break;
+		default: fprintf(stderr, "inv size in mul %d\n", size); exit(EXIT_FAILURE);
+	}
+
+	a &= mask;
+	b &= mask;
+	res = ((uint64_t)a * (uint64_t)b);
+	return (res >> 32) & mask;
+}
+
+
+unsigned int imul_lo_op_08(char a, char b)
+{
+	return a*b;
+}
+
+unsigned int imul_lo_op_16(short a, short b)
+{
+	return a*b;
+}
+
+unsigned int imul_lo_op_32(int a, int b)
+{
+	return a*b;
+}
+
+int imul_hi_op_08(char a, char b)
+{
+	int64_t res = 0;
+	res = a*b;
+	return (int)(res>>8);
+}
+
+int imul_hi_op_16(short a, short b)
+{
+	int64_t res = 0;
+	res = a*b;
+	return (int)(res>>16);
+}
+
+int imul_hi_op_32(int a, int b)
+{
+	int64_t res = 0;
+	res = (int64_t)a*(int64_t)b;
+	return (int)(res>>32ULL);
+}
+
+unsigned int umul16_lo(unsigned short a, unsigned short b)
+{
+	return (a*b) & 0xffff;
+}
+
+unsigned int umul16_hi(unsigned short a, unsigned short b)
+{
+	uint32_t c;
+	c = a*b;
+	return (c>>16) & 0xffff;
+}
+
+uint64_t rot_left(uint64_t size, uint64_t a, uint64_t b)
+{
+    uint64_t tmp;
+
+    b = b & 0x3F;
+    b %= size;
+    switch(size){
+	    case 8:
+		    tmp = (a << b) | ((a & 0xFF) >> (size - b));
+		    return tmp & 0xFF;
+	    case 16:
+		    tmp = (a << b) | ((a & 0xFFFF) >> (size - b));
+		    return tmp & 0xFFFF;
+	    case 32:
+		    tmp = (a << b) | ((a & 0xFFFFFFFF) >> (size - b));
+		    return tmp & 0xFFFFFFFF;
+	    case 64:
+		    tmp = (a << b) | ((a&0xFFFFFFFFFFFFFFFF) >> (size - b));
+		    return tmp & 0xFFFFFFFFFFFFFFFF;
+
+	    /* Support cases for rcl */
+	    case 9:
+		    tmp = (a << b) | ((a & 0x1FF) >> (size - b));
+		    return tmp & 0x1FF;
+	    case 17:
+		    tmp = (a << b) | ((a & 0x1FFFF) >> (size - b));
+		    return tmp & 0x1FFFF;
+	    case 33:
+		    tmp = (a << b) | ((a & 0x1FFFFFFFF) >> (size - b));
+		    return tmp & 0x1FFFFFFFF;
+	    /* TODO XXX: support rcl in 64 bit mode */
+
+	    default:
+		    fprintf(stderr, "inv size in rotleft %"PRIX64"\n", size);
+		    exit(EXIT_FAILURE);
+    }
+}
+
+uint64_t rot_right(uint64_t size, uint64_t a, uint64_t b)
+{
+    uint64_t tmp;
+
+    b = b & 0x3F;
+    b %= size;
+    switch(size){
+	    case 8:
+		    tmp = ((a & 0xFF) >> b) | (a << (size - b));
+		    return tmp & 0xff;
+	    case 16:
+		    tmp = ((a & 0xFFFF) >> b) | (a << (size - b));
+		    return tmp & 0xFFFF;
+	    case 32:
+		    tmp = ((a & 0xFFFFFFFF) >> b) | (a << (size - b));
+		    return tmp & 0xFFFFFFFF;
+	    case 64:
+		    tmp = ((a & 0xFFFFFFFFFFFFFFFF) >> b) | (a << (size - b));
+		    return tmp & 0xFFFFFFFFFFFFFFFF;
+
+	    /* Support cases for rcr */
+	    case 9:
+		    tmp = ((a & 0x1FF) >> b) | (a << (size - b));
+		    return tmp & 0x1FF;
+	    case 17:
+		    tmp = ((a & 0x1FFFF) >> b) | (a << (size - b));
+		    return tmp & 0x1FFFF;
+	    case 33:
+		    tmp = ((a & 0x1FFFFFFFF) >> b) | (a << (size - b));
+		    return tmp & 0x1FFFFFFFF;
+	    /* TODO XXX: support rcr in 64 bit mode */
+
+	    default:
+		    fprintf(stderr, "inv size in rotright %"PRIX64"\n", size);
+		    exit(EXIT_FAILURE);
+    }
+}
+
+/*
+ * Count leading zeros - count the number of zero starting at the most
+ * significant bit
+ *
+ * Example:
+ * - cntleadzeros(size=32, src=2): 30
+ * - cntleadzeros(size=32, src=0): 32
+ */
+uint64_t cntleadzeros(uint64_t size, uint64_t src)
+{
+	int64_t i;
+
+	for (i=(int64_t)size-1; i>=0; i--){
+		if (src & (1ull << i))
+			return (uint64_t)(size - (i + 1));
+	}
+	return (uint64_t)size;
+}
+
+/*
+ * Count trailing zeros - count the number of zero starting at the least
+ * significant bit
+ *
+ * Example:
+ * - cnttrailzeros(size=32, src=2): 1
+ * - cnttrailzeros(size=32, src=0): 32
+ */
+unsigned int cnttrailzeros(uint64_t size, uint64_t src)
+{
+	uint64_t i;
+	for (i=0; i<size; i++){
+		if (src & (1ull << i))
+			return (unsigned int)i;
+	}
+	return (unsigned int)size;
+}
+
+
+unsigned int my_imul08(unsigned int a, unsigned int b)
+{
+	char a08, b08;
+	short a16;
+
+	a08 = a&0xFF;
+	b08 = b&0xFF;
+	a16 = a08*b08;
+	return (int)a16;
+}
+
+
+
+unsigned int x86_cpuid(unsigned int a, unsigned int reg_num)
+{
+	if (reg_num >3){
+		fprintf(stderr, "not implemented x86_cpuid reg %x\n", reg_num);
+		exit(EXIT_FAILURE);
+	}
+	// cases are output: EAX: 0; EBX: 1; ECX: 2; EDX: 3
+	if (a == 0){
+		switch(reg_num){
+		case 0:
+			return 0xa;
+		// "GenuineIntel"
+		case 1:
+			return 0x756E6547;
+		case 2:
+			return 0x6C65746E;
+		case 3:
+			return 0x49656E69;
+		}
+	}
+
+	else if (a == 1){
+		switch(reg_num){
+		case 0:
+			// Using a version too high will enable recent
+			// instruction set
+			return 0x000006FB;
+			//return 0x00020652;
+		case 1:
+			//return 0x02040800;
+			return 0x00000800;
+		case 2:
+			//return 0x0004E3BD;
+			return 0x00000209;
+		case 3:
+			return (/* fpu */ 1 << 0) |
+				(/* tsc */ 1 << 4) |
+				(/* cx8 */ 1 << 8) |
+				(/* cmov */ 1 << 15) |
+				(/* mmx */ 1 << 23) |
+				(/* sse */ 1 << 25) |
+				(/* sse2 */ 1 << 26) |
+				(/* ia64 */ 1 << 30);
+		}
+	}
+	// Cache and TLB
+	else if (a == 2){
+		switch(reg_num){
+		case 0:
+			return 0x00000000;
+		case 1:
+			return 0x00000000;
+		case 2:
+			return 0x00000000;
+		case 3:
+			return 0x00000000;
+		}
+	}
+	// Intel thread/core and cache topology
+	else if (a == 4){
+		switch(reg_num){
+		case 0:
+			return 0x00000000;
+		case 1:
+			return 0x00000000;
+		case 2:
+			return 0x00000000;
+		case 3:
+			return 0x00000000;
+		}
+	}
+	// Extended features
+	else if (a == 7){
+		switch(reg_num){
+		case 0:
+			return 0x00000000;
+		case 1:
+			return (/* fsgsbase */ 1 << 0) | (/* bmi1 */ 1 << 3);
+		case 2:
+			return 0x00000000;
+		case 3:
+			return 0x00000000;
+		}
+	}
+	// Extended Function CPUID Information
+	else if (a == 0x80000000){
+		switch(reg_num){
+		case 0:
+			// Pentium 4 Processor supporting Hyper-Threading
+			// Technology to Intel Xeon Processor 5100 Series
+			return 0x80000008;
+		case 1:
+			return 0x00000000;
+		case 2:
+			return 0x00000000;
+		case 3:
+			return 0x00000000;
+		}
+	}
+	else if (a == 0x80000001){
+		switch(reg_num){
+		case 0:
+			// Extended Processor Signature and Extended Feature
+			// Bits
+			return 0x00000000;
+		case 1:
+			return 0x00000000;
+		case 2:
+			return (/* LAHF-SAHF */ 1 << 0)
+			| (/* LZCNT */ 0 << 5)
+			| (/* PREFETCHW */ 1 << 8);
+		case 3:
+			return (/* SYSCALL/SYSRET */ 1 << 11)
+			| (/* Execute Disable Bit available */ 0 << 20)
+			| (/* 1-GByte pages available */ 0 << 26)
+			| (/* RDTSCP and IA32_TSC_AUX available */ 0 << 27)
+			| (/* Intel ® 64 Architecture available */ 1 << 29);
+		}
+	}
+	else{
+		fprintf(stderr, "WARNING not implemented x86_cpuid index %X!\n", a);
+		exit(EXIT_FAILURE);
+	}
+	return 0;
+}
+
+//#define DEBUG_MIASM_DOUBLE
+
+void dump_float(void)
+{
+	/*
+	printf("%e\n", vmmngr.float_st0);
+	printf("%e\n", vmmngr.float_st1);
+	printf("%e\n", vmmngr.float_st2);
+	printf("%e\n", vmmngr.float_st3);
+	printf("%e\n", vmmngr.float_st4);
+	printf("%e\n", vmmngr.float_st5);
+	printf("%e\n", vmmngr.float_st6);
+	printf("%e\n", vmmngr.float_st7);
+	*/
+}
+
+typedef union {
+	uint32_t u32;
+	float flt;
+} float_uint32_t;
+
+
+typedef union {
+	uint64_t u64;
+	double dbl;
+} double_uint64_t;
+
+
+uint32_t fpu_fadd32(uint32_t a, uint32_t b)
+{
+	float_uint32_t a_cast, b_cast, c_cast;
+
+	a_cast.u32 = a;
+	b_cast.u32 = b;
+
+	c_cast.flt = a_cast.flt + b_cast.flt;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e + %e -> %e\n", a, b, c_cast.flt);
+#endif
+	return c_cast.u32;
+}
+
+uint64_t fpu_fadd64(uint64_t a, uint64_t b)
+{
+	double_uint64_t a_cast, b_cast, c_cast;
+
+	a_cast.u64 = a;
+	b_cast.u64 = b;
+
+	c_cast.dbl = a_cast.dbl + b_cast.dbl;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e + %e -> %e\n", a, b, c_cast.dbl);
+#endif
+	return c_cast.u64;
+}
+
+uint32_t fpu_fsub32(uint32_t a, uint32_t b)
+{
+	float_uint32_t a_cast, b_cast, c_cast;
+
+	a_cast.u32 = a;
+	b_cast.u32 = b;
+
+	c_cast.flt = a_cast.flt - b_cast.flt;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e + %e -> %e\n", a, b, c_cast.flt);
+#endif
+	return c_cast.u32;
+}
+
+uint64_t fpu_fsub64(uint64_t a, uint64_t b)
+{
+	double_uint64_t a_cast, b_cast, c_cast;
+
+	a_cast.u64 = a;
+	b_cast.u64 = b;
+
+	c_cast.dbl = a_cast.dbl - b_cast.dbl;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e + %e -> %e\n", a, b, c_cast.dbl);
+#endif
+	return c_cast.u64;
+}
+
+uint32_t fpu_fmul32(uint32_t a, uint32_t b)
+{
+	float_uint32_t a_cast, b_cast, c_cast;
+
+	a_cast.u32 = a;
+	b_cast.u32 = b;
+
+	c_cast.flt = a_cast.flt * b_cast.flt;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e * %e -> %e\n", a, b, c_cast.flt);
+#endif
+	return c_cast.u32;
+}
+
+uint64_t fpu_fmul64(uint64_t a, uint64_t b)
+{
+	double_uint64_t a_cast, b_cast, c_cast;
+
+	a_cast.u64 = a;
+	b_cast.u64 = b;
+
+	c_cast.dbl = a_cast.dbl * b_cast.dbl;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e * %e -> %e\n", a, b, c_cast.dbl);
+#endif
+	return c_cast.u64;
+}
+
+uint32_t fpu_fdiv32(uint32_t a, uint32_t b)
+{
+	float_uint32_t a_cast, b_cast, c_cast;
+
+	a_cast.u32 = a;
+	b_cast.u32 = b;
+
+	c_cast.flt = a_cast.flt / b_cast.flt;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e * %e -> %e\n", a, b, c_cast.flt);
+#endif
+	return c_cast.u32;
+}
+
+uint64_t fpu_fdiv64(uint64_t a, uint64_t b)
+{
+	double_uint64_t a_cast, b_cast, c_cast;
+
+	a_cast.u64 = a;
+	b_cast.u64 = b;
+
+	c_cast.dbl = a_cast.dbl / b_cast.dbl;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e * %e -> %e\n", a, b, c_cast.dbl);
+#endif
+	return c_cast.u64;
+}
+
+double fpu_ftan(double a)
+{
+	double b;
+	b = tan(a);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e tan %e\n", a, b);
+#endif
+	return b;
+}
+
+double fpu_frndint(double a)
+{
+	int64_t b;
+	double c;
+	b = (int64_t)a;
+	c = (double)b;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e double %e\n", a, c);
+#endif
+	return c;
+}
+
+double fpu_fsin(double a)
+{
+	double b;
+	b = sin(a);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e sin %e\n", a, b);
+#endif
+	return b;
+}
+
+double fpu_fcos(double a)
+{
+	double b;
+	b = cos(a);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e cos %e\n", a, b);
+#endif
+	return b;
+}
+
+
+double fpu_fscale(double a, double b)
+{
+	double c;
+	c = a * exp2(trunc(b));
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e *exp2 %e -> %e\n", a, b, c);
+#endif
+	return c;
+}
+
+double fpu_f2xm1(double a)
+{
+	double b;
+	b = exp2(a)-1;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e exp2 -1 %e\n", a, b);
+#endif
+	return b;
+}
+
+uint32_t fpu_fsqrt32(uint32_t a)
+{
+	float_uint32_t a_cast;
+	a_cast.u32 = a;
+	a_cast.flt = sqrtf(a_cast.flt);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e sqrt %e\n", a, a_cast.flt);
+#endif
+	return a_cast.u32;
+}
+
+uint64_t fpu_fsqrt64(uint64_t a)
+{
+	double_uint64_t a_cast;
+
+	a_cast.u64 = a;
+	a_cast.dbl = sqrt(a_cast.dbl);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e sqrt %e\n", a, a_cast.dbl);
+#endif
+	return a_cast.u64;
+}
+
+uint64_t fpu_fabs64(uint64_t a)
+{
+	double_uint64_t a_cast;
+
+	a_cast.u64 = a;
+	a_cast.dbl = fabs(a_cast.dbl);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e abs %e\n", a, a_cast.dbl);
+#endif
+	return a_cast.u64;
+}
+
+uint64_t fpu_fprem64(uint64_t a, uint64_t b)
+{
+	double_uint64_t a_cast, b_cast, c_cast;
+
+	a_cast.u64 = a;
+	b_cast.u64 = b;
+
+	c_cast.dbl = fmod(a_cast.dbl, b_cast.dbl);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e %% %e -> %e\n", a, b, c);
+#endif
+	return c_cast.u64;
+}
+
+double fpu_fchs(double a)
+{
+	double b;
+	b = -a;
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf(" - %e -> %e\n", a, b);
+#endif
+	return b;
+}
+
+double fpu_fyl2x(double a, double b)
+{
+	double c;
+	c = b * (log(a) / log(2));
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("%e * log(%e) -> %e\n", b, a, c);
+#endif
+	return c;
+}
+
+double fpu_fpatan(double a, double b)
+{
+	double c;
+	c = atan2(b, a);
+#ifdef DEBUG_MIASM_DOUBLE
+	dump_float();
+	printf("arctan(%e / %e) -> %e\n", b, a, c);
+#endif
+	return c;
+}
+
+unsigned int fpu_fcom_c0(double a, double b)
+{
+	if (isnan(a) || isnan(b))
+		return 1;
+	if (a>=b)
+		return 0;
+	return 1;
+}
+unsigned int fpu_fcom_c1(double a, double b)
+{
+	//XXX
+	return 0;
+}
+unsigned int fpu_fcom_c2(double a, double b)
+{
+	if (isnan(a) || isnan(b))
+		return 1;
+	return 0;
+}
+unsigned int fpu_fcom_c3(double a, double b)
+{
+	if (isnan(a) || isnan(b))
+		return 1;
+	if (a==b)
+		return 1;
+	return 0;
+}
+
+uint64_t sint_to_fp_64(int64_t a)
+{
+	double_uint64_t a_cast;
+	a_cast.dbl = (double) a;
+	return a_cast.u64;
+}
+
+uint32_t sint_to_fp_32(int32_t a)
+{
+	float_uint32_t a_cast;
+	a_cast.flt = (float) a;
+	return a_cast.u32;
+}
+
+int32_t fp32_to_sint32(uint32_t a)
+{
+	// Enforce nearbyint (IEEE-754 behavior)
+	float rounded;
+	float_uint32_t a_cast;
+	a_cast.u32 = a;
+	rounded = nearbyintf(a_cast.flt);
+	return (int32_t) rounded;
+}
+
+int64_t fp64_to_sint64(uint64_t a)
+{
+	// Enforce nearbyint (IEEE-754 behavior)
+	double rounded;
+	double_uint64_t a_cast;
+	a_cast.u64 = a;
+	rounded = nearbyint(a_cast.dbl);
+	return (int64_t) rounded;
+}
+
+int32_t fp64_to_sint32(uint64_t a)
+{
+	// Enforce nearbyint (IEEE-754 behavior)
+	double rounded;
+	double_uint64_t a_cast;
+	a_cast.u64 = a;
+	rounded = nearbyint(a_cast.dbl);
+	return (int32_t) rounded;
+}
+
+uint32_t fp64_to_fp32(uint64_t a)
+{
+	float_uint32_t a_cast32;
+	double_uint64_t a_cast64;
+	a_cast64.u64 = a;
+	a_cast32.flt = (float)a_cast64.dbl;
+	return a_cast32.u32;
+}
+
+uint64_t fp32_to_fp64(uint32_t a)
+{
+	float_uint32_t a_cast32;
+	double_uint64_t a_cast64;
+	a_cast32.u32 = a;
+	a_cast64.dbl = (double)a_cast32.flt;
+	return a_cast64.u64;
+}
+
+uint32_t fpround_towardszero_fp32(uint32_t a)
+{
+	float_uint32_t a_cast;
+	a_cast.u32 = a;
+	a_cast.flt = truncf(a_cast.flt);
+	return a_cast.u32;
+}
+
+uint64_t fpround_towardszero_fp64(uint64_t a)
+{
+	double_uint64_t a_cast;
+	a_cast.u64 = a;
+	a_cast.dbl = trunc(a_cast.dbl);
+	return a_cast.u64;
+}
+
+
+UDIV(8)
+UDIV(16)
+UDIV(32)
+UDIV(64)
+
+UMOD(8)
+UMOD(16)
+UMOD(32)
+UMOD(64)
+
+SDIV(8)
+SDIV(16)
+SDIV(32)
+SDIV(64)
+
+SMOD(8)
+SMOD(16)
+SMOD(32)
+SMOD(64)
diff --git a/src/miasm/jitter/op_semantics.h b/src/miasm/jitter/op_semantics.h
new file mode 100644
index 00000000..b76a350c
--- /dev/null
+++ b/src/miasm/jitter/op_semantics.h
@@ -0,0 +1,172 @@
+#ifndef OP_SEMANTICS_H
+#define OP_SEMANTICS_H
+
+#include <stdint.h>
+
+#if _WIN32
+#define _MIASM_EXPORT __declspec(dllexport)
+#define _MIASM_IMPORT __declspec(dllimport)
+#else
+#define _MIASM_EXPORT
+#define _MIASM_IMPORT
+#endif
+
+#define CC_P 1
+#ifdef PARITY_IMPORT
+_MIASM_IMPORT extern const uint8_t parity_table[256];
+#else
+_MIASM_EXPORT extern const uint8_t parity_table[256];
+#endif
+#define parity(a) parity_table[(a) & 0xFF]
+
+
+_MIASM_EXPORT uint16_t bcdadd_16(uint16_t a, uint16_t b);
+_MIASM_EXPORT uint16_t bcdadd_cf_16(uint16_t a, uint16_t b);
+
+
+_MIASM_EXPORT unsigned int my_imul08(unsigned int a, unsigned int b);
+_MIASM_EXPORT unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b);
+_MIASM_EXPORT unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b);
+_MIASM_EXPORT unsigned int imul_lo_op_08(char a, char b);
+_MIASM_EXPORT unsigned int imul_lo_op_16(short a, short b);
+_MIASM_EXPORT unsigned int imul_lo_op_32(int a, int b);
+_MIASM_EXPORT int imul_hi_op_08(char a, char b);
+_MIASM_EXPORT int imul_hi_op_16(short a, short b);
+_MIASM_EXPORT int imul_hi_op_32(int a, int b);
+
+
+_MIASM_EXPORT unsigned int umul16_lo(unsigned short a, unsigned short b);
+_MIASM_EXPORT unsigned int umul16_hi(unsigned short a, unsigned short b);
+
+
+_MIASM_EXPORT uint64_t rot_left(uint64_t size, uint64_t a, uint64_t b);
+_MIASM_EXPORT uint64_t rot_right(uint64_t size, uint64_t a, uint64_t b);
+
+_MIASM_EXPORT uint64_t cntleadzeros(uint64_t size, uint64_t src);
+_MIASM_EXPORT unsigned int cnttrailzeros(uint64_t size, uint64_t src);
+
+#define UDIV(sizeA)						\
+	uint ## sizeA ## _t udiv ## sizeA (uint ## sizeA ## _t a, uint ## sizeA ## _t b) \
+	{								\
+		uint ## sizeA ## _t r;					\
+		if (b == 0) {						\
+			fprintf(stderr, "Should not happen\n");		\
+			exit(EXIT_FAILURE);				\
+		}							\
+		r = a/b;						\
+		return r;						\
+	}
+
+
+#define UMOD(sizeA)						\
+	uint ## sizeA ## _t umod ## sizeA (uint ## sizeA ## _t a, uint ## sizeA ## _t b) \
+	{								\
+		uint ## sizeA ## _t r;					\
+		if (b == 0) {						\
+			fprintf(stderr, "Should not happen\n");		\
+			exit(EXIT_FAILURE);				\
+		}							\
+		r = a%b;						\
+		return r;						\
+	}
+
+
+#define SDIV(sizeA)						\
+	int ## sizeA ## _t sdiv ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \
+	{								\
+		int ## sizeA ## _t r;					\
+		if (b == 0) {						\
+			fprintf(stderr, "Should not happen\n");		\
+			exit(EXIT_FAILURE);				\
+		}							\
+		r = a/b;						\
+		return r;						\
+	}
+
+
+#define SMOD(sizeA)						\
+	int ## sizeA ## _t smod ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \
+	{								\
+		int ## sizeA ## _t r;					\
+		if (b == 0) {						\
+			fprintf(stderr, "Should not happen\n");		\
+			exit(EXIT_FAILURE);				\
+		}							\
+		r = a%b;						\
+		return r;						\
+	}
+
+_MIASM_EXPORT uint64_t udiv64(uint64_t a, uint64_t b);
+_MIASM_EXPORT uint64_t umod64(uint64_t a, uint64_t b);
+_MIASM_EXPORT int64_t sdiv64(int64_t a, int64_t b);
+_MIASM_EXPORT int64_t smod64(int64_t a, int64_t b);
+
+_MIASM_EXPORT uint32_t udiv32(uint32_t a, uint32_t b);
+_MIASM_EXPORT uint32_t umod32(uint32_t a, uint32_t b);
+_MIASM_EXPORT int32_t sdiv32(int32_t a, int32_t b);
+_MIASM_EXPORT int32_t smod32(int32_t a, int32_t b);
+
+_MIASM_EXPORT uint16_t udiv16(uint16_t a, uint16_t b);
+_MIASM_EXPORT uint16_t umod16(uint16_t a, uint16_t b);
+_MIASM_EXPORT int16_t sdiv16(int16_t a, int16_t b);
+_MIASM_EXPORT int16_t smod16(int16_t a, int16_t b);
+
+_MIASM_EXPORT uint8_t udiv8(uint8_t a, uint8_t b);
+_MIASM_EXPORT uint8_t umod8(uint8_t a, uint8_t b);
+_MIASM_EXPORT int8_t sdiv8(int8_t a, int8_t b);
+_MIASM_EXPORT int8_t smod8(int8_t a, int8_t b);
+
+_MIASM_EXPORT unsigned int x86_cpuid(unsigned int a, unsigned int reg_num);
+
+_MIASM_EXPORT uint32_t fpu_fadd32(uint32_t a, uint32_t b);
+_MIASM_EXPORT uint64_t fpu_fadd64(uint64_t a, uint64_t b);
+_MIASM_EXPORT uint32_t fpu_fsub32(uint32_t a, uint32_t b);
+_MIASM_EXPORT uint64_t fpu_fsub64(uint64_t a, uint64_t b);
+_MIASM_EXPORT uint32_t fpu_fmul32(uint32_t a, uint32_t b);
+_MIASM_EXPORT uint64_t fpu_fmul64(uint64_t a, uint64_t b);
+_MIASM_EXPORT uint32_t fpu_fdiv32(uint32_t a, uint32_t b);
+_MIASM_EXPORT uint64_t fpu_fdiv64(uint64_t a, uint64_t b);
+_MIASM_EXPORT double fpu_ftan(double a);
+_MIASM_EXPORT double fpu_frndint(double a);
+_MIASM_EXPORT double fpu_fsin(double a);
+_MIASM_EXPORT double fpu_fcos(double a);
+_MIASM_EXPORT double fpu_fscale(double a, double b);
+_MIASM_EXPORT double fpu_f2xm1(double a);
+_MIASM_EXPORT uint32_t fpu_fsqrt32(uint32_t a);
+_MIASM_EXPORT uint64_t fpu_fsqrt64(uint64_t a);
+_MIASM_EXPORT uint64_t fpu_fabs64(uint64_t a);
+_MIASM_EXPORT uint64_t fpu_fprem64(uint64_t a, uint64_t b);
+_MIASM_EXPORT double fpu_fchs(double a);
+_MIASM_EXPORT double fpu_fyl2x(double a, double b);
+_MIASM_EXPORT double fpu_fpatan(double a, double b);
+_MIASM_EXPORT unsigned int fpu_fcom_c0(double a, double b);
+_MIASM_EXPORT unsigned int fpu_fcom_c1(double a, double b);
+_MIASM_EXPORT unsigned int fpu_fcom_c2(double a, double b);
+_MIASM_EXPORT unsigned int fpu_fcom_c3(double a, double b);
+
+_MIASM_EXPORT uint64_t sint_to_fp_64(int64_t a);
+_MIASM_EXPORT uint32_t sint_to_fp_32(int32_t a);
+_MIASM_EXPORT int32_t fp32_to_sint32(uint32_t a);
+_MIASM_EXPORT int64_t fp64_to_sint64(uint64_t a);
+_MIASM_EXPORT int32_t fp64_to_sint32(uint64_t a);
+_MIASM_EXPORT uint32_t fp64_to_fp32(uint64_t a);
+_MIASM_EXPORT uint64_t fp32_to_fp64(uint32_t a);
+_MIASM_EXPORT uint32_t fpround_towardszero_fp32(uint32_t a);
+_MIASM_EXPORT uint64_t fpround_towardszero_fp64(uint64_t a);
+
+#define SHIFT_RIGHT_ARITH(size, value, shift)				\
+	((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))?	\
+			      (((int ## size ## _t) (value)) < 0 ? -1 : 0) : \
+			      (((int ## size ## _t) (value)) >> (shift))))
+
+#define SHIFT_RIGHT_LOGIC(size, value, shift)				\
+	((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))?	\
+			      0 :					\
+			      (((uint ## size ## _t) (value)) >> (shift))))
+
+#define SHIFT_LEFT_LOGIC(size, value, shift)		\
+	((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))?	\
+			      0 :					\
+			      (((uint ## size ## _t) (value)) << (shift))))
+
+#endif
diff --git a/src/miasm/jitter/queue.h b/src/miasm/jitter/queue.h
new file mode 100644
index 00000000..0caf72fb
--- /dev/null
+++ b/src/miasm/jitter/queue.h
@@ -0,0 +1,553 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+//#include <sys/cdefs.h>
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *				SLIST	LIST	STAILQ	TAILQ
+ * _HEAD			+	+	+	+
+ * _HEAD_INITIALIZER		+	+	+	+
+ * _ENTRY			+	+	+	+
+ * _INIT			+	+	+	+
+ * _EMPTY			+	+	+	+
+ * _FIRST			+	+	+	+
+ * _NEXT			+	+	+	+
+ * _PREV			-	-	-	+
+ * _LAST			-	-	+	+
+ * _FOREACH			+	+	+	+
+ * _FOREACH_SAFE		+	+	+	+
+ * _FOREACH_REVERSE		-	-	-	+
+ * _FOREACH_REVERSE_SAFE	-	-	-	+
+ * _INSERT_HEAD			+	+	+	+
+ * _INSERT_BEFORE		-	+	-	+
+ * _INSERT_AFTER		+	+	+	+
+ * _INSERT_TAIL			-	-	+	+
+ * _CONCAT			-	-	+	+
+ * _REMOVE_HEAD			+	-	+	-
+ * _REMOVE			+	+	+	+
+ *
+ */
+#define	QUEUE_MACRO_DEBUG 0
+#if QUEUE_MACRO_DEBUG
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+	char * lastfile;
+	int lastline;
+	char * prevfile;
+	int prevline;
+};
+
+#define	TRACEBUF	struct qm_trace trace;
+#define	TRASHIT(x)	do {(x) = (void *)-1;} while (0)
+
+#define	QMD_TRACE_HEAD(head) do {					\
+	(head)->trace.prevline = (head)->trace.lastline;		\
+	(head)->trace.prevfile = (head)->trace.lastfile;		\
+	(head)->trace.lastline = __LINE__;				\
+	(head)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#define	QMD_TRACE_ELEM(elem) do {					\
+	(elem)->trace.prevline = (elem)->trace.lastline;		\
+	(elem)->trace.prevfile = (elem)->trace.lastfile;		\
+	(elem)->trace.lastline = __LINE__;				\
+	(elem)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#else
+#define	QMD_TRACE_ELEM(elem)
+#define	QMD_TRACE_HEAD(head)
+#define	TRACEBUF
+#define	TRASHIT(x)
+#endif	/* QUEUE_MACRO_DEBUG */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
+	for ((varp) = &SLIST_FIRST((head));				\
+	    ((var) = *(varp)) != NULL;					\
+	    (varp) = &SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_NEXT(curelm, field) =				\
+		    SLIST_NEXT(SLIST_NEXT(curelm, field), field);	\
+	}								\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+
+#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = STAILQ_FIRST((head));				\
+	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY((head)) ?						\
+		NULL :							\
+	        ((struct type *)					\
+		((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		if ((STAILQ_NEXT(curelm, field) =			\
+		     STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+			(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+	}								\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {			\
+	if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = LIST_FIRST((head));				\
+	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+	TRACEBUF							\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+	TRACEBUF							\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+		QMD_TRACE_HEAD(head);					\
+		QMD_TRACE_HEAD(head2);					\
+	}								\
+} while (0)
+
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
+	    (var) = (tvar))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+	QMD_TRACE_HEAD(head);						\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else {								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+		QMD_TRACE_HEAD(head);					\
+	}								\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+	QMD_TRACE_ELEM(&listelm->field);				\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+	QMD_TRACE_ELEM(&listelm->field);				\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+	QMD_TRACE_HEAD(head);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+	QMD_TRACE_HEAD(head);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else {								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+		QMD_TRACE_HEAD(head);					\
+	}								\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+	TRASHIT((elm)->field.tqe_next);					\
+	TRASHIT((elm)->field.tqe_prev);					\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+
+#ifdef _KERNEL
+
+/*
+ * XXX insque() and remque() are an old way of handling certain queues.
+ * They bogusly assumes that all queue heads look alike.
+ */
+
+struct quehead {
+	struct quehead *qh_link;
+	struct quehead *qh_rlink;
+};
+
+#if defined(__GNUC__) || defined(__INTEL_COMPILER)
+
+static __inline void
+insque(void *a, void *b)
+{
+	struct quehead *element = (struct quehead *)a,
+		 *head = (struct quehead *)b;
+
+	element->qh_link = head->qh_link;
+	element->qh_rlink = head;
+	head->qh_link = element;
+	element->qh_link->qh_rlink = element;
+}
+
+static __inline void
+remque(void *a)
+{
+	struct quehead *element = (struct quehead *)a;
+
+	element->qh_link->qh_rlink = element->qh_rlink;
+	element->qh_rlink->qh_link = element->qh_link;
+	element->qh_rlink = 0;
+}
+
+#else /* !(__GNUC__ || __INTEL_COMPILER) */
+
+void	insque(void *a, void *b);
+void	remque(void *a);
+
+#endif /* __GNUC__ || __INTEL_COMPILER */
+
+#endif /* _KERNEL */
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/src/miasm/jitter/vm_mngr.c b/src/miasm/jitter/vm_mngr.c
new file mode 100644
index 00000000..9fe8ab65
--- /dev/null
+++ b/src/miasm/jitter/vm_mngr.c
@@ -0,0 +1,1032 @@
+/*
+** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License along
+** with this program; if not, write to the Free Software Foundation, Inc.,
+** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "vm_mngr.h"
+
+#include <inttypes.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "queue.h"
+
+
+
+/****************memory manager**************/
+
+
+
+
+#define MIN(a,b)  (((a)<(b))?(a):(b))
+#define MAX(a,b)  (((a)>(b))?(a):(b))
+
+// #define DEBUG_MIASM_AUTOMOD_CODE
+#define MEMORY_ACCESS_LIST_INITIAL_COUNT 100
+
+/*
+  To avoid alloc/free for each instruction access, the buffer is allocated here,
+  and is increased depending of program needs.
+ */
+void memory_access_list_init(struct memory_access_list * access)
+{
+	access->array = malloc(MEMORY_ACCESS_LIST_INITIAL_COUNT * sizeof(struct memory_access));
+	if (access->array == NULL) {
+		fprintf(stderr, "cannot realloc struct memory_access access->array\n");
+		exit(EXIT_FAILURE);
+	}
+	access->allocated = MEMORY_ACCESS_LIST_INITIAL_COUNT;
+	access->num = 0;
+}
+
+void memory_access_list_reset(struct memory_access_list * access)
+{
+	access->num = 0;
+}
+
+void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop)
+{
+	if (access->num >= access->allocated) {
+		if (access->allocated == 0)
+			access->allocated = 1;
+		else {
+			if (access->allocated >= SIZE_MAX / 2) {
+				fprintf(stderr, "Cannot alloc more pages\n");
+				exit(EXIT_FAILURE);
+			}
+			access->allocated *= 2;
+		}
+		access->array = realloc(access->array, access->allocated * sizeof(struct memory_access));
+		if (access->array == NULL) {
+			fprintf(stderr, "cannot realloc struct memory_access access->array\n");
+			exit(EXIT_FAILURE);
+		}
+	}
+	access->array[access->num].start = start;
+	access->array[access->num].stop = stop;
+	access->num += 1;
+}
+
+
+
+uint16_t set_endian16(vm_mngr_t* vm_mngr, uint16_t val)
+{
+	if (vm_mngr->sex == __BYTE_ORDER)
+		return val;
+	else
+		return Endian16_Swap(val);
+}
+
+uint32_t set_endian32(vm_mngr_t* vm_mngr, uint32_t val)
+{
+	if (vm_mngr->sex == __BYTE_ORDER)
+		return val;
+	else
+		return Endian32_Swap(val);
+}
+
+uint64_t set_endian64(vm_mngr_t* vm_mngr, uint64_t val)
+{
+	if (vm_mngr->sex == __BYTE_ORDER)
+		return val;
+	else
+		return Endian64_Swap(val);
+}
+
+void print_val(uint64_t base, uint64_t addr)
+{
+	uint64_t *ptr = (uint64_t *) (intptr_t) addr;
+	fprintf(stderr, "addr 0x%"PRIX64" val 0x%"PRIX64"\n", addr-base, *ptr);
+}
+
+int midpoint(int imin, int imax)
+{
+	return (imin + imax) / 2;
+}
+
+
+int find_page_node(struct memory_page_node * array, uint64_t key, int imin, int imax)
+{
+	// continue searching while [imin,imax] is not empty
+	while (imin <= imax) {
+		// calculate the midpoint for roughly equal partition
+		int imid = midpoint(imin, imax);
+		if(array[imid].ad <= key && key < array[imid].ad + array[imid].size)
+			// key found at index imid
+			return imid;
+		// determine which subarray to search
+		else if (array[imid].ad < key)
+			// change min index to search upper subarray
+			imin = imid + 1;
+		else
+			// change max index to search lower subarray
+			imax = imid - 1;
+	}
+	// key was not found
+	return -1;
+}
+
+struct memory_page_node * get_memory_page_from_address(vm_mngr_t* vm_mngr, uint64_t ad, int raise_exception)
+{
+	struct memory_page_node * mpn;
+	int i;
+
+	i = find_page_node(vm_mngr->memory_pages_array,
+			   ad,
+			   0,
+			   vm_mngr->memory_pages_number - 1);
+	if (i >= 0) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		if ((mpn->ad <= ad) && (ad < mpn->ad + mpn->size))
+			return mpn;
+	}
+	if (raise_exception) {
+		fprintf(stderr, "WARNING: address 0x%"PRIX64" is not mapped in virtual memory:\n", ad);
+		vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL;
+	}
+	return NULL;
+}
+
+static uint64_t memory_page_read(vm_mngr_t* vm_mngr, unsigned int my_size, uint64_t ad)
+{
+	struct memory_page_node * mpn;
+	unsigned char * addr;
+	uint64_t ret = 0;
+	struct memory_breakpoint_info * b;
+
+
+	mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+	if (!mpn)
+		return 0;
+
+	if ((mpn->access & PAGE_READ) == 0){
+		fprintf(stderr, "access to non readable page!! %"PRIX64"\n", ad);
+		vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL;
+		return 0;
+	}
+
+	/* check read breakpoint */
+	LIST_FOREACH(b, &vm_mngr->memory_breakpoint_pool, next){
+		if ((b->access & BREAKPOINT_READ) == 0)
+			continue;
+		if ((b->ad <= ad) && (ad < b->ad + b->size))
+			vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+	}
+
+
+	addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+
+	/* read fits in a page */
+	if (ad - mpn->ad + my_size/8 <= mpn->size){
+		switch(my_size){
+		case 8:
+			ret = *((unsigned char*)addr)&0xFF;
+			break;
+		case 16:
+			ret = *((unsigned short*)addr)&0xFFFF;
+			ret = set_endian16(vm_mngr, (uint16_t)ret);
+			break;
+		case 32:
+			ret = *((unsigned int*)addr)&0xFFFFFFFF;
+			ret = set_endian32(vm_mngr, (uint32_t)ret);
+			break;
+		case 64:
+			ret = *((uint64_t*)addr)&0xFFFFFFFFFFFFFFFFULL;
+			ret = set_endian64(vm_mngr, ret);
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	/* read is multiple page wide */
+	else{
+		unsigned int new_size = my_size;
+		int index = 0;
+		while (new_size){
+			mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+			if (!mpn)
+				return 0;
+			addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+			ret |= ((uint64_t)(*((unsigned char*)addr)&0xFF))<<(index);
+			index +=8;
+			new_size -= 8;
+			ad ++;
+		}
+		switch(my_size){
+		case 8:
+			break;
+		case 16:
+			ret = set_endian16(vm_mngr, (uint16_t)ret);
+			break;
+		case 32:
+			ret = set_endian32(vm_mngr, (uint32_t)ret);
+			break;
+		case 64:
+			ret = set_endian64(vm_mngr, ret);
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	return ret;
+}
+
+static void memory_page_write(vm_mngr_t* vm_mngr, unsigned int my_size,
+			      uint64_t ad, uint64_t src)
+{
+	struct memory_page_node * mpn;
+	unsigned char * addr;
+	struct memory_breakpoint_info * b;
+
+	mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+	if (!mpn)
+		return;
+
+	if ((mpn->access & PAGE_WRITE) == 0){
+		fprintf(stderr, "access to non writable page!! %"PRIX64"\n", ad);
+		vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL;
+		return ;
+	}
+
+	/* check read breakpoint*/
+	LIST_FOREACH(b, &vm_mngr->memory_breakpoint_pool, next){
+		if ((b->access & BREAKPOINT_WRITE) == 0)
+			continue;
+		if ((b->ad <= ad) && (ad < b->ad + b->size))
+			vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+	}
+
+	addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+
+	/* write fits in a page */
+	if (ad - mpn->ad + my_size/8 <= mpn->size){
+		switch(my_size){
+		case 8:
+			*((unsigned char*)addr) = src&0xFF;
+			break;
+		case 16:
+			src = set_endian16(vm_mngr, (uint16_t)src);
+			*((unsigned short*)addr) = src&0xFFFF;
+			break;
+		case 32:
+			src = set_endian32(vm_mngr, (uint32_t)src);
+			*((unsigned int*)addr) = src&0xFFFFFFFF;
+			break;
+		case 64:
+			src = set_endian64(vm_mngr, src);
+			*((uint64_t*)addr) = src&0xFFFFFFFFFFFFFFFFULL;
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+	/* write is multiple page wide */
+	else{
+		switch(my_size){
+
+		case 8:
+			break;
+		case 16:
+			src = set_endian16(vm_mngr, (uint16_t)src);
+			break;
+		case 32:
+			src = set_endian32(vm_mngr, (uint32_t)src);
+			break;
+		case 64:
+			src = set_endian64(vm_mngr, src);
+			break;
+		default:
+			fprintf(stderr, "Bad memory access size %d\n", my_size);
+			exit(EXIT_FAILURE);
+			break;
+		}
+		while (my_size){
+			mpn = get_memory_page_from_address(vm_mngr, ad, 1);
+			if (!mpn)
+				return;
+
+			addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad];
+			*((unsigned char*)addr) = src&0xFF;
+			my_size -= 8;
+			src >>=8;
+			ad ++;
+		}
+	}
+}
+
+// ##################
+
+void dump_code_bloc(vm_mngr_t* vm_mngr)
+{
+	struct code_bloc_node * cbp;
+	LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
+		fprintf(stderr, "%"PRIX64"%"PRIX64"\n", cbp->ad_start,  cbp->ad_stop);
+	}
+
+}
+
+void add_range_to_list(struct memory_access_list * access, uint64_t addr1, uint64_t addr2)
+{
+	if (access->num > 0) {
+		/* Check match on upper bound */
+		 if (access->array[access->num-1].stop == addr1) {
+			 access->array[access->num-1].stop = addr2;
+			 return;
+		 }
+
+		/* Check match on lower bound */
+		 if (access->array[0].start == addr2) {
+			 access->array[0].start = addr1;
+			 return;
+		 }
+	}
+
+	/* No merge, add to the list */
+	memory_access_list_add(access, addr1, addr2);
+}
+
+
+void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
+{
+	add_range_to_list(&(vm_mngr->memory_r), addr, addr + size);
+}
+
+void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size)
+{
+	add_range_to_list(&(vm_mngr->memory_w), addr, addr + size);
+}
+
+void check_invalid_code_blocs(vm_mngr_t* vm_mngr)
+{
+	size_t i;
+	struct code_bloc_node * cbp;
+	for (i=0;i<vm_mngr->memory_w.num; i++) {
+		if (vm_mngr->exception_flags & EXCEPT_CODE_AUTOMOD)
+			break;
+		if (vm_mngr->memory_w.array[i].stop <= vm_mngr->code_bloc_pool_ad_min ||
+		    vm_mngr->memory_w.array[i].start >=vm_mngr->code_bloc_pool_ad_max)
+			continue;
+
+		LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
+			if ((cbp->ad_start < vm_mngr->memory_w.array[i].stop) &&
+			    (vm_mngr->memory_w.array[i].start < cbp->ad_stop)){
+#ifdef DEBUG_MIASM_AUTOMOD_CODE
+				fprintf(stderr, "**********************************\n");
+				fprintf(stderr, "self modifying code %"PRIX64" %"PRIX64"\n",
+					vm_mngr->memory_w.array[i].start,
+					vm_mngr->memory_w.array[i].stop);
+				fprintf(stderr, "**********************************\n");
+#endif
+				vm_mngr->exception_flags |= EXCEPT_CODE_AUTOMOD;
+				break;
+			}
+		}
+	}
+}
+
+
+void check_memory_breakpoint(vm_mngr_t* vm_mngr)
+{
+	size_t i;
+	struct memory_breakpoint_info * memory_bp;
+
+	/* Check memory breakpoints */
+	LIST_FOREACH(memory_bp, &vm_mngr->memory_breakpoint_pool, next) {
+		if (vm_mngr->exception_flags & EXCEPT_BREAKPOINT_MEMORY)
+			break;
+		if (memory_bp->access & BREAKPOINT_READ) {
+			for (i=0;i<vm_mngr->memory_r.num; i++) {
+				if ((memory_bp->ad < vm_mngr->memory_r.array[i].stop) &&
+				    (vm_mngr->memory_r.array[i].start < memory_bp->ad + memory_bp->size)) {
+					vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+					break;
+				}
+			}
+		}
+		if (memory_bp->access & BREAKPOINT_WRITE) {
+			for (i=0;i<vm_mngr->memory_w.num; i++) {
+				if ((memory_bp->ad < vm_mngr->memory_w.array[i].stop) &&
+				    (vm_mngr->memory_w.array[i].start < memory_bp->ad + memory_bp->size)) {
+					vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY;
+					break;
+				}
+			}
+		}
+	}
+}
+
+
+PyObject* get_memory_pylist(vm_mngr_t* vm_mngr, struct memory_access_list* memory_list)
+{
+	size_t i;
+	PyObject *pylist;
+	PyObject *range;
+
+	pylist = PyList_New(memory_list->num);
+	for (i=0;i<memory_list->num;i++) {
+		range = PyTuple_New(2);
+		PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].start));
+		PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].stop));
+		PyList_SetItem(pylist, i, range);
+	}
+	return pylist;
+
+}
+
+PyObject* get_memory_read(vm_mngr_t* vm_mngr)
+{
+	return get_memory_pylist(vm_mngr, &vm_mngr->memory_r);
+}
+
+PyObject* get_memory_write(vm_mngr_t* vm_mngr)
+{
+	return get_memory_pylist(vm_mngr, &vm_mngr->memory_w);
+}
+
+void vm_MEM_WRITE_08(vm_mngr_t* vm_mngr, uint64_t addr, unsigned char src)
+{
+	add_mem_write(vm_mngr, addr, 1);
+	memory_page_write(vm_mngr, 8, addr, src);
+}
+
+void vm_MEM_WRITE_16(vm_mngr_t* vm_mngr, uint64_t addr, unsigned short src)
+{
+	add_mem_write(vm_mngr, addr, 2);
+	memory_page_write(vm_mngr, 16, addr, src);
+}
+void vm_MEM_WRITE_32(vm_mngr_t* vm_mngr, uint64_t addr, unsigned int src)
+{
+	add_mem_write(vm_mngr, addr, 4);
+	memory_page_write(vm_mngr, 32, addr, src);
+}
+void vm_MEM_WRITE_64(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t src)
+{
+	add_mem_write(vm_mngr, addr, 8);
+	memory_page_write(vm_mngr, 64, addr, src);
+}
+
+unsigned char vm_MEM_LOOKUP_08(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	unsigned char ret;
+	add_mem_read(vm_mngr, addr, 1);
+	ret = (unsigned char)memory_page_read(vm_mngr, 8, addr);
+	return ret;
+}
+unsigned short vm_MEM_LOOKUP_16(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	unsigned short ret;
+	add_mem_read(vm_mngr, addr, 2);
+	ret = (unsigned short)memory_page_read(vm_mngr, 16, addr);
+	return ret;
+}
+unsigned int vm_MEM_LOOKUP_32(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	unsigned int ret;
+	add_mem_read(vm_mngr, addr, 4);
+	ret = (unsigned int)memory_page_read(vm_mngr, 32, addr);
+	return ret;
+}
+uint64_t vm_MEM_LOOKUP_64(vm_mngr_t* vm_mngr, uint64_t addr)
+{
+	uint64_t ret;
+	add_mem_read(vm_mngr, addr, 8);
+	ret = memory_page_read(vm_mngr, 64, addr);
+	return ret;
+}
+
+
+int vm_read_mem(vm_mngr_t* vm_mngr, uint64_t addr, char** buffer_ptr, size_t size)
+{
+       char* buffer;
+       size_t len;
+       uint64_t addr_diff;
+       size_t addr_diff_st;
+       struct memory_page_node * mpn;
+
+       buffer = malloc(size);
+       *buffer_ptr = buffer;
+       if (!buffer){
+	      fprintf(stderr, "Error: cannot alloc read\n");
+	      exit(EXIT_FAILURE);
+       }
+
+       /* read is multiple page wide */
+       while (size){
+	      mpn = get_memory_page_from_address(vm_mngr, addr, 1);
+	      if (!mpn){
+		      free(*buffer_ptr);
+		      PyErr_SetString(PyExc_RuntimeError, "Error: cannot find address");
+		      return -1;
+	      }
+
+	      addr_diff = addr - mpn->ad;
+	      if (addr_diff > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	      }
+	      addr_diff_st = (size_t) addr_diff;
+	      len = MIN(size, mpn->size - addr_diff_st);
+	      memcpy(buffer, (char*)mpn->ad_hp + (addr_diff_st), len);
+	      buffer += len;
+	      addr += len;
+	      size -= len;
+       }
+
+       return 0;
+}
+
+
+/*
+   Try to read @size bytes from vm mmemory
+   Return the number of bytes consecutively read
+*/
+uint64_t vm_read_mem_ret_buf(vm_mngr_t* vm_mngr, uint64_t addr, size_t size, char *buffer)
+{
+	size_t len;
+	uint64_t addr_diff;
+	uint64_t size_out;
+	size_t addr_diff_st;
+
+	struct memory_page_node * mpn;
+
+	size_out = 0;
+	/* read is multiple page wide */
+	while (size){
+		mpn = get_memory_page_from_address(vm_mngr, addr, 0);
+		if (!mpn){
+			return size_out;
+		}
+
+		addr_diff = addr - mpn->ad;
+		if (addr_diff > SIZE_MAX) {
+			fprintf(stderr, "Size too big\n");
+			exit(EXIT_FAILURE);
+		}
+		addr_diff_st = (size_t) addr_diff;
+		len = MIN(size, mpn->size - addr_diff_st);
+		memcpy(buffer, (char*)mpn->ad_hp + (addr_diff_st), len);
+		buffer += len;
+		size_out += len;
+		addr += len;
+		size -= len;
+	}
+
+	return size_out;
+}
+
+
+int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, size_t size)
+{
+       size_t len;
+       uint64_t addr_diff;
+       size_t addr_diff_st;
+       struct memory_page_node * mpn;
+
+       if (size > SIZE_MAX) {
+	       fprintf(stderr, "Write size wider than supported system\n");
+	       exit(EXIT_FAILURE);
+       }
+
+       /* write is multiple page wide */
+       while (size){
+	      mpn = get_memory_page_from_address(vm_mngr, addr, 1);
+	      if (!mpn){
+		      PyErr_SetString(PyExc_RuntimeError, "Error: cannot find address");
+		      return -1;
+	      }
+
+	      addr_diff = addr - mpn->ad;
+	      if (addr_diff > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	      }
+	      addr_diff_st = (size_t) addr_diff;
+	      len = MIN(size, mpn->size - addr_diff_st);
+	      memcpy((char*)mpn->ad_hp + addr_diff_st, buffer, len);
+	      buffer += len;
+	      addr += len;
+	      size -= len;
+       }
+
+       return 0;
+}
+
+
+
+int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, size_t size)
+{
+       size_t len;
+       uint64_t addr_diff;
+       size_t addr_diff_st;
+       struct memory_page_node * mpn;
+
+       if (size > SIZE_MAX) {
+	       fprintf(stderr, "Test size wider than supported system\n");
+	       exit(EXIT_FAILURE);
+       }
+
+       /* test multiple page wide */
+       while (size){
+	      mpn = get_memory_page_from_address(vm_mngr, addr, 0);
+	      if (!mpn)
+		      return 0;
+
+	      addr_diff = addr - mpn->ad;
+	      if (addr_diff > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	      }
+	      addr_diff_st = (size_t) addr_diff;
+	      len = MIN(size, mpn->size - addr_diff_st);
+	      addr += len;
+	      size -= len;
+       }
+
+       return 1;
+}
+
+struct memory_page_node * create_memory_page_node(uint64_t ad, size_t size, unsigned int access, const char *name)
+{
+	struct memory_page_node * mpn;
+	void* ad_hp;
+
+	mpn = malloc(sizeof(*mpn));
+	if (!mpn){
+		fprintf(stderr, "Error: cannot alloc mpn\n");
+		return NULL;
+	}
+	ad_hp = malloc(size);
+	if (!ad_hp){
+		free(mpn);
+		fprintf(stderr, "Error: cannot alloc %zu\n", size);
+		return NULL;
+	}
+	mpn->name = malloc(strlen(name) + 1);
+	if (!mpn->name){
+		free(mpn);
+		free(ad_hp);
+		fprintf(stderr, "Error: cannot alloc\n");
+		return NULL;
+	}
+
+	mpn->ad = ad;
+	mpn->size = size;
+	mpn->access = access;
+	mpn->ad_hp = ad_hp;
+	strcpy(mpn->name, name);
+
+	return mpn;
+}
+
+
+struct code_bloc_node * create_code_bloc_node(uint64_t ad_start, uint64_t ad_stop)
+{
+	struct code_bloc_node * cbp;
+
+	cbp = malloc(sizeof(*cbp));
+	if (!cbp){
+		fprintf(stderr, "Error: cannot alloc cbp\n");
+		exit(EXIT_FAILURE);
+	}
+
+	cbp->ad_start = ad_start;
+	cbp->ad_stop = ad_stop;
+
+	return cbp;
+}
+
+
+void add_code_bloc(vm_mngr_t* vm_mngr, struct code_bloc_node* cbp)
+{
+	LIST_INSERT_HEAD(&vm_mngr->code_bloc_pool, cbp, next);
+	if (vm_mngr->code_bloc_pool_ad_min> cbp->ad_start)
+		vm_mngr->code_bloc_pool_ad_min = cbp->ad_start;
+	if (vm_mngr->code_bloc_pool_ad_max< cbp->ad_stop)
+		vm_mngr->code_bloc_pool_ad_max = cbp->ad_stop;
+}
+
+void dump_code_bloc_pool(vm_mngr_t* vm_mngr)
+{
+	struct code_bloc_node * cbp;
+
+	LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){
+		printf("ad start %"PRIX64" ad_stop %"PRIX64"\n",
+		       cbp->ad_start,
+		       cbp->ad_stop);
+	}
+}
+
+
+void init_memory_page_pool(vm_mngr_t* vm_mngr)
+{
+
+	vm_mngr->memory_pages_number = 0;
+	vm_mngr->memory_pages_array = NULL;
+}
+
+void init_code_bloc_pool(vm_mngr_t* vm_mngr)
+{
+	LIST_INIT(&vm_mngr->code_bloc_pool);
+	vm_mngr->code_bloc_pool_ad_min = 0xffffffffffffffffULL;
+	vm_mngr->code_bloc_pool_ad_max = 0;
+
+	memory_access_list_init(&(vm_mngr->memory_r));
+	memory_access_list_init(&(vm_mngr->memory_w));
+
+
+}
+
+void init_memory_breakpoint(vm_mngr_t* vm_mngr)
+{
+	LIST_INIT(&vm_mngr->memory_breakpoint_pool);
+}
+
+
+void reset_memory_page_pool(vm_mngr_t* vm_mngr)
+{
+	struct memory_page_node * mpn;
+	int i;
+	for (i=0;i<vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		free(mpn->ad_hp);
+		free(mpn->name);
+	}
+	free(vm_mngr->memory_pages_array);
+	vm_mngr->memory_pages_array = NULL;
+	vm_mngr->memory_pages_number = 0;
+}
+
+
+void reset_code_bloc_pool(vm_mngr_t* vm_mngr)
+{
+	struct code_bloc_node * cbp;
+
+
+	while (!LIST_EMPTY(&vm_mngr->code_bloc_pool)) {
+		cbp = LIST_FIRST(&vm_mngr->code_bloc_pool);
+		LIST_REMOVE(cbp, next);
+		free(cbp);
+	}
+	vm_mngr->code_bloc_pool_ad_min = 0xffffffffffffffffULL;
+	vm_mngr->code_bloc_pool_ad_max = 0;
+}
+
+void reset_memory_access(vm_mngr_t* vm_mngr)
+{
+	memory_access_list_reset(&(vm_mngr->memory_r));
+	memory_access_list_reset(&(vm_mngr->memory_w));
+}
+
+void reset_memory_breakpoint(vm_mngr_t* vm_mngr)
+{
+	struct memory_breakpoint_info * mpn;
+
+	while (!LIST_EMPTY(&vm_mngr->memory_breakpoint_pool)) {
+		mpn = LIST_FIRST(&vm_mngr->memory_breakpoint_pool);
+		LIST_REMOVE(mpn, next);
+		free(mpn);
+	}
+
+}
+
+
+
+/* We don't use dichotomy here for the insertion */
+int is_mpn_in_tab(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a)
+{
+	struct memory_page_node * mpn;
+	int i;
+
+	for (i=0;i<vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		if (mpn->ad >= mpn_a->ad + mpn_a->size)
+			continue;
+		if (mpn->ad + mpn->size  <= mpn_a->ad)
+			continue;
+		fprintf(stderr,
+			"Error: attempt to add page (0x%"PRIX64" 0x%"PRIX64") "
+			"overlapping page (0x%"PRIX64" 0x%"PRIX64")\n",
+			mpn_a->ad, mpn_a->ad + mpn_a->size,
+			mpn->ad, mpn->ad + mpn->size);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/* We don't use dichotomy here for the insertion */
+void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a)
+{
+	struct memory_page_node * mpn;
+	int i;
+
+	for (i=0; i < vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		if (mpn->ad < mpn_a->ad)
+			continue;
+		break;
+	}
+	vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array,
+					      sizeof(struct memory_page_node) *
+					      (vm_mngr->memory_pages_number+1));
+	if (vm_mngr->memory_pages_array == NULL) {
+		fprintf(stderr, "cannot realloc struct memory_page_node vm_mngr->memory_pages_array\n");
+		exit(EXIT_FAILURE);
+	}
+
+
+	memmove(&vm_mngr->memory_pages_array[i+1],
+		&vm_mngr->memory_pages_array[i],
+		sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i)
+		);
+
+	vm_mngr->memory_pages_array[i] = *mpn_a;
+	vm_mngr->memory_pages_number ++;
+}
+
+void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad)
+{
+  struct memory_page_node * mpn;
+  int i;
+
+  i = find_page_node(vm_mngr->memory_pages_array,
+		     ad,
+		     0,
+		     vm_mngr->memory_pages_number - 1);
+  if (i < 0) {
+    return;
+  }
+
+  mpn = &vm_mngr->memory_pages_array[i];
+  free(mpn->name);
+  free(mpn->ad_hp);
+  memmove(&vm_mngr->memory_pages_array[i],
+  	      &vm_mngr->memory_pages_array[i+1],
+  	      sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i - 1)
+  	      );
+  vm_mngr->memory_pages_number --;
+  vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array,
+					sizeof(struct memory_page_node) *
+					(vm_mngr->memory_pages_number));
+}
+
+/* Return a char* representing the repr of vm_mngr_t object */
+char* dump(vm_mngr_t* vm_mngr)
+{
+	char buf[0x100];
+	int length;
+	char *buf_final;
+	int i;
+	char buf_addr[0x20];
+	char buf_size[0x20];
+	struct memory_page_node * mpn;
+	/*             0x1234567812345678 0x1234567812345678        */
+	char* intro = "Addr               Size               Access Comment\n";
+	size_t total_len = strlen(intro) + 1;
+
+	buf_final = malloc(total_len);
+	if (buf_final == NULL) {
+		fprintf(stderr, "Error: cannot alloc char* buf_final\n");
+		exit(EXIT_FAILURE);
+	}
+	strcpy(buf_final, intro);
+	for (i=0; i< vm_mngr->memory_pages_number; i++) {
+		mpn = &vm_mngr->memory_pages_array[i];
+		snprintf(buf_addr, sizeof(buf_addr),
+			 "0x%"PRIX64, (uint64_t)mpn->ad);
+		snprintf(buf_size, sizeof(buf_size),
+			 "0x%"PRIX64, (uint64_t)mpn->size);
+
+		length = snprintf(buf, sizeof(buf) - 1,
+				  "%-18s %-18s %c%c%c    %s",
+				  buf_addr,
+				  buf_size,
+				  mpn->access & PAGE_READ? 'R':'_',
+				  mpn->access & PAGE_WRITE? 'W':'_',
+				  mpn->access & PAGE_EXEC? 'X':'_',
+				  mpn->name
+				  );
+		strcat(buf, "\n");
+		total_len += length + 1 + 1;
+		buf_final = realloc(buf_final, total_len);
+		if (buf_final == NULL) {
+			fprintf(stderr, "cannot realloc char* buf_final\n");
+			exit(EXIT_FAILURE);
+		}
+		strcat(buf_final, buf);
+	}
+
+	return buf_final;
+}
+
+void dump_memory_breakpoint_pool(vm_mngr_t* vm_mngr)
+{
+	struct memory_breakpoint_info * mpn;
+
+	LIST_FOREACH(mpn, &vm_mngr->memory_breakpoint_pool, next){
+		printf("ad %"PRIX64" size %"PRIX64" access %"PRIX64"\n",
+		       mpn->ad,
+		       mpn->size,
+		       mpn->access
+		       );
+	}
+}
+
+
+void add_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, uint64_t size, unsigned int access)
+{
+	struct memory_breakpoint_info * mpn_a;
+	mpn_a = malloc(sizeof(*mpn_a));
+	if (!mpn_a) {
+		fprintf(stderr, "Error: cannot alloc\n");
+		exit(EXIT_FAILURE);
+	}
+	mpn_a->ad = ad;
+	mpn_a->size = size;
+	mpn_a->access = access;
+
+	LIST_INSERT_HEAD(&vm_mngr->memory_breakpoint_pool, mpn_a, next);
+
+}
+
+void remove_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, unsigned int access)
+{
+	struct memory_breakpoint_info * mpn;
+
+	LIST_FOREACH(mpn, &vm_mngr->memory_breakpoint_pool, next){
+		if (mpn->ad == ad && mpn->access == access)
+			LIST_REMOVE(mpn, next);
+	}
+
+}
+
+
+/********************************************/
+
+void hexdump(char* m, unsigned int l)
+{
+  unsigned int i, j, last;
+  last = 0;
+  for (i=0;i<l;i++){
+      if (!(i%0x10) && i){
+      last = i;
+      printf("    ");
+      for (j=-0x10;j<0;j++){
+	      if (isprint(m[i+j])){
+		      printf("%c", m[i+j]);
+	      }
+	      else{
+		      printf(".");
+	      }
+      }
+      printf("\n");
+      }
+      printf("%.2X ", m[i]&0xFF);
+  }
+  l-=last;
+  if (l){
+    for (j=i;j<last+0x10;j++)
+      printf("   ");
+    printf("    ");
+    for (j = 0;l;j++){
+      if (isprint(m[last+j])){
+	      printf("%c", m[last+j]);
+      }
+      else{
+	      printf(".");
+      }
+      l--;
+    }
+  }
+  printf("\n");
+
+}
+
+
+// Return vm_mngr's exception flag value
+_MIASM_EXPORT uint64_t get_exception_flag(vm_mngr_t* vm_mngr)
+{
+	return vm_mngr->exception_flags;
+}
diff --git a/src/miasm/jitter/vm_mngr.h b/src/miasm/jitter/vm_mngr.h
new file mode 100644
index 00000000..f7aea5b8
--- /dev/null
+++ b/src/miasm/jitter/vm_mngr.h
@@ -0,0 +1,311 @@
+/*
+** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License along
+** with this program; if not, write to the Free Software Foundation, Inc.,
+** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef CODENAT_H
+#define CODENAT_H
+
+#if defined(_WIN32) || defined(_WIN64)
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+#endif
+
+#if _WIN32
+#define _MIASM_EXPORT __declspec(dllexport)
+#else
+#define _MIASM_EXPORT
+#endif
+
+#include <Python.h>
+#include <stdint.h>
+
+#include "queue.h"
+
+#ifdef __APPLE__
+#define __BYTE_ORDER __BYTE_ORDER__
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#define __BYTE_ORDER _BYTE_ORDER
+#define __BIG_ENDIAN _BIG_ENDIAN
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#elif defined(_WIN32) || defined(_WIN64)
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define __BIG_ENDIAN '>'
+#define __LITTLE_ENDIAN '<'
+#elif defined(__ANDROID__)
+#define __BYTE_ORDER __BYTE_ORDER__
+#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
+#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#endif
+
+
+#define Endian16_Swap(value) \
+      ((((uint16_t)((value) & 0x00FF)) << 8) | \
+       (((uint16_t)((value) & 0xFF00)) >> 8))
+
+#define Endian32_Swap(value) \
+	((((uint32_t)((value) & 0x000000FF)) << 24) |	\
+	 (((uint32_t)((value) & 0x0000FF00)) << 8) |	\
+	 (((uint32_t)((value) & 0x00FF0000)) >> 8) |	\
+	 (((uint32_t)((value) & 0xFF000000)) >> 24))
+
+#define Endian64_Swap(value)					      \
+	(((((uint64_t)value)<<56) & 0xFF00000000000000ULL)  |	      \
+	 ((((uint64_t)value)<<40) & 0x00FF000000000000ULL)  |	      \
+	 ((((uint64_t)value)<<24) & 0x0000FF0000000000ULL)  |	      \
+	 ((((uint64_t)value)<< 8) & 0x000000FF00000000ULL)  |	      \
+	 ((((uint64_t)value)>> 8) & 0x00000000FF000000ULL)  |	      \
+	 ((((uint64_t)value)>>24) & 0x0000000000FF0000ULL)  |	      \
+	 ((((uint64_t)value)>>40) & 0x000000000000FF00ULL)  |	      \
+	 ((((uint64_t)value)>>56) & 0x00000000000000FFULL))
+
+
+LIST_HEAD(code_bloc_list_head, code_bloc_node);
+LIST_HEAD(memory_breakpoint_info_head, memory_breakpoint_info);
+
+
+#define BREAKPOINT_READ 1
+#define BREAKPOINT_WRITE 2
+
+#define BREAK_SIGALARM 1<<5
+
+#define MAX_MEMORY_PAGE_POOL_TAB 0x100000
+#define MEMORY_PAGE_POOL_MASK_BIT 12
+#define VM_BIG_ENDIAN 1
+#define VM_LITTLE_ENDIAN 2
+
+
+struct memory_page_node {
+	uint64_t ad;
+	size_t size;
+	uint64_t access;
+	void* ad_hp;
+	char* name;
+};
+
+struct memory_access {
+	uint64_t start;
+	uint64_t stop;
+};
+
+struct memory_access_list {
+	struct memory_access *array;
+	size_t allocated;
+	size_t num;
+};
+
+typedef struct {
+	int sex;
+	struct code_bloc_list_head code_bloc_pool;
+	struct memory_breakpoint_info_head memory_breakpoint_pool;
+
+	int memory_pages_number;
+	struct memory_page_node* memory_pages_array;
+
+	uint64_t code_bloc_pool_ad_min;
+	uint64_t code_bloc_pool_ad_max;
+
+	uint64_t exception_flags;
+	uint64_t exception_flags_new;
+	PyObject *addr2obj;
+
+
+	struct memory_access_list memory_r;
+	struct memory_access_list memory_w;
+
+
+	int write_num;
+
+}vm_mngr_t;
+
+
+
+typedef struct {
+	PyObject *func;
+}func_resolver;
+
+
+
+
+//extern vm_mngr_t vmmngr;
+
+struct code_bloc_node {
+	uint64_t ad_start;
+	uint64_t ad_stop;
+	uint64_t ad_code;
+	LIST_ENTRY(code_bloc_node)   next;
+};
+
+
+struct memory_breakpoint_info {
+	uint64_t ad;
+	uint64_t size;
+	uint64_t access;
+	LIST_ENTRY(memory_breakpoint_info)   next;
+};
+
+
+
+#define PAGE_READ 1
+#define PAGE_WRITE 2
+#define PAGE_EXEC 4
+
+#define EXCEPT_DO_NOT_UPDATE_PC (1<<25)
+
+// interrupt with eip update after instr
+#define EXCEPT_CODE_AUTOMOD (1<<0)
+#define EXCEPT_SOFT_BP (1<<1)
+#define EXCEPT_INT_XX (1<<2)
+
+#define EXCEPT_BREAKPOINT_MEMORY (1<<10)
+// Deprecated
+#define EXCEPT_BREAKPOINT_INTERN (EXCEPT_BREAKPOINT_MEMORY)
+
+#define EXCEPT_NUM_UPDT_EIP (1<<11)
+// interrupt with eip at instr
+#define EXCEPT_UNK_MEM_AD ((1<<12) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_THROW_SEH ((1<<13) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_UNK_EIP ((1<<14) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_ACCESS_VIOL ((1<<14) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_INT_DIV_BY_ZERO ((1<<16) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_PRIV_INSN ((1<<17) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_ILLEGAL_INSN ((1<<18) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_UNK_MNEMO ((1<<19) | EXCEPT_DO_NOT_UPDATE_PC)
+#define EXCEPT_INT_1 ((1<<20) | EXCEPT_DO_NOT_UPDATE_PC)
+
+
+int is_mem_mapped(vm_mngr_t* vm_mngr, uint64_t ad);
+uint64_t get_mem_base_addr(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t *addr_base);
+unsigned int MEM_LOOKUP(vm_mngr_t* vm_mngr, unsigned int my_size, uint64_t addr);
+
+int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, size_t size);
+void vm_throw(vm_mngr_t* vm_mngr, unsigned long flags);
+
+void vm_MEM_WRITE_08(vm_mngr_t* vm_mngr, uint64_t addr, unsigned char src);
+void vm_MEM_WRITE_16(vm_mngr_t* vm_mngr, uint64_t addr, unsigned short src);
+void vm_MEM_WRITE_32(vm_mngr_t* vm_mngr, uint64_t addr, unsigned int src);
+void vm_MEM_WRITE_64(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t src);
+
+unsigned char vm_MEM_LOOKUP_08(vm_mngr_t* vm_mngr, uint64_t addr);
+unsigned short vm_MEM_LOOKUP_16(vm_mngr_t* vm_mngr, uint64_t addr);
+unsigned int vm_MEM_LOOKUP_32(vm_mngr_t* vm_mngr, uint64_t addr);
+uint64_t vm_MEM_LOOKUP_64(vm_mngr_t* vm_mngr, uint64_t addr);
+
+void MEM_WRITE_08_PASSTHROUGH(uint64_t addr, unsigned char src);
+void MEM_WRITE_16_PASSTHROUGH(uint64_t addr, unsigned short src);
+void MEM_WRITE_32_PASSTHROUGH(uint64_t addr, unsigned int src);
+void MEM_WRITE_64_PASSTHROUGH(uint64_t addr, uint64_t src);
+unsigned char MEM_LOOKUP_08_PASSTHROUGH(uint64_t addr);
+unsigned short MEM_LOOKUP_16_PASSTHROUGH(uint64_t addr);
+unsigned int MEM_LOOKUP_32_PASSTHROUGH(uint64_t addr);
+uint64_t MEM_LOOKUP_64_PASSTHROUGH(uint64_t addr);
+
+int vm_read_mem(vm_mngr_t* vm_mngr, uint64_t addr, char** buffer_ptr, size_t size);
+int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, size_t size);
+
+void memory_access_list_init(struct memory_access_list * access);
+void memory_access_list_reset(struct memory_access_list * access);
+void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop);
+
+uint16_t set_endian16(vm_mngr_t* vm_mngr, uint16_t val);
+uint32_t set_endian32(vm_mngr_t* vm_mngr, uint32_t val);
+uint64_t set_endian64(vm_mngr_t* vm_mngr, uint64_t val);
+
+
+void hexdump(char* m, unsigned int l);
+
+struct code_bloc_node * create_code_bloc_node(uint64_t ad_start, uint64_t ad_stop);
+void add_code_bloc(vm_mngr_t* vm_mngr, struct code_bloc_node* cbp);
+
+struct memory_page_node * create_memory_page_node(uint64_t ad, size_t size, unsigned int access, const char *name);//memory_page* mp);
+void init_memory_page_pool(vm_mngr_t* vm_mngr);
+void init_code_bloc_pool(vm_mngr_t* vm_mngr);
+void reset_memory_page_pool(vm_mngr_t* vm_mngr);
+void reset_code_bloc_pool(vm_mngr_t* vm_mngr);
+void dump_code_bloc_pool(vm_mngr_t* vm_mngr);
+void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a);
+void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad);
+
+
+void init_memory_breakpoint(vm_mngr_t* vm_mngr);
+void reset_memory_breakpoint(vm_mngr_t* vm_mngr);
+void add_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, uint64_t size, unsigned int access);
+void remove_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, unsigned int access);
+
+void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn);
+
+void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size);
+void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size);
+_MIASM_EXPORT void check_invalid_code_blocs(vm_mngr_t* vm_mngr);
+_MIASM_EXPORT void check_memory_breakpoint(vm_mngr_t* vm_mngr);
+_MIASM_EXPORT void reset_memory_access(vm_mngr_t* vm_mngr);
+PyObject* get_memory_read(vm_mngr_t* vm_mngr);
+PyObject* get_memory_write(vm_mngr_t* vm_mngr);
+
+
+char* dump(vm_mngr_t* vm_mngr);
+void dump_memory_breakpoint_pool(vm_mngr_t* vm_mngr);
+PyObject* addr2BlocObj(vm_mngr_t* vm_mngr, uint64_t addr);
+
+
+
+
+/********************************************/
+unsigned int get_memory_page_max_address(void);
+unsigned int get_memory_page_max_user_address(void);
+
+
+int is_mpn_in_tab(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a);
+
+
+void _func_free(void);
+void _func_alloc(void);
+unsigned int _get_memory_page_max_address_py(void);
+unsigned int _get_memory_page_max_user_address_py(void);
+unsigned int _get_memory_page_from_min_ad_py(unsigned int size);
+
+void _func_malloc_memory_page(void);
+void _func_free_memory_page(void);
+void _func_virtualalloc_memory_page(void);
+void _func_virtualfree_memory_page(void);
+void _func_loadlib_fake(void);
+void _func_getproc_fake(void);
+
+
+void func_free(void);
+void func_alloc(void);
+unsigned int get_memory_page_max_address_py(void);
+unsigned int get_memory_page_max_user_address_py(void);
+unsigned int get_memory_page_from_min_ad_py(unsigned int size);
+struct memory_page_node * get_memory_page_from_address(vm_mngr_t*, uint64_t ad, int raise_exception);
+void func_malloc_memory_page(void);
+void func_free_memory_page(void);
+void func_virtualalloc_memory_page(void);
+void func_virtualfree_memory_page(void);
+void func_loadlib_fake(void);
+void func_getproc_fake(void);
+
+unsigned int access_segment(unsigned int d);
+unsigned int access_segment_ok(unsigned int d);
+
+unsigned int load_segment_limit(unsigned int d);
+unsigned int load_segment_limit_ok(unsigned int d);
+
+unsigned int load_tr_segment_selector(unsigned int d);
+
+#endif
diff --git a/src/miasm/jitter/vm_mngr_py.c b/src/miasm/jitter/vm_mngr_py.c
new file mode 100644
index 00000000..dd1bd9b1
--- /dev/null
+++ b/src/miasm/jitter/vm_mngr_py.c
@@ -0,0 +1,1089 @@
+/*
+** Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License along
+** with this program; if not, write to the Free Software Foundation, Inc.,
+** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <Python.h>
+#include "structmember.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include <signal.h>
+#include "compat_py23.h"
+#include "queue.h"
+#include "vm_mngr.h"
+#include "bn.h"
+#include "vm_mngr_py.h"
+
+#define MIN(a,b)  (((a)<(b))?(a):(b))
+#define MAX(a,b)  (((a)>(b))?(a):(b))
+
+extern struct memory_page_list_head memory_page_pool;
+extern struct code_bloc_list_head code_bloc_pool;
+
+#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;}
+
+
+
+/* XXX POC signals */
+VmMngr* global_vmmngr;
+
+PyObject* _vm_get_exception(unsigned int xcpt)
+{
+	PyObject*p;
+
+	if (!xcpt)
+		p = NULL;
+	else if (xcpt & EXCEPT_CODE_AUTOMOD)
+		p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_CODE_AUTOMOD" );
+	else if (xcpt & EXCEPT_UNK_EIP)
+		p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNK_EIP" );
+	else if (xcpt & EXCEPT_UNK_MEM_AD)
+		p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNK_MEM_AD" );
+
+	else  p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNKNOWN" );
+	return p;
+}
+
+static void sig_alarm(int signo)
+{
+	global_vmmngr->vm_mngr.exception_flags |= BREAK_SIGALARM;
+	return;
+}
+
+PyObject* set_alarm(VmMngr* self)
+{
+	global_vmmngr = self;
+	signal(SIGALRM, sig_alarm);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+
+PyObject* vm_add_memory_page(VmMngr* self, PyObject* args)
+{
+	PyObject *addr;
+	PyObject *access;
+	PyObject *item_str;
+	PyObject *name=NULL;
+	uint64_t buf_size;
+	size_t buf_size_st;
+	char* buf_data;
+	Py_ssize_t length;
+	uint64_t page_addr;
+	uint64_t page_access;
+	const char *name_ptr;
+
+	struct memory_page_node * mpn;
+
+	if (!PyArg_ParseTuple(args, "OOO|O", &addr, &access, &item_str, &name))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(addr, page_addr);
+	PyGetInt_uint64_t(access, page_access);
+
+	if(!PyBytes_Check(item_str))
+		RAISE(PyExc_TypeError,"arg must be bytes");
+
+	buf_size = PyBytes_Size(item_str);
+	PyBytes_AsStringAndSize(item_str, &buf_data, &length);
+
+	if (name == NULL) {
+		name_ptr = (char*)"";
+	} else {
+		PyGetStr(name_ptr, name);
+	}
+	mpn = create_memory_page_node(page_addr, (size_t)buf_size, (unsigned int)page_access, name_ptr);
+	if (mpn == NULL)
+		RAISE(PyExc_TypeError,"cannot create page");
+	if (is_mpn_in_tab(&self->vm_mngr, mpn)) {
+		free(mpn->ad_hp);
+		free(mpn);
+		RAISE(PyExc_TypeError,"known page in memory");
+	}
+
+	if (buf_size > SIZE_MAX) {
+		      fprintf(stderr, "Size too big\n");
+		      exit(EXIT_FAILURE);
+	}
+	buf_size_st = (size_t) buf_size;
+
+	memcpy(mpn->ad_hp, buf_data, buf_size_st);
+	add_memory_page(&self->vm_mngr, mpn);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject* vm_remove_memory_page(VmMngr* self, PyObject* args)
+{
+  PyObject *addr;
+  uint64_t page_addr;
+
+  if (!PyArg_ParseTuple(args, "O", &addr))
+    RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+  PyGetInt_uint64_t(addr, page_addr);
+
+  remove_memory_page(&self->vm_mngr, page_addr);
+
+  Py_INCREF(Py_None);
+  return Py_None;
+
+
+}
+
+PyObject* vm_set_mem_access(VmMngr* self, PyObject* args)
+{
+	PyObject *addr;
+	PyObject *access;
+	uint64_t page_addr;
+	uint64_t page_access;
+	struct memory_page_node * mpn;
+
+	if (!PyArg_ParseTuple(args, "OO", &addr, &access))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(addr, page_addr);
+	PyGetInt_uint64_t(access, page_access);
+
+	mpn = get_memory_page_from_address(&self->vm_mngr, page_addr, 1);
+	if (!mpn){
+		PyErr_SetString(PyExc_RuntimeError, "cannot find address");
+		return 0;
+	}
+
+	mpn->access = page_access;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* vm_set_mem(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_buffer;
+       Py_ssize_t py_length;
+
+       char * buffer;
+       Py_ssize_t pysize;
+       uint64_t addr;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_buffer))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+
+       if (!PyBytes_Check(py_buffer))
+	       RAISE(PyExc_TypeError,"arg must be bytes");
+
+       pysize = PyBytes_Size(py_buffer);
+       if (pysize < 0) {
+	       RAISE(PyExc_TypeError,"Python error");
+       }
+       PyBytes_AsStringAndSize(py_buffer, &buffer, &py_length);
+
+       ret = vm_write_mem(&self->vm_mngr, addr, buffer, pysize);
+       if (ret < 0)
+	      RAISE(PyExc_TypeError, "Error in set_mem");
+
+       add_mem_write(&self->vm_mngr, addr, (size_t)pysize);
+       check_invalid_code_blocs(&self->vm_mngr);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+
+
+PyObject* vm_get_mem_access(VmMngr* self, PyObject* args)
+{
+	PyObject *py_addr;
+	uint64_t page_addr;
+	struct memory_page_node * mpn;
+
+	if (!PyArg_ParseTuple(args, "O", &py_addr))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(py_addr, page_addr);
+
+	mpn = get_memory_page_from_address(&self->vm_mngr, page_addr, 1);
+	if (!mpn){
+		PyErr_SetString(PyExc_RuntimeError, "cannot find address");
+		return 0;
+	}
+
+	return PyLong_FromUnsignedLongLong((uint64_t)mpn->access);
+}
+
+PyObject* vm_get_mem(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_len;
+
+       uint64_t addr;
+       uint64_t size;
+       size_t size_st;
+       PyObject *obj_out;
+       char * buf_out;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_len))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+       PyGetInt_uint64_t(py_len, size);
+
+       if (size > SIZE_MAX) {
+	       fprintf(stderr, "Size too big\n");
+	       exit(EXIT_FAILURE);
+       }
+       size_st = (size_t) size;
+
+       ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, size_st);
+       if (ret < 0) {
+	       RAISE(PyExc_RuntimeError,"Cannot find address");
+       }
+
+       obj_out = PyBytes_FromStringAndSize(buf_out, size_st);
+       free(buf_out);
+       return obj_out;
+}
+
+PyObject* vm_get_u8(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+
+       uint64_t addr;
+       PyObject *obj_out;
+       char * buf_out;
+       int ret;
+       uint32_t value;
+
+       if (!PyArg_ParseTuple(args, "O", &py_addr))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+
+       ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 1);
+       if (ret < 0) {
+	       RAISE(PyExc_RuntimeError,"Cannot find address");
+       }
+
+       value = *(uint8_t*)buf_out;
+
+       obj_out = PyLong_FromUnsignedLongLong(value);
+       free(buf_out);
+       return obj_out;
+}
+
+PyObject* vm_get_u16(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+
+       uint64_t addr;
+       PyObject *obj_out;
+       char * buf_out;
+       int ret;
+       uint16_t value;
+
+       if (!PyArg_ParseTuple(args, "O", &py_addr))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+
+       ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 2);
+       if (ret < 0) {
+	       RAISE(PyExc_RuntimeError,"Cannot find address");
+       }
+
+       value = set_endian16(&self->vm_mngr, *(uint16_t*)buf_out);
+
+       obj_out = PyLong_FromUnsignedLongLong(value);
+       free(buf_out);
+       return obj_out;
+}
+
+PyObject* vm_get_u32(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+
+       uint64_t addr;
+       PyObject *obj_out;
+       char * buf_out;
+       int ret;
+       uint32_t value;
+
+       if (!PyArg_ParseTuple(args, "O", &py_addr))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+
+       ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 4);
+       if (ret < 0) {
+	       RAISE(PyExc_RuntimeError,"Cannot find address");
+       }
+
+       value = set_endian32(&self->vm_mngr, *(uint32_t*)buf_out);
+
+       obj_out = PyLong_FromUnsignedLongLong(value);
+       free(buf_out);
+       return obj_out;
+}
+
+
+PyObject* vm_get_u64(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+
+       uint64_t addr;
+       PyObject *obj_out;
+       char * buf_out;
+       int ret;
+       uint64_t value;
+
+       if (!PyArg_ParseTuple(args, "O", &py_addr))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+
+       ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 8);
+       if (ret < 0) {
+	       RAISE(PyExc_RuntimeError,"Cannot find address");
+       }
+
+       value = set_endian64(&self->vm_mngr, *(uint64_t*)buf_out);
+
+       obj_out = PyLong_FromUnsignedLongLong(value);
+       free(buf_out);
+       return obj_out;
+}
+
+
+PyObject* vm_set_u8(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_val;
+       uint8_t value;
+       uint64_t addr;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+       PyGetInt_uint8_t(py_val, value);
+
+       ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 1);
+       if (ret < 0)
+	      RAISE(PyExc_TypeError, "Error in set_mem");
+
+       add_mem_write(&self->vm_mngr, addr, 1);
+       check_invalid_code_blocs(&self->vm_mngr);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+PyObject* vm_set_u16(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_val;
+       uint16_t value;
+
+       uint64_t addr;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+       PyGetInt_uint16_t(py_val, value);
+
+       value = set_endian16(&self->vm_mngr, value);
+       ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 2);
+       if (ret < 0)
+	      RAISE(PyExc_TypeError, "Error in set_mem");
+
+       add_mem_write(&self->vm_mngr, addr, 2);
+       check_invalid_code_blocs(&self->vm_mngr);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+PyObject* vm_set_u32(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_val;
+       uint32_t value;
+       uint64_t addr;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+       PyGetInt_uint32_t(py_val, value);
+
+       value = set_endian32(&self->vm_mngr, value);
+
+       ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 4);
+       if (ret < 0)
+	      RAISE(PyExc_TypeError, "Error in set_mem");
+
+       add_mem_write(&self->vm_mngr, addr, 4);
+       check_invalid_code_blocs(&self->vm_mngr);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+PyObject* vm_set_u64(VmMngr* self, PyObject* args)
+{
+       PyObject *py_addr;
+       PyObject *py_val;
+       uint64_t value;
+       uint64_t addr;
+       int ret;
+
+       if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val))
+	       RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+       PyGetInt_uint64_t(py_addr, addr);
+       PyGetInt_uint64_t(py_val, value);
+
+       value = set_endian64(&self->vm_mngr, value);
+
+       ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 8);
+       if (ret < 0)
+	      RAISE(PyExc_TypeError, "Error in set_mem");
+
+       add_mem_write(&self->vm_mngr, addr, 8);
+       check_invalid_code_blocs(&self->vm_mngr);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+
+
+
+
+PyObject* vm_add_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+	PyObject *ad;
+	PyObject *size;
+	PyObject *access;
+
+	uint64_t b_ad;
+	uint64_t b_size;
+	uint64_t b_access;
+
+	if (!PyArg_ParseTuple(args, "OOO", &ad, &size, &access))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(ad, b_ad);
+	PyGetInt_uint64_t(size, b_size);
+	PyGetInt_uint64_t(access, b_access);
+
+	add_memory_breakpoint(&self->vm_mngr, b_ad, b_size, (unsigned int)b_access);
+
+	/* Raise exception in the following pattern:
+	   - set_mem(XXX)
+	   - add_memory_breakpoint(XXX)
+	   -> Here, there is a pending breakpoint not raise
+	 */
+	check_memory_breakpoint(&self->vm_mngr);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject* vm_remove_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+	PyObject *ad;
+	PyObject *access;
+	uint64_t b_ad;
+	uint64_t b_access;
+
+	if (!PyArg_ParseTuple(args, "OO", &ad, &access))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(ad, b_ad);
+	PyGetInt_uint64_t(access, b_access);
+	remove_memory_breakpoint(&self->vm_mngr, b_ad, (unsigned int)b_access);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject* vm_set_exception(VmMngr* self, PyObject* args)
+{
+	PyObject *item1;
+	uint64_t exception_flags;
+
+	if (!PyArg_ParseTuple(args, "O", &item1))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(item1, exception_flags);
+
+	self->vm_mngr.exception_flags = exception_flags;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* vm_get_exception(VmMngr* self, PyObject* args)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)self->vm_mngr.exception_flags);
+}
+
+
+
+
+PyObject* vm_init_memory_page_pool(VmMngr* self, PyObject* args)
+{
+    init_memory_page_pool(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject* vm_init_code_bloc_pool(VmMngr* self, PyObject* args)
+{
+    init_code_bloc_pool(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+
+}
+
+PyObject* vm_init_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+    init_memory_breakpoint(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+
+}
+
+PyObject* vm_reset_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+    reset_memory_breakpoint(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+
+}
+
+PyObject* vm_reset_memory_access(VmMngr* self, PyObject* args)
+{
+    reset_memory_access(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject* py_add_mem_read(VmMngr* self, PyObject* args)
+{
+	PyObject *py_addr;
+	PyObject *py_size;
+	uint64_t addr;
+	uint64_t size;
+
+	if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_size))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(py_addr, addr);
+	PyGetInt_uint64_t(py_size, size);
+	add_mem_read(&self->vm_mngr, addr, size);
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+PyObject* py_add_mem_write(VmMngr* self, PyObject* args)
+{
+	PyObject *py_addr;
+	PyObject *py_size;
+	uint64_t addr;
+	uint64_t size;
+
+	if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_size))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(py_addr, addr);
+	PyGetInt_uint64_t(py_size, size);
+	add_mem_write(&self->vm_mngr, addr, size);
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+PyObject* vm_check_invalid_code_blocs(VmMngr* self, PyObject* args)
+{
+    check_invalid_code_blocs(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject* vm_check_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+    check_memory_breakpoint(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject *vm_dump(PyObject* self)
+{
+	char* buf_final;
+	PyObject* ret_obj;
+
+	buf_final = dump(&((VmMngr* )self)->vm_mngr);
+	ret_obj = PyUnicode_FromString(buf_final);
+	free(buf_final);
+	return ret_obj;
+}
+
+PyObject* vm_dump_memory_breakpoint(VmMngr* self, PyObject* args)
+{
+	dump_memory_breakpoint_pool(&self->vm_mngr);
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+PyObject* vm_get_all_memory(VmMngr* self, PyObject* args)
+{
+	PyObject *o;
+	struct memory_page_node * mpn;
+	PyObject *dict;
+	PyObject *dict2;
+	int i;
+
+
+	dict =  PyDict_New();
+
+	for (i=0;i<self->vm_mngr.memory_pages_number; i++) {
+		mpn = &self->vm_mngr.memory_pages_array[i];
+
+		dict2 =  PyDict_New();
+
+		o = PyBytes_FromStringAndSize(mpn->ad_hp, mpn->size);
+		PyDict_SetItemString(dict2, "data", o);
+		Py_DECREF(o);
+
+		o = PyLong_FromLong((long)mpn->size);
+		PyDict_SetItemString(dict2, "size", o);
+		Py_DECREF(o);
+
+		o = PyLong_FromLong((long)mpn->access);
+		PyDict_SetItemString(dict2, "access", o);
+		Py_DECREF(o);
+
+		o = PyLong_FromUnsignedLongLong(mpn->ad);
+		PyDict_SetItem(dict, o, dict2);
+		Py_DECREF(o);
+		Py_DECREF(dict2);
+	}
+	return dict;
+}
+
+
+PyObject* vm_reset_memory_page_pool(VmMngr* self, PyObject* args)
+{
+    reset_memory_page_pool(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+
+}
+
+PyObject* vm_reset_code_bloc_pool(VmMngr* self, PyObject* args)
+{
+    reset_code_bloc_pool(&self->vm_mngr);
+    Py_INCREF(Py_None);
+    return Py_None;
+
+}
+
+
+PyObject* vm_add_code_bloc(VmMngr *self, PyObject *args)
+{
+	PyObject *item1;
+	PyObject *item2;
+	uint64_t ad_start, ad_stop, ad_code = 0;
+
+	struct code_bloc_node * cbp;
+
+	if (!PyArg_ParseTuple(args, "OO", &item1, &item2))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(item1, ad_start);
+	PyGetInt_uint64_t(item2, ad_stop);
+
+	cbp = create_code_bloc_node(ad_start, ad_stop);
+	cbp->ad_start = ad_start;
+	cbp->ad_stop = ad_stop;
+	cbp->ad_code = ad_code;
+	add_code_bloc(&self->vm_mngr, cbp);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+PyObject* vm_dump_code_bloc_pool(VmMngr* self)
+{
+	dump_code_bloc_pool(&self->vm_mngr);
+	Py_INCREF(Py_None);
+	return Py_None;
+
+}
+
+
+
+PyObject* vm_is_mapped(VmMngr* self, PyObject* args)
+{
+	PyObject *ad;
+	PyObject *size;
+	uint64_t b_ad;
+	size_t b_size;
+	int ret;
+
+	if (!PyArg_ParseTuple(args, "OO", &ad, &size))
+		RAISE(PyExc_TypeError,"Cannot parse arguments");
+
+	PyGetInt_uint64_t(ad, b_ad);
+	PyGetInt_size_t(size, b_size);
+	ret = is_mapped(&self->vm_mngr, b_ad, b_size);
+	return PyLong_FromUnsignedLongLong((uint64_t)ret);
+}
+
+PyObject* vm_get_memory_read(VmMngr* self, PyObject* args)
+{
+	PyObject* result;
+	result = get_memory_read(&self->vm_mngr);
+	Py_INCREF(result);
+	return result;
+}
+
+PyObject* vm_get_memory_write(VmMngr* self, PyObject* args)
+{
+	PyObject* result;
+	result = get_memory_write(&self->vm_mngr);
+	Py_INCREF(result);
+	return result;
+}
+
+
+
+static PyObject *
+vm_set_big_endian(VmMngr *self, PyObject *value, void *closure)
+{
+	self->vm_mngr.sex   = __BIG_ENDIAN;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+vm_set_little_endian(VmMngr *self, PyObject *value, void *closure)
+{
+	self->vm_mngr.sex   = __LITTLE_ENDIAN;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+
+static PyObject *
+vm_is_little_endian(VmMngr *self, PyObject *value, void *closure)
+{
+	if (self->vm_mngr.sex == __BIG_ENDIAN) {
+		return PyLong_FromUnsignedLongLong(0);
+	} else {
+		return PyLong_FromUnsignedLongLong(1);
+	}
+}
+
+
+static void
+VmMngr_dealloc(VmMngr* self)
+{
+    vm_reset_memory_page_pool(self, NULL);
+    vm_reset_code_bloc_pool(self, NULL);
+    vm_reset_memory_breakpoint(self, NULL);
+    Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject *
+VmMngr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    VmMngr *self;
+
+    self = (VmMngr *)type->tp_alloc(type, 0);
+    return (PyObject *)self;
+}
+
+static PyObject *
+VmMngr_get_vmmngr(VmMngr *self, void *closure)
+{
+	return PyLong_FromUnsignedLongLong((uint64_t)(intptr_t)&(self->vm_mngr));
+}
+
+static int
+VmMngr_set_vmmngr(VmMngr *self, PyObject *value, void *closure)
+{
+	PyErr_SetString(PyExc_TypeError, "immutable vmmngr");
+	return -1;
+}
+
+static PyMemberDef VmMngr_members[] = {
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef VmMngr_methods[] = {
+	{"init_memory_page_pool", (PyCFunction)vm_init_memory_page_pool, METH_VARARGS,
+	 "init_memory_page_pool() -> Initialize the VmMngr memory"},
+	{"init_memory_breakpoint", (PyCFunction)vm_init_memory_breakpoint, METH_VARARGS,
+	 "init_memory_breakpoint() -> Initialize the VmMngr memory breakpoints"},
+	{"init_code_bloc_pool",(PyCFunction)vm_init_code_bloc_pool, METH_VARARGS,
+	 "init_code_bloc_pool() -> Initialize the VmMngr jitted code blocks"},
+	{"set_mem_access", (PyCFunction)vm_set_mem_access, METH_VARARGS,
+	 "set_mem_access(address, access) -> Change the protection of the page at @address with @access"},
+	{"set_mem", (PyCFunction)vm_set_mem, METH_VARARGS,
+	 "set_mem(address, data) -> Set a @data in memory at @address"},
+	{"is_mapped", (PyCFunction)vm_is_mapped, METH_VARARGS,
+	 "is_mapped(address, size) -> Check if the memory region at @address of @size bytes is fully mapped"},
+	{"add_code_bloc",(PyCFunction)vm_add_code_bloc, METH_VARARGS,
+	 "add_code_bloc(address_start, address_stop) -> Add a jitted code block between [@address_start, @address_stop["},
+	{"get_mem_access", (PyCFunction)vm_get_mem_access, METH_VARARGS,
+	 "get_mem_access(address) -> Retrieve the memory protection of the page at @address"},
+	{"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS,
+	 "get_mem(addr, size) -> Get the memory content at @address of @size bytes"},
+
+	{"get_u8", (PyCFunction)vm_get_u8, METH_VARARGS,
+	 "get_u8(addr) -> Get a u8 at @address of @size bytes (vm endianness)"},
+	{"get_u16", (PyCFunction)vm_get_u16, METH_VARARGS,
+	 "get_u16(addr) -> Get a u16 at @address of @size bytes (vm endianness)"},
+	{"get_u32", (PyCFunction)vm_get_u32, METH_VARARGS,
+	 "get_u32(addr) -> Get a u32 at @address of @size bytes (vm endianness)"},
+	{"get_u64", (PyCFunction)vm_get_u64, METH_VARARGS,
+	 "get_u64(addr) -> Get a u64 at @address of @size bytes (vm endianness)"},
+
+
+	{"set_u8", (PyCFunction)vm_set_u8, METH_VARARGS,
+	 "set_u8(addr, value) -> Set a u8 at @address of @size bytes (vm endianness)"},
+	{"set_u16", (PyCFunction)vm_set_u16, METH_VARARGS,
+	 "set_u16(addr, value) -> Set a u16 at @address of @size bytes (vm endianness)"},
+	{"set_u32", (PyCFunction)vm_set_u32, METH_VARARGS,
+	 "set_u32(addr, value) -> Set a u32 at @address of @size bytes (vm endianness)"},
+	{"set_u64", (PyCFunction)vm_set_u64, METH_VARARGS,
+	 "set_u64(addr, value) -> Set a u64 at @address of @size bytes (vm endianness)"},
+
+	{"add_memory_page",(PyCFunction)vm_add_memory_page, METH_VARARGS,
+	 "add_memory_page(address, access, content [, cmt]) -> Maps a memory page at @address of len(@content) bytes containing @content with protection @access\n"
+	"@cmt is a comment linked to the memory page"},
+	{"remove_memory_page",(PyCFunction)vm_remove_memory_page, METH_VARARGS,
+	 "remove_memory_page(address) -> removes a previously allocated memory page at @address"},
+	{"add_memory_breakpoint",(PyCFunction)vm_add_memory_breakpoint, METH_VARARGS,
+	 "add_memory_breakpoint(address, size, access) -> Add a memory breakpoint at @address of @size bytes with @access type"},
+	{"remove_memory_breakpoint",(PyCFunction)vm_remove_memory_breakpoint, METH_VARARGS,
+	 "remove_memory_breakpoint(address, access) -> Remove a memory breakpoint at @address with @access type"},
+	{"set_exception", (PyCFunction)vm_set_exception, METH_VARARGS,
+	 "set_exception(exception) -> Set the VmMngr exception flags to @exception"},
+	{"dump_memory_breakpoint", (PyCFunction)vm_dump_memory_breakpoint, METH_VARARGS,
+	 "dump_memory_breakpoint() -> Lists each memory breakpoint"},
+	{"get_all_memory",(PyCFunction)vm_get_all_memory, METH_VARARGS,
+	 "get_all_memory() -> Returns a dictionary representing the VmMngr memory.\n"
+	 "Keys are the addresses of each memory page.\n"
+	 "Values are another dictionary containing page properties ('data', 'size', 'access')"
+	},
+	{"reset_memory_page_pool", (PyCFunction)vm_reset_memory_page_pool, METH_VARARGS,
+	 "reset_memory_page_pool() -> Remove all memory pages"},
+	{"reset_memory_breakpoint", (PyCFunction)vm_reset_memory_breakpoint, METH_VARARGS,
+	 "reset_memory_breakpoint() -> Remove all memory breakpoints"},
+	{"reset_code_bloc_pool", (PyCFunction)vm_reset_code_bloc_pool, METH_VARARGS,
+	 "reset_code_bloc_pool() -> Remove all jitted blocks"},
+	{"set_alarm", (PyCFunction)set_alarm, METH_VARARGS,
+	 "set_alarm() -> Force a timer based alarm during a code emulation"},
+	{"get_exception",(PyCFunction)vm_get_exception, METH_VARARGS,
+	 "get_exception() -> Returns the VmMngr exception flags"},
+	{"set_big_endian",(PyCFunction)vm_set_big_endian, METH_VARARGS,
+	 "set_big_endian() -> Set the VmMngr to Big Endian"},
+	{"set_little_endian",(PyCFunction)vm_set_little_endian, METH_VARARGS,
+	 "set_little_endian() -> Set the VmMngr to Little Endian"},
+	{"is_little_endian",(PyCFunction)vm_is_little_endian, METH_VARARGS,
+	 "is_little_endian() -> Return True if the VmMngr is Little Endian"},
+	{"get_memory_read",(PyCFunction)vm_get_memory_read, METH_VARARGS,
+	 "get_memory_read() -> Retrieve last instruction READ access\n"
+	 "This function is only valid in a memory breakpoint callback."
+	},
+	{"get_memory_write",(PyCFunction)vm_get_memory_write, METH_VARARGS,
+	 "get_memory_write() -> Retrieve last instruction WRITE access\n"
+	 "This function is only valid in a memory breakpoint callback."
+	},
+	{"reset_memory_access",(PyCFunction)vm_reset_memory_access, METH_VARARGS,
+	 "reset_memory_access() -> Reset last memory READ/WRITE"},
+	{"add_mem_read",(PyCFunction)py_add_mem_read, METH_VARARGS,
+	 "add_mem_read(address, size) -> Add a READ access at @address of @size bytes"},
+	{"add_mem_write",(PyCFunction)py_add_mem_write, METH_VARARGS,
+	 "add_mem_write(address, size) -> Add a WRITE access at @address of @size bytes"},
+	{"check_invalid_code_blocs",(PyCFunction)vm_check_invalid_code_blocs, METH_VARARGS,
+	 "check_invalid_code_blocs() -> Set the AUTOMOD flag in exception in case of automodified code"},
+	{"check_memory_breakpoint",(PyCFunction)vm_check_memory_breakpoint, METH_VARARGS,
+	 "check_memory_breakpoint() -> Set the BREAKPOINT_MEMORY flag in exception in case of memory breakpoint occurred"},
+
+	{NULL}  /* Sentinel */
+};
+
+static int
+VmMngr_init(VmMngr *self, PyObject *args, PyObject *kwds)
+{
+	memset(&(self->vm_mngr), 0, sizeof(self->vm_mngr));
+	return 0;
+}
+
+static PyGetSetDef VmMngr_getseters[] = {
+    {"vmmngr",
+     (getter)VmMngr_get_vmmngr, (setter)VmMngr_set_vmmngr,
+     "vmmngr object",
+     NULL},
+    {NULL}  /* Sentinel */
+};
+
+static PyTypeObject VmMngrType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "VmMngr",                  /*tp_name*/
+    sizeof(VmMngr),            /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)VmMngr_dealloc,/*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    vm_dump,                   /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "VmMngr object",           /* tp_doc */
+    0,			       /* tp_traverse */
+    0,			       /* tp_clear */
+    0,			       /* tp_richcompare */
+    0,			       /* tp_weaklistoffset */
+    0,			       /* tp_iter */
+    0,			       /* tp_iternext */
+    VmMngr_methods,            /* tp_methods */
+    VmMngr_members,            /* tp_members */
+    VmMngr_getseters,          /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)VmMngr_init,     /* tp_init */
+    0,                         /* tp_alloc */
+    VmMngr_new,                /* tp_new */
+};
+
+static PyMethodDef VmMngr_Methods[] = {
+	{NULL, NULL, 0, NULL}        /* Sentinel */
+
+};
+
+char vm_mngr_mod_docs[] = "vm_mngr module.";
+char vm_mngr_mod_name[] = "VmMngr";
+
+
+MOD_INIT(VmMngr)
+{
+	PyObject *module = NULL;
+
+	MOD_DEF(module, "VmMngr", "vm_mngr module", VmMngr_Methods);
+
+	if (module == NULL)
+		RET_MODULE;
+
+	if (PyType_Ready(&VmMngrType) < 0)
+		RET_MODULE;
+
+	Py_INCREF(&VmMngrType);
+	if (PyModule_AddObject(module, "Vm", (PyObject *)&VmMngrType) < 0)
+		RET_MODULE;
+
+	RET_MODULE;
+}
+
+bn_t PyLong_to_bn(PyObject* py_long)
+{
+	int j;
+	uint64_t tmp_mask;
+	PyObject* py_tmp;
+	PyObject* py_long_tmp;
+	PyObject* cst_32;
+	PyObject* cst_ffffffff;
+	bn_t bn;
+
+	cst_ffffffff = PyLong_FromLong(0xffffffff);
+	cst_32 = PyLong_FromLong(32);
+	bn = bignum_from_int(0);
+
+	for (j = 0; j < BN_BYTE_SIZE; j += 4) {
+		py_tmp = PyObject_CallMethod(py_long, "__and__", "O", cst_ffffffff);
+		py_long_tmp = PyObject_CallMethod(py_long, "__rshift__", "O", cst_32);
+		Py_DECREF(py_long);
+		py_long = py_long_tmp;
+		tmp_mask = PyLong_AsUnsignedLongLongMask(py_tmp);
+		Py_DECREF(py_tmp);
+		bn = bignum_or(bn, bignum_lshift(bignum_from_uint64(tmp_mask), 8 * j));
+	}
+
+	Py_DECREF(cst_32);
+	Py_DECREF(cst_ffffffff);
+
+	return bn;
+}
+
+PyObject* bn_to_PyLong(bn_t bn)
+{
+	int j;
+	PyObject* py_long;
+	PyObject* py_long_new;
+	PyObject* py_tmp;
+	PyObject* cst_32;
+	uint64_t tmp;
+
+	py_long = PyLong_FromLong(0);
+	cst_32 = PyLong_FromLong(32);
+
+	for (j = BN_BYTE_SIZE - 4; j >= 0 ; j -= 4) {
+		tmp = bignum_to_uint64(bignum_mask(bignum_rshift(bn, 8 * j), 32));
+		py_tmp = PyLong_FromUnsignedLong((unsigned long)tmp);
+		py_long_new = PyObject_CallMethod(py_long, "__lshift__", "O", cst_32);
+		Py_DECREF(py_long);
+		py_long = PyObject_CallMethod(py_long_new, "__add__", "O", py_tmp);
+		Py_DECREF(py_long_new);
+		Py_DECREF(py_tmp);
+	}
+
+	Py_DECREF(cst_32);
+
+	return py_long;
+}
diff --git a/src/miasm/jitter/vm_mngr_py.h b/src/miasm/jitter/vm_mngr_py.h
new file mode 100644
index 00000000..a8f7dcd0
--- /dev/null
+++ b/src/miasm/jitter/vm_mngr_py.h
@@ -0,0 +1,17 @@
+#ifndef VM_MNGR_PY_H
+#define VM_MNGR_PY_H
+
+#ifdef _WIN32
+#define SIGALRM 0
+#endif
+
+typedef struct {
+	PyObject_HEAD
+	PyObject *vmmngr;
+	vm_mngr_t vm_mngr;
+} VmMngr;
+
+#endif// VM_MNGR_PY_H
+
+bn_t PyLong_to_bn(PyObject* py_long);
+PyObject* bn_to_PyLong(bn_t bn);