about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--example/ida/depgraph.py10
-rw-r--r--example/ida/graph_ir.py8
-rw-r--r--miasm2/analysis/data_flow.py6
-rw-r--r--miasm2/arch/aarch64/sem.py42
-rw-r--r--miasm2/arch/arm/sem.py27
-rw-r--r--miasm2/arch/mips32/ira.py15
-rw-r--r--miasm2/arch/mips32/jit.py31
-rw-r--r--miasm2/arch/mips32/sem.py19
-rw-r--r--miasm2/arch/x86/jit.py6
-rw-r--r--miasm2/arch/x86/sem.py91
-rw-r--r--miasm2/core/sembuilder.py24
-rw-r--r--miasm2/ir/analysis.py40
-rw-r--r--miasm2/ir/ir.py202
-rw-r--r--miasm2/jitter/codegen.py12
-rw-r--r--miasm2/jitter/llvmconvert.py9
15 files changed, 293 insertions, 249 deletions
diff --git a/example/ida/depgraph.py b/example/ida/depgraph.py
index cbd0cf0f..ab033e15 100644
--- a/example/ida/depgraph.py
+++ b/example/ida/depgraph.py
@@ -7,7 +7,7 @@ from miasm2.expression import expression as m2_expr
 
 from miasm2.expression.simplifications import expr_simp
 from miasm2.analysis.depgraph import DependencyGraph
-from miasm2.ir.ir import AssignBlock
+from miasm2.ir.ir import AssignBlock, IRBlock
 
 from utils import guess_machine
 
@@ -173,10 +173,11 @@ settings.Execute()
 label, elements, line_nb = settings.label, settings.elements, settings.line_nb
 # Simplify affectations
 for irb in ir_arch.blocks.values():
+    irs = []
     fix_stack = irb.label.offset is not None and settings.unalias_stack
-    for i, assignblk in enumerate(irb.irs):
+    for assignblk in irb.irs:
         if fix_stack:
-            stk_high = m2_expr.ExprInt(GetSpd(irb.irs[i].instr.offset), ir_arch.sp.size)
+            stk_high = m2_expr.ExprInt(GetSpd(assignblk.instr.offset), ir_arch.sp.size)
             fix_dct = {ir_arch.sp: mn.regs.regs_init[ir_arch.sp] + stk_high}
 
         new_assignblk = {}
@@ -187,7 +188,8 @@ for irb in ir_arch.blocks.values():
                     dst = dst.replace_expr(fix_dct)
             dst, src = expr_simp(dst), expr_simp(src)
             new_assignblk[dst] = src
-        irb.irs[i] = AssignBlock(new_assignblk, instr=assignblk.instr)
+        irs.append(AssignBlock(new_assignblk, instr=assignblk.instr))
+    ir_arch.blocks[irb.label] = IRBlock(irb.label, irs)
 
 # Get dependency graphs
 dg = settings.depgraph
diff --git a/example/ida/graph_ir.py b/example/ida/graph_ir.py
index 6ff4304a..bb06fd0b 100644
--- a/example/ida/graph_ir.py
+++ b/example/ida/graph_ir.py
@@ -11,7 +11,7 @@ from miasm2.expression.expression import *
 from miasm2.analysis.data_analysis import inter_bloc_flow, \
     intra_bloc_flow_symbexec
 from miasm2.analysis.data_flow import dead_simp
-from miasm2.ir.ir import AssignBlock
+from miasm2.ir.ir import AssignBlock, IRBlock
 
 from utils import guess_machine, expr2colorstr
 
@@ -136,12 +136,14 @@ for block in ab:
 print "IR ok... %x" % ad
 
 for irb in ir_arch.blocks.itervalues():
-    for i, assignblk in enumerate(irb.irs):
+    irs = []
+    for assignblk in irb.irs:
         new_assignblk = {
             expr_simp(dst): expr_simp(src)
             for dst, src in assignblk.iteritems()
         }
-        irb.irs[i] = AssignBlock(new_assignblk, instr=assignblk.instr)
+        irs.append(AssignBlock(new_assignblk, instr=assignblk.instr))
+    ir_arch.blocks[irb.label] = IRBlock(irb.label, irs)
 
 out = ir_arch.graph.dot()
 open(os.path.join(tempfile.gettempdir(), 'graph.dot'), 'wb').write(out)
diff --git a/miasm2/analysis/data_flow.py b/miasm2/analysis/data_flow.py
index 892a01c3..67768264 100644
--- a/miasm2/analysis/data_flow.py
+++ b/miasm2/analysis/data_flow.py
@@ -2,7 +2,7 @@
 
 from collections import namedtuple
 from miasm2.core.graph import DiGraph
