about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--example/expression/access_c.py4
-rw-r--r--example/symbol_exec/depgraph.py4
-rw-r--r--miasm2/analysis/data_flow.py7
-rw-r--r--miasm2/analysis/depgraph.py6
-rw-r--r--miasm2/arch/aarch64/sem.py10
-rw-r--r--miasm2/arch/mips32/ira.py10
-rw-r--r--miasm2/arch/mips32/jit.py12
-rw-r--r--miasm2/arch/x86/ira.py4
-rw-r--r--miasm2/arch/x86/jit.py27
-rw-r--r--miasm2/arch/x86/sem.py12
-rw-r--r--miasm2/ir/analysis.py14
-rw-r--r--miasm2/ir/ir.py235
-rw-r--r--miasm2/jitter/codegen.py255
-rw-r--r--miasm2/jitter/jitcore_python.py18
-rw-r--r--miasm2/jitter/llvmconvert.py39
-rw-r--r--miasm2/jitter/vm_mngr_py.c2
-rw-r--r--miasm2/os_dep/win_api_x86_32.py1
-rw-r--r--test/analysis/data_flow.py8
-rw-r--r--test/analysis/depgraph.py5
-rw-r--r--test/ir/ir.py46
-rwxr-xr-xtest/ir/symbexec.py3
-rwxr-xr-xtest/test_all.py1
22 files changed, 447 insertions, 276 deletions
diff --git a/example/expression/access_c.py b/example/expression/access_c.py
index eabc3770..923a3331 100644
--- a/example/expression/access_c.py
+++ b/example/expression/access_c.py
@@ -109,8 +109,8 @@ def get_funcs_arg0(ctx, ira, lbl_head):
     element = ira.arch.regs.RSI
 
     for irb, index in find_call(ira):
-        line = irb.lines[index]
-        print 'Analysing references from:', hex(line.offset), line
+        instr = irb.irs[index].instr
+        print 'Analysing references from:', hex(instr.offset), instr
         g_list = g_dep.get(irb.label, set([element]), index, set([lbl_head]))
         for dep in g_list:
             emul_result = dep.emul(ctx)
