about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/tests.yml10
-rw-r--r--example/expression/interfer.py111
-rw-r--r--miasm/analysis/data_flow.py26
-rw-r--r--miasm/arch/aarch64/arch.py74
-rw-r--r--miasm/arch/arm/arch.py98
-rw-r--r--miasm/arch/arm/lifter_model_call.py2
-rw-r--r--miasm/arch/mep/arch.py33
-rw-r--r--miasm/arch/mips32/arch.py15
-rw-r--r--miasm/arch/msp430/arch.py24
-rw-r--r--miasm/arch/ppc/arch.py23
-rw-r--r--miasm/arch/x86/arch.py59
-rw-r--r--miasm/arch/x86/sem.py4
-rw-r--r--miasm/core/asmblock.py10
-rw-r--r--miasm/core/cpu.py14
-rw-r--r--miasm/core/graph.py12
-rw-r--r--miasm/core/utils.py24
-rw-r--r--miasm/ir/ir.py117
-rw-r--r--miasm/jitter/arch/JitCore_m68k.c467
-rw-r--r--miasm/jitter/arch/JitCore_m68k.h55
-rw-r--r--miasm/loader/pe.py24
-rw-r--r--requirements.txt2
-rw-r--r--setup.py13
-rw-r--r--test/arch/aarch64/arch.py6
-rw-r--r--test/arch/arm/arch.py2
-rw-r--r--test/arch/mips32/arch.py1
-rw-r--r--test/arch/msp430/arch.py1
-rw-r--r--test/arch/ppc32/arch.py1
-rw-r--r--test/arch/x86/arch.py1
-rwxr-xr-xtest/test_all.py1
29 files changed, 1188 insertions, 42 deletions
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 327b2426..49926aed 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -7,7 +7,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ['2.7', '3.6']
+        python-version: ['2.7', '3.6', '3.8']
 
     steps:
 
@@ -19,6 +19,9 @@ jobs:
       with:
         python-version: ${{ matrix.python-version }}
 
+    - name: Update pip
+      run: pip install pip --upgrade
+
     - name: Install requirements
       run: pip install -r requirements.txt
 
@@ -90,6 +93,11 @@ jobs:
         MIASM_TEST_EXTRA_ARG: -o cparser
 
     - name: Loader tests