-from miasm2.ir.ir import AssignBlock
+from miasm2.ir.ir import AssignBlock, IRBlock
 
 class ReachingDefinitions(dict):
     """
@@ -248,11 +248,13 @@ def dead_simp(ir_a):
     defuse = DiGraphDefUse(reaching_defs, deref_mem=True)
     useful = set(dead_simp_useful_instrs(defuse, reaching_defs))
     for block in ir_a.blocks.itervalues():
+        irs = []
         for idx, assignblk in enumerate(block.irs):
             new_assignblk = dict(assignblk)
             for lval in assignblk:
                 if InstrNode(block.label, idx, lval) not in useful:
                     del new_assignblk[lval]
                     modified = True
-            block.irs[idx] = AssignBlock(new_assignblk, assignblk.instr)
+            irs.append(AssignBlock(new_assignblk, assignblk.instr))
+        ir_a.blocks[block.label] = IRBlock(block.label, irs)
     return modified
diff --git a/miasm2/arch/aarch64/sem.py b/miasm2/arch/aarch64/sem.py
index 79c72d32..d5209e3e 100644
--- a/miasm2/arch/aarch64/sem.py
+++ b/miasm2/arch/aarch64/sem.py
@@ -782,14 +782,14 @@ class ir_aarch64l(IntermediateRepresentation):
         src = self.expr_fix_regs_for_mode(e.src)
         return m2_expr.ExprAff(dst, src)
 
-    def irbloc_fix_regs_for_mode(self, irbloc, mode=64):
-        for idx, assignblk in enumerate(irbloc.irs):
+    def irbloc_fix_regs_for_mode(self, irblock, mode=64):
+        irs = []
+        for assignblk in irblock.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 (isinstance(dst, m2_expr.ExprId) and
                     dst.size == 32 and
                     dst in replace_regs):
@@ -799,27 +799,24 @@ class ir_aarch64l(IntermediateRepresentation):
                 dst = self.expr_fix_regs_for_mode(dst)
                 src = self.expr_fix_regs_for_mode(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)
+            irs.append(AssignBlock(new_assignblk, assignblk.instr))
+        return IRBlock(irblock.label, irs)
 
     def mod_pc(self, instr, instr_ir, extra_ir):
         "Replace PC by the instruction's offset"
         cur_offset = m2_expr.ExprInt(instr.offset, 64)
+        pc_fixed = {self.pc: cur_offset}
         for i, expr in enumerate(instr_ir):
             dst, src = expr.dst, expr.src
             if dst != self.pc:
-                dst = dst.replace_expr({self.pc: cur_offset})
-            src = src.replace_expr({self.pc: cur_offset})
+                dst = dst.replace_expr(pc_fixed)
+            src = src.replace_expr(pc_fixed)
             instr_ir[i] = m2_expr.ExprAff(dst, src)
-        for irblock in extra_ir:
-            for irs in irblock.irs:
-                for i, expr in enumerate(irs):
-                    dst, src = expr.dst, expr.src
-                    if dst != self.pc:
-                        dst = dst.replace_expr({self.pc: cur_offset})
-                    src = src.replace_expr({self.pc: cur_offset})
-                    irs[i] = m2_expr.ExprAff(dst, src)
+
+        for idx, irblock in enumerate(extra_ir):
+            extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
+                                                 if expr != self.pc else expr,
+                                                 lambda expr: expr.replace_expr(pc_fixed))
 
 
     def del_dst_zr(self, instr, instr_ir, extra_ir):
@@ -827,11 +824,16 @@ class ir_aarch64l(IntermediateRepresentation):
         regs_to_fix = [WZR, XZR]
         instr_ir = [expr for expr in instr_ir if expr.dst not in regs_to_fix]
 
+        new_irblocks = []
         for irblock in extra_ir:
-            for i, irs in enumerate(irblock.irs):
-                irblock.irs[i] = [expr for expr in irs if expr.dst not in regs_to_fix]
-
-        return instr_ir, extra_ir
+            irs = []
+            for assignblk in irblock.irs:
+                new_dsts = {dst:src for dst, src in assignblk.iteritems()
+                                if dst not in regs_to_fix}
+                irs.append(AssignBlock(new_dsts, assignblk.instr))
+            new_irblocks.append(IRBlock(irblock.label, irs))
+
+        return instr_ir, new_irblocks
 
 
 class ir_aarch64b(ir_aarch64l):
diff --git a/miasm2/arch/arm/sem.py b/miasm2/arch/arm/sem.py
index 710cdc9f..29b25538 100644
--- a/miasm2/arch/arm/sem.py
+++ b/miasm2/arch/arm/sem.py
@@ -1,5 +1,5 @@
 from miasm2.expression.expression import *
-from miasm2.ir.ir import IntermediateRepresentation, IRBlock
+from miasm2.ir.ir import IntermediateRepresentation, IRBlock, AssignBlock
 from miasm2.arch.arm.arch import mn_arm, mn_armt
 from miasm2.arch.arm.regs import *
 
@@ -1055,7 +1055,7 @@ def add_condition_expr(ir, instr, cond, instr_ir):
             break
     if not has_irdst:
         instr_ir.append(ExprAff(ir.IRDst, lbl_next))
-    e_do = IRBlock(lbl_do.name, [instr_ir])
+    e_do = IRBlock(lbl_do.name, [AssignBlock(instr_ir, instr)])
     e = [ExprAff(ir.IRDst, dst_cond)]
     return e, [e_do]
 
@@ -1246,20 +1246,15 @@ class ir_arml(IntermediateRepresentation):
                                   args[-1].args[0],
                                   args[-1].args[-1][:8].zeroExtend(32))
         instr_ir, extra_ir = get_mnemo_expr(self, instr, *args)
-        # if self.name.startswith('B'):
-        #    return instr_ir, extra_ir
-        for i, x in enumerate(instr_ir):
-            x = ExprAff(x.dst, x.src.replace_expr(
-                {self.pc: ExprInt(instr.offset + 8, 32)}))
-            instr_ir[i] = x
-        for irblock in extra_ir:
-            for irs in irblock.irs:
-                for i, x in enumerate(irs):
-                    x = ExprAff(x.dst, x.src.replace_expr(
-                        {self.pc: ExprInt(instr.offset + 8, 32)}))
-                    irs[i] = x
-        # return out_ir, extra_ir
-        return instr_ir, extra_ir
+
+        pc_fixed = {self.pc: ExprInt(instr.offset + 8, 32)}
+        for i, expr in enumerate(instr_ir):
+            instr_ir[i] = ExprAff(expr.dst, expr.src.replace_expr(pc_fixed))
+
+        new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(pc_fixed))
+                        for irblock in extra_ir]
+
+        return instr_ir, new_extra_ir
 
 
 class ir_armb(ir_arml):
diff --git a/miasm2/arch/mips32/ira.py b/miasm2/arch/mips32/ira.py
index a2eab4fb..e342a6fd 100644
--- a/miasm2/arch/mips32/ira.py
+++ b/miasm2/arch/mips32/ira.py
@@ -11,12 +11,13 @@ class ir_a_mips32l(ir_mips32l, ira):
         ir_mips32l.__init__(self, symbol_pool)
         self.ret_reg = self.arch.regs.V0
 
-    def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_updt):
+    def pre_add_instr(self, block, instr, assignments, ir_blocks_all, gen_pc_updt):
         # Avoid adding side effects, already done in post_add_bloc
-        return irb_cur
+        return False
 
     def post_add_bloc(self, block, ir_blocks):
         IntermediateRepresentation.post_add_bloc(self, block, ir_blocks)
+        new_irblocks = []
         for irb in ir_blocks:
             pc_val = None
             lr_val = None
@@ -25,13 +26,15 @@ class ir_a_mips32l(ir_mips32l, ira):
                 lr_val = assignblk.get(self.arch.regs.RA, lr_val)
 
             if pc_val is None or lr_val is None:
+                new_irblocks.append(irb)
                 continue
             if not expr_is_int_or_label(lr_val):
+                new_irblocks.append(irb)
                 continue
             if expr_is_label(lr_val):
                 lr_val = ExprInt(lr_val.name.offset, 32)
 
-            instr = block.irs[-2].instr
+            instr = block.lines[-2]
             if lr_val.arg != instr.offset + 8:
                 raise ValueError("Wrong arg")
 
@@ -42,9 +45,9 @@ class ir_a_mips32l(ir_mips32l, ira):
             irs.append(AssignBlock([ExprAff(self.IRDst,
                                             ExprId(lbl, size=self.pc.size))],
                                    instr))
-            nblock = IRBlock(new_lbl, irs)
-            self.blocks[new_lbl] = nblock
-            irb.dst = ExprId(new_lbl, size=self.pc.size)
+            new_irblocks.append(IRBlock(new_lbl, irs))
+            new_irblocks.append(irb.set_dst(ExprId(new_lbl, size=self.pc.size)))
+        return new_irblocks
 
     def get_out_regs(self, _):
         return set([self.ret_reg, self.sp])
diff --git a/miasm2/arch/mips32/jit.py b/miasm2/arch/mips32/jit.py
index 9b46589f..493da595 100644
--- a/miasm2/arch/mips32/jit.py
+++ b/miasm2/arch/mips32/jit.py
@@ -5,7 +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
+from miasm2.ir.ir import AssignBlock, IRBlock
 import miasm2.expression.expression as m2_expr
 
 log = logging.getLogger('jit_mips32')
@@ -40,24 +40,27 @@ class mipsCGen(CGen):
 
     def block2assignblks(self, block):
         irblocks_list = super(mipsCGen, self).block2assignblks(block)
-        for instr, irblocks in zip(block.lines, irblocks_list):
-            if not instr.breakflow():
-                continue
-            for irblock in irblocks:
-                for idx, assignblock in enumerate(irblock.irs):
+        for irblocks in irblocks_list:
+            for blk_idx, irblock in enumerate(irblocks):
+                has_breakflow = any(assignblock.instr.breakflow() for assignblock in irblock.irs)
+                if not has_breakflow:
+                    continue
+
+                irs = []
+                for assignblock in irblock.irs:
                     if self.ir_arch.pc not in assignblock:
+                        irs.append(AssignBlock(assignments, assignblock.instr))
                         continue
-                    new_assignblock = dict(assignblock)
+                    assignments = dict(assignblock)
                     # Add internal branch destination
-                    new_assignblock[self.delay_slot_dst] = assignblock[
+                    assignments[self.delay_slot_dst] = assignblock[
                         self.ir_arch.pc]
-                    new_assignblock[self.delay_slot_set] = m2_expr.ExprInt(1, 32)
+                    assignments[self.delay_slot_set] = m2_expr.ExprInt(1, 32)
                     # Replace IRDst with next instruction
-                    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)
+                    assignments[self.ir_arch.IRDst] = m2_expr.ExprId(
+                        self.ir_arch.get_next_instr(assignblock.instr))
+                    irs.append(AssignBlock(assignments, assignblock.instr))
+                irblocks[blk_idx] = IRBlock(irblock.label, irs)
 
         return irblocks_list
 
diff --git a/miasm2/arch/mips32/sem.py b/miasm2/arch/mips32/sem.py
index bc050b38..645f9a4f 100644
--- a/miasm2/arch/mips32/sem.py
+++ b/miasm2/arch/mips32/sem.py
@@ -441,17 +441,14 @@ class ir_mips32l(IntermediateRepresentation):
         args = instr.args
         instr_ir, extra_ir = get_mnemo_expr(self, instr, *args)
 
-        for i, x in enumerate(instr_ir):
-            x = m2_expr.ExprAff(x.dst, x.src.replace_expr(
-                {self.pc: m2_expr.ExprInt(instr.offset + 4, 32)}))
-            instr_ir[i] = x
-        for irblock in extra_ir:
-            for irs in irblock.irs:
-                for i, x in enumerate(irs):
-                    x = m2_expr.ExprAff(x.dst, x.src.replace_expr(
-                        {self.pc: m2_expr.ExprInt(instr.offset + 4, 32)}))
-                    irs[i] = x
-        return instr_ir, extra_ir
+        pc_fixed = {self.pc: m2_expr.ExprInt(instr.offset + 4, 32)}
+
+        instr_ir = [m2_expr.ExprAff(expr.dst, expr.src.replace_expr(pc_fixed))
+                    for expr in instr_ir]
+
+        new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(pc_fixed))
+                        for irblock in extra_ir]
+        return instr_ir, new_extra_ir
 
     def get_next_instr(self, instr):
         return self.symbol_pool.getby_offset_create(instr.offset  + 4)
diff --git a/miasm2/arch/x86/jit.py b/miasm2/arch/x86/jit.py
index 6d9be8ac..9acab5ed 100644
--- a/miasm2/arch/x86/jit.py
+++ b/miasm2/arch/x86/jit.py
@@ -45,7 +45,7 @@ class jitter_x86_16(jitter):
         self.ir_arch.irbloc_fix_regs_for_mode = self.ir_archbloc_fix_regs_for_mode
 
     def ir_archbloc_fix_regs_for_mode(self, irblock, attrib=64):
-        self.orig_irbloc_fix_regs_for_mode(irblock, 64)
+        return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
 
     def push_uint16_t(self, value):
         self.cpu.SP -= self.ir_arch.sp.size / 8
@@ -78,7 +78,7 @@ class jitter_x86_32(jitter):
         self.ir_arch.irbloc_fix_regs_for_mode = self.ir_archbloc_fix_regs_for_mode
 
     def ir_archbloc_fix_regs_for_mode(self, irblock, attrib=64):
-        self.orig_irbloc_fix_regs_for_mode(irblock, 64)
+        return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
 
     def push_uint32_t(self, value):
         self.cpu.ESP -= self.ir_arch.sp.size / 8
@@ -183,7 +183,7 @@ class jitter_x86_64(jitter):
         self.ir_arch.irbloc_fix_regs_for_mode = self.ir_archbloc_fix_regs_for_mode
 
     def ir_archbloc_fix_regs_for_mode(self, irblock, attrib=64):
-        self.orig_irbloc_fix_regs_for_mode(irblock, 64)
+        return self.orig_irbloc_fix_regs_for_mode(irblock, 64)
 
     def push_uint64_t(self, value):
         self.cpu.RSP -= self.ir_arch.sp.size / 8
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
index e32b8001..e1847fe7 100644
--- a/miasm2/arch/x86/sem.py
+++ b/miasm2/arch/x86/sem.py
@@ -263,7 +263,7 @@ def gen_fcmov(ir, instr, cond, arg1, arg2, mov_if):
     e_do, extra_irs = [m2_expr.ExprAff(arg1, arg2)], []
     e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
     e.append(m2_expr.ExprAff(ir.IRDst, m2_expr.ExprCond(cond, dstA, dstB)))
-    return e, [IRBlock(lbl_do.name, [e_do])]
+    return e, [IRBlock(lbl_do.name, [AssignBlock(e_do, instr)])]
 
 
 def gen_cmov(ir, instr, cond, dst, src, mov_if):
@@ -283,7 +283,7 @@ def gen_cmov(ir, instr, cond, dst, src, mov_if):
     e_do, extra_irs = mov(ir, instr, dst, src)
     e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
     e.append(m2_expr.ExprAff(ir.IRDst, m2_expr.ExprCond(cond, dstA, dstB)))
-    return e, [IRBlock(lbl_do.name, [e_do])]
+    return e, [IRBlock(lbl_do.name, [AssignBlock(e_do, instr)])]
 
 
 def mov(_, instr, dst, src):
@@ -504,7 +504,7 @@ def _rotate_tpl(ir, instr, dst, src, op, left=False, include_cf=False):
     e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
     e.append(m2_expr.ExprAff(
         ir.IRDst, m2_expr.ExprCond(shifter, lbl_do, lbl_skip)))
-    return (e, [IRBlock(lbl_do.name, [e_do])])
+    return (e, [IRBlock(lbl_do.name, [AssignBlock(e_do, instr)])])
 
 
 def l_rol(ir, instr, dst, src):
@@ -601,7 +601,7 @@ def _shift_tpl(op, ir, instr, a, b, c=None, op_inv=None, left=False,
     e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_skip))
     e.append(m2_expr.ExprAff(ir.IRDst, m2_expr.ExprCond(shifter, lbl_do,
                                                         lbl_skip)))
-    return e, [IRBlock(lbl_do.name, [e_do])]
+    return e, [IRBlock(lbl_do.name, [AssignBlock(e_do, instr)])]
 
 
 def sar(ir, instr, dst, src):
@@ -949,7 +949,7 @@ def cmps(ir, instr, size):
     e0.append(m2_expr.ExprAff(b.arg,
                               b.arg + m2_expr.ExprInt(size / 8, b.arg.size)))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e0 = IRBlock(lbl_df_0.name, [e0])
+    e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
     e1.append(m2_expr.ExprAff(a.arg,
@@ -957,7 +957,7 @@ def cmps(ir, instr, size):
     e1.append(m2_expr.ExprAff(b.arg,
                               b.arg - m2_expr.ExprInt(size / 8, b.arg.size)))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e1 = IRBlock(lbl_df_1.name, [e1])
+    e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
     e.append(m2_expr.ExprAff(ir.IRDst,
                              m2_expr.ExprCond(df, lbl_df_1, lbl_df_0)))
@@ -978,13 +978,13 @@ def scas(ir, instr, size):
     e0.append(m2_expr.ExprAff(a.arg,
                               a.arg + m2_expr.ExprInt(size / 8, a.arg.size)))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e0 = IRBlock(lbl_df_0.name, [e0])
+    e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
     e1.append(m2_expr.ExprAff(a.arg,
                               a.arg - m2_expr.ExprInt(size / 8, a.arg.size)))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e1 = IRBlock(lbl_df_1.name, [e1])
+    e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
     e.append(m2_expr.ExprAff(ir.IRDst,
                              m2_expr.ExprCond(df, lbl_df_1, lbl_df_0)))
@@ -1455,13 +1455,13 @@ def div(ir, instr, src1):
     do_div = []
     do_div += e
     do_div.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    blk_div = IRBlock(lbl_div.name, [do_div])
+    blk_div = IRBlock(lbl_div.name, [AssignBlock(do_div, instr)])
 
     do_except = []
     do_except.append(m2_expr.ExprAff(exception_flags, m2_expr.ExprInt(
         EXCEPT_DIV_BY_ZERO, exception_flags.size)))
     do_except.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    blk_except = IRBlock(lbl_except.name, [do_except])
+    blk_except = IRBlock(lbl_except.name, [AssignBlock(do_except, instr)])
 
     e = []
     e.append(m2_expr.ExprAff(ir.IRDst,
@@ -1501,13 +1501,13 @@ def idiv(ir, instr, src1):
     do_div = []
     do_div += e
     do_div.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    blk_div = IRBlock(lbl_div.name, [do_div])
+    blk_div = IRBlock(lbl_div.name, [AssignBlock(do_div, instr)])
 
     do_except = []
     do_except.append(m2_expr.ExprAff(exception_flags, m2_expr.ExprInt(
         EXCEPT_DIV_BY_ZERO, exception_flags.size)))
     do_except.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    blk_except = IRBlock(lbl_except.name, [do_except])
+    blk_except = IRBlock(lbl_except.name, [AssignBlock(do_except, instr)])
 
     e = []
     e.append(m2_expr.ExprAff(ir.IRDst,
@@ -1667,12 +1667,12 @@ def stos(ir, instr, size):
     e0 = []
     e0.append(m2_expr.ExprAff(addr_o, addr_p))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e0 = IRBlock(lbl_df_0.name, [e0])
+    e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
     e1.append(m2_expr.ExprAff(addr_o, addr_m))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e1 = IRBlock(lbl_df_1.name, [e1])
+    e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
     e = []
     e.append(m2_expr.ExprAff(ir.ExprMem(addr, size), b))
@@ -1702,12 +1702,12 @@ def lods(ir, instr, size):
     e0 = []
     e0.append(m2_expr.ExprAff(addr_o, addr_p))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e0 = IRBlock(lbl_df_0.name, [e0])
+    e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
     e1.append(m2_expr.ExprAff(addr_o, addr_m))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e1 = IRBlock(lbl_df_1.name, [e1])
+    e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
     e = []
     if instr.mode == 64 and b.size == 32:
@@ -1744,13 +1744,13 @@ def movs(ir, instr, size):
     e0.append(m2_expr.ExprAff(a, a + m2_expr.ExprInt(size / 8, a.size)))
     e0.append(m2_expr.ExprAff(b, b + m2_expr.ExprInt(size / 8, b.size)))
     e0.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e0 = IRBlock(lbl_df_0.name, [e0])
+    e0 = IRBlock(lbl_df_0.name, [AssignBlock(e0, instr)])
 
     e1 = []
     e1.append(m2_expr.ExprAff(a, a - m2_expr.ExprInt(size / 8, a.size)))
     e1.append(m2_expr.ExprAff(b, b - m2_expr.ExprInt(size / 8, b.size)))
     e1.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    e1 = IRBlock(lbl_df_1.name, [e1])
+    e1 = IRBlock(lbl_df_1.name, [AssignBlock(e1, instr)])
 
     e.append(m2_expr.ExprAff(ir.IRDst,
                              m2_expr.ExprCond(df, lbl_df_1, lbl_df_0)))
@@ -2783,8 +2783,8 @@ def bsr_bsf(ir, instr, dst, src, op_name):
     e_src_not_null.append(m2_expr.ExprAff(dst, m2_expr.ExprOp(op_name, src)))
     e_src_not_null.append(aff_dst)
 
-    return e, [IRBlock(lbl_src_null.name, [e_src_null]),
-               IRBlock(lbl_src_not_null.name, [e_src_not_null])]
+    return e, [IRBlock(lbl_src_null.name, [AssignBlock(e_src_null, instr)]),
+               IRBlock(lbl_src_not_null.name, [AssignBlock(e_src_not_null, instr)])]
 
 
 def bsf(ir, instr, dst, src):
@@ -3682,7 +3682,8 @@ def ps_rl_ll(ir, instr, dst, src, op, size):
     e_do = []
     e.append(m2_expr.ExprAff(dst[0:dst.size], m2_expr.ExprCompose(*slices)))
     e_do.append(m2_expr.ExprAff(ir.IRDst, lbl_next))
-    return e, [IRBlock(lbl_do.name, [e_do]), IRBlock(lbl_zero.name, [e_zero])]
+    return e, [IRBlock(lbl_do.name, [AssignBlock(e_do, instr)]),
+               IRBlock(lbl_zero.name, [AssignBlock(e_zero, instr)])]
 
 
 def psrlw(ir, instr, dst, src):
@@ -4598,11 +4599,10 @@ class ir_x86_16(IntermediateRepresentation):
         lbl_skip = m2_expr.ExprId(self.get_next_label(instr), self.IRDst.size)
         lbl_next = m2_expr.ExprId(self.get_next_label(instr), self.IRDst.size)
 
-        for irblock in extra_ir:
-            for ir in irblock.irs:
-                for i, e in enumerate(ir):
-                    src = e.src.replace_expr({lbl_next: lbl_end})
-                    ir[i] = m2_expr.ExprAff(e.dst, src)
+        fix_next_lbl = {lbl_next: lbl_end}
+        new_extra_ir = [irblock.modify_exprs(mod_src=lambda expr: expr.replace_expr(fix_next_lbl))
+                        for irblock in extra_ir]
+
         cond_bloc = []
         cond_bloc.append(m2_expr.ExprAff(c_reg,
                                          c_reg - m2_expr.ExprInt(1,
@@ -4610,14 +4610,14 @@ class ir_x86_16(IntermediateRepresentation):
         cond_bloc.append(m2_expr.ExprAff(self.IRDst, m2_expr.ExprCond(c_cond,
                                                                       lbl_skip,
                                                                       lbl_do)))
-        cond_bloc = IRBlock(lbl_end.name, [cond_bloc])
+        cond_bloc = IRBlock(lbl_end.name, [AssignBlock(cond_bloc, instr)])
         e_do = instr_ir
 
-        c = IRBlock(lbl_do.name, [e_do])
+        c = IRBlock(lbl_do.name, [AssignBlock(e_do, instr)])
         c.except_automod = False
         e_n = [m2_expr.ExprAff(self.IRDst, m2_expr.ExprCond(c_reg, lbl_do,
                                                             lbl_skip))]
-        return e_n, [cond_bloc, c] + extra_ir
+        return e_n, [cond_bloc, c] + new_extra_ir
 
     def expr_fix_regs_for_mode(self, e, mode=64):
         return e.replace_expr(replace_regs[mode])
@@ -4627,8 +4627,9 @@ class ir_x86_16(IntermediateRepresentation):
         src = self.expr_fix_regs_for_mode(e.src, mode)
         return m2_expr.ExprAff(dst, src)
 
-    def irbloc_fix_regs_for_mode(self, irbloc, mode=64):
-        for idx, assignblk in enumerate(irbloc.irs):
+    def irbloc_fix_regs_for_mode(self, irblock, mode=64):
+        irs = []
+        for assignblk in irblock.irs:
             new_assignblk = dict(assignblk)
             for dst, src in assignblk.iteritems():
                 del new_assignblk[dst]
@@ -4643,9 +4644,8 @@ class ir_x86_16(IntermediateRepresentation):
                 dst = self.expr_fix_regs_for_mode(dst, mode)
                 src = self.expr_fix_regs_for_mode(src, mode)
                 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)
+            irs.append(AssignBlock(new_assignblk, assignblk.instr))
+        return IRBlock(irblock.label, irs)
 
 
 class ir_x86_32(ir_x86_16):
@@ -4677,21 +4677,16 @@ class ir_x86_64(ir_x86_16):
 
     def mod_pc(self, instr, instr_ir, extra_ir):
         # fix RIP for 64 bit
+        pc_fixed = {self.pc: m2_expr.ExprInt(instr.offset + instr.l, 64)}
+
         for i, expr in enumerate(instr_ir):
             dst, src = expr.dst, expr.src
             if dst != self.pc:
-                dst = dst.replace_expr(
-                    {self.pc: m2_expr.ExprInt(instr.offset + instr.l, 64)})
-            src = src.replace_expr(
-                {self.pc: m2_expr.ExprInt(instr.offset + instr.l, 64)})
+                dst = dst.replace_expr(pc_fixed)
+            src = src.replace_expr(pc_fixed)
             instr_ir[i] = m2_expr.ExprAff(dst, src)
-        for irblock in extra_ir:
-            for irs in irblock.irs:
-                for i, expr in enumerate(irs):
-                    dst, src = expr.dst, expr.src
-                    if dst != self.pc:
-                        new_pc = m2_expr.ExprInt(instr.offset + instr.l, 64)
-                        dst = dst.replace_expr({self.pc: new_pc})
-                    src = src.replace_expr(
-                        {self.pc: m2_expr.ExprInt(instr.offset + instr.l, 64)})
-                    irs[i] = m2_expr.ExprAff(dst, src)
+
+        for idx, irblock in enumerate(extra_ir):
+            extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
+                                                 if expr != self.pc else expr,
+                                                 lambda expr: expr.replace_expr(pc_fixed))
diff --git a/miasm2/core/sembuilder.py b/miasm2/core/sembuilder.py
index 138e4552..8d6d3e07 100644
--- a/miasm2/core/sembuilder.py
+++ b/miasm2/core/sembuilder.py
@@ -5,7 +5,7 @@ import ast
 import re
 
 import miasm2.expression.expression as m2_expr
-from miasm2.ir.ir import IRBlock
+from miasm2.ir.ir import IRBlock, AssignBlock
 
 
 class MiasmTransformer(ast.NodeTransformer):
@@ -127,6 +127,7 @@ class SemBuilder(object):
         self.transformer = MiasmTransformer()
         self._ctx = dict(m2_expr.__dict__)
         self._ctx["IRBlock"] = IRBlock
+        self._ctx["AssignBlock"] = AssignBlock
         self._functions = {}
 
         # Update context
@@ -246,20 +247,31 @@ class SemBuilder(object):
                                        starargs=None,
                                        kwargs=None)
                     sub_blocks[-1][-1].append(jmp_end)
-                    sub_blocks[-1][-1] = ast.List(elts=sub_blocks[-1][-1],
-                                                  ctx=ast.Load())
-                    sub_blocks[-1] = ast.List(elts=sub_blocks[-1],
-                                              ctx=ast.Load())
+
+
+                    instr = ast.Name(id='instr', ctx=ast.Load())
+                    effects = ast.List(elts=sub_blocks[-1][-1],
+                                       ctx=ast.Load())
+                    assignblk = ast.Call(func=ast.Name(id='AssignBlock',
+                                                       ctx=ast.Load()),
+                                         args=[effects, instr],
+                                         keywords=[],
+                                         starargs=None,
+                                         kwargs=None)
+
 
                     ## Replace the block with a call to 'IRBlock'
                     lbl_if_name = ast.Attribute(value=ast.Name(id=lbl_name,
                                                                ctx=ast.Load()),
                                                 attr='name', ctx=ast.Load())
 
+                    assignblks = ast.List(elts=[assignblk],
+                                          ctx=ast.Load())
+
                     sub_blocks[-1] = ast.Call(func=ast.Name(id='IRBlock',
                                                             ctx=ast.Load()),
                                               args=[lbl_if_name,
-                                                    sub_blocks[-1]],
+                                                    assignblks],
                                               keywords=[],
                                               starargs=None,
                                               kwargs=None)
diff --git a/miasm2/ir/analysis.py b/miasm2/ir/analysis.py
index 1d9310fc..fc0c81c9 100644
--- a/miasm2/ir/analysis.py
+++ b/miasm2/ir/analysis.py
@@ -1,13 +1,12 @@
 #-*- coding:utf-8 -*-
 
+import warnings
 import logging
 
 from miasm2.ir.symbexec import SymbolicExecutionEngine
 from miasm2.ir.ir import IntermediateRepresentation, AssignBlock
-from miasm2.expression.expression \
-    import ExprAff, ExprCond, ExprId, ExprInt, ExprMem, ExprOp
+from miasm2.expression.expression import ExprAff, ExprOp
 from miasm2.analysis.data_flow import dead_simp as new_dead_simp_imp
-import warnings
 
 log = logging.getLogger("analysis")
 console_handler = logging.StreamHandler()
@@ -29,47 +28,30 @@ class ira(IntermediateRepresentation):
 
     """
 