diff --git a/example/symbol_exec/depgraph.py b/example/symbol_exec/depgraph.py
index 0b971b15..56ca3f82 100644
--- a/example/symbol_exec/depgraph.py
+++ b/example/symbol_exec/depgraph.py
@@ -75,8 +75,8 @@ dg = DependencyGraph(ir_arch, implicit=args.implicit,
 target_addr = int(args.target_addr, 0)
 current_block = list(ir_arch.getby_offset(target_addr))[0]
 line_nb = 0
-for line_nb, line in enumerate(current_block.lines):
-    if line.offset == target_addr:
+for line_nb, assignblk in enumerate(current_block.irs):
+    if assignblk.instr.offset == target_addr:
         break
 
 # Enumerate solutions
diff --git a/miasm2/analysis/data_flow.py b/miasm2/analysis/data_flow.py
index b9764daa..dc1bf6ae 100644
--- a/miasm2/analysis/data_flow.py
+++ b/miasm2/analysis/data_flow.py
@@ -2,6 +2,7 @@
 
 from collections import namedtuple
 from miasm2.core.graph import DiGraph
+from miasm2.ir.ir import AssignBlock
 
 class ReachingDefinitions(dict):
     """
@@ -247,6 +248,8 @@ def dead_simp(ir_a):
     useful = set(dead_simp_useful_instrs(defuse, reaching_defs))
     for block in ir_a.blocks.itervalues():
         for idx, assignblk in enumerate(block.irs):
-            for lval in assignblk.keys():
+            new_assignblk = dict(assignblk)
+            for lval in assignblk:
                 if InstrNode(block.label, idx, lval) not in useful:
-                    del assignblk[lval]
+                    del new_assignblk[lval]
+            block.irs[idx] = AssignBlock(new_assignblk, assignblk.instr)
diff --git a/miasm2/analysis/depgraph.py b/miasm2/analysis/depgraph.py
index bab4d2bc..d1ac13c8 100644
--- a/miasm2/analysis/depgraph.py
+++ b/miasm2/analysis/depgraph.py
@@ -263,12 +263,12 @@ class DependencyResult(DependencyState):
         for line_nb, elements in sorted(line2elements.iteritems()):
             if max_line is not None and line_nb >= max_line:
                 break
-            assignblk = AssignBlock()
+            assignmnts = {}
             for element in elements:
                 if element in irb.irs[line_nb]:
                     # constants, label, ... are not in destination
-                    assignblk[element] = irb.irs[line_nb][element]
-            assignblks.append(assignblk)
+                    assignmnts[element] = irb.irs[line_nb][element]
+            assignblks.append(AssignBlock(assignmnts))
 
         return IRBlock(irb.label, assignblks)
 
diff --git a/miasm2/arch/aarch64/sem.py b/miasm2/arch/aarch64/sem.py
index e9eaffc8..599cdc98 100644
--- a/miasm2/arch/aarch64/sem.py
+++ b/miasm2/arch/aarch64/sem.py
@@ -777,9 +777,10 @@ class ir_aarch64l(IntermediateRepresentation):
         return m2_expr.ExprAff(dst, src)
 
     def irbloc_fix_regs_for_mode(self, irbloc, mode=64):
-        for assignblk in irbloc.irs:
-            for dst, src in assignblk.items():
-                del(assignblk[dst])
+        for idx, assignblk in enumerate(irbloc.irs):
+            new_assignblk = dict(assignblk)
+            for dst, src in assignblk.iteritems():
+                del(new_assignblk[dst])
                 # Special case for 64 bits:
                 # If destination is a 32 bit reg, zero extend the 64 bit reg
 
@@ -791,7 +792,8 @@ class ir_aarch64l(IntermediateRepresentation):
 
                 dst = self.expr_fix_regs_for_mode(dst)
                 src = self.expr_fix_regs_for_mode(src)
-                assignblk[dst] = src
+                new_assignblk[dst] = src
+            irbloc.irs[idx] = AssignBlock(new_assignblk, assignblk.instr)
         if irbloc.dst is not None:
             irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst)
 
diff --git a/miasm2/arch/mips32/ira.py b/miasm2/arch/mips32/ira.py
index 92af5cc5..a2eab4fb 100644
--- a/miasm2/arch/mips32/ira.py
+++ b/miasm2/arch/mips32/ira.py
@@ -31,18 +31,18 @@ class ir_a_mips32l(ir_mips32l, ira):
             if expr_is_label(lr_val):
                 lr_val = ExprInt(lr_val.name.offset, 32)
 
-            line = block.lines[-2]
-            if lr_val.arg != line.offset + 8:
+            instr = block.irs[-2].instr
+            if lr_val.arg != instr.offset + 8:
                 raise ValueError("Wrong arg")
 
             # CALL
             lbl = block.get_next()
             new_lbl = self.gen_label()
-            irs = self.call_effects(pc_val, line)
+            irs = self.call_effects(pc_val, instr)
             irs.append(AssignBlock([ExprAff(self.IRDst,
-                                            ExprId(lbl, size=self.pc.size))]))
+                                            ExprId(lbl, size=self.pc.size))],
+                                   instr))
             nblock = IRBlock(new_lbl, irs)
-            nblock.lines = [line] * len(irs)
             self.blocks[new_lbl] = nblock
             irb.dst = ExprId(new_lbl, size=self.pc.size)
 
diff --git a/miasm2/arch/mips32/jit.py b/miasm2/arch/mips32/jit.py
index bfa9c5fd..9b46589f 100644
--- a/miasm2/arch/mips32/jit.py
+++ b/miasm2/arch/mips32/jit.py
@@ -5,6 +5,7 @@ from miasm2.core import asmblock
 from miasm2.core.utils import pck32, upck32
 from miasm2.arch.mips32.sem import ir_mips32l, ir_mips32b
 from miasm2.jitter.codegen import CGen
+from miasm2.ir.ir import AssignBlock
 import miasm2.expression.expression as m2_expr
 
 log = logging.getLogger('jit_mips32')
@@ -43,18 +44,21 @@ class mipsCGen(CGen):
             if not instr.breakflow():
                 continue
             for irblock in irblocks:
-                for assignblock in irblock.irs:
+                for idx, assignblock in enumerate(irblock.irs):
                     if self.ir_arch.pc not in assignblock:
                         continue
+                    new_assignblock = dict(assignblock)
                     # Add internal branch destination
-                    assignblock[self.delay_slot_dst] = assignblock[
+                    new_assignblock[self.delay_slot_dst] = assignblock[
                         self.ir_arch.pc]
-                    assignblock[self.delay_slot_set] = m2_expr.ExprInt(1, 32)
+                    new_assignblock[self.delay_slot_set] = m2_expr.ExprInt(1, 32)
                     # Replace IRDst with next instruction
-                    assignblock[self.ir_arch.IRDst] = m2_expr.ExprId(
+                    new_assignblock[self.ir_arch.IRDst] = m2_expr.ExprId(
                         self.ir_arch.get_next_instr(instr))
                     irblock.dst = m2_expr.ExprId(
                         self.ir_arch.get_next_instr(instr))
+                    irblock.irs[idx] = AssignBlock(new_assignblock, assignblock.instr)
+
         return irblocks_list
 
     def gen_finalize(self, block):
diff --git a/miasm2/arch/x86/ira.py b/miasm2/arch/x86/ira.py
index 1fcaaa52..d0bebfb6 100644
--- a/miasm2/arch/x86/ira.py
+++ b/miasm2/arch/x86/ira.py
@@ -53,7 +53,9 @@ class ir_a_x86_64(ir_x86_64, ir_a_x86_16):
                                                           )),
                              ExprAff(self.sp, ExprOp('call_func_stack',
                                                      ad, self.sp)),
-                ])]
+                            ],
+                             instr
+                           )]
 
     def sizeof_char(self):
         return 8
diff --git a/miasm2/arch/x86/jit.py b/miasm2/arch/x86/jit.py
index ef1f162b..e64c610b 100644
--- a/miasm2/arch/x86/jit.py
+++ b/miasm2/arch/x86/jit.py
@@ -140,6 +140,33 @@ class jitter_x86_32(jitter):
     get_arg_n_systemv = get_stack_arg
 
 
+    # fastcall
+    @named_arguments
+    def func_args_fastcall(self, n_args):
+        args_regs = ['ECX', 'EDX']
+        ret_ad = self.pop_uint32_t()
+        args = []
+        for i in xrange(n_args):
+            args.append(self.get_arg_n_fastcall(i))
+        return ret_ad, args
+
+    def func_prepare_fastcall(self, ret_addr, *args):
+        args_regs = ['ECX', 'EDX']
+        self.push_uint32_t(ret_addr)
+        for i in xrange(min(len(args), len(args_regs))):
+            setattr(self.cpu, args_regs[i], args[i])
+        remaining_args = args[len(args_regs):]
+        for arg in reversed(remaining_args):
+            self.push_uint32_t(arg)
+
+    def get_arg_n_fastcall(self, index):
+        args_regs = ['ECX', 'EDX']
+        if index < len(args_regs):
+            return getattr(self.cpu, args_regs[index])
+        return self.get_stack_arg(index - len(args_regs))
+
+
+
 class jitter_x86_64(jitter):
 
     C_Gen = x86_64_CGen
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
index 98866e65..0312891b 100644
--- a/miasm2/arch/x86/sem.py
+++ b/miasm2/arch/x86/sem.py
@@ -21,7 +21,7 @@ from miasm2.expression.simplifications import expr_simp
 from miasm2.arch.x86.regs import *
 from miasm2.arch.x86.arch import mn_x86, repeat_mn, replace_regs
 from miasm2.expression.expression_helper import expr_cmps, expr_cmpu
-from miasm2.ir.ir import IntermediateRepresentation, IRBlock
+from miasm2.ir.ir import IntermediateRepresentation, IRBlock, AssignBlock
 from miasm2.core.sembuilder import SemBuilder
 import math
 import struct
@@ -4602,9 +4602,10 @@ class ir_x86_16(IntermediateRepresentation):
         return m2_expr.ExprAff(dst, src)
 
     def irbloc_fix_regs_for_mode(self, irbloc, mode=64):
-        for assignblk in irbloc.irs:
-            for dst, src in assignblk.items():
-                del assignblk[dst]
+        for idx, assignblk in enumerate(irbloc.irs):
+            new_assignblk = dict(assignblk)
+            for dst, src in assignblk.iteritems():
+                del new_assignblk[dst]
                 # Special case for 64 bits:
                 # If destination is a 32 bit reg, zero extend the 64 bit reg
                 if mode == 64:
@@ -4615,7 +4616,8 @@ class ir_x86_16(IntermediateRepresentation):
                         dst = replace_regs[64][dst].arg
                 dst = self.expr_fix_regs_for_mode(dst, mode)
                 src = self.expr_fix_regs_for_mode(src, mode)
-                assignblk[dst] = src
+                new_assignblk[dst] = src
+            irbloc.irs[idx] = AssignBlock(new_assignblk, assignblk.instr)
         if irbloc.dst is not None:
             irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst, mode)
 
diff --git a/miasm2/ir/analysis.py b/miasm2/ir/analysis.py
index 5c5193c9..1d9310fc 100644
--- a/miasm2/ir/analysis.py
+++ b/miasm2/ir/analysis.py
@@ -39,11 +39,11 @@ class ira(IntermediateRepresentation):
         @instr: native instruction which is responsible of the call
         """
 
-        return [AssignBlock(
-            [ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)),
-             ExprAff(self.sp, ExprOp(
-                 'call_func_stack', ad, self.sp)),
-             ])]
+        assignblk = AssignBlock({
+            self.ret_reg: ExprOp('call_func_ret', ad, self.sp),
+            self.sp: ExprOp('call_func_stack', ad, self.sp)},
+            instr)
+        return [assignblk]
 
     def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_update):
         """Replace function call with corresponding call effects,
@@ -53,7 +53,6 @@ class ira(IntermediateRepresentation):
         call_effects = self.call_effects(instr.args[0], instr)
         for assignblk in call_effects:
             irb_cur.irs.append(assignblk)
-            irb_cur.lines.append(instr)
         return None
 
     def gen_equations(self):
@@ -70,8 +69,7 @@ class ira(IntermediateRepresentation):
                 eqs.append(ExprAff(n_w, v))
             print '*' * 40
             print irb
-            irb.irs = [eqs]
-            irb.lines = [None]
+            irb.irs = [AssignBlock(eqs)]
 
     def sizeof_char(self):
         "Return the size of a char in bits"
diff --git a/miasm2/ir/ir.py b/miasm2/ir/ir.py
index f8ac6722..caf2c0ed 100644
--- a/miasm2/ir/ir.py
+++ b/miasm2/ir/ir.py
@@ -29,19 +29,41 @@ from miasm2.core.asmblock import AsmSymbolPool, expr_is_label, AsmLabel, \
 from miasm2.core.graph import DiGraph
 
 
-class AssignBlock(dict):
+class AssignBlock(object):
+    """Represent parallel IR assignment, such as:
+    EAX = EBX
+    EBX = EAX
 
