about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorFabrice Desclaux <fabrice.desclaux@cea.fr>2017-04-14 13:32:59 +0200
committerFabrice Desclaux <fabrice.desclaux@cea.fr>2017-04-20 12:31:33 +0200
commit16fc339e53bfc908dbcd73fc912d7d75aed7218c (patch)
treef13faa66157ddd4c12dff191d314d81e5f2bf33f
parentff981a11ef71960a239ec44295f06bb384124521 (diff)
downloadmiasm-16fc339e53bfc908dbcd73fc912d7d75aed7218c.tar.gz
miasm-16fc339e53bfc908dbcd73fc912d7d75aed7218c.zip
Ir: make AssignBlock immutable
-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/jit.py12
-rw-r--r--miasm2/arch/x86/sem.py12
-rw-r--r--miasm2/ir/ir.py74
-rw-r--r--miasm2/jitter/codegen.py255
-rw-r--r--miasm2/jitter/llvmconvert.py39
-rw-r--r--test/analysis/data_flow.py5
-rwxr-xr-xtest/ir/symbexec.py3
10 files changed, 249 insertions, 174 deletions
diff --git a/miasm2/analysis/data_flow.py b/miasm2/analysis/data_flow.py
index b9764daa..3c77fc40 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)
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..edc6e3a5 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)
         if irbloc.dst is not None:
             irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst)
 
diff --git a/miasm2/arch/mips32/jit.py b/miasm2/arch/mips32/jit.py
index bfa9c5fd..939a0e50 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)
+
         return irblocks_list
 
     def gen_finalize(self, block):
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
index 98866e65..b0cdc280 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)
         if irbloc.dst is not None:
             irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst, mode)
 
diff --git a/miasm2/ir/ir.py b/miasm2/ir/ir.py
index f8ac6722..bdad4f30 100644
--- a/miasm2/ir/ir.py
+++ b/miasm2/ir/ir.py
@@ -29,19 +29,24 @@ from miasm2.core.asmblock import AsmSymbolPool, expr_is_label, AsmLabel, \
 from miasm2.core.graph import DiGraph
 
 
-class AssignBlock(dict):
+class AssignBlock(object):
+    __slots__ = ["_assigns"]
 
     def __init__(self, irs=None):
         """@irs seq"""
         if irs is None:
             irs = []
-        super(AssignBlock, self).__init__()
+        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):
+    def _set(self, dst, src):
         """
         Special cases:
         * if dst is an ExprSlice, expand it to affect the full Expression
@@ -64,7 +69,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 +108,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):
@@ -207,15 +256,14 @@ 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
-
+        self.irs[self._dst_linenb] = AssignBlock(new_assignblk)
     dst = property(_get_dst, _set_dst)
 
     @property
diff --git a/miasm2/jitter/codegen.py b/miasm2/jitter/codegen.py
index 09a6fecf..8a03c667 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)]
+        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/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/test/analysis/data_flow.py b/test/analysis/data_flow.py
index 1784f87f..e9029e8e 100644
--- a/test/analysis/data_flow.py
+++ b/test/analysis/data_flow.py
@@ -32,6 +32,8 @@ LBL4 = AsmLabel("lbl4")
 LBL5 = AsmLabel("lbl5")
 LBL6 = AsmLabel("lbl6")
 
+IRDst = ExprId('IRDst', 32)
+dummy = ExprId('dummy', 32)
 
 
 def gen_irblock(label, exprs_list):
@@ -43,6 +45,7 @@ def gen_irblock(label, exprs_list):
         else:
             irs.append(AssignBlock(exprs))
 
+    irs.append(AssignBlock({IRDst:dummy}))
     irbl = IRBlock(label, irs, lines)
     return irbl
 
@@ -67,7 +70,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/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)