-    def call_effects(self, ad, instr):
-        """Default modelisation of a function call to @ad. This may be used to:
+    def call_effects(self, addr, instr):
+        """Default modelisation of a function call to @addr. This may be used to:
 
         * insert dependencies to arguments (stack base, registers, ...)
         * add some side effects (stack clean, return value, ...)
 
-        @ad: (Expr) address of the called function
+        @addr: (Expr) address of the called function
         @instr: native instruction which is responsible of the call
         """
 
         assignblk = AssignBlock({
-            self.ret_reg: ExprOp('call_func_ret', ad, self.sp),
-            self.sp: ExprOp('call_func_stack', ad, self.sp)},
+            self.ret_reg: ExprOp('call_func_ret', addr, self.sp),
+            self.sp: ExprOp('call_func_stack', addr, self.sp)},
             instr)
         return [assignblk]
 
-    def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_update):
+    def pre_add_instr(self, block, instr, assignments, ir_blocks_all, gen_pc_update):
         """Replace function call with corresponding call effects,
         inside the IR block"""
         if not instr.is_subcall():
-            return irb_cur
+            return False
         call_effects = self.call_effects(instr.args[0], instr)
-        for assignblk in call_effects:
-            irb_cur.irs.append(assignblk)
-        return None
-
-    def gen_equations(self):
-        for irb in self.blocks.values():
-            symbols_init = dict(self.arch.regs.all_regs_ids_init)
-
-            sb = SymbolicExecutionEngine(self, dict(symbols_init))
-            sb.emulbloc(irb)
-            eqs = []
-            for n_w in sb.symbols:
-                v = sb.symbols[n_w]
-                if n_w in symbols_init and symbols_init[n_w] == v:
-                    continue
-                eqs.append(ExprAff(n_w, v))
-            print '*' * 40
-            print irb
-            irb.irs = [AssignBlock(eqs)]
+        assignments+= call_effects
+        return True
 
     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 8154d4da..6dbf7835 100644
--- a/miasm2/ir/ir.py
+++ b/miasm2/ir/ir.py
@@ -266,15 +266,21 @@ class IRBlock(object):
 
         assert isinstance(label, AsmLabel)
         self.label = label
-        self.irs = irs
+        for assignblk in irs:
+            assert isinstance(assignblk, AssignBlock)
+        self._assignments = tuple(irs)
         self.except_automod = True
         self._dst = None
         self._dst_linenb = None
 
-    def _get_dst(self):
-        """Find the IRDst affectation and update dst, dst_linenb accordingly"""
-        if self._dst is not None:
-            return self._dst
+    @property
+    def irs(self):
+        return self._assignments
+
+    def is_dst_set(self):
+        return self._dst is not None
+
+    def cache_dst(self):
         final_dst = None
         final_linenb = None
         for linenb, assignblk in enumerate(self.irs):
@@ -288,25 +294,34 @@ class IRBlock(object):
         self._dst_linenb = final_linenb
         return final_dst
 
-    def _set_dst(self, value):
-        """Find and replace the IRDst affectation's source by @value"""
-        if self._dst_linenb is None:
-            self._get_dst()
+    @property
+    def dst(self):
+        """Find the IRDst affectation and update dst, dst_linenb accordingly"""
+        if self.is_dst_set():
+            return self._dst
+        return self.cache_dst()
 