-    def __init__(self, irs=None):
-        """@irs seq"""
+    Also provides common manipulation on this assignments
+    """
+    __slots__ = ["_assigns", "_instr"]
+
+    def __init__(self, irs=None, instr=None):
+        """Create a new AssignBlock
+        @irs: (optional) sequence of ExprAff, or dictionnary dst (Expr) -> src
+              (Expr)
+        @instr: (optional) associate an instruction with this AssignBlock
+
+        """
         if irs is None:
             irs = []
-        super(AssignBlock, self).__init__()
+        self._instr = instr
+        self._assigns = {} # ExprAff.dst -> ExprAff.src
 
-        for expraff in irs:
-            # Concurrent assignments are handled in __setitem__
-            self[expraff.dst] = expraff.src
+        # Concurrent assignments are handled in _set
+        if hasattr(irs, "iteritems"):
+            for dst, src in irs.iteritems():
+                self._set(dst, src)
+        else:
+            for expraff in irs:
+                self._set(expraff.dst, expraff.src)
 
-    def __setitem__(self, dst, src):
+    @property
+    def instr(self):
+        """Return the associated instruction, if any"""
+        return self._instr
+
+    def _set(self, dst, src):
         """
         Special cases:
         * if dst is an ExprSlice, expand it to affect the full Expression
@@ -64,7 +86,7 @@ class AssignBlock(dict):
         else:
             new_dst, new_src = dst, src
 
-        if new_dst in self and isinstance(new_src, m2_expr.ExprCompose):
+        if new_dst in self._assigns and isinstance(new_src, m2_expr.ExprCompose):
             if not isinstance(self[new_dst], m2_expr.ExprCompose):
                 # prev_RAX = 0x1122334455667788
                 # input_RAX[0:8] = 0x89
@@ -103,7 +125,51 @@ class AssignBlock(dict):
             args = [expr for (expr, _, _) in args]
             new_src = m2_expr.ExprCompose(*args)
 
-        super(AssignBlock, self).__setitem__(new_dst, new_src)
+        self._assigns[new_dst] = new_src
+
+    def __setitem__(self, dst, src):
+        raise RuntimeError('AssignBlock is immutable')
+
+    def __getitem__(self, key):
+        return self._assigns[key]
+
+    def __contains__(self, key):
+        return key in self._assigns
+
+    def iteritems(self):
+        for dst, src in self._assigns.iteritems():
+            yield dst, src
+
+    def itervalues(self):
+        for src in self._assigns.itervalues():
+            yield src
+
+    def keys(self):
+        return self._assigns.keys()
+
+    def values(self):
+        return self._assigns.values()
+
+    def __iter__(self):
+        for dst in self._assigns:
+            yield dst
+
+    def __delitem__(self, _):
+        raise RuntimeError('AssignBlock is immutable')
+
+    def update(self, _):
+        raise RuntimeError('AssignBlock is immutable')
+
+    def __eq__(self, other):
+        if self.keys() != other.keys():
+            return False
+        return all(other[dst] == src for dst, src in self.iteritems())
+
+    def __len__(self):
+        return len(self._assigns)
+
+    def get(self, key, default):
+        return self._assigns.get(key, default)
 
     @staticmethod
     def get_modified_slice(dst, src):
@@ -152,7 +218,7 @@ class AssignBlock(dict):
 
     def __str__(self):
         out = []
-        for dst, src in sorted(self.iteritems()):
+        for dst, src in sorted(self._assigns.iteritems()):
             out.append("%s = %s" % (dst, src))
         return "\n".join(out)
 
@@ -161,6 +227,18 @@ class AssignBlock(dict):
         @dst: Expr instance"""
         return m2_expr.ExprAff(dst, self[dst])
 
+    def simplify(self, simplifier):
+        """Return a new AssignBlock with expression simplified
+        @simplifier: ExpressionSimplifier instance"""
+        new_assignblk = {}
+        for dst, src in self.iteritems():
+            if dst == src:
+                continue
+            src = simplifier(src)
+            dst = simplifier(dst)
+            new_assignblk[dst] = src
+        return AssignBlock(irs=new_assignblk, instr=self.instr)
+
 
 class IRBlock(object):
     """Intermediate representation block object.
@@ -168,19 +246,15 @@ class IRBlock(object):
     Stand for an intermediate representation  basic block.
     """
 
-    def __init__(self, label, irs, lines=None):
+    def __init__(self, label, irs):
         """
         @label: AsmLabel of the IR basic block
         @irs: list of AssignBlock