+      run: cd example/loader; python --version |& grep -q "Python 3" || flags="-W error"; for i in ../../miasm-extended-tests/loader/dll_win_xp/*.dll; do python get_exports.py $i; done
+      env:
+        MIASM_EXTENTED_TESTS_LOADER: loader
+
+    - name: Loader tests
       run: cd "miasm-extended-tests/$MIASM_EXTENTED_TESTS_LOADER" && ./test_dll.py
       env:
         MIASM_EXTENTED_TESTS_LOADER: loader
diff --git a/example/expression/interfer.py b/example/expression/interfer.py
new file mode 100644
index 00000000..5055e1f6
--- /dev/null
+++ b/example/expression/interfer.py
@@ -0,0 +1,111 @@
+from miasm.analysis.data_flow import State
+from miasm.expression.expression import *
+
+"""
+Test memory interferences
+"""
+
+a32 = ExprId('a', 32)
+b32 = ExprId('b', 32)
+
+a64 = ExprId('a', 64)
+b64 = ExprId('b', 64)
+
+mem_a32_32 = ExprMem(a32, 32)
+mem_b32_32 = ExprMem(b32, 32)
+
+mem_a64_32 = ExprMem(a64, 32)
+
+mem_a32_m1_8 = ExprMem(a32 + ExprInt(-1, 32), 8)
+mem_a32_p0_8 = ExprMem(a32, 8)
+mem_a32_p1_8 = ExprMem(a32 + ExprInt(1, 32), 8)
+mem_a32_p2_8 = ExprMem(a32 + ExprInt(2, 32), 8)
+mem_a32_p3_8 = ExprMem(a32 + ExprInt(3, 32), 8)
+mem_a32_p4_8 = ExprMem(a32 + ExprInt(4, 32), 8)
+
+
+mem_a32_m4_32 = ExprMem(a32 + ExprInt(-4, 32), 32)
+mem_a32_m3_32 = ExprMem(a32 + ExprInt(-3, 32), 32)
+mem_a32_m2_32 = ExprMem(a32 + ExprInt(-2, 32), 32)
+mem_a32_m1_32 = ExprMem(a32 + ExprInt(-1, 32), 32)
+mem_a32_p0_32 = ExprMem(a32, 32)
+mem_a32_p1_32 = ExprMem(a32 + ExprInt(1, 32), 32)
+mem_a32_p2_32 = ExprMem(a32 + ExprInt(2, 32), 32)
+mem_a32_p3_32 = ExprMem(a32 + ExprInt(3, 32), 32)
+mem_a32_p4_32 = ExprMem(a32 + ExprInt(4, 32), 32)
+
+
+mem_a64_m4_32 = ExprMem(a64 + ExprInt(-4, 64), 32)
+mem_a64_m3_32 = ExprMem(a64 + ExprInt(-3, 64), 32)
+mem_a64_m2_32 = ExprMem(a64 + ExprInt(-2, 64), 32)
+mem_a64_m1_32 = ExprMem(a64 + ExprInt(-1, 64), 32)
+mem_a64_p0_32 = ExprMem(a64, 32)
+mem_a64_p1_32 = ExprMem(a64 + ExprInt(1, 64), 32)
+mem_a64_p2_32 = ExprMem(a64 + ExprInt(2, 64), 32)
+mem_a64_p3_32 = ExprMem(a64 + ExprInt(3, 64), 32)
+mem_a64_p4_32 = ExprMem(a64 + ExprInt(4, 64), 32)
+
+
+state = State()
+
+
+assert state.may_interfer(set([mem_a32_32]), mem_b32_32) == True
+assert state.may_interfer(set([mem_b32_32]), mem_a32_32) == True
+
+# Test 8 bit accesses
+assert state.may_interfer(set([mem_a32_m1_8]), mem_a32_32) == False
+assert state.may_interfer(set([mem_a32_p0_8]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p1_8]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p2_8]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p3_8]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p4_8]), mem_a32_32) == False
+
+assert state.may_interfer(set([mem_a32_32]), mem_a32_m1_8) == False
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p0_8) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p1_8) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p2_8) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p3_8) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p4_8) == False
+
+
+# Test 32 bit accesses
+assert state.may_interfer(set([mem_a32_m4_32]), mem_a32_32) == False
+assert state.may_interfer(set([mem_a32_m3_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_m2_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_m1_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p0_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p1_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p2_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p3_32]), mem_a32_32) == True
+assert state.may_interfer(set([mem_a32_p4_32]), mem_a32_32) == False
+
+assert state.may_interfer(set([mem_a32_32]), mem_a32_m4_32) == False
+assert state.may_interfer(set([mem_a32_32]), mem_a32_m3_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_m2_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_m1_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p0_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p1_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p2_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p3_32) == True
+assert state.may_interfer(set([mem_a32_32]), mem_a32_p4_32) == False
+
+# Test 32 bit accesses with 64 bit memory address
+assert state.may_interfer(set([mem_a64_m4_32]), mem_a64_32) == False
+assert state.may_interfer(set([mem_a64_m3_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_m2_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_m1_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_p0_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_p1_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_p2_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_p3_32]), mem_a64_32) == True
+assert state.may_interfer(set([mem_a64_p4_32]), mem_a64_32) == False
+
+assert state.may_interfer(set([mem_a64_32]), mem_a64_m4_32) == False
+assert state.may_interfer(set([mem_a64_32]), mem_a64_m3_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_m2_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_m1_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_p0_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_p1_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_p2_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_p3_32) == True
+assert state.may_interfer(set([mem_a64_32]), mem_a64_p4_32) == False
diff --git a/miasm/analysis/data_flow.py b/miasm/analysis/data_flow.py
index 9274d9d6..06453264 100644
--- a/miasm/analysis/data_flow.py
+++ b/miasm/analysis/data_flow.py
@@ -1921,29 +1921,29 @@ class State(object):
                 if dst in src:
                     return True
                 if dst.is_mem() and src.is_mem():
-                    base1, offset1 = get_expr_base_offset(dst.ptr)
-                    base2, offset2 = get_expr_base_offset(src.ptr)
-                    if base1 != base2:
+                    dst_base, dst_offset = get_expr_base_offset(dst.ptr)
+                    src_base, src_offset = get_expr_base_offset(src.ptr)
+                    if dst_base != src_base:
                         return True
-                    size1 = dst.size // 8
-                    size2 = src.size // 8
+                    dst_size = dst.size // 8
+                    src_size = src.size // 8
                     # Special case:
                     # @32[ESP + 0xFFFFFFFE], @32[ESP]
                     # Both memories alias
-                    if offset1 + size1 <= int(base1.mask) + 1:
+                    if dst_offset + dst_size <= int(dst_base.mask) + 1:
                         # @32[ESP + 0xFFFFFFFC] => [0xFFFFFFFC, 0xFFFFFFFF]
-                        interval1 = interval([(offset1, offset1 + dst.size // 8 - 1)])
+                        interval1 = interval([(dst_offset, dst_offset + dst.size // 8 - 1)])
                     else:
                         # @32[ESP + 0xFFFFFFFE] => [0x0, 0x1] U [0xFFFFFFFE, 0xFFFFFFFF]
-                        interval1 = interval([(offset1, int(base1.mask))])
-                        interval1 += interval([(0, size1 - (int(base1.mask) + 1 - offset1) - 1 )])
-                    if offset2 + size2 <= int(base2.mask) + 1:
+                        interval1 = interval([(dst_offset, int(dst_base.mask))])
+                        interval1 += interval([(0, dst_size - (int(dst_base.mask) + 1 - dst_offset) - 1 )])
+                    if src_offset + src_size <= int(src_base.mask) + 1:
                         # @32[ESP + 0xFFFFFFFC] => [0xFFFFFFFC, 0xFFFFFFFF]
-                        interval2 = interval([(offset2, offset2 + src.size // 8 - 1)])
+                        interval2 = interval([(src_offset, src_offset + src.size // 8 - 1)])
                     else:
                         # @32[ESP + 0xFFFFFFFE] => [0x0, 0x1] U [0xFFFFFFFE, 0xFFFFFFFF]
-                        interval2 = interval([(offset2, int(base2.mask))])
-                        interval2 += interval([(0, size2 - (int(base2.mask) + 1 - offset2) - 1)])
+                        interval2 = interval([(src_offset, int(src_base.mask))])
+                        interval2 += interval([(0, src_size - (int(src_base.mask) + 1 - src_offset) - 1)])
                     if (interval1 & interval2).empty:
                         continue
                     return True
diff --git a/miasm/arch/aarch64/arch.py b/miasm/arch/aarch64/arch.py
index f4882845..f05a0a15 100644
--- a/miasm/arch/aarch64/arch.py
+++ b/miasm/arch/aarch64/arch.py
@@ -14,6 +14,8 @@ from miasm.arch.aarch64.regs import *
 from miasm.core.cpu import log as log_cpu
 from miasm.core.modint import mod_size2int
 from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+from miasm.core import utils
 
 log = logging.getLogger("aarch64dis")
 console_handler = logging.StreamHandler()
@@ -367,6 +369,73 @@ class instruction_aarch64(instruction):
         else:
             raise NotImplementedError("bad op")
 
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        wb = False
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op in shift_expr:
+            op_str = shift_str[shift_expr.index(expr.op)]
+            return "%s %s %s" % (
+                color_expr_html(expr.args[0], loc_db),
+                utils.set_html_text_color(op_str, utils.COLOR_OP),
+                color_expr_html(expr.args[1], loc_db)
+            )
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "slice_at":
+            return "%s LSL %s" % (
+                color_expr_html(expr.args[0], loc_db),
+                color_expr_html(expr.args[1], loc_db)
+            )
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op in extend_lst:
+            op_str = expr.op
+            return "%s %s %s" % (
+                color_expr_html(expr.args[0], loc_db),
+                op_str,
+                color_expr_html(expr.args[1], loc_db)
+            )
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "postinc":
+            if int(expr.args[1]) != 0:
+                return "[%s], %s" % (
+                    color_expr_html(expr.args[0], loc_db),
+                    color_expr_html(expr.args[1], loc_db)
+                )
+            else:
+                return "[%s]" % (color_expr_html(expr.args[0], loc_db))
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc_wb":
+            if int(expr.args[1]) != 0:
+                return "[%s, %s]!" % (
+                    color_expr_html(expr.args[0], loc_db),
+                    color_expr_html(expr.args[1], loc_db)
+                )
+            else:
+                return "[%s]" % (color_expr_html(expr.args[0], loc_db))
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == "preinc":
+            if len(expr.args) == 1:
+                return "[%s]" % (color_expr_html(expr.args[0], loc_db))
+            elif not isinstance(expr.args[1], m2_expr.ExprInt) or int(expr.args[1]) != 0:
+                return "[%s, %s]" % (
+                    color_expr_html(expr.args[0], loc_db),
+                    color_expr_html(expr.args[1], loc_db)
+                )
+            else:
+                return "[%s]" % color_expr_html(expr.args[0], loc_db)
+        elif isinstance(expr, m2_expr.ExprOp) and expr.op == 'segm':
+            arg = expr.args[1]
+            if isinstance(arg, m2_expr.ExprId):
+                arg = str(arg)
+            elif arg.op == 'LSL' and int(arg.args[1]) == 0:
+                arg = str(arg.args[0])
+            else:
+                arg = "%s %s %s" % (
+                    color_expr_html(arg.args[0], loc_db),
+                    utils.set_html_text_color(arg.op, utils.COLOR_OP),
+                    color_expr_html(arg.args[1], loc_db)
+                )
+            return '[%s, %s]' % (color_expr_html(expr.args[0], loc_db), arg)
+
+        else:
+            raise NotImplementedError("bad op")
+
     def dstflow(self):
         return self.name in BRCOND + ["B", "BL", "BR", "BLR"]
 
@@ -2216,12 +2285,15 @@ aarch64op("ldarh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('1'), bs('0'), bs
 aarch64op("ldaxp",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('1'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
 aarch64op("ldaxr",[bs('1'), sf, bs('001000'), bs('0'), bs('1'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
 
+aarch64op("stlr", [bs('1'), sf, bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt], [rt, rn64_deref_nooff])
+aarch64op("stlrb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
+aarch64op("stlrh",[bs('0'), bs('1'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
+
 aarch64op("stlxr", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt], [rs32, rt, rn64_deref_nooff])
 aarch64op("stlxrb",[bs('0'), bs('0'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff])
 aarch64op("stlxrh",[bs('0'), bs('1'), bs('001000'), bs('0'), bs('0'), bs('0'), rs32, bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rs32, rt32, rn64_deref_nooff])
 aarch64op("stlxp", [bs('1'), sf, bs('001000'), bs('0'), bs('0'), bs('1'), rs32, bs('1'), rt2, rn64_deref_nooff, rt], [rs32, rt, rt2, rn64_deref_nooff])
 
-aarch64op("stlrb",[bs('0'), bs('0'), bs('001000'), bs('1'), bs('0'), bs('0'), bs('11111'), bs('1'), bs('11111'), rn64_deref_nooff, rt32], [rt32, rn64_deref_nooff])
 
 # barriers p.135
 aarch64op("dsb", [bs('1101010100'), bs('0000110011'), crm, bs('1'), bs('00'), bs('11111')], [crm])
diff --git a/miasm/arch/arm/arch.py b/miasm/arch/arm/arch.py
index 6c5b0ce2..7b07387c 100644
--- a/miasm/arch/arm/arch.py
+++ b/miasm/arch/arm/arch.py
@@ -12,6 +12,8 @@ from miasm.core.bin_stream import bin_stream
 import miasm.arch.arm.regs as regs_module
 from miasm.arch.arm.regs import *
 from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
+from miasm.core import utils
 
 # A1 encoding
 
@@ -426,6 +428,85 @@ class instruction_arm(instruction):
             o += "!"
         return o
 
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        wb = False
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        if isinstance(expr, ExprOp) and expr.op in expr2shift_dct:
+            if len(expr.args) == 1:
+                return '%s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op])
+            elif len(expr.args) == 2:
+                return '%s %s %s' % (color_expr_html(expr.args[0], loc_db), expr2shift_dct[expr.op], expr.args[1])
+            else:
+                raise NotImplementedError('zarb arg2str')
+
+
+        sb = False
+        if isinstance(expr, ExprOp) and expr.op == "sbit":
+            sb = True
+            expr = expr.args[0]
+        if isinstance(expr, ExprOp) and expr.op == "reglist":
+            o = [gpregs.expr.index(x) for x in expr.args]
+            out = reglist2html(o)
+            if sb:
+                out += "^"
+            return out
+
+
+        if isinstance(expr, ExprOp) and expr.op == 'wback':
+            wb = True
+            expr = expr.args[0]
+        if isinstance(expr, ExprId):
+            out = color_expr_html(expr, loc_db)
+            if wb:
+                out += "!"
+            return out
+
+        if not isinstance(expr, ExprMem):
+            return color_expr_html(expr, loc_db)
+
+        expr = expr.ptr
+        if isinstance(expr, ExprOp) and expr.op == 'wback':
+            wb = True
+            expr = expr.args[0]
+
+
+        if isinstance(expr, ExprId):
+            r, s = expr, None
+        elif len(expr.args) == 1 and isinstance(expr.args[0], ExprId):
+            r, s = expr.args[0], None
+        elif isinstance(expr.args[0], ExprId):
+            r, s = expr.args[0], expr.args[1]
+        else:
+            r, s = expr.args[0].args
+        if isinstance(s, ExprOp) and s.op in expr2shift_dct:
+            s_html = ' '.join(
+                str(x)
+                for x in (
+                        color_expr_html(s.args[0], loc_db),
+                        utils.set_html_text_color(expr2shift_dct[s.op], utils.COLOR_OP),
+                        color_expr_html(s.args[1], loc_db)
+                )
+            )
+        else:
+            s_html = color_expr_html(s, loc_db)
+
+        if isinstance(expr, ExprOp) and expr.op == 'postinc':
+            o = '[%s]' % color_expr_html(r, loc_db)
+            if s and not (isinstance(s, ExprInt) and int(s) == 0):
+                o += ', %s' % s_html
+        else:
+            if s and not (isinstance(s, ExprInt) and int(s) == 0):
+                o = '[%s, %s]' % (color_expr_html(r, loc_db), s_html)
+            else:
+                o = '[%s]' % color_expr_html(r, loc_db)
+
+
+        if wb:
+            o += "!"
+        return o
+
 
     def dstflow(self):
         if self.is_subcall():
@@ -1258,6 +1339,23 @@ def reglist2str(rlist):
             i = j + 1
     return "{" + ", ".join(out) + '}'
 
+def reglist2html(rlist):
+    out = []
+    i = 0
+    while i < len(rlist):
+        j = i + 1
+        while j < len(rlist) and rlist[j] < 13 and rlist[j] == rlist[j - 1] + 1:
+            j += 1
+        j -= 1
+        if j < i + 2:
+            out.append(color_expr_html(regs_expr[rlist[i]], None))
+            i += 1
+        else:
+            out.append(color_expr_html(regs_expr[rlist[i]], None) + '-' + color_expr_html(regs_expr[rlist[j]], None))
+            i = j + 1
+    out = utils.fix_html_chars("{") + ", ".join(out) + utils.fix_html_chars("}")
+    return out
+
 
 class arm_rlist(arm_arg):
     parser = gpreg_list
diff --git a/miasm/arch/arm/lifter_model_call.py b/miasm/arch/arm/lifter_model_call.py
index f9c39ab6..9aac74a4 100644
--- a/miasm/arch/arm/lifter_model_call.py
+++ b/miasm/arch/arm/lifter_model_call.py
@@ -63,7 +63,7 @@ class LifterModelCallArml(LifterModelCallArmlBase):
             call_assignblk,
             AssignBlock([ExprAssign(self.IRDst, loc_next_expr)], instr),
         ]
-        e_do = IRBlock(loc_do, call_assignblks)
+        e_do = IRBlock(self.loc_db, loc_do, call_assignblks)
         assignblks_out = [
             AssignBlock([ExprAssign(self.IRDst, dst_cond)], instr)
         ]
diff --git a/miasm/arch/mep/arch.py b/miasm/arch/mep/arch.py
index a6b994ac..67dd5288 100644
--- a/miasm/arch/mep/arch.py
+++ b/miasm/arch/mep/arch.py
@@ -10,6 +10,7 @@ from miasm.core.asm_ast import AstId, AstMem
 
 from miasm.arch.mep.regs import *
 import miasm.arch.mep.regs as mep_regs_module  # will be used to set mn_mep.regs
+from miasm.ir.ir import color_expr_html
 
 
 # Note: pyparsing is used to alter the way special operands are parsed
@@ -97,6 +98,38 @@ class instruction_mep(instruction):
                    to do with a '%s' instance." % type(expr)
         raise Disasm_Exception(message)
 
+    @staticmethod
+    def arg2html(expr, pos=None, loc_db=None):
+        """Convert mnemonics arguments into readable html strings according to the
+        MeP-c4 architecture manual and their internal types
+
+        Notes:
+            - it must be implemented ! However, a simple 'return str(expr)'
+              could do the trick.
+            - it is used to mimic objdump output
+
+        Args:
+            expr: argument as a miasm expression
+            pos: position index in the arguments list
+        """
+
+        if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or isinstance(expr, ExprLoc):
+            return color_expr_html(expr, loc_db)
+
+        elif isinstance(expr, ExprMem) and (isinstance(expr.ptr, ExprId) or isinstance(expr.ptr, ExprInt)):
+            return "(%s)" % color_expr_html(expr.ptr, loc_db)
+
+        elif isinstance(expr, ExprMem) and isinstance(expr.ptr, ExprOp):
+            return "%s(%s)" % (
+                color_expr_html(expr.ptr.args[1], loc_db),
+                color_expr_html(expr.ptr.args[0], loc_db)
+            )
+
+        # Raise an exception if the expression type was not processed
+        message = "instruction_mep.arg2str(): don't know what \
+                   to do with a '%s' instance." % type(expr)
+        raise Disasm_Exception(message)
+
     def __str__(self):
         """Return the mnemonic as a string.
 
diff --git a/miasm/arch/mips32/arch.py b/miasm/arch/mips32/arch.py
index 803f9eef..3d4aa356 100644
--- a/miasm/arch/mips32/arch.py
+++ b/miasm/arch/mips32/arch.py
@@ -9,6 +9,7 @@ from miasm.expression.expression import ExprMem, ExprInt, ExprId, ExprOp, ExprLo
 from miasm.core.bin_stream import bin_stream
 import miasm.arch.mips32.regs as regs
 import miasm.core.cpu as cpu
+from miasm.ir.ir import color_expr_html
 
 from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
 
@@ -75,6 +76,20 @@ class instruction_mips32(cpu.instruction):
         assert(len(arg.args) == 2 and arg.op == '+')
         return "%s(%s)"%(arg.args[1], arg.args[0])
 
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        assert(isinstance(expr, ExprMem))
+        arg = expr.ptr
+        if isinstance(arg, ExprId):
+            return "(%s)"%color_expr_html(arg, loc_db)
+        assert(len(arg.args) == 2 and arg.op == '+')
+        return "%s(%s)"%(
+            color_expr_html(arg.args[1], loc_db),
+            color_expr_html(arg.args[0], loc_db)
+        )
+
     def dstflow(self):
         if self.name == 'BREAK':
             return False
diff --git a/miasm/arch/msp430/arch.py b/miasm/arch/msp430/arch.py
index 8d208d26..dbe93fd2 100644
--- a/miasm/arch/msp430/arch.py
+++ b/miasm/arch/msp430/arch.py
@@ -11,6 +11,7 @@ from miasm.core.bin_stream import bin_stream
 import miasm.arch.msp430.regs as regs_module
 from miasm.arch.msp430.regs import *
 from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
 
 log = logging.getLogger("msp430dis")
 console_handler = logging.StreamHandler()
@@ -130,6 +131,29 @@ class instruction_msp430(instruction):
             raise NotImplementedError('unknown instance expr = %s' % type(expr))
         return o
 
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        if isinstance(expr, ExprId) or isinstance(expr, ExprInt) or expr.is_loc():
+            return color_expr_html(expr, loc_db)
+        elif isinstance(expr, ExprOp) and expr.op == "autoinc":
+            o = "@%s+" % color_expr_html(expr.args[0], loc_db)
+        elif isinstance(expr, ExprMem):
+            if isinstance(expr.ptr, ExprId):
+                if index == 0:
+                    o = "@%s" % color_expr_html(expr.ptr, loc_db)
+                else:
+                    o = "0x0(%s)" % color_expr_html(expr.ptr, loc_db)
+            elif isinstance(expr.ptr, ExprInt):
+                o = "@%s" % color_expr_html(expr.ptr, loc_db)
+            elif isinstance(expr.ptr, ExprOp):
+                o = "%s(%s)" % (
+                    color_expr_html(expr.ptr.args[1], loc_db),
+                    color_expr_html(expr.ptr.args[0], loc_db)
+                )
+        else:
+            raise NotImplementedError('unknown instance expr = %s' % type(expr))
+        return o
+
 
     def dstflow2label(self, loc_db):
         expr = self.args[0]
diff --git a/miasm/arch/ppc/arch.py b/miasm/arch/ppc/arch.py
index 41259180..d4edc58e 100644
--- a/miasm/arch/ppc/arch.py
+++ b/miasm/arch/ppc/arch.py
@@ -9,6 +9,7 @@ from miasm.core.bin_stream import bin_stream
 import miasm.arch.ppc.regs as regs_module
 from miasm.arch.ppc.regs import *
 from miasm.core.asm_ast import AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
 
 log = logging.getLogger("ppcdis")
 console_handler = logging.StreamHandler()
@@ -94,6 +95,28 @@ class instruction_ppc(instruction):
 
         return str(e)
 
+
+    @staticmethod
+    def arg2html(e, pos = None, loc_db=None):
+        if isinstance(e, ExprId) or isinstance(e, ExprInt) or isinstance(e, ExprLoc):
+            return color_expr_html(e, loc_db)
+        elif isinstance(e, ExprMem):
+            addr = e.ptr
+            if isinstance(addr, ExprInt) or isinstance(addr, ExprId):
+                out = '(%s)'%color_expr_html(addr, loc_db)
+            elif isinstance(addr, ExprOp):
+                if len(addr.args) == 1:
+                    out = '(%s)'%color_expr_html(addr, loc_db)
+                elif len(addr.args) == 2:
+                    out = '%s(%s)'%(color_expr_html(addr.args[1], loc_db), color_expr_html(addr.args[0], loc_db))
+                else:
+                    raise NotImplementedError('More than two args to ExprOp of address')
+            else:
+                raise NotImplementedError('Invalid memory expression')
+            return out
+
+        return color_expr_html(e, loc_db)
+
     @staticmethod
     def is_conditional_jump(s):
         return (s[0] == 'B' and
diff --git a/miasm/arch/x86/arch.py b/miasm/arch/x86/arch.py
index a886e799..ae58e69b 100644
--- a/miasm/arch/x86/arch.py
+++ b/miasm/arch/x86/arch.py
@@ -6,7 +6,7 @@ import re
 
 from future.utils import viewitems
 
-from miasm.core.utils import int_to_byte
+from miasm.core import utils
 from miasm.expression.expression import *
 from pyparsing import *
 from miasm.core.cpu import *
@@ -14,6 +14,7 @@ from collections import defaultdict
 import miasm.arch.x86.regs as regs_module
 from miasm.arch.x86.regs import *
 from miasm.core.asm_ast import AstNode, AstInt, AstId, AstMem, AstOp
+from miasm.ir.ir import color_expr_html
 
 
 log = logging.getLogger("x86_arch")
@@ -570,6 +571,26 @@ class instruction_x86(instruction):
                 o = "REPE %s" % o
         return o
 
+    def to_html(self, loc_db=None):
+        o = super(instruction_x86, self).to_html(loc_db)
+        if self.additional_info.g1.value & 1:
+            text =  utils.set_html_text_color("LOCK", utils.COLOR_MNEMO)
+            o = "%s %s" % (text, o)
+        if self.additional_info.g1.value & 2:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF2":
+                text =  utils.set_html_text_color("REPNE", utils.COLOR_MNEMO)
+                o = "%s %s" % (text, o)
+        if self.additional_info.g1.value & 8:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3":
+                text =  utils.set_html_text_color("REP", utils.COLOR_MNEMO)
+                o = "%s %s" % (text, o)
+        elif self.additional_info.g1.value & 4:
+            if getattr(self.additional_info.prefixed, 'default', b"") != b"\xF3":
+                text =  utils.set_html_text_color("REPE", utils.COLOR_MNEMO)
+                o = "%s %s" % (text, o)
+        return o
+
+
     def get_args_expr(self):
         args = []
         for a in self.args:
@@ -612,6 +633,40 @@ class instruction_x86(instruction):
         return "%s" % o
 
 
+    @staticmethod
+    def arg2html(expr, index=None, loc_db=None):
+        if expr.is_id() or expr.is_int() or expr.is_loc():
+            o = color_expr_html(expr, loc_db)
+        elif ((isinstance(expr, ExprOp) and expr.op == 'far' and
+               isinstance(expr.args[0], ExprMem)) or
+              isinstance(expr, ExprMem)):
+            if isinstance(expr, ExprOp):
+                prefix, expr = "FAR ", expr.args[0]
+            else:
+                prefix = ""
+            sz = SIZE2MEMPREFIX[expr.size]
+            sz =  '<font color="%s">%s</font>' % (utils.COLOR_MEM, sz)
+            segm = ""
+            if is_mem_segm(expr):
+                segm = "%s:" % expr.ptr.args[0]
+                expr = expr.ptr.args[1]
+            else:
+                expr = expr.ptr
+            if isinstance(expr, ExprOp):
+                s = color_expr_html(expr, loc_db)#.replace('(', '').replace(')', '')
+            else:
+                s = color_expr_html(expr, loc_db)
+            o = prefix + sz + ' PTR %s[%s]' % (segm, s)
+        elif isinstance(expr, ExprOp) and expr.op == 'segm':
+            o = "%s:%s" % (
+                color_expr_html(expr.args[0], loc_db),
+                color_expr_html(expr.args[1], loc_db)
+            )
+        else:
+            raise ValueError('check this %r' % expr)
+        return "%s" % o
+
+
 
 class mn_x86(cls_mn):
     name = "x86"
@@ -864,7 +919,7 @@ class mn_x86(cls_mn):
         if self.rex_b.value:
             rex |= 0x1
         if rex != 0x40 or self.rex_p.value == 1:
-            v = int_to_byte(rex) + v
+            v = utils.int_to_byte(rex) + v
             if hasattr(self, 'no_rex'):
                 return None
 
diff --git a/miasm/arch/x86/sem.py b/miasm/arch/x86/sem.py
index 5b6ff917..ffa2641c 100644
--- a/miasm/arch/x86/sem.py
+++ b/miasm/arch/x86/sem.py
@@ -929,8 +929,8 @@ def pop_gen(ir, instr, src, size):
 
     sp = mRSP[instr.mode]
     new_sp = sp + m2_expr.ExprInt(src.size // 8, sp.size)
-    # don't generate ESP incrementation on POP ESP
-    if src != ir.sp:
+    # Don't generate SP/ESP/RSP incrementation on POP SP/ESP/RSP
+    if not (src in mRSP.values()):
         e.append(m2_expr.ExprAssign(sp, new_sp))
     # XXX FIX XXX for pop [esp]
     if isinstance(src, m2_expr.ExprMem):
diff --git a/miasm/core/asmblock.py b/miasm/core/asmblock.py
index 47bffb34..e92034fe 100644
--- a/miasm/core/asmblock.py
+++ b/miasm/core/asmblock.py
@@ -35,6 +35,9 @@ class AsmRaw(object):
     def to_string(self, loc_db):
         return str(self)
 
+    def to_html(self, loc_db):
+        return str(self)
+
 
 class AsmConstraint(object):
     c_to = "c_to"
@@ -439,6 +442,9 @@ class AsmCFG(DiGraph):
             # between the two graphs
             self.add_edge(*edge, constraint=graph.edges2constraint[edge])
 
+    def escape_text(self, text):
+        return text
+
 
     def node2lines(self, node):
         loc_key_name = self.loc_db.pretty_str(node)
@@ -462,9 +468,9 @@ class AsmCFG(DiGraph):
             if self._dot_offset:
                 yield [self.DotCellDescription(text="%.8X" % line.offset,
                                                attr={}),
-                       self.DotCellDescription(text=line.to_string(self.loc_db), attr={})]
+                       self.DotCellDescription(text=line.to_html(self.loc_db), attr={})]
             else:
-                yield self.DotCellDescription(text=line.to_string(self.loc_db), attr={})
+                yield self.DotCellDescription(text=line.to_html(self.loc_db), attr={})
 
     def node_attr(self, node):
         block = self._loc_key_to_block.get(node, None)
diff --git a/miasm/core/cpu.py b/miasm/core/cpu.py
index d9c1955b..fac03248 100644
--- a/miasm/core/cpu.py
+++ b/miasm/core/cpu.py
@@ -19,6 +19,7 @@ from miasm.expression.simplifications import expr_simp
 
 
 from miasm.core.asm_ast import AstNode, AstInt, AstId, AstOp
+from miasm.core import utils
 from future.utils import with_metaclass
 
 log = logging.getLogger("cpuhelper")
@@ -1005,6 +1006,19 @@ class instruction(object):
         o += self.gen_args(args)
         return o
 
+    def to_html(self, loc_db=None):
+        out = "%-10s " % self.name
+        out = '<font color="%s">%s</font>' % (utils.COLOR_MNEMO, out)
+
+        args = []
+        for i, arg in enumerate(self.args):
+            if not isinstance(arg, m2_expr.Expr):
+                raise ValueError('zarb arg type')
+            x = self.arg2html(arg, i, loc_db)
+            args.append(x)
+        out += self.gen_args(args)
+        return out
+
     def get_asm_offset(self, expr):
         return m2_expr.ExprInt(self.offset, expr.size)
 
diff --git a/miasm/core/graph.py b/miasm/core/graph.py
index 1ee30c9f..0dfd7e6a 100644
--- a/miasm/core/graph.py
+++ b/miasm/core/graph.py
@@ -20,6 +20,9 @@ class DiGraph(object):
         # N -> Nodes N2 with a edge (N2 -> N)
         self._nodes_pred = {}
 
+        self.escape_chars = re.compile('[' + re.escape('{}') + '&|<>' + ']')
+
+
     def __repr__(self):
         out = []
         for node in self._nodes:
@@ -239,10 +242,12 @@ class DiGraph(object):
                            **attr))
         )
 
+    def escape_text(self, text):
+        return self.escape_chars.sub(self._fix_chars, text)
+
     def dot(self):
         """Render dot graph with HTML"""
 
-        escape_chars = re.compile('[' + re.escape('{}') + '&|<>' + ']')
         td_attr = {'align': 'left'}
         nodes_attr = {'shape': 'Mrecord',
                       'fontname': 'Courier New'}
@@ -266,7 +271,7 @@ class DiGraph(object):
                 for col in lineDesc:
                     out_render += "<td %s>%s</td>" % (
                         self._attr2str(td_attr, col.attr),
-                        escape_chars.sub(self._fix_chars, str(col.text)))
+                        self.escape_text(str(col.text)))
                 node_html_lines.append(out_render)
 
             node_html_lines = ('<tr>' +
@@ -302,7 +307,6 @@ class DiGraph(object):
 
             self.gv = graphviz.Digraph('html_table')
             self._dot_offset = False
-            escape_chars = re.compile('[' + re.escape('{}') + '&|<>' + ']')
             td_attr = {'align': 'left'}
             nodes_attr = {'shape': 'Mrecord',
                           'fontname': 'Courier New'}
@@ -320,7 +324,7 @@ class DiGraph(object):
                     for col in lineDesc:
                         out_render += "<td %s>%s</td>" % (
                             self._attr2str(td_attr, col.attr),
-                            escape_chars.sub(self._fix_chars, str(col.text)))
+                            self.escape_text(str(col.text)))
                     node_html_lines.append(out_render)
 
                 node_html_lines = ('<tr>' +
diff --git a/miasm/core/utils.py b/miasm/core/utils.py
index cfe96de4..41bf78c1 100644
--- a/miasm/core/utils.py
+++ b/miasm/core/utils.py
@@ -1,4 +1,5 @@
 from __future__ import print_function
+import re
 import sys
 from builtins import range
 import struct
@@ -16,6 +17,28 @@ from future.utils import viewitems
 
 import collections
 
+COLOR_INT = "azure4"
+COLOR_ID = "forestgreen"#"chartreuse3"
+COLOR_MEM = "deeppink4"
+COLOR_OP_FUNC = "blue1"
+COLOR_LOC = "darkslateblue"
+COLOR_OP = "black"
+
+COLOR_MNEMO = "blue1"
+
+ESCAPE_CHARS = re.compile('[' + re.escape('{}') + '&|<>' + ']')
+
+def set_html_text_color(text, color):
+    return '<font color="%s">%s</font>' % (color, text)
+
+
+def _fix_chars(token):
+    return "&#%04d;" % ord(token.group())
+
+
+def fix_html_chars(text):
+    return ESCAPE_CHARS.sub(_fix_chars, str(text))
+
 upck8 = lambda x: struct.unpack('B', x)[0]
 upck16 = lambda x: struct.unpack('H', x)[0]
 upck32 = lambda x: struct.unpack('I', x)[0]
@@ -261,3 +284,4 @@ class BoundedDict(DictMixin):
 
     def __iter__(self):
         return iter(self._data)
+
diff --git a/miasm/ir/ir.py b/miasm/ir/ir.py
index b712b0ee..e9b86899 100644
--- a/miasm/ir/ir.py
+++ b/miasm/ir/ir.py
@@ -27,7 +27,10 @@ import miasm.expression.expression as m2_expr
 from miasm.expression.expression_helper import get_missing_interval
 from miasm.core.asmblock import AsmBlock, AsmBlockBad, AsmConstraint
 from miasm.core.graph import DiGraph
+from miasm.ir.translators import Translator
 from functools import reduce
+from miasm.core import utils
+import re
 
 
 def _expr_loc_to_symb(expr, loc_db):
@@ -44,6 +47,108 @@ def _expr_loc_to_symb(expr, loc_db):
             name = sorted(names)[0]
     return m2_expr.ExprId(name, expr.size)
 
+
+ESCAPE_CHARS = re.compile('[' + re.escape('{}') + '&|<>' + ']')
+
+class TranslatorHtml(Translator):
+    __LANG__ = "custom_expr_color"
+
+    @staticmethod
+    def _fix_chars(token):
+        return "&#%04d;" % ord(token.group())
+
+    def __init__(self, loc_db=None, **kwargs):
+        super(TranslatorHtml, self).__init__(**kwargs)
+        self.loc_db = loc_db
+
+    def str_protected_child(self, child, parent):
+        return ("(%s)" % (
+            self.from_expr(child)) if m2_expr.should_parenthesize_child(child, parent)
+                else self.from_expr(child)
+        )
+
+    def from_ExprInt(self, expr):
+        out = str(expr)
+        out = '<font color="%s">%s</font>' % (utils.COLOR_INT, out)
+        return out
+
+    def from_ExprId(self, expr):
+        out = str(expr)
+        out = '<font color="%s">%s</font>' % (utils.COLOR_ID, out)
+        return out
+
+    def from_ExprLoc(self, expr):
+
+        if self.loc_db is None:
+            name = ESCAPE_CHARS.sub(self._fix_chars, str((expr)))
+        else:
+            names = self.loc_db.get_location_names(expr.loc_key)
+            if not names:
+                name = self.loc_db.pretty_str(expr.loc_key)
+            else:
+                # Use only one name for readability
+                name = sorted(names)[0]
+        name = ESCAPE_CHARS.sub(self._fix_chars, name)
+        out = '<font color="%s">%s</font>' % (utils.COLOR_LOC, name)
+        return out
+
+    def from_ExprMem(self, expr):
+        ptr = self.from_expr(expr.ptr)
+        size = '@' + str(expr.size)
+        size = '<font color="%s">%s</font>' % (utils.COLOR_MEM, size)
+        bracket_left = ESCAPE_CHARS.sub(self._fix_chars, '[')
+        bracket_right = ESCAPE_CHARS.sub(self._fix_chars, ']')
+        out = '%s%s%s%s' % (size, bracket_left, ptr, bracket_right)
+        return out
+
+    def from_ExprSlice(self, expr):
+        base = self.from_expr(expr.arg)
+        start = str(expr.start)
+        stop = str(expr.stop)
+        bracket_left = ESCAPE_CHARS.sub(self._fix_chars, '[')
+        bracket_right = ESCAPE_CHARS.sub(self._fix_chars, ']')
+        out = "(%s)%s%s:%s%s" % (base, bracket_left, start, stop, bracket_right)
+        return out
+
+    def from_ExprCompose(self, expr):
+        out = ESCAPE_CHARS.sub(self._fix_chars, "{")
+        out += ", ".join(["%s, %s, %s" % (self.from_expr(subexpr),
+                                          str(idx),
+                                          str(idx + subexpr.size))
+                          for idx, subexpr in expr.iter_args()])
+        out += ESCAPE_CHARS.sub(self._fix_chars, "}")
+        return out
+
+    def from_ExprCond(self, expr):
+        cond = self.str_protected_child(expr.cond, expr)
+        src1 = self.from_expr(expr.src1)
+        src2 = self.from_expr(expr.src2)
+        out = "%s?(%s,%s)" % (cond, src1, src2)
+        return out
+
+    def from_ExprOp(self, expr):
+        op = ESCAPE_CHARS.sub(self._fix_chars, expr._op)
+        if expr._op == '-':		# Unary minus
+            return '-' + self.str_protected_child(expr._args[0], expr)
+        if expr.is_associative() or expr.is_infix():
+            return (' ' + op + ' ').join([self.str_protected_child(arg, expr)
+                                          for arg in expr._args])
+
+        op = '<font color="%s">%s</font>' % (utils.COLOR_OP_FUNC, op)
+        return (op + '(' +
+                ', '.join(
+                    self.from_expr(arg)
+                    for arg in expr._args
+                ) + ')')
+
+    def from_ExprAssign(self, expr):
+        return "%s = %s" % tuple(map(expr.from_expr, (expr.dst, expr.src)))
+
+
+def color_expr_html(expr, loc_db):
+    translator = TranslatorHtml(loc_db=loc_db)
+    return translator.from_expr(expr)
+
 def slice_rest(expr):
     "Return the completion of the current slice"
     size = expr.arg.size
@@ -489,6 +594,7 @@ class irbloc(IRBlock):
         super(irbloc, self).__init__(loc_key, irs)
 
 
+
 class IRCFG(DiGraph):
 
     """DiGraph for IR instances"""
@@ -528,6 +634,9 @@ class IRCFG(DiGraph):
             if dst.is_loc():
                 self.add_uniq_edge(irblock.loc_key, dst.loc_key)
 
+    def escape_text(self, text):
+        return text
+
     def node2lines(self, node):
         node_name = self.loc_db.pretty_str(node)
         yield self.DotCellDescription(
@@ -543,10 +652,10 @@ class IRCFG(DiGraph):
             return
         for i, assignblk in enumerate(self._blocks[node]):
             for dst, src in viewitems(assignblk):
-
-                new_src = src.visit(lambda expr:_expr_loc_to_symb(expr, self.loc_db))
-                new_dst = dst.visit(lambda expr:_expr_loc_to_symb(expr, self.loc_db))
-                line = "%s = %s" % (new_dst, new_src)
+                line = "%s = %s" % (
+                    color_expr_html(dst, self.loc_db),
+                    color_expr_html(src, self.loc_db)
+                )
                 if self._dot_offset:
                     yield [self.DotCellDescription(text="%-4d" % i, attr={}),
                            self.DotCellDescription(text=line, attr={})]
diff --git a/miasm/jitter/arch/JitCore_m68k.c b/miasm/jitter/arch/JitCore_m68k.c
new file mode 100644
index 00000000..0989fde1
--- /dev/null
+++ b/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/miasm/jitter/arch/JitCore_m68k.h b/miasm/jitter/arch/JitCore_m68k.h
new file mode 100644
index 00000000..6ff6b326
--- /dev/null
+++ b/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/miasm/loader/pe.py b/miasm/loader/pe.py
index 2d257906..ea7cbc52 100644
--- a/miasm/loader/pe.py
+++ b/miasm/loader/pe.py
@@ -714,9 +714,9 @@ class DirExport(CStruct):
         self.expdesc.name = rva
         rva += len(self.dlldescname)
         self.expdesc.addressoffunctions = rva
-        rva += len(self.f_address) * rva_size
+        rva += len(self.f_address) * 4
         self.expdesc.addressofnames = rva
-        rva += len(self.f_names) * rva_size
+        rva += len(self.f_names) * 4
         self.expdesc.addressofordinals = rva
         rva += len(self.f_nameordinals) * 2  # Ordinal size
         for func in self.f_names:
@@ -730,8 +730,8 @@ class DirExport(CStruct):
             return length
         length += len(self.expdesc)
         length += len(self.dlldescname)
-        length += len(self.f_address) * rva_size
-        length += len(self.f_names) * rva_size
+        length += len(self.f_address) * 4
+        length += len(self.f_names) * 4
         length += len(self.f_nameordinals) * 2  # Ordinal size
         for entry in self.f_names:
             length += len(entry.name)
@@ -775,16 +775,16 @@ class DirExport(CStruct):
         self.dlldescname.name = name
         self.f_address = struct_array(self, None,
                                       None,
-                                      Rva)
+                                      Rva32)
         self.f_names = struct_array(self, None,
                                     None,
-                                    Rva)
+                                    Rva32)
         self.f_nameordinals = struct_array(self, None,
                                            None,
                                            Ordinal)
         self.expdesc.base = 1
 
-    def add_name(self, name, rva=0xdeadc0fe):
+    def add_name(self, name, rva=0xdeadc0fe, ordinal=None):
         if self.expdesc is None:
             return
         names = [func.name.name for func in self.f_names]
@@ -798,14 +798,18 @@ class DirExport(CStruct):
         descname = DescName(self.parent_head)
 
         descname.name = name
-        wname = Rva(self.parent_head)
+        wname = Rva32(self.parent_head)
 
         wname.name = descname
-        woffset = Rva(self.parent_head)
+        woffset = Rva32(self.parent_head)
         woffset.rva = rva
         wordinal = Ordinal(self.parent_head)
         # func is append to list
-        wordinal.ordinal = len(self.f_address)
+        if ordinal is None:
+            wordinal.ordinal = len(self.f_address)
+        else:
+            wordinal.ordinal = ordinal
+
         self.f_address.append(woffset)
         # self.f_names.insert(index, wname)
         # self.f_nameordinals.insert(index, wordinal)
diff --git a/requirements.txt b/requirements.txt
index eb542916..5db3c2a8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,2 @@
-pyparsing
+pyparsing~=2.0
 future
diff --git a/setup.py b/setup.py
index 4980028f..e317877a 100644
--- a/setup.py
+++ b/setup.py
@@ -197,6 +197,17 @@ def buil_all():
                 "miasm/jitter/bn.h",
             ]
         ),
+        Extension(
+            "miasm.jitter.arch.JitCore_m68k",
+            [
+                "miasm/jitter/JitCore.c",
+                "miasm/jitter/vm_mngr.c",
+                "miasm/jitter/vm_mngr_py.c",
+                "miasm/jitter/op_semantics.c",
+                "miasm/jitter/bn.c",
+                "miasm/jitter/arch/JitCore_m68k.c"
+            ]
+        ),
         Extension("miasm.jitter.Jitllvm",
                   ["miasm/jitter/Jitllvm.c",
                    "miasm/jitter/bn.c",
@@ -242,7 +253,7 @@ def buil_all():
                         "VERSION"
                     ]
                 },
-                install_requires=['future', 'pyparsing'],
+                install_requires=['future', 'pyparsing~=2.0'],
                 cmdclass={"install_data": smart_install_data},
                 ext_modules = ext_modules,
                 # Metadata
diff --git a/test/arch/aarch64/arch.py b/test/arch/aarch64/arch.py
index 9be0c6c5..57ec9b14 100644
--- a/test/arch/aarch64/arch.py
+++ b/test/arch/aarch64/arch.py
@@ -1829,8 +1829,13 @@ reg_tests_aarch64 = [
     ("XXXXXXXX    STLXRB     W17, W16, [X14]",
      "D0FD1108"),
 
+    ("XXXXXXXX    STLR       W9, [X8]",
+     "09FD9F88"),
     ("XXXXXXXX    STLRB      W1, [X0]",
      "01FC9F08"),
+    ("XXXXXXXX    STLRH      W9, [X8]",
+     "09FD9F48"),
+
     ("XXXXXXXX    IC         0x0, c1, 0x0, XZR",
      "1F7108D5"),
     ("XXXXXXXX    CLREX      0xF",
@@ -1865,4 +1870,5 @@ for s, l in reg_tests_aarch64[:]:
     print([x for x in a])
     print(repr(b))
     assert(b in a)
+    print(l.to_html())
 
diff --git a/test/arch/arm/arch.py b/test/arch/arm/arch.py
index 740655da..42e80772 100644
--- a/test/arch/arm/arch.py
+++ b/test/arch/arm/arch.py
@@ -261,6 +261,7 @@ for s, l in reg_tests_arm:
     print([x for x in a])
     print(repr(b))
     assert(b in a)
+    print(l.to_html())
 
 reg_tests_armt = [
     ("0006ff5c    LSLS       R2, R0, 0x1A",
@@ -733,6 +734,7 @@ for s, l in reg_tests_armt:
     print([x for x in a])
     print(repr(b))
     assert(b in a)
+    print(l.to_html())
 
 print('TEST time', time.time() - ts)
 
diff --git a/test/arch/mips32/arch.py b/test/arch/mips32/arch.py
index de6d4547..0509f033 100644
--- a/test/arch/mips32/arch.py
+++ b/test/arch/mips32/arch.py
@@ -274,3 +274,4 @@ for s, l in reg_tests_mips32:
     print([x for x in a])
     print(repr(b))
     assert(b in a)
+    print(l.to_html())
diff --git a/test/arch/msp430/arch.py b/test/arch/msp430/arch.py
index bc38c363..133b8b55 100644
--- a/test/arch/msp430/arch.py
+++ b/test/arch/msp430/arch.py
@@ -104,3 +104,4 @@ for s, l in reg_tests_msp:
     print([x for x in a])
     print(repr(b))
     assert(b in a)
+    print(l.to_html())
diff --git a/test/arch/ppc32/arch.py b/test/arch/ppc32/arch.py
index 13c69c73..f5503330 100644
--- a/test/arch/ppc32/arch.py
+++ b/test/arch/ppc32/arch.py
@@ -114,6 +114,7 @@ for mode, s, l, in reg_tests:
     a = mn_ppc.asm(l)
     print('asm result %s' % [x for x in a])
     print(repr(b))
+    print(l.to_html())
 
     print('test re dis')
     for x in a:
diff --git a/test/arch/x86/arch.py b/test/arch/x86/arch.py
index 55694dfe..22cfcf39 100644
--- a/test/arch/x86/arch.py
+++ b/test/arch/x86/arch.py
@@ -3153,6 +3153,7 @@ for mode, s, l, in reg_tests:
     a = mn_x86.asm(l)
     print('asm result', [x for x in a])
     print(repr(b))
+    print(l.to_html())
 
     for x in a:
         print("BYTES", repr(x))
diff --git a/test/test_all.py b/test/test_all.py
index f0ac755e..a49f6ff9 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -710,6 +710,7 @@ for script in [["basic_op.py"],
                ["expr_random.py"],
                ["expr_translate.py"],
                ["expr_reduce.py"],
+               ["interfer.py"],
                ]:
     testset += ExampleExpression(script)