-        new_assignblk = dict(self.irs[self._dst_linenb])
-        for dst in new_assignblk:
-            if dst.is_id("IRDst"):
-                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)
+    def set_dst(self, value):
+        """Generate a new IRBlock with a dst fixed to @value"""
+        irs = []
+        dst_found = False
+        for assignblk in self.irs:
+            new_assignblk = {}
+            for dst, src in assignblk.iteritems():
+                if dst.is_id("IRDst"):
+                    assert dst_found is False
+                    dst_found = True
+                    new_assignblk[dst] = value
+                else:
+                    new_assignblk[dst] = src
+            irs.append(AssignBlock(new_assignblk, assignblk.instr))
+        return IRBlock(self.label, irs)
 
     @property
     def dst_linenb(self):
         """Line number of the IRDst setting statement in the current irs"""
+        if not self.is_dst_set():
+            self.cache_dst()
         return self._dst_linenb
 
     def __str__(self):
@@ -319,6 +334,28 @@ class IRBlock(object):
         return "\n".join(out)
 
 
+    def modify_exprs(self, mod_dst=None, mod_src=None):
+        """
+        Generate a new IRBlock with its AssignBlock expressions modified
+        according to @mod_dst and @mod_src
+        @mod_dst: function called to modify Expression destination
+        @mod_src: function called to modify Expression source
+        """
+
+        if mod_dst is None:
+            mod_dst = lambda expr:expr
+        if mod_src is None:
+            mod_src = lambda expr:expr
+
+        assignblks = []
+        for assignblk in self.irs:
+            new_assignblk = {}
+            for dst, src in assignblk.iteritems():
+                new_assignblk[mod_dst(dst)] = mod_src(src)
+            assignblks.append(AssignBlock(new_assignblk, assignblk.instr))
+        return IRBlock(self.label, assignblks)
+
+
 class irbloc(IRBlock):
     """
     DEPRECATED object
@@ -415,14 +452,14 @@ class IntermediateRepresentation(object):
         raise NotImplementedError("Abstract Method")
 
     def instr2ir(self, instr):
-        ir_bloc_cur, extra_assignblk = self.get_ir(instr)
-        for irb in extra_assignblk:
+        ir_bloc_cur, extra_irblocks = self.get_ir(instr)
+        for index, irb in enumerate(extra_irblocks):
             irs = []
             for assignblk in irb.irs:
                 irs.append(AssignBlock(assignblk, instr))
-            irb.irs = irs
+            extra_irblocks[index] = IRBlock(irb.label, irs)
         assignblk = AssignBlock(ir_bloc_cur, instr)
-        return assignblk, extra_assignblk
+        return assignblk, extra_irblocks
 
     def get_label(self, addr):
         """Transforms an ExprId/ExprInt/label/int into a label