-        @lines: list of native instructions
         """
 
         assert isinstance(label, AsmLabel)
-        if lines is None:
-            lines = []
         self.label = label
         self.irs = irs
-        self.lines = lines
         self.except_automod = True
         self._dst = None
         self._dst_linenb = None
@@ -207,15 +281,15 @@ class IRBlock(object):
         if self._dst_linenb is None:
             self._get_dst()
 
-        assignblk = self.irs[self._dst_linenb]
-        for dst in assignblk:
+        new_assignblk = dict(self.irs[self._dst_linenb])
+        for dst in new_assignblk:
             if isinstance(dst, m2_expr.ExprId) and dst.name == "IRDst":
-                del assignblk[dst]
-                assignblk[dst] = value
+                new_assignblk[dst] = value
                 # Sanity check is already done in _get_dst
                 break
         self._dst = value
-
+        instr = self.irs[self._dst_linenb].instr
+        self.irs[self._dst_linenb] = AssignBlock(new_assignblk, instr)
     dst = property(_get_dst, _set_dst)
 
     @property
@@ -262,7 +336,7 @@ class irbloc(IRBlock):
 
     def __init__(self, label, irs, lines=None):
         warnings.warn('DEPRECATION WARNING: use "IRBlock" instead of "irblock"')
-        super(irbloc, self).__init__(label, irs, lines)
+        super(irbloc, self).__init__(label, irs)
 
 
 class DiGraphIR(DiGraph):
@@ -349,54 +423,55 @@ class IntermediateRepresentation(object):
     def get_ir(self, instr):
         raise NotImplementedError("Abstract Method")
 
-    def instr2ir(self, l):
-        ir_bloc_cur, extra_assignblk = self.get_ir(l)
-        assignblk = AssignBlock(ir_bloc_cur)
+    def instr2ir(self, instr):
+        ir_bloc_cur, extra_assignblk = self.get_ir(instr)
         for irb in extra_assignblk:
-            irb.irs = map(AssignBlock, irb.irs)
+            irs = []
+            for assignblk in irb.irs:
+                irs.append(AssignBlock(assignblk, instr))
+            irb.irs = irs
+        assignblk = AssignBlock(ir_bloc_cur, instr)
         return assignblk, extra_assignblk
 
-    def get_label(self, ad):
+    def get_label(self, addr):
         """Transforms an ExprId/ExprInt/label/int into a label
-        @ad: an ExprId/ExprInt/label/int"""
-
-        if (isinstance(ad, m2_expr.ExprId) and
-                isinstance(ad.name, AsmLabel)):
-            ad = ad.name
-        if isinstance(ad, m2_expr.ExprInt):
-            ad = int(ad)
-        if isinstance(ad, (int, long)):
-            ad = self.symbol_pool.getby_offset_create(ad)
-        elif isinstance(ad, AsmLabel):
-            ad = self.symbol_pool.getby_name_create(ad.name)
-        return ad
-
-    def get_bloc(self, ad):
+        @addr: an ExprId/ExprInt/label/int"""
+
+        if (isinstance(addr, m2_expr.ExprId) and
+                isinstance(addr.name, AsmLabel)):
+            addr = addr.name
+        if isinstance(addr, m2_expr.ExprInt):
+            addr = int(addr)
+        if isinstance(addr, (int, long)):
+            addr = self.symbol_pool.getby_offset_create(addr)
+        elif isinstance(addr, AsmLabel):
+            addr = self.symbol_pool.getby_name_create(addr.name)
+        return addr
+
+    def get_bloc(self, addr):
         """Returns the irbloc associated to an ExprId/ExprInt/label/int
-        @ad: an ExprId/ExprInt/label/int"""
+        @addr: an ExprId/ExprInt/label/int"""
 
-        label = self.get_label(ad)
+        label = self.get_label(addr)
         return self.blocks.get(label, None)
 
-    def add_instr(self, l, ad=0, gen_pc_updt=False):
-        b = AsmBlock(self.gen_label())
-        b.lines = [l]
-        self.add_bloc(b, gen_pc_updt)
+    def add_instr(self, line, addr=0, gen_pc_updt=False):
+        block = AsmBlock(self.gen_label())
+        block.lines = [line]
+        self.add_bloc(block, gen_pc_updt)
 
     def getby_offset(self, offset):
         out = set()
         for irb in self.blocks.values():
-            for l in irb.lines:
-                if l.offset <= offset < l.offset + l.l:
+            for assignblk in irb.irs:
+                instr = assignblk.instr
+                if instr.offset <= offset < instr.offset + instr.l:
                     out.add(irb)
         return out
 
-    def gen_pc_update(self, c, l):
-        c.irs.append(AssignBlock([m2_expr.ExprAff(self.pc,
-                                                  m2_expr.ExprInt(l.offset,
-                                                                  self.pc.size)
-                                                 )]))
-        c.lines.append(l)
+    def gen_pc_update(self, irblock, instr):
+        irblock.irs.append(AssignBlock({self.pc: m2_expr.ExprInt(instr.offset, self.pc.size)},
+                                       instr))
 
     def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_updt):
         """Function called before adding an instruction from the the native @block to
@@ -439,11 +514,8 @@ class IntermediateRepresentation(object):
             self.gen_pc_update(irb_cur, instr)
 
         irb_cur.irs.append(assignblk)
-        irb_cur.lines.append(instr)
 
         if ir_blocks_extra:
-            for irblock in ir_blocks_extra:
-                irblock.lines = [instr] * len(irblock.irs)
             ir_blocks_all += ir_blocks_extra
             irb_cur = None
         return irb_cur
@@ -460,28 +532,28 @@ class IntermediateRepresentation(object):
         for instr in block.lines:
             if irb_cur is None:
                 label = self.get_instr_label(instr)
-                irb_cur = IRBlock(label, [], [])
+                irb_cur = IRBlock(label, [])
                 ir_blocks_all.append(irb_cur)
             irb_cur = self.add_instr_to_irblock(block, instr, irb_cur,
                                                 ir_blocks_all, gen_pc_updt)
         self.post_add_bloc(block, ir_blocks_all)
         return ir_blocks_all
 
-    def expr_fix_regs_for_mode(self, e, *args, **kwargs):
-        return e
+    def expr_fix_regs_for_mode(self, expr, *args, **kwargs):
+        return expr
 
-    def expraff_fix_regs_for_mode(self, e, *args, **kwargs):
-        return e
+    def expraff_fix_regs_for_mode(self, expr, *args, **kwargs):
+        return expr
 
     def irbloc_fix_regs_for_mode(self, irbloc, *args, **kwargs):
         return
 
-    def is_pc_written(self, b):
+    def is_pc_written(self, block):
         all_pc = self.arch.pc.values()
-        for irs in b.irs:
-            for ir in irs:
-                if ir.dst in all_pc:
-                    return ir
+        for irs in block.irs:
+            for assignblk in irs:
+                if assignblk.dst in all_pc:
+                    return assignblk
         return None
 
     def set_empty_dst_to_next(self, block, ir_blocks):
@@ -495,8 +567,8 @@ class IntermediateRepresentation(object):
             else:
                 dst = m2_expr.ExprId(next_lbl,
                                      self.pc.size)
-            irblock.irs.append(AssignBlock([m2_expr.ExprAff(self.IRDst, dst)]))
-            irblock.lines.append(irblock.lines[-1])
+            irblock.irs.append(AssignBlock({self.IRDst: dst},
+                                           irblock.irs[-1].instr))
 
     def post_add_bloc(self, block, ir_blocks):
         self.set_empty_dst_to_next(block, ir_blocks)
@@ -516,12 +588,12 @@ class IntermediateRepresentation(object):
 
     def gen_label(self):
         # TODO: fix hardcoded offset
-        l = self.symbol_pool.gen_label()
-        return l
+        label = self.symbol_pool.gen_label()
+        return label
 
     def get_next_label(self, instr):
-        l = self.symbol_pool.getby_offset_create(instr.offset + instr.l)
-        return l
+        label = self.symbol_pool.getby_offset_create(instr.offset + instr.l)
+        return label
 
     def simplify_blocs(self):
         for irblock in self.blocks.values():