@@ -460,16 +497,18 @@ class IntermediateRepresentation(object):
                     out.add(irb)
         return out
 
-    def gen_pc_update(self, irblock, instr):
-        irblock.irs.append(AssignBlock({self.pc: m2_expr.ExprInt(instr.offset, self.pc.size)},
-                                       instr))
+    def gen_pc_update(self, assignments, instr):
+        offset = m2_expr.ExprInt(instr.offset, self.pc.size)
+        assignments.append(AssignBlock({self.pc:offset}, instr))
 
-    def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_updt):
+    def pre_add_instr(self, block, instr, assignments, ir_blocks_all, gen_pc_updt):
         """Function called before adding an instruction from the the native @block to
         the current irbloc.
 
-        Returns None if the addition needs an irblock split, @irb_cur in other
-        cases.
+        Returns a couple. The first element is the new irblock. The second the a
+        bool:
+        * True if the current irblock must be split
+        * False in other cases.
 
         @block: native block source
         @instr: native instruction
@@ -479,14 +518,16 @@ class IntermediateRepresentation(object):
 
         """
 
-        return irb_cur
+        return False
 
-    def add_instr_to_irblock(self, block, instr, irb_cur, ir_blocks_all, gen_pc_updt):
+    def add_instr_to_irblock(self, block, instr, assignments, ir_blocks_all, gen_pc_updt):
         """
         Add the IR effects of an instruction to the current irblock.
 
-        Returns None if the addition needs an irblock split, @irb_cur in other
-        cases.
+        Returns a couple. The first element is the new irblock. The second the a
+        bool:
+        * True if the current irblock must be split
+        * False in other cases.
 
         @block: native block source
         @instr: native instruction
@@ -495,21 +536,20 @@ class IntermediateRepresentation(object):
         @gen_pc_updt: insert PC update effects between instructions
         """
 
-        irb_cur = self.pre_add_instr(block, instr, irb_cur, ir_blocks_all, gen_pc_updt)
-        if irb_cur is None:
-            return None
+        split = self.pre_add_instr(block, instr, assignments, ir_blocks_all, gen_pc_updt)
+        if split:
+            return True
 
         assignblk, ir_blocks_extra = self.instr2ir(instr)
 
         if gen_pc_updt is not False:
-            self.gen_pc_update(irb_cur, instr)
-
-        irb_cur.irs.append(assignblk)
+            self.gen_pc_update(assignments, instr)
 
+        assignments.append(assignblk)
+        ir_blocks_all += ir_blocks_extra
         if ir_blocks_extra:
-            ir_blocks_all += ir_blocks_extra
-            irb_cur = None
-        return irb_cur
+            return True
+        return False
 
     def add_bloc(self, block, gen_pc_updt=False):
         """
@@ -518,17 +558,25 @@ class IntermediateRepresentation(object):
         @gen_pc_updt: insert PC update effects between instructions
         """
 
-        irb_cur = None
+        label = None
         ir_blocks_all = []
         for instr in block.lines:
-            if irb_cur is None:
+            if label is None:
+                assignments = []
                 label = self.get_instr_label(instr)
-                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
+            split = self.add_instr_to_irblock(block, instr, assignments,
+                                              ir_blocks_all, gen_pc_updt)
+            if split:
+                ir_blocks_all.append(IRBlock(label, assignments))
+                label = None
+                assignments = []
+        if label is not None:
+            ir_blocks_all.append(IRBlock(label, assignments))
+
+        new_ir_blocks_all = self.post_add_bloc(block, ir_blocks_all)
+        for irblock in new_ir_blocks_all:
+            self.blocks[irblock.label] = irblock
+        return new_ir_blocks_all
 
     def expr_fix_regs_for_mode(self, expr, *args, **kwargs):
         return expr