@@ -596,15 +668,14 @@ class IntermediateRepresentation(object):
         Gen irbloc digraph
         """
         self._graph = DiGraphIR(self.blocks)
-        for lbl, b in self.blocks.iteritems():
+        for lbl, block in self.blocks.iteritems():
             self._graph.add_node(lbl)
-            dst = self.dst_trackback(b)
-            for d in dst:
-                if isinstance(d, m2_expr.ExprInt):
-                    d = m2_expr.ExprId(
-                        self.symbol_pool.getby_offset_create(int(d)))
-                if expr_is_label(d):
-                    self._graph.add_edge(lbl, d.name)
+            for dst in self.dst_trackback(block):
+                if dst.is_int():
+                    dst_lbl = self.symbol_pool.getby_offset_create(int(dst))
+                    dst = m2_expr.ExprId(dst_lbl)
+                if expr_is_label(dst):
+                    self._graph.add_edge(lbl, dst.name)
 
     @property
     def graph(self):
diff --git a/miasm2/jitter/codegen.py b/miasm2/jitter/codegen.py
index 09a6fecf..e91f3505 100644
--- a/miasm2/jitter/codegen.py
+++ b/miasm2/jitter/codegen.py
@@ -1,5 +1,9 @@
+"""
+Module to generate C code for a given native @block
+"""
+
 import miasm2.expression.expression as m2_expr
-from miasm2.ir.ir import IRBlock
+from miasm2.ir.ir import IRBlock, AssignBlock
 from miasm2.ir.translators import Translator
 from miasm2.core.asmblock import expr_is_label, AsmBlockBad, AsmLabel
 
@@ -131,17 +135,22 @@ class CGen(object):
     def assignblk_to_irbloc(self, instr, assignblk):
         """
         Ensure IRDst is always set in the head @assignblk of the @instr
-        @assignblk: Assignblk instance
         @instr: an instruction instance
+        @assignblk: Assignblk instance
         """
+        new_assignblk = dict(assignblk)
         if self.ir_arch.IRDst not in assignblk:
-            assignblk[self.ir_arch.IRDst] = m2_expr.ExprInt(
-                instr.offset + instr.l,
-                self.ir_arch.IRDst.size)
-
-        return IRBlock(self.ir_arch.get_instr_label(instr), [assignblk])
+            offset = instr.offset + instr.l
+            dst = m2_expr.ExprInt(offset, self.ir_arch.IRDst.size)
+            new_assignblk[self.ir_arch.IRDst] = dst
+        irs = [AssignBlock(new_assignblk, instr)]
+        return IRBlock(self.ir_arch.get_instr_label(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.ir_arch.instr2ir(instr)
@@ -155,16 +164,13 @@ class CGen(object):
             irblocks_list.append(irblocks)
         return irblocks_list
 
-    def gen_mem_prefetch(self, assignblk, mems_to_prefetch):
-        out = []
-        for expr, prefetcher in sorted(mems_to_prefetch.iteritems()):
-            str_src = self.id_to_c(expr)
-            str_dst = self.id_to_c(prefetcher)
-            out.append('%s = %s;' % (str_dst, str_src))
-        assignblk.C_prefetch = out
-        return out
-
     def add_local_var(self, dst_var, dst_index, expr):
+        """
+        Add local varaible used to store temporay result
+        @dst_var: dictionnary of Expr -> local_var_expr
+        @dst_index : dictionnary of size -> local var count
+        @expr: Expression source
+        """
         size = expr.size
         if size < 8:
             size = 8
@@ -176,17 +182,51 @@ class CGen(object):
         dst_var[expr] = dst
         return dst
 
-    def gen_assignments(self, assignblk, prefetchers):
-        out_var = []
-        out_main = []
-        out_mem = []
-        out_updt = []
+    def get_mem_prefetch(self, assignblk):
+        """
+        Generate temporary variables used to fetch memory used in the @assignblk
+        Return a dictionnary: 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, m2_expr.ExprMem):
+                continue
+            var_num = mem_index[expr.size]
+            mem_index[expr.size] += 1
+            var = m2_expr.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 informations 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}
+        dst_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0}
         dst_var = {}
 
+        prefetchers = self.get_mem_prefetch(assignblk)
+
+        for expr, prefetcher in sorted(prefetchers.iteritems()):
+            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 prefetchers.itervalues():
-            out_var.append("uint%d_t %s;" % (var.size, var))
+            c_var.append("uint%d_t %s;" % (var.size, var))
 
         for dst, src in sorted(assignblk.iteritems()):
             src = src.replace_expr(prefetchers)
@@ -196,10 +236,10 @@ class CGen(object):
                 new_dst = self.add_local_var(dst_var, dst_index, dst)
                 if dst in self.ir_arch.arch.regs.regs_flt_expr:
                     # Dont mask float affectation
-                    out_main.append(
+                    c_main.append(
                         '%s = (%s);' % (self.id_to_c(new_dst), self.id_to_c(src)))
                 else:
-                    out_main.append(
+                    c_main.append(
                         '%s = (%s)&0x%X;' % (self.id_to_c(new_dst),
                                              self.id_to_c(src),
                                              SIZE_TO_MASK[src.size]))
@@ -207,48 +247,17 @@ class CGen(object):
                 ptr = dst.arg.replace_expr(prefetchers)
                 new_dst = m2_expr.ExprMem(ptr, dst.size)
                 str_dst = self.id_to_c(new_dst).replace('MEM_LOOKUP', 'MEM_WRITE')
-                out_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src)))
+                c_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src)))
             else:
                 raise ValueError("Unknown dst")
 
         for dst, new_dst in dst_var.iteritems():
             if dst is self.ir_arch.IRDst:
                 continue
-            out_updt.append('%s = %s;' % (self.id_to_c(dst), self.id_to_c(new_dst)))
-            out_var.append("uint%d_t %s;" % (new_dst.size, new_dst))
-
-        assignblk.C_var = out_var
-        assignblk.C_main = out_main
-        assignblk.C_mem = out_mem
-        assignblk.C_updt = out_updt
+            c_updt.append('%s = %s;' % (self.id_to_c(dst), self.id_to_c(new_dst)))
+            c_var.append("uint%d_t %s;" % (new_dst.size, new_dst))
 
-    def gen_c_assignblk(self, assignblk):
-        mem_read, mem_write = False, False
-
-        mem_index = {8: 0, 16: 0, 32: 0, 64: 0}
-        mem_var = {}
-        prefetch_index = {8: 0, 16: 0, 32: 0, 64: 0}
-
-        # Prefetch memory read
-        for expr in assignblk.get_r(mem_read=True):
-            if not isinstance(expr, m2_expr.ExprMem):
-                continue
-            mem_read = True
-            var_num = mem_index[expr.size]
-            mem_index[expr.size] += 1
-            var = m2_expr.ExprId(
-                "prefetch_%.2d_%.2d" % (expr.size, var_num), expr.size)
-            mem_var[expr] = var
-
-        # Check if assignblk can write mem
-        mem_write = any(isinstance(expr, m2_expr.ExprMem)
-                        for expr in assignblk.get_w())
-
-        assignblk.mem_write = mem_write
-        assignblk.mem_read = mem_read
-
-        # Generate memory prefetch
-        return mem_var
+        return c_prefetch, c_var, c_main, c_mem, c_updt
 
     def gen_check_memory_exception(self, address):
         dst = self.dst_to_c(address)
@@ -313,12 +322,12 @@ class CGen(object):
 
         return out
 
-    def gen_pre_code(self, attrib):
+    def gen_pre_code(self, instr_attrib):
         out = []
 
-        if attrib.log_mn:
-            out.append('printf("%.8X %s\\n");' % (attrib.instr.offset,
-                                                  attrib.instr))
+        if instr_attrib.log_mn:
+            out.append('printf("%.8X %s\\n");' % (instr_attrib.instr.offset,
+                                                  instr_attrib.instr))
         return out
 
     def gen_post_code(self, attrib):
@@ -357,7 +366,7 @@ class CGen(object):
         """
         Generate code for possible @dst2index.
 
-        @attrib: an Attributs instance
+        @attrib: an Attributes instance
         @instr_offsets: list of instructions offsets
         @dst2index: link from destination to index
         """
@@ -377,54 +386,57 @@ class CGen(object):
                     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, assignblk, c_dst):
+    def gen_c_code(self, attrib, c_dst, c_assignmnts):
         """
-        Generate the C code for @assignblk.
-        @assignblk: an Assignblk instance
+        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 += assignblk.C_var
+        out += c_var
         out.append("// Prefetch")
-        out += assignblk.C_prefetch
+        out += c_prefetch
         out.append("// Dst")
         out += c_dst
         out.append("// Main")
-        out += assignblk.C_main
+        out += c_main
 
         out.append("// Check op/mem exceptions")
 
         # Check memory access if assignblk has memory read
-        if assignblk.C_prefetch:
-            out += self.gen_check_memory_exception(assignblk.instr_addr)
+        if c_prefetch:
+            out += self.gen_check_memory_exception(attrib.instr.offset)
 
         # Check if operator raised exception flags
-        if assignblk.op_set_exception:
-            out += self.gen_check_cpu_exception(assignblk.instr_addr)
+        if attrib.op_set_exception:
+            out += self.gen_check_cpu_exception(attrib.instr.offset)
 
         out.append("// Mem updt")
-        out += assignblk.C_mem
+        out += c_mem
 
         out.append("// Check exception Mem write")
         # Check memory write exceptions
-        if assignblk.mem_write:
-            out += self.gen_check_memory_exception(assignblk.instr_addr)
+        if attrib.mem_write:
+            out += self.gen_check_memory_exception(attrib.instr.offset)
 
         out.append("// Updt")
-        out += assignblk.C_updt
+        out += c_updt
 
         out.append("// Checks exception")
 
         # Check post assignblk exception flags
-        if assignblk.set_exception:
-            out += self.gen_check_cpu_exception(assignblk.instr_addr)
+        if attrib.set_exception:
+            out += self.gen_check_cpu_exception(attrib.instr.offset)
 
         out.append("}")
 
@@ -436,29 +448,27 @@ class CGen(object):
         return any(operator.startswith(except_op)
                    for except_op in self.IMPLICIT_EXCEPTION_OP)
 
-    def get_caracteristics(self, irblock):
+    def get_caracteristics(self, assignblk, attrib):
         """
-        Get the carateristics of each assignblk in the @irblock
-        @irblock: an irbloc instance
+        Set the carateristics in @attrib according to the @assignblk
+        @assignblk: an AssignBlock instance
+        @attrib: an Attributes instance
         """
 
-        for assignblk in irblock.irs:
-            assignblk.mem_read, assignblk.mem_write = False, False
-            assignblk.op_set_exception = False
-            # Check explicit exception raising
-            assignblk.set_exception = self.ir_arch.arch.regs.exception_flags in assignblk
-
-            element_read = assignblk.get_r(mem_read=True)
-            # Check implicit exception raising
-            assignblk.op_set_exception = any(self.is_exception_operator(operator)
-                                             for elem in assignblk.values()
-                                             for operator in m2_expr.get_expr_ops(elem))
-            # Check mem read
-            assignblk.mem_read = any(isinstance(expr, m2_expr.ExprMem)
-                                     for expr in element_read)
-            # Check mem write
-            assignblk.mem_write = any(isinstance(dst, m2_expr.ExprMem)
-                                      for dst in assignblk)
+        # Check explicit exception raising
+        attrib.set_exception = self.ir_arch.arch.regs.exception_flags in assignblk
+
+        element_read = assignblk.get_r(mem_read=True)
+        # Check implicit exception raising
+        attrib.op_set_exception = any(self.is_exception_operator(operator)
+                                      for elem in assignblk.values()
+                                      for operator in m2_expr.get_expr_ops(elem))
+        # Check mem read
+        attrib.mem_read = any(isinstance(expr, m2_expr.ExprMem)
+                              for expr in element_read)
+        # Check mem write
+        attrib.mem_write = any(isinstance(dst, m2_expr.ExprMem)
+                               for dst in assignblk)
 
     def get_attributes(self, instr, irblocks, log_mn=False, log_regs=False):
         """
@@ -469,17 +479,24 @@ class CGen(object):
         @log_regs: generate code to log registers states
         """
 
-        attrib = Attributes(log_mn, log_regs)
+        instr_attrib = Attributes()
+        instr_attrib.instr = instr
+        irblocks_attributes = []
 
         for irblock in irblocks:
+            attributes = []
+            irblocks_attributes.append(attributes)
             for assignblk in irblock.irs:
-                self.get_caracteristics(irblock)
-                attrib.mem_read |= assignblk.mem_read
-                attrib.mem_write |= assignblk.mem_write
-                attrib.set_exception |= assignblk.set_exception
-                attrib.op_set_exception |= assignblk.op_set_exception
-        attrib.instr = instr
-        return attrib
+                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.op_set_exception |= attrib.op_set_exception
+                instr_attrib.set_exception |= attrib.set_exception
+
+        return instr_attrib, irblocks_attributes
 
     def gen_bad_block(self):
         """
@@ -503,12 +520,11 @@ class CGen(object):
         lbl_start = self.ir_arch.symbol_pool.getby_offset_create(instr_offsets[0])
         return (self.CODE_INIT % self.label_to_jitlabel(lbl_start)).split("\n"), instr_offsets
 
-    def gen_irblock(self, attrib, instr_offsets, instr, irblock):
+    def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock):
         """
         Generate the C code for an @irblock
-        @instr: the current instruction to translate
         @irblock: an irbloc instance
-        @attrib: an Attributs instance
+        @attributes: an Attributes instance list
         """
 
         out = []
@@ -518,17 +534,14 @@ class CGen(object):
                 c_dst, dst2index = self.gen_assignblk_dst(irblock.dst)
             else:
                 c_dst = []