@@ -536,8 +584,8 @@ class IntermediateRepresentation(object):
     def expraff_fix_regs_for_mode(self, expr, *args, **kwargs):
         return expr
 
-    def irbloc_fix_regs_for_mode(self, irbloc, *args, **kwargs):
-        return
+    def irbloc_fix_regs_for_mode(self, irblock, *args, **kwargs):
+        return irblock
 
     def is_pc_written(self, block):
         all_pc = self.arch.pc.values()
@@ -548,7 +596,7 @@ class IntermediateRepresentation(object):
         return None
 
     def set_empty_dst_to_next(self, block, ir_blocks):
-        for irblock in ir_blocks:
+        for index, irblock in enumerate(ir_blocks):
             if irblock.dst is not None:
                 continue
             next_lbl = block.get_next()
@@ -558,18 +606,20 @@ class IntermediateRepresentation(object):
             else:
                 dst = m2_expr.ExprId(next_lbl,
                                      self.pc.size)
-            irblock.irs.append(AssignBlock({self.IRDst: dst},
-                                           irblock.irs[-1].instr))
+            assignblk = AssignBlock({self.IRDst: dst}, irblock.irs[-1].instr)
+            ir_blocks[index] = IRBlock(irblock.label, list(irblock.irs) + [assignblk])
 
     def post_add_bloc(self, block, ir_blocks):
         self.set_empty_dst_to_next(block, ir_blocks)
 