-            assignblk.instr_addr = instr.offset
-            prefetchers = self.gen_c_assignblk(assignblk)
-            self.gen_mem_prefetch(assignblk, prefetchers)
-            self.gen_assignments(assignblk, prefetchers)
 
-            out += self.gen_c_code(assignblk, 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(attrib, instr_offsets, dst2index)
+            out += self.gen_dst_goto(instr_attrib, instr_offsets, dst2index)
 
         return out
 
@@ -556,7 +569,7 @@ class CGen(object):
         out, instr_offsets = self.gen_init(block)
 
         for instr, irblocks in zip(block.lines, irblocks_list):
-            attrib = self.get_attributes(instr, irblocks, log_mn, log_regs)
+            instr_attrib, irblocks_attributes = self.get_attributes(instr, irblocks, log_mn, log_regs)
 
             for index, irblock in enumerate(irblocks):
                 self.ir_arch.irbloc_fix_regs_for_mode(
@@ -569,8 +582,8 @@ class CGen(object):
                     out.append("%-40s // %.16X %s" %
                                (self.label_to_jitlabel(irblock.label) + ":", instr.offset, instr))
                 if index == 0:
-                    out += self.gen_pre_code(attrib)
-                out += self.gen_irblock(attrib, instr_offsets, instr, irblock)
+                    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/miasm2/jitter/jitcore_python.py b/miasm2/jitter/jitcore_python.py
index cbd582ab..6d954aae 100644
--- a/miasm2/jitter/jitcore_python.py
+++ b/miasm2/jitter/jitcore_python.py
@@ -72,18 +72,18 @@ class JitCore_Python(jitcore.JitCore):
                 exec_engine.update_engine_from_cpu()
 
                 # Execute current ir bloc
-                for ir, line in zip(irb.irs, irb.lines):
-
+                for assignblk in irb.irs:
+                    instr = assignblk.instr
                     # For each new instruction (in assembly)
-                    if line.offset not in offsets_jitted:
+                    if instr.offset not in offsets_jitted:
                         # Test exceptions
                         vmmngr.check_invalid_code_blocs()
                         vmmngr.check_memory_breakpoint()
                         if vmmngr.get_exception():
                             exec_engine.update_cpu_from_engine()
-                            return line.offset
+                            return instr.offset
 
-                        offsets_jitted.add(line.offset)
+                        offsets_jitted.add(instr.offset)
 
                         # Log registers values
                         if self.log_regs:
@@ -92,21 +92,21 @@ class JitCore_Python(jitcore.JitCore):
 
                         # Log instruction
                         if self.log_mn:
-                            print "%08x %s" % (line.offset, line)
+                            print "%08x %s" % (instr.offset, instr)
 
                         # Check for exception
                         if (vmmngr.get_exception() != 0 or
                             cpu.get_exception() != 0):
                             exec_engine.update_cpu_from_engine()
-                            return line.offset
+                            return instr.offset
 
                     # Eval current instruction (in IR)
-                    exec_engine.eval_ir(ir)
+                    exec_engine.eval_ir(assignblk)
                     # Check for exceptions which do not update PC
                     exec_engine.update_cpu_from_engine()
                     if (vmmngr.get_exception() & csts.EXCEPT_DO_NOT_UPDATE_PC != 0 or
                         cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP):
-                        return line.offset
+                        return instr.offset
 
                 vmmngr.check_invalid_code_blocs()
                 vmmngr.check_memory_breakpoint()
diff --git a/miasm2/jitter/llvmconvert.py b/miasm2/jitter/llvmconvert.py
index b2e1e957..e7a1d6bc 100644
--- a/miasm2/jitter/llvmconvert.py
+++ b/miasm2/jitter/llvmconvert.py
@@ -1003,10 +1003,10 @@ class LLVMFunction():
         # Reactivate object caching
         self.main_stream = current_main_stream
 
-    def gen_pre_code(self, attributes):
-        if attributes.log_mn:
-            self.printf("%.8X %s\n" % (attributes.instr.offset,
-                                       attributes.instr))
+    def gen_pre_code(self, instr_attrib):
+        if instr_attrib.log_mn:
+            self.printf("%.8X %s\n" % (instr_attrib.instr.offset,
+                                       instr_attrib.instr))
 
     def gen_post_code(self, attributes):
         if attributes.log_regs:
@@ -1110,19 +1110,20 @@ class LLVMFunction():
         self.set_ret(dst)
 
 
-    def gen_irblock(self, attrib, instr, instr_offsets, irblock):
+    def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock):
         """
         Generate the code for an @irblock
-        @instr: the current instruction to translate
-        @irblock: an irbloc instance
-        @attrib: an Attributs instance
+        @instr_attrib: an Attributs instance or the instruction to translate
+        @attributes: list of Attributs 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 assignblk in irblock.irs:
+        for index, assignblk in enumerate(irblock.irs):
             # Enable cache
             self.main_stream = True
             self.expr_cache = {}
@@ -1141,12 +1142,12 @@ class LLVMFunction():
                     values[dst] = self.add_ir(src)
 
             # Check memory access exception
-            if assignblk.mem_read:
+            if attributes[index].mem_read:
                 self.check_memory_exception(instr.offset,
                                             restricted_exception=True)
 
             # Check operation exception
-            if assignblk.op_set_exception:
+            if attributes[index].op_set_exception:
                 self.check_cpu_exception(instr.offset, restricted_exception=True)
 
             # Update the memory
@@ -1155,7 +1156,7 @@ class LLVMFunction():
                     self.affect(src, dst)
 
             # Check memory write exception
-            if assignblk.mem_write:
+            if attributes[index].mem_write:
                 self.check_memory_exception(instr.offset,
                                             restricted_exception=True)
 
@@ -1165,14 +1166,14 @@ class LLVMFunction():
                     self.affect(src, dst)
 
             # Check post assignblk exception flags
-            if assignblk.set_exception:
+            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(attrib, instr_offsets, case2dst.values()[0])
+            self.gen_jump2dst(instr_attrib, instr_offsets, case2dst.values()[0])
         else:
             current_bbl = self.builder.basic_block
 
@@ -1184,7 +1185,7 @@ class LLVMFunction():
                 bbl = self.append_basic_block(name)
                 case2bbl[case] = bbl
                 self.builder.position_at_start(bbl)
-                self.gen_jump2dst(attrib, instr_offsets, dst)
+                self.gen_jump2dst(instr_attrib, instr_offsets, dst)
 
             # Jump on the correct output
             self.builder.position_at_end(current_bbl)
@@ -1311,8 +1312,8 @@ class LLVMFunction():
 
 
         for instr, irblocks in zip(asmblock.lines, irblocks_list):
-            attrib = codegen.get_attributes(instr, irblocks, self.log_mn,
-                                            self.log_regs)
+            instr_attrib, irblocks_attributes = codegen.get_attributes(instr, irblocks, self.log_mn,
+                                                                       self.log_regs)
 
             # Pre-create basic blocks
             for irblock in irblocks:
@@ -1328,8 +1329,8 @@ class LLVMFunction():
                 self.builder.position_at_end(self.get_basic_bloc_by_label(name))
 
                 if index == 0:
-                    self.gen_pre_code(attrib)
-                self.gen_irblock(attrib, instr, instr_offsets, irblock)
+                    self.gen_pre_code(instr_attrib)
+                self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, irblock)
 
         # Gen finalize (see codegen::CGen) is unrecheable, except with delayslot
         self.gen_finalize(asmblock, codegen)
diff --git a/miasm2/jitter/vm_mngr_py.c b/miasm2/jitter/vm_mngr_py.c
index b53e098a..4436add2 100644
--- a/miasm2/jitter/vm_mngr_py.c
+++ b/miasm2/jitter/vm_mngr_py.c
@@ -619,7 +619,7 @@ static PyMethodDef VmMngr_methods[] = {
 	{"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS,
 	 "get_mem(addr, size) -> Get the memory content at @address of @size bytes"},
 	{"add_memory_page",(PyCFunction)vm_add_memory_page, METH_VARARGS,
-	 "add_memory_page(address, access, size [, cmt]) -> Maps a memory page at @address of @size bytes with protection @access\n"
+	 "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"},
 	{"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"},
diff --git a/miasm2/os_dep/win_api_x86_32.py b/miasm2/os_dep/win_api_x86_32.py
index 265bad86..d9c659d3 100644
--- a/miasm2/os_dep/win_api_x86_32.py
+++ b/miasm2/os_dep/win_api_x86_32.py
@@ -1786,6 +1786,7 @@ def ntdll_LdrGetProcedureAddress(jitter):
     fname = jitter.get_str_ansi(p_src)
 
     ad = winobjs.runtime_dll.lib_get_add_func(args.libbase, fname)
+    jitter.add_breakpoint(ad, jitter.handle_lib)
 
     jitter.vm.set_mem(args.p_ad, pck32(ad))
 
diff --git a/test/analysis/data_flow.py b/test/analysis/data_flow.py
index 1784f87f..2c24773a 100644
--- a/test/analysis/data_flow.py
+++ b/test/analysis/data_flow.py
@@ -32,10 +32,11 @@ LBL4 = AsmLabel("lbl4")
 LBL5 = AsmLabel("lbl5")
 LBL6 = AsmLabel("lbl6")
 
+IRDst = ExprId('IRDst', 32)
+dummy = ExprId('dummy', 32)
 
 
 def gen_irblock(label, exprs_list):
-    lines = [None for _ in xrange(len(exprs_list))]
     irs = []
     for exprs in exprs_list:
         if isinstance(exprs, AssignBlock):
@@ -43,7 +44,8 @@ def gen_irblock(label, exprs_list):
         else:
             irs.append(AssignBlock(exprs))
 
-    irbl = IRBlock(label, irs, lines)
+    irs.append(AssignBlock({IRDst:dummy}))
+    irbl = IRBlock(label, irs)
     return irbl
 
 
@@ -67,7 +69,7 @@ class IRATest(ira):
     def __init__(self, symbol_pool=None):
         arch = Arch()
         super(IRATest, self).__init__(arch, 32, symbol_pool)
-        self.IRDst = pc
+        self.IRDst = IRDst
         self.ret_reg = r
 
     def get_out_regs(self, _):
diff --git a/test/analysis/depgraph.py b/test/analysis/depgraph.py
index 005ab32c..63313861 100644
--- a/test/analysis/depgraph.py
+++ b/test/analysis/depgraph.py
@@ -50,10 +50,9 @@ LBL5 = AsmLabel("lbl5")
 LBL6 = AsmLabel("lbl6")
 
 def gen_irblock(label, exprs_list):
-    """ Returns an IRBlock with empty lines.
+    """ Returns an IRBlock.
     Used only for tests purpose
     """
-    lines = [None for _ in xrange(len(exprs_list))]
     irs = []
     for exprs in exprs_list:
         if isinstance(exprs, AssignBlock):
@@ -61,7 +60,7 @@ def gen_irblock(label, exprs_list):
         else:
             irs.append(AssignBlock(exprs))
 
-    irbl = IRBlock(label, irs, lines)
+    irbl = IRBlock(label, irs)
     return irbl
 
 
diff --git a/test/ir/ir.py b/test/ir/ir.py
new file mode 100644
index 00000000..5c428a94
--- /dev/null
+++ b/test/ir/ir.py
@@ -0,0 +1,46 @@
+from miasm2.expression.expression import *
+from miasm2.ir.ir import AssignBlock
+from miasm2.expression.simplifications import expr_simp
+
+id_a = ExprId("a")
+id_b = ExprId("b")
+int0 = ExprInt(0, id_a.size)
+
+# Test AssignBlock
+## Constructors
+assignblk1 = AssignBlock([ExprAff(id_a, id_b)])
+assignblk2 = AssignBlock({id_a: id_b})
+
+## Equality
+assignblk1_bis = AssignBlock([ExprAff(id_a, id_b)])
+assert assignblk1 == assignblk1_bis
+assert assignblk1 == assignblk2
+
+## Immutability
+try:
+    assignblk1[id_a] = id_a
+except RuntimeError:
+    pass
+else:
+    raise RuntimeError("An error was expected")
+try:
+    del assignblk1[id_a]
+except RuntimeError:
+    pass
+else:
+    raise RuntimeError("An error was expected")
+
+## Basic APIs
+assert assignblk1.get_r() == set([id_b])
+assert assignblk1.get_w() == set([id_a])
+assert assignblk1.get_rw() == {id_a: set([id_b])}
+assert assignblk1.keys() == [id_a]
+assert dict(assignblk1) == {id_a: id_b}
+assert assignblk1[id_a] == id_b
+
+## Simplify
+assignblk3 = AssignBlock({id_a: id_b - id_b})
+assert assignblk3[id_a] != int0
+assignblk4 = assignblk3.simplify(expr_simp)
+assert assignblk3[id_a] != int0
+assert assignblk4[id_a] == int0
diff --git a/test/ir/symbexec.py b/test/ir/symbexec.py
index bd28c4ee..e2bd411f 100755
--- a/test/ir/symbexec.py
+++ b/test/ir/symbexec.py
@@ -63,8 +63,7 @@ class TestSymbExec(unittest.TestCase):
         # apply_change / eval_ir / apply_expr
 
         ## x = a (with a = 0x0)
-        assignblk = AssignBlock()
-        assignblk[id_x] = id_a
+        assignblk = AssignBlock({id_x:id_a})
         e.eval_ir(assignblk)
         self.assertEqual(e.apply_expr(id_x), addr0)
 
diff --git a/test/test_all.py b/test/test_all.py
index 48ce76ba..d2c3e5e2 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -245,6 +245,7 @@ for script in ["modint.py",
 
 ## IR
 for script in ["symbexec.py",
+               "ir.py",
                ]:
     testset += RegressionTest([script], base_dir="ir")