+        new_irblocks = []
         for irblock in ir_blocks:
-            self.irbloc_fix_regs_for_mode(irblock, self.attrib)
-            self.blocks[irblock.label] = irblock
-
+            new_irblock = self.irbloc_fix_regs_for_mode(irblock, self.attrib)
+            self.blocks[irblock.label] = new_irblock
+            new_irblocks.append(new_irblock)
         # Forget graph if any
         self._graph = None
+        return new_irblocks
 
     def get_instr_label(self, instr):
         """Returns the label associated to an instruction
@@ -683,16 +733,14 @@ class IntermediateRepresentation(object):
 
     def remove_empty_assignblks(self):
         modified = False
-        for block in self.blocks.itervalues():
-            to_del = []
-            for idx, assignblk in enumerate(block.irs):
-                if len(assignblk) == 0:
-                    to_del.append(idx)
-            for idx in reversed(to_del):
-                del block.irs[idx]
-                block._dst_linenb = None
-                block._dst = None
-                modified = True
+        for label, block in self.blocks.iteritems():
+            irs = []
+            for assignblk in block.irs:
+                if len(assignblk):
+                    irs.append(assignblk)
+                else:
+                    modified = True
+            self.blocks[label] = IRBlock(label, irs)
         return modified
 
     def remove_jmp_blocks(self):
@@ -714,11 +762,12 @@ class IntermediateRepresentation(object):
                 continue
             if not expr_is_label(assignblk[self.IRDst]):
                 continue
-            jmp_blocks.add(block)
+            jmp_blocks.add(block.label)
 
         # Remove them, relink graph
         modified = False
-        for block in jmp_blocks:
+        for label in jmp_blocks:
+            block = self.blocks[label]
             dst_label = block.dst.name
             parents = self.graph.predecessors(block.label)
             for lbl in parents:
@@ -752,13 +801,14 @@ class IntermediateRepresentation(object):
                         dst = src1
                 else:
                     continue
-                parent.dst = dst
+                new_parent = parent.set_dst(dst)
+                self.blocks[parent.label] = new_parent
 
         # Remove unlinked useless nodes
-        for block in jmp_blocks:
-            if (len(self.graph.predecessors(block.label)) == 0 and
-                len(self.graph.successors(block.label)) == 0):
-                self.graph.del_node(block.label)
+        for label in jmp_blocks:
+            if (len(self.graph.predecessors(label)) == 0 and
+                len(self.graph.successors(label)) == 0):
+                self.graph.del_node(label)
         return modified
 
     def merge_blocks(self):
@@ -782,7 +832,7 @@ class IntermediateRepresentation(object):
                 continue
             # Block has one son, son has one parent => merge
             assignblks =[]
-            for linenb, assignblk in enumerate(self.blocks[block].irs):
+            for assignblk in self.blocks[block].irs:
                 if self.IRDst not in assignblk:
                     assignblks.append(assignblk)
                     continue
diff --git a/miasm2/jitter/codegen.py b/miasm2/jitter/codegen.py
index 15f172ee..61a9a784 100644
--- a/miasm2/jitter/codegen.py
+++ b/miasm2/jitter/codegen.py
@@ -577,18 +577,16 @@ class CGen(object):
             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(
-                    irblock, self.ir_arch.attrib)
-
-                if irblock.label.offset is None:
+                new_irblock = self.ir_arch.irbloc_fix_regs_for_mode(irblock, self.ir_arch.attrib)
+                if new_irblock.label.offset is None:
                     out.append("%-40s // %.16X %s" %
-                               (str(irblock.label.name) + ":", instr.offset, instr))
+                               (str(new_irblock.label.name) + ":", instr.offset, instr))
                 else:
                     out.append("%-40s // %.16X %s" %
-                               (self.label_to_jitlabel(irblock.label) + ":", instr.offset, instr))
+                               (self.label_to_jitlabel(new_irblock.label) + ":", instr.offset, instr))
                 if index == 0:
                     out += self.gen_pre_code(instr_attrib)
-                out += self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, irblock)
+                out += self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, new_irblock)
 
         out += self.gen_finalize(block)
         return ['\t' + line for line in out]
diff --git a/miasm2/jitter/llvmconvert.py b/miasm2/jitter/llvmconvert.py
index ae018c18..ed55aff8 100644
--- a/miasm2/jitter/llvmconvert.py
+++ b/miasm2/jitter/llvmconvert.py
@@ -1299,7 +1299,8 @@ class LLVMFunction():
 
 
         for instr, irblocks in zip(asmblock.lines, irblocks_list):
-            instr_attrib, irblocks_attributes = codegen.get_attributes(instr, irblocks, self.log_mn,
+            instr_attrib, irblocks_attributes = codegen.get_attributes(instr, irblocks,
+                                                                       self.log_mn,
                                                                        self.log_regs)
 
             # Pre-create basic blocks
@@ -1308,16 +1309,16 @@ class LLVMFunction():
 
             # Generate the corresponding code
             for index, irblock in enumerate(irblocks):
-                self.llvm_context.ir_arch.irbloc_fix_regs_for_mode(
+                new_irblock = self.llvm_context.ir_arch.irbloc_fix_regs_for_mode(
                     irblock, self.llvm_context.ir_arch.attrib)
 
                 # Set the builder at the begining of the correct bbl
-                name = self.canonize_label_name(irblock.label)
+                name = self.canonize_label_name(new_irblock.label)
                 self.builder.position_at_end(self.get_basic_bloc_by_label(name))
 
                 if index == 0:
                     self.gen_pre_code(instr_attrib)
-                self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, irblock)
+                self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, new_irblock)
 
         # Gen finalize (see codegen::CGen) is unrecheable, except with delayslot
         self.gen_finalize(asmblock, codegen)