about summary refs log tree commit diff stats
path: root/miasm2/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--miasm2/arch/x86/__init__.py1
-rw-r--r--miasm2/arch/x86/arch.py3839
-rw-r--r--miasm2/arch/x86/disasm.py51
-rw-r--r--miasm2/arch/x86/ira.py91
-rw-r--r--miasm2/arch/x86/regs.py405
-rw-r--r--miasm2/arch/x86/sem.py3029
6 files changed, 7416 insertions, 0 deletions
diff --git a/miasm2/arch/x86/__init__.py b/miasm2/arch/x86/__init__.py
new file mode 100644
index 00000000..bbad893b
--- /dev/null
+++ b/miasm2/arch/x86/__init__.py
@@ -0,0 +1 @@
+__all__ = ["arch", "disasm", "regs", "sem"]
diff --git a/miasm2/arch/x86/arch.py b/miasm2/arch/x86/arch.py
new file mode 100644
index 00000000..5ccc4a9c
--- /dev/null
+++ b/miasm2/arch/x86/arch.py
@@ -0,0 +1,3839 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+import re
+from miasm2.expression.expression import *
+from pyparsing import *
+from miasm2.core.cpu import *
+from collections import defaultdict
+import regs as regs_module
+from regs import *
+from miasm2.ir.ir import *
+
+log = logging.getLogger("x86_arch")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(logging.WARN)
+
+
+f_isad = "AD"
+f_s08 = "S08"
+f_u08 = "U08"
+f_s16 = "S16"
+f_u16 = "U16"
+f_s32 = "S32"
+f_u32 = "U32"
+f_s64 = "S64"
+f_u64 = "U64"
+f_imm = 'IMM'
+
+f_imm2size = {f_s08: 8, f_s16: 16, f_s32: 32, f_s64: 64,
+              f_u08: 8, f_u16: 16, f_u32: 32, f_u64: 64}
+
+
+size2gpregs = {8: gpregs08, 16: gpregs16,
+               32: gpregs32, 64: gpregs64}
+
+
+replace_regs64 = {
+    AL: RAX[:8], CL: RCX[:8], DL: RDX[:8], BL: RBX[:8],
+    AH: RAX[8:16], CH: RCX[8:16], DH: RDX[8:16], BH: RBX[8:16],
+    SPL: RSP[0:8], BPL: RBP[0:8], SIL: RSI[0:8], DIL: RDI[0:8],
+    R8B: R8[0:8], R9B: R9[0:8], R10B: R10[0:8], R11B: R11[0:8],
+    R12B: R12[0:8], R13B: R13[0:8], R14B: R14[0:8], R15B: R15[0:8],
+
+    AX: RAX[:16], CX: RCX[:16], DX: RDX[:16], BX: RBX[:16],
+    SP: RSP[:16], BP: RBP[:16], SI: RSI[:16], DI: RDI[:16],
+    R8W:  R8[:16], R9W:  R9[:16], R10W: R10[:16], R11W: R11[:16],
+    R12W: R12[:16], R13W: R13[:16], R14W: R14[:16], R15W: R15[:16],
+
+
+    EAX: RAX[:32], ECX: RCX[:32], EDX: RDX[:32], EBX: RBX[:32],
+    ESP: RSP[:32], EBP: RBP[:32], ESI: RSI[:32], EDI: RDI[:32],
+    R8D: R8[:32], R9D: R9[:32], R10D: R10[:32], R11D: R11[:32],
+    R12D: R12[:32], R13D: R13[:32], R14D: R14[:32], R15D: R15[:32],
+
+    IP: RIP[:16], EIP: RIP[:32],
+
+}
+
+replace_regs32 = {
+    AL: EAX[:8],   CL: ECX[:8],   DL: EDX[:8],   BL: EBX[:8],
+    AH: EAX[8:16], CH: ECX[8:16], DH: EDX[8:16], BH: EBX[8:16],
+
+    AX: EAX[:16], CX: ECX[:16], DX: EDX[:16], BX: EBX[:16],
+    SP: ESP[:16], BP: EBP[:16], SI: ESI[:16], DI: EDI[:16],
+
+    IP: EIP[:16]
+}
+
+replace_regs16 = {
+    AL: AX[:8],   CL: CX[:8],   DL: DX[:8],   BL: BX[:8],
+    AH: AX[8:16], CH: CX[8:16], DH: DX[8:16], BH: BX[8:16],
+
+    AX: AX[:16],  CX: CX[:16],  DX: DX[:16],  BX: BX[:16],
+    SP: SP[:16],  BP: BP[:16],  SI: SI[:16],  DI: DI[:16],
+}
+
+replace_regs = {16: replace_regs16,
+                32: replace_regs32,
+                64: replace_regs64}
+
+
+# parser helper ###########
+PLUS = Suppress("+")
+MULT = Suppress("*")
+
+COLON = Suppress(":")
+
+
+LBRACK = Suppress("[")
+RBRACK = Suppress("]")
+
+dbreg = Group(gpregs16.parser | gpregs32.parser | gpregs64.parser)
+gpreg = (gpregs08.parser | gpregs08_64.parser | gpregs16.parser   |
+         gpregs32.parser | gpregs64.parser    | gpregs_xmm.parser |
+         gpregs_mm.parser)
+
+
+def reg2exprid(r):
+    if not r.name in all_regs_ids_byname:
+        raise ValueError('unknown reg')
+    return all_regs_ids_byname[r.name]
+
+
+def parse_deref_reg(s, l, t):
+    t = t[0][0]
+    return t[0]
+
+
+def parse_deref_int(s, l, t):
+    t = t[0]
+    return t[0]
+
+
+def parse_deref_regint(s, l, t):
+    t = t[0]
+    r1 = reg2exprid(t[0][0])
+    i1 = ExprInt_from(r1, t[1].arg)
+    return r1 + i1
+
+
+def parse_deref_regreg(s, l, t):
+    t = t[0]
+    return t[0][0] + t[1][0]
+
+
+def parse_deref_regregint(s, l, t):
+    t = t[0]
+    r1 = reg2exprid(t[0][0])
+    r2 = reg2exprid(t[1][0])
+    i1 = ExprInt_from(r1, t[2].arg)
+    return r1 + r2 + i1
+
+
+def parse_deref_reg_intmreg(s, l, t):
+    t = t[0]
+    r1 = reg2exprid(t[0][0])
+    r2 = reg2exprid(t[1][0])
+    i1 = ExprInt_from(r1, t[2].arg)
+    return r1 + (r2 * i1)
+
+
+def parse_deref_reg_intmreg_int(s, l, t):
+    t = t[0]
+    r1 = reg2exprid(t[0][0])
+    r2 = reg2exprid(t[1][0])
+    i1 = ExprInt_from(r1, t[2].arg)
+    i2 = ExprInt_from(r1, t[3].arg)
+    return r1 + (r2 * i1) + i2
+
+
+def parse_deref_intmreg(s, l, t):
+    t = t[0]
+    r1 = reg2exprid(t[0][0])
+    i1 = ExprInt_from(r1, t[1].arg)
+    return r1 * i1
+
+
+def parse_deref_intmregint(s, l, t):
+    t = t[0]
+    r1 = reg2exprid(t[0][0])
+    i1 = ExprInt_from(r1, t[1].arg)
+    i2 = ExprInt_from(r1, t[1].arg)
+    return (r1 * i1) + i2
+
+
+def getreg(s, l, t):
+    t = t[0]
+    return t[0]
+
+
+def parse_deref_ptr(s, l, t):
+    t = t[0]
+    return ExprMem(ExprOp('segm', t[0], t[1]))
+
+
+variable, operand, base_expr = gen_base_expr()
+
+
+def ast_id2expr(t):
+    if not t in mn_x86.regs.all_regs_ids_byname:
+        r = ExprId(t)
+    else:
+        r = mn_x86.regs.all_regs_ids_byname[t]
+    return r
+
+
+def ast_int2expr(a):
+    return ExprInt64(a)
+
+
+my_var_parser = parse_ast(ast_id2expr, ast_int2expr)
+base_expr.setParseAction(my_var_parser)
+
+int_or_expr = base_expr
+
+deref_mem_ad = Group(LBRACK + dbreg + RBRACK).setParseAction(parse_deref_reg)
+deref_mem_ad |= Group(
+    LBRACK + int_or_expr + RBRACK).setParseAction(parse_deref_int)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + PLUS +
+    int_or_expr + RBRACK).setParseAction(parse_deref_regint)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + PLUS +
+    dbreg + RBRACK).setParseAction(parse_deref_regreg)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + PLUS + dbreg + PLUS +
+    int_or_expr + RBRACK).setParseAction(parse_deref_regregint)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + PLUS + dbreg + MULT +
+    int_or_expr + RBRACK).setParseAction(parse_deref_reg_intmreg)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + PLUS + dbreg + MULT + int_or_expr +
+    PLUS + int_or_expr + RBRACK).setParseAction(parse_deref_reg_intmreg_int)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + MULT +
+    int_or_expr + RBRACK).setParseAction(parse_deref_intmreg)
+deref_mem_ad |= Group(
+    LBRACK + dbreg + MULT + int_or_expr +
+    PLUS + int_or_expr + RBRACK).setParseAction(parse_deref_intmregint)
+
+
+deref_ptr = Group(int_or_expr + COLON +
+                  int_or_expr).setParseAction(parse_deref_ptr)
+
+
+PTR = Suppress('PTR')
+
+
+BYTE = Literal('BYTE')
+WORD = Literal('WORD')
+DWORD = Literal('DWORD')
+QWORD = Literal('QWORD')
+TBYTE = Literal('TBYTE')
+
+
+def parse_deref_mem(s, l, t):
+    sz = {'BYTE': 8, 'WORD': 16, 'DWORD': 32, 'QWORD': 64, 'TBYTE': 80}
+    t = t[0]
+    if len(t) == 2:
+        s, ptr = t
+        return ExprMem(ptr, sz[s[0]])
+    elif len(t) == 3:
+        s, segm, ptr = t
+        return ExprMem(ExprOp('segm', segm[0], ptr), sz[s[0]])
+    else:
+        raise ValueError('len(t) > 3')
+
+mem_size = Group(BYTE | DWORD | QWORD | WORD | TBYTE)
+deref_mem = Group(mem_size + PTR + Optional(Group(int_or_expr + COLON))
+                  + deref_mem_ad).setParseAction(parse_deref_mem)
+
+
+rmarg = Group(gpregs08.parser |
+              gpregs08_64.parser |
+              gpregs16.parser |
+              gpregs32.parser |
+              gpregs64.parser |
+              gpregs_mm.parser |
+              gpregs_xmm.parser
+              ).setParseAction(getreg)
+
+rmarg |= deref_mem
+
+
+cl_or_imm = Group(r08_ecx.parser).setParseAction(getreg)
+cl_or_imm |= int_or_expr
+
+
+class r_al(reg_noarg, m_arg):
+    reg_info = r08_eax
+    parser = reg_info.parser
+
+
+class r_ax(reg_noarg, m_arg):
+    reg_info = r16_eax
+    parser = reg_info.parser
+
+
+class r_dx(reg_noarg, m_arg):
+    reg_info = r16_edx
+    parser = reg_info.parser
+
+
+class r_eax(reg_noarg, m_arg):
+    reg_info = r32_eax
+    parser = reg_info.parser
+
+
+class r_rax(reg_noarg, m_arg):
+    reg_info = r64_eax
+    parser = reg_info.parser
+
+
+class r_cl(reg_noarg, m_arg):
+    reg_info = r08_ecx
+    parser = reg_info.parser
+
+
+invmode = {16: 32, 32: 16}
+
+
+def opmode_prefix(mode):
+    size, opmode, admode = mode
+    if size in [16, 32]:
+        if opmode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        if opmode:
+            return 16
+        else:
+            return 32
+    raise NotImplementedError('not fully functional')
+
+
+def admode_prefix(mode):
+    size, opmode, admode = mode
+    if size in [16, 32]:
+        if admode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        return 64
+    raise NotImplementedError('not fully functional')
+
+
+def v_opmode_info(size, opmode, rex_w, stk):
+    if size in [16, 32]:
+        if opmode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        if rex_w == 1:
+            return 64
+        elif stk:
+            if opmode == 1:
+                return 16
+            else:
+                return 64
+        elif opmode == 1:
+            return 16
+        return 32
+
+
+def v_opmode(p):
+    stk = hasattr(p, 'stk')
+    return v_opmode_info(p.mode, p.opmode, p.rex_w.value, stk)
+
+
+def v_admode_info(size, admode):
+    if size in [16, 32]:
+        if admode:
+            return invmode[size]
+        else:
+            return size
+    elif size == 64:
+        if admode == 1:
+            return 32
+        return 64
+
+
+def v_admode(p):
+    return v_admode_info(p.mode, p.admode)
+
+
+def offsize(p):
+    if p.opmode:
+        return 16
+    else:
+        return p.mode
+
+
+def get_prefix(s):
+    g = re.search('(\S+)(\s+)', s)
+    if not g:
+        return None, s
+    prefix, b = g.groups()
+    return prefix, s[len(prefix) + len(b):]
+
+
+repeat_mn = ["INS", "OUTS",
+             "MOVSB", "MOVSW", "MOVSD", "MOVSQ",
+             "SCASB", "SCASW", "SCASD", "SCASQ",
+             "LODSB", "LODSW", "LODSD", "LODSQ",
+             "STOSB", "STOSW", "STOSD", "STOSQ",
+             "CMPSB", "CMPSW", "CMPSD", "CMPSQ",
+             ]
+
+segm2enc = {CS: 1, SS: 2, DS: 3, ES: 4, FS: 5, GS: 6}
+enc2segm = dict([(x[1], x[0]) for x in segm2enc.items()])
+
+
+class group:
+
+    def __init__(self):
+        self.value = None
+
+
+class additional_info:
+
+    def __init__(self):
+        self.except_on_instr = False
+        self.g1 = group()
+        self.g2 = group()
+        self.vopmode = None
+        self.stk = False
+        self.v_opmode = None
+        self.v_admode = None
+        self.prefixed = ''
+
+
+class instruction_x86(instruction):
+    delayslot = 0
+
+    def __init__(self, *args, **kargs):
+        super(instruction_x86, self).__init__(*args, **kargs)
+        self.additional_info.stk = hasattr(self, 'stk')
+
+    def v_opmode(self):
+        return self.additional_info.v_opmode
+
+    def v_admode(self):
+        return self.additional_info.v_admode
+
+    def dstflow(self):
+        if self.name.startswith('J'):
+            return True
+        if self.name.startswith('LOOP'):
+            return True
+        # repxx yyy generate split flow
+        # if self.g1.value & 6 and self.name in repeat_mn:
+        #    return True
+        return self.name in ['CALL']
+
+    def dstflow2label(self, symbol_pool):
+        if self.additional_info.g1.value & 6 and self.name in repeat_mn:
+            return
+        e = self.args[0]
+        if isinstance(e, ExprId) and not e.name in all_regs_ids_byname:
+            l = symbol_pool.getby_name_create(e.name)
+            s = ExprId(l, e.size)
+            self.args[0] = s
+        elif isinstance(e, ExprInt):
+            ad = e.arg + int(self.offset) + self.l
+            l = symbol_pool.getby_offset_create(ad)
+            s = ExprId(l, e.size)
+            self.args[0] = s
+        else:
+            return
+
+    def breakflow(self):
+        if self.name.startswith('J'):
+            return True
+        if self.name.startswith('LOOP'):
+            return True
+        if self.name.startswith('RET'):
+            return True
+        if self.name.startswith('INT'):
+            return True
+        if self.name.startswith('SYS'):
+            return True
+        # repxx yyy generate split flow
+        # if self.g1.value & 6 and self.name in repeat_mn:
+        #    return True
+        return self.name in ['CALL', 'HLT', 'IRET', 'ICEBP']
+
+    def splitflow(self):
+        if self.name.startswith('JMP'):
+            return False
+        if self.name.startswith('J'):
+            return True
+        if self.name.startswith('LOOP'):
+            return True
+        if self.name.startswith('SYS'):
+            return True
+        # repxx yyy generate split flow
+        # if self.g1.value & 6 and self.name in repeat_mn:
+        #    return True
+        return self.name in ['CALL']
+
+    def setdstflow(self, a):
+        return
+
+    def is_subcall(self):
+        return self.name in ['CALL']
+
+    def getdstflow(self, symbol_pool):
+        if self.additional_info.g1.value & 6 and self.name in repeat_mn:
+            ad = int(self.offset)
+            l = symbol_pool.getby_offset_create(ad)
+            # XXX size ???
+            s = ExprId(l, self.v_opmode())
+            return [s]
+        return [self.args[0]]
+
+    def get_symbol_size(self, symbol, symbol_pool):
+        return self.mode
+
+    def fixDstOffset(self):
+        e = self.args[0]
+        if self.offset is None:
+            raise ValueError('symbol not resolved %s' % l)
+        if not isinstance(e, ExprInt):
+            # raise ValueError('dst must be int or label')
+            log.warning('dynamic dst %r' % e)
+            return
+        # return ExprInt32(e.arg - (self.offset + self.l))
+        self.args[0] = ExprInt_fromsize(
+            self.mode, e.arg - (self.offset + self.l))
+
+    def get_info(self, c):
+        self.additional_info.g1.value = c.g1.value
+        self.additional_info.g2.value = c.g2.value
+        self.additional_info.v_opmode = c.v_opmode()
+        self.additional_info.v_admode = c.v_admode()
+        self.additional_info.prefix = c.prefix
+        self.additional_info.prefixed = getattr(c, "prefixed", "")
+
+    def __str__(self):
+        o = super(instruction_x86, self).__str__()
+        if self.additional_info.g1.value & 1:
+            o = "LOCK %s" % o
+        if self.additional_info.g1.value & 2:
+            if getattr(self.additional_info.prefixed, 'default', "") != "\xF2":
+                o = "REPNE %s" % o
+        if self.additional_info.g1.value & 4:
+            if getattr(self.additional_info.prefixed, 'default', "") != "\xF3":
+                o = "REPE %s" % o
+        return o
+
+    def get_args_expr(self):
+        args = []
+        for a in self.args:
+            a = a.replace_expr(replace_regs[self.mode])
+            args.append(a)
+        return args
+
+
+class mn_x86(cls_mn):
+    name = "x86"
+    prefix_op_size = False
+    prefix_ad_size = False
+    regs = regs_module
+    all_mn = []
+    all_mn_mode = defaultdict(list)
+    all_mn_name = defaultdict(list)
+    all_mn_inst = defaultdict(list)
+    bintree = {}
+    num = 0
+    delayslot = 0
+    pc = {16: IP, 32: EIP, 64: RIP}
+    sp = {16: SP, 32: ESP, 64: RSP}
+    instruction = instruction_x86
+    max_instruction_len = 15
+
+    @classmethod
+    def getpc(cls, attrib):
+        return cls.pc[attrib]
+
+    @classmethod
+    def getsp(cls, attrib):
+        return cls.sp[attrib]
+
+    def v_opmode(self):
+        if hasattr(self, 'stk'):
+            stk = 1
+        else:
+            stk = 0
+        return v_opmode_info(self.mode, self.opmode, self.rex_w.value, stk)
+
+    def v_admode(self):
+        size, opmode, admode = self.mode, self.opmode, self.admode
+        if size in [16, 32]:
+            if admode:
+                return invmode[size]
+            else:
+                return size
+        elif size == 64:
+            if admode == 1:
+                return 32
+            return 64
+
+    def additional_info(self):
+        info = additional_info()
+        info.g1.value = self.g1.value
+        info.g2.value = self.g2.value
+        info.v_opmode = self.v_opmode()
+        info.prefixed = ""
+        if hasattr(self, 'prefixed'):
+            info.prefixed = self.prefixed.default
+        return info
+
+    @classmethod
+    def check_mnemo(cls, fields):
+        pass
+
+    @classmethod
+    def getmn(cls, name):
+        return name.upper()
+
+    @classmethod
+    def mod_fields(cls, fields):
+        prefix = [d_g1, d_g2, d_rex_p, d_rex_w, d_rex_r, d_rex_x, d_rex_b]
+        return prefix + fields
+
+    @classmethod
+    def gen_modes(cls, subcls, name, bases, dct, fields):
+        dct['mode'] = None
+        return [(subcls, name, bases, dct, fields)]
+
+    @classmethod
+    def fromstring(cls, s, mode):
+        pref = 0
+        prefix, new_s = get_prefix(s)
+        if prefix == "LOCK":
+            pref |= 1
+            s = new_s
+        elif prefix == "REPNE":
+            pref |= 2
+            s = new_s
+        elif prefix == "REPE":
+            pref |= 4
+            s = new_s
+        c = super(mn_x86, cls).fromstring(s, mode)
+        c.additional_info.g1.value = pref
+        return c
+
+    @classmethod
+    def pre_dis(cls, v, mode, offset):
+        offset_o = offset
+        pre_dis_info = {'opmode': 0,
+                        'admode': 0,
+                        'g1': 0,
+                        'g2': 0,
+                        'rex_p': 0,
+                        'rex_w': 0,
+                        'rex_r': 0,
+                        'rex_x': 0,
+                        'rex_b': 0,
+                        'prefix': "",
+                        'prefixed': "",
+                        }
+        while True:
+            c = v.getbytes(offset)
+            if c == '\x66':
+                # pre_dis_info.opmode = 1
+                pre_dis_info['opmode'] = 1
+            elif c == '\x67':
+                pre_dis_info['admode'] = 1
+            elif c == '\xf0':
+                pre_dis_info['g1'] = 1
+            elif c == '\xf2':
+                pre_dis_info['g1'] = 2
+            elif c == '\xf3':
+                pre_dis_info['g1'] = 4
+
+            elif c == '\x2e':
+                pre_dis_info['g2'] = 1
+            elif c == '\x36':
+                pre_dis_info['g2'] = 2
+            elif c == '\x3e':
+                pre_dis_info['g2'] = 3
+            elif c == '\x26':
+                pre_dis_info['g2'] = 4
+            elif c == '\x64':
+                pre_dis_info['g2'] = 5
+            elif c == '\x65':
+                pre_dis_info['g2'] = 6
+
+            elif mode == 64 and c in '@ABCDEFGHIJKLMNO':
+                x = ord(c)
+                pre_dis_info['rex_p'] = 1
+                pre_dis_info['rex_w'] = (x >> 3) & 1
+                pre_dis_info['rex_r'] = (x >> 2) & 1
+                pre_dis_info['rex_x'] = (x >> 1) & 1
+                pre_dis_info['rex_b'] = (x >> 0) & 1
+                offset += 1
+                break
+            else:
+                c = ''
+                break
+            pre_dis_info['prefix'] += c
+            offset += 1
+        # pre_dis_info.b = v[:offset]
+        return pre_dis_info, v, mode, offset, offset - offset_o
+
+    @classmethod
+    def get_cls_instance(cls, cc, mode, infos=None):
+        for opmode in [0, 1]:
+            for admode in [0, 1]:
+                # c = cls.all_mn_inst[cc][0]
+                c = cc()
+                c.init_class()
+
+                c.reset_class()
+                c.add_pre_dis_info()
+                c.dup_info(infos)
+
+                c.mode = mode
+                c.opmode = opmode
+                c.admode = admode
+
+                if hasattr(c, "fopmode") and c.fopmode.mode == 64:
+                    c.rex_w.value = 1
+                yield c
+
+    def post_dis(self):
+        if self.g2.value:
+            for a in self.args:
+                if not isinstance(a.expr, ExprMem):
+                    continue
+                m = a.expr
+                a.expr = ExprMem(
+                    ExprOp('segm', enc2segm[self.g2.value], m.arg), m.size)
+        if self.name == 'LEA':
+            if not isinstance(self.args[1].expr, ExprMem):
+                return None
+        return self
+
+    def dup_info(self, infos):
+        if infos is not None:
+            self.g1.value = infos.g1.value
+            self.g2.value = infos.g2.value
+
+    def reset_class(self):
+        super(mn_x86, self).reset_class()
+        # self.rex_w.value, self.rex_b.value,
+        # self.rex_x.value = None, None, None
+        # self.opmode.value, self.admode.value = None, None
+        if hasattr(self, "opmode"):
+            del(self.opmode)
+        if hasattr(self, "admode"):
+            del(self.admode)
+        # self.opmode = 0
+        # self.admode = 0
+
+    def add_pre_dis_info(self, pre_dis_info=None):
+        # print 'add_pre_dis_info', pre_dis_info
+
+        if pre_dis_info is None:
+            return True
+        if hasattr(self, "prefixed") and self.prefixed.default == "\x66":
+            pre_dis_info['opmode'] = 0
+            # if self.opmode != 0:
+            #    return False
+
+        # if pre_dis_info['opmode'] != self.opmode:
+        #    return False
+        # if pre_dis_info['admode'] != self.admode:
+        #    return False
+        self.opmode = pre_dis_info['opmode']
+        self.admode = pre_dis_info['admode']
+
+        if hasattr(self, 'no_xmm_pref') and\
+                pre_dis_info['prefix'] and\
+                pre_dis_info['prefix'][-1] in '\x66\xf2\xf3':
+            return False
+        if (hasattr(self, "prefixed") and
+            not pre_dis_info['prefix'].endswith(self.prefixed.default)):
+            return False
+        # print self.rex_w.value, pre_dis_info['rex_w']
+        # print 'rex', self.rex_w.value, self.rex_b.value, self.rex_x.value
+        if (self.rex_w.value is not None and
+            self.rex_w.value != pre_dis_info['rex_w']):
+            return False
+        else:
+            self.rex_w.value = pre_dis_info['rex_w']
+        self.rex_r.value = pre_dis_info['rex_r']
+        self.rex_b.value = pre_dis_info['rex_b']
+        self.rex_x.value = pre_dis_info['rex_x']
+        self.rex_p.value = pre_dis_info['rex_p']
+        self.g1.value = pre_dis_info['g1']
+        self.g2.value = pre_dis_info['g2']
+        self.prefix = pre_dis_info['prefix']
+        # self.prefixed = pre_dis_info['prefixed']
+
+        """
+        if hasattr(self, "p_"):
+            self.prefixed = self.p_.default
+            if self.p_.default == "\x66":
+                pre_dis_info['opmode'] = 0
+                if self.opmode != 0:
+                    return False
+        #self.pre_dis_info = pre_dis_info
+        """
+        return True
+
+    def post_asm(self, v):
+        return v
+
+    def encodefields(self, decoded):
+        v = super(mn_x86, self).encodefields(decoded)
+        if hasattr(self, 'prefixed'):
+            v = self.prefixed.default + v
+
+        rex = 0x40
+        if self.g1.value is None:
+            self.g1.value = 0
+        if self.g2.value is None:
+            self.g2.value = 0
+
+        if self.rex_w.value:
+            rex |= 0x8
+        if self.rex_r.value:
+            rex |= 0x4
+        if self.rex_x.value:
+            rex |= 0x2
+        if self.rex_b.value:
+            rex |= 0x1
+        if rex != 0x40 or self.rex_p.value == 1:
+            v = chr(rex) + v
+        if self.g1.value & 1:
+            v = "\xf0" + v
+        if self.g1.value & 2:
+            if hasattr(self, 'no_xmm_pref'):
+                return None
+            v = "\xf2" + v
+        if self.g1.value & 4:
+            if hasattr(self, 'no_xmm_pref'):
+                return None
+            v = "\xf3" + v
+        if self.g2.value:
+            v = {1: '\x2e', 2: '\x36', 3: '\x3e', 4:
+                 '\x26', 5: '\x64', 6: '\x65'}[self.g2.value] + v
+        # mode prefix
+        if hasattr(self, "admode") and self.admode:
+            v = "\x67" + v
+
+        if hasattr(self, "opmode") and self.opmode:
+            if hasattr(self, 'no_xmm_pref'):
+                return None
+            v = "\x66" + v
+
+        return v
+
+    def getnextflow(self, symbol_pool):
+        raise NotImplementedError('not fully functional')
+        return self.offset + 4
+
+    def ir_pre_instruction(self):
+        return [ExprAff(mRIP[self.mode],
+            ExprInt_from(mRIP[self.mode], self.offset + self.l))]
+
+    @classmethod
+    def filter_asm_candidates(cls, instr, candidates):
+
+        cand_same_mode = []
+        cand_diff_mode = []
+        out = []
+        for c, v in candidates:
+            if (hasattr(c, 'no_xmm_pref') and
+                (c.g1.value & 2 or c.g1.value & 4 or c.opmode)):
+                continue
+            if hasattr(c, "fopmode") and v_opmode(c) != c.fopmode.mode:
+                # print 'DROP', c, v_opmode(c), c.fopmode.mode
+                continue
+            if hasattr(c, "fadmode") and v_admode(c) != c.fadmode.mode:
+                # print 'DROP', c, v_opmode(c), c.fopmode.mode
+                continue
+            # relative dstflow must not have opmode set
+            # (affect IP instead of EIP for instance)
+            if (instr.dstflow() and
+                instr.name not in ["JCXZ", "JECXZ", "JRCXZ"] and
+                len(instr.args) == 1 and
+                    isinstance(instr.args[0], ExprInt) and c.opmode):
+                continue
+
+            out.append((c, v))
+        candidates = out
+        # return [x[1][0] for x in candidates]
+        for c, v in candidates:
+            if v_opmode(c) == instr.mode:
+                cand_same_mode += v
+        for c, v in candidates:
+            if v_opmode(c) != instr.mode:
+                cand_diff_mode += v
+        cand_same_mode.sort(key=lambda x: len(x))
+        cand_diff_mode.sort(key=lambda x: len(x))
+        return cand_same_mode + cand_diff_mode
+
+
+class bs8(bs):
+    prio = default_prio
+
+    def __init__(self, v, cls=None, fname=None, **kargs):
+        super(bs8, self).__init__(int2bin(v, 8), 8,
+                                  cls=cls, fname=fname, **kargs)
+
+
+class bs_modname_size(bs_divert):
+    prio = 1
+
+    def divert(self, i, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            fopmode = opmode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode']))
+            mode = dct['mode']
+            size, opmode, admode = dct['mode'], dct['opmode'], dct['admode']
+            # no mode64 existance in name means no 64bit version of mnemo
+            if mode == 64:
+                if mode in self.args['name']:
+                    nfields = fields[:]
+                    f, i = getfieldindexby_name(nfields, 'rex_w')
+                    # f = bs("1", l=0, fname = 'rex_w')
+                    f = bs("1", l=0, cls=(bs_fbit,), fname="rex_w")
+                    osize = v_opmode_info(size, opmode, 1, 0)
+                    nfields[i] = f
+                    nfields = nfields[:-1]
+                    args = dict(self.args)
+                    ndct = dict(dct)
+                    if osize in self.args['name']:
+                        ndct['name'] = self.args['name'][osize]
+                        out.append((cls, ndct['name'], bases, ndct, nfields))
+
+                    nfields = fields[:]
+                    nfields = nfields[:-1]
+                    f, i = getfieldindexby_name(nfields, 'rex_w')
+                    # f = bs("0", l=0, fname = 'rex_w')
+                    f = bs("0", l=0, cls=(bs_fbit,), fname="rex_w")
+                    osize = v_opmode_info(size, opmode, 0, 0)
+                    nfields[i] = f
+                    args = dict(self.args)
+                    ndct = dict(dct)
+                    if osize in self.args['name']:
+                        ndct['name'] = self.args['name'][osize]
+                        out.append((cls, ndct['name'], bases, ndct, nfields))
+            else:
+                l = opmode_prefix((dct['mode'], dct['opmode'], dct['admode']))
+                osize = v_opmode_info(size, opmode, None, 0)
+                nfields = fields[:-1]
+                args = dict(self.args)
+                ndct = dict(dct)
+                if osize in self.args['name']:
+                    ndct['name'] = self.args['name'][osize]
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class bs_modname_jecx(bs_divert):
+    prio = 1
+
+    def divert(self, i, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            fopmode = opmode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode']))
+            mode = dct['mode']
+            size, opmode, admode = dct['mode'], dct['opmode'], dct['admode']
+
+            nfields = fields[:]
+            nfields = nfields[:-1]
+            args = dict(self.args)
+            ndct = dict(dct)
+            if mode == 64:
+                if admode:
+                    ndct['name'] = "JECXZ"
+                else:
+                    ndct['name'] = "JRCXZ"
+            elif mode == 32:
+                if admode:
+                    ndct['name'] = "JCXZ"
+                else:
+                    ndct['name'] = "JECXZ"
+            elif mode == 16:
+                if admode:
+                    ndct['name'] = "JECXZ"
+                else:
+                    ndct['name'] = "JCXZ"
+            else:
+                raise ValueError('unhandled mode')
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class bs_modname_mode(bs_divert):
+    prio = 1
+
+    def divert(self, i, candidates):
+        out = []
+        for candidate in candidates:
+            cls, name, bases, dct, fields = candidate
+            fopmode = opmode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode']))
+            size, opmode, admode = dct['mode'], dct['opmode'], dct['admode']
+
+            mode = dct['mode']
+            l = opmode_prefix((dct['mode'], dct['opmode'], dct['admode']))
+            osize = v_opmode_info(size, opmode, None, 0)
+            nfields = fields[:-1]
+            args = dict(self.args)
+            ndct = dict(dct)
+            if mode == 64 or osize == 32:
+                ndct['name'] = self.args['name'][mode]
+            else:
+                ndct['name'] = self.args['name'][16]
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class x86_imm(imm_noarg):
+    parser = base_expr
+
+    def decodeval(self, v):
+        return swap_uint(self.l, v)
+
+    def encodeval(self, v):
+        return swap_uint(self.l, v)
+
+
+class x86_imm_fix(imm_noarg):
+    parser = base_expr
+
+    def decodeval(self, v):
+        return self.ival
+
+    def encodeval(self, v):
+        if v != self.ival:
+            return False
+        return self.ival
+
+
+class x86_08(x86_imm):
+    intsize = 8
+    intmask = (1 << intsize) - 1
+
+
+class x86_16(x86_imm):
+    intsize = 16
+    intmask = (1 << intsize) - 1
+
+
+class x86_32(x86_imm):
+    intsize = 32
+    intmask = (1 << intsize) - 1
+
+
+class x86_64(x86_imm):
+    intsize = 64
+    intmask = (1 << intsize) - 1
+
+
+class x86_08_ne(x86_imm):
+    intsize = 8
+    intmask = (1 << intsize) - 1
+
+    def encode(self):
+        return True
+
+    def decode(self, v):
+        v = swap_uint(self.l, v)
+        p = self.parent
+        admode = p.v_admode()
+        e = sign_ext(v, self.intsize, admode)
+        e = ExprInt_fromsize(admode, e)
+        self.expr = e
+        return True
+
+
+class x86_16_ne(x86_08_ne):
+    intsize = 16
+    intmask = (1 << intsize) - 1
+
+
+class x86_32_ne(x86_08_ne):
+    intsize = 32
+    intmask = (1 << intsize) - 1
+
+
+class x86_64_ne(x86_08_ne):
+    intsize = 64
+    intmask = (1 << intsize) - 1
+
+
+class x86_s08to16(x86_imm):
+    in_size = 8
+    out_size = 16
+
+    def myexpr(self, x):
+        return ExprInt16(x)
+
+    def int2expr(self, v):
+        return self.myexpr(v)
+
+    def expr2int(self, e):
+        if not isinstance(e, ExprInt):
+            return None
+        v = int(e.arg)
+        if v & ~((1 << self.l) - 1) != 0:
+            return None
+        return v
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        if self.parent.v_opmode() == 64:
+            self.expr = ExprInt64(sign_ext(v, self.in_size, 64))
+        else:
+            if (1 << (self.l - 1)) & v:
+                v = sign_ext(v, self.l, self.out_size)
+            self.expr = self.myexpr(v)
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            return False
+        v = int(self.expr.arg)
+        opmode = self.parent.v_opmode()
+
+        out_size = self.out_size
+        if opmode != self.out_size:
+            if opmode == 32 and self.out_size == 64:
+                out_size = opmode
+                if v == sign_ext(
+                    int(v & ((1 << self.in_size) - 1)), self.in_size, out_size):
+                    pass
+                else:
+                    # print 'cannot encode1', hex(v),
+                    # print hex(sign_ext(int(v&((1<<self.in_size)-1)),
+                    #     self.in_size, out_size))
+                    # test with rex_w
+                    self.parent.rex_w.value = 1
+                    opmode = self.parent.v_opmode()
+                    out_size = opmode
+                    if (v != sign_ext(
+                        int(v & ((1 << self.in_size) - 1)),
+                        self.in_size, out_size)):
+                        # print 'cannot encode2', hex(v),
+                        # hex(sign_ext(int(v&((1<<self.in_size)-1)),
+                        # self.in_size, out_size))
+                        return False
+                    else:
+                        pass
+            else:
+                pass
+        if v != sign_ext(
+            int(v & ((1 << self.in_size) - 1)), self.in_size, out_size):
+            # print 'cannot encode3', hex(v),
+            # hex(sign_ext(int(v&((1<<self.in_size)-1)), self.in_size,
+            # self.out_size))
+            return False
+        v = self.encodeval(v)
+        self.value = (v & 0xffffffff) & self.lmask
+        return True
+
+    def decodeval(self, v):
+        return swap_uint(self.l, v)
+
+    def encodeval(self, v):
+        return swap_sint(self.l, v)
+
+
+class x86_s08to32(x86_s08to16):
+    myexpr = lambda self, x: ExprInt32(x)
+    in_size = 8
+    out_size = 32
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        if self.parent.rex_w.value == 1:
+            v = ExprInt64(sign_ext(v, self.in_size, 64))
+        else:
+            v = ExprInt32(sign_ext(v, self.in_size, 32))
+
+        self.expr = v
+        # print "INT1", self.parent.rex_w.value, self.expr, self.expr.size
+        return True
+
+
+class x86_s08to64(x86_s08to16):
+    myexpr = lambda self, x: ExprInt64(x)
+    in_size = 8
+    out_size = 64
+
+    def decode(self, v):
+        v = v & self.lmask
+        v = self.decodeval(v)
+        if self.parent.rex_w.value == 1:
+            v = ExprInt64(sign_ext(v, self.in_size, 64))
+        else:
+            v = ExprInt32(sign_ext(v, self.in_size, 32))
+
+        self.expr = v
+        # print "INT1X", self.parent.prefix.rex_w, self.expr, self.expr.size
+        return True
+
+
+class x86_s32to64(x86_s08to32):
+    myexpr = lambda self, x: ExprInt64(x)
+    in_size = 32
+    out_size = 64
+
+
+class bs_eax(m_arg):
+    reg_info = r_eax_all
+    rindex = 0
+    parser = reg_info.parser
+
+    def decode(self, v):
+        p = self.parent
+        e = None
+        if hasattr(p, 'w8') and p.w8.value == 0:
+            e = regs08_expr[self.rindex]
+        else:
+            e = size2gpregs[p.v_opmode()].expr[self.rindex]
+        self.expr = e
+        return True
+
+    def encode(self):
+        self.value = 0
+        p = self.parent
+        e = self.expr
+        # print "EEEEE", e, p.w8.value
+        # print 'XXX', p.mode, p.opmode
+        osize = p.v_opmode()
+        if hasattr(p, 'w8'):
+            if p.w8.value is None:
+                # XXX TODO: priority in w8 erase?
+                if e.size == 8:
+                    p.w8.value = 0
+                else:
+                    p.w8.value = 1
+        if hasattr(p, 'w8') and p.w8.value == 0:
+            return e == regs08_expr[self.rindex]
+        elif p.mode in [16, 32]:
+            return e == size2gpregs[osize].expr[self.rindex]
+        elif p.mode == 64:
+            if e == size2gpregs[64].expr[self.rindex]:
+                p.rex_w.value = 1
+                return True
+            elif e == size2gpregs[osize].expr[self.rindex]:
+                return True
+            return False
+
+
+class bs_seg(m_arg):
+    reg_info = r_eax_all
+    rindex = 0
+    parser = reg_info.parser
+
+    def decode(self, v):
+        self.expr = self.reg_info.expr[0]
+        return True
+
+    def encode(self):
+        self.value = 0
+        return self.expr == self.reg_info.expr[0]
+
+
+class bs_edx(bs_eax):
+    reg_info = r_edx_all
+    rindex = 2
+    parser = reg_info.parser
+
+
+class bs_st(bs_eax):
+    reg_info = r_st_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_cs(bs_seg):
+    reg_info = r_cs_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_ds(bs_seg):
+    reg_info = r_ds_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_es(bs_seg):
+    reg_info = r_es_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_ss(bs_seg):
+    reg_info = r_ss_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_fs(bs_seg):
+    reg_info = r_fs_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class bs_gs(bs_seg):
+    reg_info = r_gs_all
+    rindex = 0
+    parser = reg_info.parser
+
+
+class x86_reg_st(reg_noarg, m_arg):
+    reg_info = r_st_all
+    parser = reg_info.parser
+
+
+class bs_sib_scale(bs_divert):
+    bsname = "sib_scale"
+
+    def divert(self, i, candidates):
+        out = []
+        done = False
+        for cls, name, bases, dct, fields in candidates:
+            if (not (admode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode'])) != 16 and
+                'rm' in dct and dct['rm'] == 0b100 and
+                'mod' in dct and dct['mod'] != 0b11)):
+                ndct = dict(dct)
+                nfields = fields[:]
+                nfields[i] = None
+                ndct[self.args['fname']] = None
+                out.append((cls, ndct['name'], bases, ndct, nfields))
+                continue
+
+            nfields = fields[:]
+            args = dict(self.args)
+            ndct = dict(dct)
+            f = bs(**args)
+            nfields[i] = f
+            ndct[self.args['fname']] = None
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+class bs_sib_index(bs_sib_scale):
+    pass
+
+
+class bs_sib_base(bs_sib_scale):
+    pass
+
+
+class bs_disp(bs_divert):
+
+    def divert(self, i, candidates):
+        out = []
+        done = False
+        for cls, name, bases, dct, fields in candidates:
+            ndct = dict(dct)
+            nfields = fields[:]
+            if (admode_prefix(
+                (dct['mode'], dct['opmode'], dct['admode'])) == 16):
+                if 'mod' in dct and dct['mod'] == 0b00 and \
+                        'rm' in dct and dct['rm'] == 0b110:
+                    nfields[i] = bs(
+                        l=16, cls=(x86_16_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b01:
+                    nfields[i] = bs(
+                        l=8, cls=(x86_08_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b10:
+                    nfields[i] = bs(
+                        l=16, cls=(x86_16_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+            else:
+                if 'mod' in dct and dct['mod'] == 0b00 and \
+                        'rm' in dct and dct['rm'] == 0b101:
+                    nfields[i] = bs(
+                        l=32, cls=(x86_32_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b01:
+                    nfields[i] = bs(
+                        l=8, cls=(x86_08_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+                elif 'mod' in dct and dct['mod'] == 0b10:
+                    nfields[i] = bs(
+                        l=32, cls=(x86_32_ne,), fname=self.args['fname'])
+                    ndct[self.args['fname']] = True
+                    out.append((cls, ndct['name'], bases, ndct, nfields))
+                    continue
+
+            nfields[i] = None
+            ndct[self.args['fname']] = None
+            out.append((cls, ndct['name'], bases, ndct, nfields))
+        return out
+
+
+def getmodrm(c):
+    return (c >> 6) & 3, (c >> 3) & 7, c & 7
+
+
+def setmodrm(mod, re, rm):
+    return ((mod & 3) << 6) | ((re & 7) << 3) | (rm & 7)
+
+
+def sib(c):
+    return modrm(c)
+
+db_afs_64 = []
+sib_64_s08_ebp = []
+
+
+def gen_modrm_form():
+    global db_afs_64, sib_64_s08_ebp
+    ebp = 5
+
+    sib_s08_ebp = [{f_isad: True} for i in range(0x100)]
+    sib_u32_ebp = [{f_isad: True} for i in range(0x100)]
+    sib_u32 = [{f_isad: True} for i in range(0x100)]
+
+    sib_u64 = []
+    for rex_x in xrange(2):
+        o = []
+        for rex_b in xrange(2):
+            x = [{f_isad: True} for i in range(0x100)]
+            o.append(x)
+        sib_u64.append(o)
+
+    sib_u64_ebp = []
+    for rex_x in xrange(2):
+        o = []
+        for rex_b in xrange(2):
+            x = [{f_isad: True} for i in range(0x100)]
+            o.append(x)
+        sib_u64_ebp.append(o)
+
+    sib_64_s08_ebp = []
+    for rex_x in xrange(2):
+        o = []
+        for rex_b in xrange(2):
+            x = [{f_isad: True} for i in range(0x100)]
+            o.append(x)
+        sib_64_s08_ebp.append(o)
+
+    for sib_rez in [sib_s08_ebp,
+                    sib_u32_ebp,
+                    sib_u32,
+                    sib_64_s08_ebp,
+                    sib_u64_ebp,
+                    sib_u64,
+                    ]:
+        for index in range(0x100):
+            ss, i, b = getmodrm(index)
+
+            if b == 0b101:
+                if sib_rez == sib_s08_ebp:
+                    sib_rez[index][f_imm] = f_s08
+                    sib_rez[index][ebp] = 1
+                elif sib_rez == sib_u32_ebp:
+                    sib_rez[index][f_imm] = f_u32
+                    sib_rez[index][ebp] = 1
+                elif sib_rez == sib_u32:
+                    sib_rez[index][f_imm] = f_u32
+                elif sib_rez == sib_u64_ebp:
+                    for rex_b in xrange(2):
+                        for rex_x in xrange(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_u32
+                            sib_rez[rex_x][rex_b][index][ebp + 8 * rex_b] = 1
+                elif sib_rez == sib_u64:
+                    for rex_b in xrange(2):
+                        for rex_x in xrange(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_u32
+                elif sib_rez == sib_64_s08_ebp:
+                    for rex_b in xrange(2):
+                        for rex_x in xrange(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_s08
+                            sib_rez[rex_x][rex_b][index][ebp + 8 * rex_b] = 1
+
+            else:
+                if sib_rez == sib_s08_ebp:
+                    sib_rez[index][b] = 1
+                    sib_rez[index][f_imm] = f_s08
+                elif sib_rez == sib_u32_ebp:
+                    sib_rez[index][b] = 1
+                    sib_rez[index][f_imm] = f_u32
+                elif sib_rez == sib_u32:
+                    sib_rez[index][b] = 1
+                elif sib_rez == sib_u64_ebp:
+                    for rex_b in xrange(2):
+                        for rex_x in xrange(2):
+                            sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_u32
+                elif sib_rez == sib_u64:
+                    for rex_b in xrange(2):
+                        for rex_x in xrange(2):
+                            sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1
+                elif sib_rez == sib_64_s08_ebp:
+                    for rex_b in xrange(2):
+                        for rex_x in xrange(2):
+                            sib_rez[rex_x][rex_b][index][f_imm] = f_s08
+                            sib_rez[rex_x][rex_b][index][b + 8 * rex_b] = 1
+
+            if i == 0b100 and sib_rez in [sib_s08_ebp, sib_u32_ebp, sib_u32]:
+                continue
+
+            if sib_rez in [sib_s08_ebp, sib_u32_ebp, sib_u32]:
+                tmp = i
+                if not tmp in sib_rez[index]:
+                    sib_rez[index][tmp] = 0  # 1 << ss
+                sib_rez[index][tmp] += 1 << ss
+            else:
+                for rex_b in xrange(2):
+                    for rex_x in xrange(2):
+                        tmp = i + 8 * rex_x
+                        if i == 0b100 and rex_x == 0:
+                            continue
+                        if not tmp in sib_rez[rex_x][rex_b][index]:
+                            sib_rez[rex_x][rex_b][index][tmp] = 0  # 1 << ss
+                        sib_rez[rex_x][rex_b][index][tmp] += 1 << ss
+
+    # 32bit
+    db_afs_32 = [None for i in range(0x100)]
+    for i in range(0x100):
+        index = i
+        mod, re, rm = getmodrm(i)
+
+        if mod == 0b00:
+            if rm == 0b100:
+                db_afs_32[index] = sib_u32
+            elif rm == 0b101:
+                db_afs_32[index] = {f_isad: True, f_imm: f_u32}
+            else:
+                db_afs_32[index] = {f_isad: True, rm: 1}
+        elif mod == 0b01:
+            if rm == 0b100:
+                db_afs_32[index] = sib_s08_ebp
+                continue
+            tmp = {f_isad: True, rm: 1, f_imm: f_s08}
+            db_afs_32[index] = tmp
+
+        elif mod == 0b10:
+            if rm == 0b100:
+                db_afs_32[index] = sib_u32_ebp
+            else:
+                db_afs_32[index] = {f_isad: True, rm: 1, f_imm: f_u32}
+        elif mod == 0b11:
+            db_afs_32[index] = {f_isad: False, rm: 1}
+
+    # 64bit
+    db_afs_64 = [None for i in range(0x400)]
+    for i in range(0x400):
+        index = i
+        rex_x = (index >> 9) & 1
+        rex_b = (index >> 8) & 1
+        mod, re, rm = getmodrm(i & 0xff)
+
+        if mod == 0b00:
+            if rm == 0b100:
+                db_afs_64[i] = sib_u64[rex_x][rex_b]
+            elif rm == 0b101:
+                db_afs_64[i] = {f_isad: True, f_imm: f_u32, 16: 1}
+            else:
+                db_afs_64[i] = {f_isad: True, rm + 8 * rex_b: 1}
+        elif mod == 0b01:
+            if rm == 0b100:
+                db_afs_64[i] = sib_64_s08_ebp[rex_x][rex_b]
+                continue
+            tmp = {f_isad: True, rm + 8 * rex_b: 1, f_imm: f_s08}
+            db_afs_64[i] = tmp
+
+        elif mod == 0b10:
+            if rm == 0b100:
+                db_afs_64[i] = sib_u64_ebp[rex_x][rex_b]
+            else:
+                db_afs_64[i] = {f_isad: True, rm + 8 * rex_b: 1, f_imm: f_u32}
+        elif mod == 0b11:
+            db_afs_64[i] = {f_isad: False, rm + 8 * rex_b: 1}
+
+    # 16bit
+    db_afs_16 = [None for i in range(0x100)]
+    _si = 6
+    _di = 7
+    _bx = 3
+    _bp = 5
+    for i in range(0x100):
+        index = i
+        mod, re, rm = getmodrm(i)
+
+        if mod == 0b00:
+            if rm == 0b100:
+                db_afs_16[index] = {f_isad: True, _si: 1}
+            elif rm == 0b101:
+                db_afs_16[index] = {f_isad: True, _di: 1}
+            elif rm == 0b110:
+                db_afs_16[index] = {
+                    f_isad: True, f_imm: f_u16}  # {f_isad:True,_bp:1}
+            elif rm == 0b111:
+                db_afs_16[index] = {f_isad: True, _bx: 1}
+            else:
+                db_afs_16[index] = {f_isad: True,
+                         [_si, _di][rm % 2]: 1,
+                    [_bx, _bp][(rm >> 1) % 2]: 1}
+        elif mod in [0b01, 0b10]:
+            if mod == 0b01:
+                my_imm = f_s08
+            else:
+                my_imm = f_u16
+
+            if rm == 0b100:
+                db_afs_16[index] = {f_isad: True, _si: 1, f_imm: my_imm}
+            elif rm == 0b101:
+                db_afs_16[index] = {f_isad: True, _di: 1, f_imm: my_imm}
+            elif rm == 0b110:
+                db_afs_16[index] = {f_isad: True, _bp: 1, f_imm: my_imm}
+            elif rm == 0b111:
+                db_afs_16[index] = {f_isad: True, _bx: 1, f_imm: my_imm}
+            else:
+                db_afs_16[index] = {f_isad: True,
+                         [_si, _di][rm % 2]: 1,
+                    [_bx, _bp][(rm >> 1) % 2]: 1,
+                    f_imm: my_imm}
+
+        elif mod == 0b11:
+            db_afs_16[index] = {f_isad: False, rm: 1}
+
+    byte2modrm = {}
+    byte2modrm[16] = db_afs_16
+    byte2modrm[32] = db_afs_32
+    byte2modrm[64] = db_afs_64
+
+    modrm2byte = {16: defaultdict(list),
+                  32: defaultdict(list),
+                  64: defaultdict(list),
+                  }
+    for size, db_afs in byte2modrm.items():
+        for i, modrm in enumerate(db_afs):
+            if not isinstance(modrm, list):
+                modrm = modrm.items()
+                modrm.sort()
+                modrm = tuple(modrm)
+                modrm2byte[size][modrm].append(i)
+                continue
+            for j, modrm_f in enumerate(modrm):
+                modrm_f = modrm_f.items()
+                modrm_f.sort()
+                modrm_f = tuple(modrm_f)
+                modrm2byte[size][modrm_f].append((i, j))
+
+    return byte2modrm, modrm2byte
+
+byte2modrm, modrm2byte = gen_modrm_form()
+
+
+# ret is modr; ret is displacement
+def exprfindmod(e, o=None):
+    if o is None:
+        o = {}
+    if isinstance(e, ExprInt):
+        return e
+    if isinstance(e, ExprId):
+        i = size2gpregs[e.size].expr.index(e)
+        o[i] = 1
+        return None
+    elif isinstance(e, ExprOp):
+        out = None
+        if e.op == '+':
+            for a in e.args:
+                r = exprfindmod(a, o)
+                if out and r1:
+                    raise ValueError('multiple displacement!')
+                out = r
+            return out
+        elif e.op == "*":
+            mul = int(e.args[1].arg)
+            a = e.args[0]
+            i = size2gpregs[a.size].expr.index(a)
+            o[i] = mul
+        else:
+            raise ValueError('bad op')
+    return None
+
+
+def expr2modrm(e, p, w8, sx=0, xmm=0, mm=0):
+    o = defaultdict(lambda x: 0)
+    if e.size == 64 and not e in gpregs_mm.expr:
+        if hasattr(p, 'sd'):
+            p.sd.value = 1
+        # print 'set64pref', str(e)
+        elif hasattr(p, 'wd'):
+            pass
+        elif hasattr(p, 'stk'):
+            pass
+        else:
+            p.rex_w.value = 1
+    opmode = p.v_opmode()
+    if sx == 1:
+        opmode = 16
+    if sx == 2:
+        opmode = 32
+    if e.size == 8 and w8 != 0:
+        return None, None, False
+
+    if w8 == 0 and e.size != 8:
+        return None, None, False
+
+    if not isinstance(e, ExprMem):
+        o[f_isad] = False
+        if xmm:
+            if e in gpregs_xmm.expr:
+                i = gpregs_xmm.expr.index(e)
+                o[i] = 1
+                return [o], None, True
+            else:
+                return None, None, False
+        if mm:
+            if e in gpregs_mm.expr:
+                i = gpregs_mm.expr.index(e)
+                o[i] = 1
+                return [o], None, True
+            else:
+                return None, None, False
+        if w8 == 0:
+            # if (p.v_opmode() == 64 or p.rex_p.value == 1) and e in
+            # gpregs08_64.expr:
+            if p.mode == 64 and e in gpregs08_64.expr:
+                r = gpregs08_64
+                p.rex_p.value = 1
+            else:
+                p.rex_p.value = 0
+                p.rex_x.value = 0
+                r = size2gpregs[8]
+            if not e in r.expr:
+                return None, None, False
+            i = r.expr.index(e)
+            o[i] = 1
+            return [o], None, True
+        # print "ttt", opmode, e.size
+        if opmode != e.size:
+            # print "FFFF"
+            return None, None, False
+        if not e in size2gpregs[opmode].expr:
+            return None, None, False
+        i = size2gpregs[opmode].expr.index(e)
+        # print 'aaa', p.mode, i
+        if i > 7:
+            if p.mode == 64:
+                # p.rex_b.value = 1
+                # i -=7
+                # print "SET REXB"
+                pass
+            else:
+                return None, None, False
+        o[i] = 1
+        return [o], None, True
+    if e.is_op_segm() and isinstance(e.arg.args[0], ExprInt):
+        return None, None, False
+
+    if e.is_op_segm():
+        segm = e.arg.args[0]
+        ptr = e.arg.args[1]
+    else:
+        segm = None
+        ptr = e.arg
+
+    o[f_isad] = True
+    ad_size = ptr.size
+    admode = p.v_admode()
+    if ad_size != admode:
+        return None, None, False
+    """
+    if e.size == 64:
+        if hasattr(p, 'sd'):
+            p.sd.value = 1
+        else:
+            p.rex_w.value = 1
+    """
+
+    if w8 == 1 and e.size != opmode:  # p.v_opmode():
+        if not (hasattr(p, 'sd') or hasattr(p, 'wd')):
+            return None, None, False
+    # print 'tttt'
+
+    if hasattr(p, 'wd'):
+        s = e.size
+        if s == 16:
+            p.wd.value = 1
+        elif s == 32:
+            pass
+        else:
+            return None, None, False
+
+    if p.mode == 64 and ptr.size == 32:
+        if p.admode != 1:
+            return None, None, False
+
+    o = {f_isad: True}
+    disp = exprfindmod(ptr, o)
+    out = []
+    if disp is None:
+        # add 0 disp
+        disp = ExprInt32(0)
+    if disp is not None:
+        for s, x in [(f_s08, ExprInt8), (f_s16, ExprInt16), (f_s32, ExprInt32),
+                     (f_u08, ExprInt8), (f_u16, ExprInt16), (f_u32, ExprInt32)]:
+            # print "1", disp
+            v = x(int(disp.arg))
+            # print "2", v, hex(sign_ext(int(v.arg), v.size, disp.size))
+            if int(disp.arg) != sign_ext(int(v.arg), v.size, disp.size):
+                # print 'nok'
+                continue
+            # print 'ok', s, v
+            x1 = dict(o)
+            x1[f_imm] = (s, v)
+            out.append(x1)
+    else:
+        out = [o]
+    return out, segm, True
+
+
+def modrm2expr(m, p, w8, sx=0, xmm=0, mm=0):
+    o = []
+    if not m[f_isad]:
+        k = [x[0] for x in m.items() if x[1] == 1]
+        if len(k) != 1:
+            raise ValueError('strange reg encoding %r' % m)
+        k = k[0]
+        if w8 == 0:
+            opmode = 8
+        elif sx == 1:
+            opmode = 16
+        elif sx == 2:
+            opmode = 32
+        else:
+            opmode = p.v_opmode()
+        """
+        if k > 7:
+            # XXX HACK TODO
+            e = size2gpregs[64].expr[k]
+        else:
+            e = size2gpregs[opmode].expr[k]
+        """
+        # print 'yyy', opmode, k
+        if xmm:
+            e = gpregs_xmm.expr[k]
+        elif mm:
+            e = gpregs_mm.expr[k]
+        elif opmode == 8 and (p.v_opmode() == 64 or p.rex_p.value == 1):
+            e = gpregs08_64.expr[k]
+        else:
+            e = size2gpregs[opmode].expr[k]
+        return e
+    # print "enc", m, p.v_admode(), p.prefix.opmode, p.prefix.admode
+    admode = p.v_admode()
+    opmode = p.v_opmode()
+    for k, v in m.items():
+        if type(k) in [int, long]:
+            e = size2gpregs[admode].expr[k]
+            if v != 1:
+                e = ExprInt_fromsize(admode, v) * e
+            o.append(e)
+    # print [str(x) for x in o]
+    if f_imm in m:
+        if p.disp.value is None:
+            return None
+        o.append(ExprInt_fromsize(admode, p.disp.expr.arg))
+    e = ExprOp('+', *o)
+    if w8 == 0:
+        opmode = 8
+    elif sx == 1:
+        opmode = 16
+    elif sx == 2:
+        opmode = 32
+    e = ExprMem(e, size=opmode)
+    # print "mem size", opmode, e
+    return e
+
+
+class x86_rm_arg(m_arg):
+    parser = rmarg
+
+    def fromstring(self, s, parser_result=None):
+        start, stop = super(x86_rm_arg, self).fromstring(s, parser_result)
+        e = self.expr
+        p = self.parent
+        if start is None:
+            return None, None
+        s = e.size
+        return start, stop
+
+    @staticmethod
+    def arg2str(e):
+        if isinstance(e, ExprId):
+            o = str(e)
+        elif isinstance(e, ExprMem):
+            sz = {8: 'BYTE', 16: 'WORD', 32: 'DWORD',
+                  64: 'QWORD', 80: 'TBYTE'}[e.size]
+            segm = ""
+            if e.is_op_segm():
+                segm = "%s:" % e.arg.args[0]
+                e = e.arg.args[1]
+            else:
+                e = e.arg
+            if isinstance(e, ExprOp):
+                # s = str(e.arg)[1:-1]
+                s = str(e).replace('(', '').replace(')', '')
+            else:
+                s = str(e)
+            o = sz + ' PTR %s[%s]' % (segm, s)
+        else:
+            raise ValueError('check this %r' % e)
+        return "%s" % o
+
+    def get_modrm(self):
+        p = self.parent
+        admode = p.v_admode()
+
+        if not admode in [16, 32, 64]:
+            raise ValueError('strange admode %r', admode)
+        v = setmodrm(p.mod.value, 0, p.rm.value)
+        v |= p.rex_b.value << 8
+        v |= p.rex_x.value << 9
+        if p.mode == 64:
+            # XXXx to check
+            admode = 64
+
+        xx = byte2modrm[admode][v]
+        if isinstance(xx, list):
+            if not p.sib_scale:
+                return False
+            v = setmodrm(p.sib_scale.value,
+                         p.sib_index.value,
+                         p.sib_base.value)
+            # print 'SIB', hex(v)
+            # v |= p.rex_b.value << 8
+            # v |= p.rex_x.value << 9
+            # if v >= 0x100:
+            #    pass
+            xx = xx[v]
+        return xx
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        mm = hasattr(self.parent, "mm")
+        xmm = hasattr(self.parent, "xmm")
+        e = modrm2expr(xx, p, 1, xmm=xmm, mm=mm)
+        if e is None:
+            return False
+        self.expr = e
+        return True
+
+    def gen_cand(self, v_cand, admode):
+        # print "GEN CAND"
+        if not admode in modrm2byte:
+            # XXX TODO: 64bit
+            raise StopIteration
+        if not v_cand:
+            raise StopIteration
+
+        p = self.parent
+        o_rex_x = p.rex_x.value
+        o_rex_b = p.rex_b.value
+        # add candidate without 0 imm
+        new_v_cand = []
+        moddd = False
+        for v in v_cand:
+            new_v_cand.append(v)
+            # print 'CANDI', v, admode
+            if f_imm in v and int(v[f_imm][1].arg) == 0:
+                v = dict(v)
+                del(v[f_imm])
+                new_v_cand.append(v)
+                moddd = True
+
+        v_cand = new_v_cand
+
+        out_c = []
+        for v in v_cand:
+            disp = None
+            # patch value in modrm
+            if f_imm in v:
+                size, disp = v[f_imm]
+                disp = int(disp.arg)
+                # disp = swap_uint(f_imm2size[size], int(disp))
+
+                v[f_imm] = size
+            vo = v
+            # print 'vv', v, disp
+            v = v.items()
+            v.sort()
+            v = tuple(v)
+            # print "II", e, admode
+            # print 'III', v
+            # if (8, 1) in v:
+            #    pass
+            if not v in modrm2byte[admode]:
+                # print 'cannot find'
+                continue
+            # print "FOUND1", v
+            xx = modrm2byte[admode][v]
+            # if opmode == 64 and admode == 64:
+            #    pdb.set_trace()
+
+            # print "FOUND2", xx
+            # default case
+            for x in xx:
+                if type(x) == tuple:
+                    modrm, sib = x
+                else:
+                    modrm = x
+                    sib = None
+                # print 'mod sib', hex(modrm), sib
+                # print p.sib_scale
+                # print p.sib_base
+                # print p.sib_index
+
+                # 16 bit cannot have sib
+                if (not sib is None) and admode == 16:
+                    continue
+                # if ((p.sib_scale and sib is None) or
+                #     (p.sib_scale is None and sib)):
+                # log.debug('dif sib %r %r'%(p.sib_scale, sib))
+                #    continue
+                # print hex(modrm), sib
+                # p.mod.value, dum, p.rm.value = getmodrm(modrm)
+                rex = modrm >> 8  # 0# XXX HACK REM temporary REX modrm>>8
+                if rex and admode != 64:
+                    continue
+                # print 'prefix', hex(rex)
+                # p.rex_x.value = o_rex_x
+                # p.rex_b.value = o_rex_b
+
+                p.rex_x.value = (rex >> 1) & 1
+                p.rex_b.value = rex & 1
+
+                if o_rex_x is not None and p.rex_x.value != o_rex_x:
+                    continue
+                if o_rex_b is not None and p.rex_b.value != o_rex_b:
+                    continue
+
+                mod, re, rm = getmodrm(modrm)
+                # check re on parent
+                if re != p.reg.value:
+                    continue
+                # p.mod.value.append(mod)
+                # p.rm.value.append(rm)
+
+                if sib:
+                    # print 'REX', p.rex_x.value, p.rex_b.value
+                    # print hex(modrm), hex(sib)
+                    # if (modrm & 0xFF == 4 and sib & 0xFF == 0x5
+                    #    and p.rex_b.value ==1 and p.rex_x.value == 0):
+                    #    pass
+                    s_scale, s_index, s_base = getmodrm(sib)
+                    # p.sib_scale.value, p.sib_index.value,
+                    # p.sib_base.value = getmodrm(sib)
+                    # p.sib_scale.decode(mod)
+                    # p.sib_index.decode(re)
+                    # p.sib_base.decode(rm)
+                    # p.sib_scale.value.append(mod)
+                    # p.sib_index.value.append(re)
+                    # p.sib_base.value.append(rm)
+                else:
+                    # p.sib_scale.value.append(None)
+                    # p.sib_index.value.append(None)
+                    # p.sib_base.value.append(None)
+                    s_scale, s_index, s_base = None, None, None
+
+                # print 'IIII', repr(p.disp), f_imm in v
+                # if p.disp and not f_imm in vo:
+                #    continue
+                # if not p.disp and f_imm in vo:
+                #    continue
+                # if p.disp:
+                #    if p.disp.l != f_imm2size[vo[f_imm]]:
+                #        continue
+                # print "DISP", repr(p.disp), p.disp.l
+                # p.disp.value = int(disp.arg)
+                # print 'append'
+                # print mod, rm, s_scale, s_index, s_base, disp
+                # print p.mod, p.rm
+                # out_c.append((mod, rm, s_scale, s_index, s_base, disp))
+                p.mod.value = mod
+                p.rm.value = rm
+                p.sib_scale.value = s_scale
+                p.sib_index.value = s_index
+                p.sib_base.value = s_base
+                p.disp.value = disp
+                if disp is not None:
+                    p.disp.l = f_imm2size[vo[f_imm]]
+
+                yield True
+
+        raise StopIteration
+
+    def encode(self):
+        e = self.expr
+        # print "eee", e
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        p = self.parent
+        admode = p.v_admode()
+        mode = e.size
+        mm = hasattr(self.parent, 'mm')
+        xmm = hasattr(self.parent, 'xmm')
+        v_cand, segm, ok = expr2modrm(e, p, 1, xmm=xmm, mm=mm)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        # print "REZ1", v_cand, ok
+        for x in self.gen_cand(v_cand, admode):
+            yield x
+
+
+class x86_rm_w8(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        e = modrm2expr(xx, p, p.w8.value)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        p = self.parent
+        if p.w8.value is None:
+            if e.size == 8:
+                p.w8.value = 0
+            else:
+                p.w8.value = 1
+
+        # print 'TTTTT', e
+        v_cand, segm, ok = expr2modrm(e, p, p.w8.value)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        # print "REZ2", v_cand, ok
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            # print 'REZ', p.rex_x.value
+            yield x
+
+
+class x86_rm_sx(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        e = modrm2expr(xx, p, p.w8.value, 1)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        p = self.parent
+        if p.w8.value is None:
+            if e.size == 8:
+                p.w8.value = 0
+            else:
+                p.w8.value = 1
+        v_cand, segm, ok = expr2modrm(e, p, p.w8.value, 1)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_sxd(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        e = modrm2expr(xx, p, 1, 2)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        p = self.parent
+        v_cand, segm, ok = expr2modrm(e, p, 1, 2)
+        if segm:
+            p.g2.value = segm2enc[segm]
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_sd(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        e = modrm2expr(xx, p, 1)
+        if not isinstance(e, ExprMem):
+            return False
+        if p.sd.value == 0:
+            e = ExprMem(e.arg, 32)
+        else:
+            e = ExprMem(e.arg, 64)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        p = self.parent
+        if not e.size in [32, 64]:
+            raise StopIteration
+        p.sd.value = 0
+        v_cand, segm, ok = expr2modrm(e, p, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_wd(x86_rm_arg):
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        e = modrm2expr(xx, p, 1)
+        if not isinstance(e, ExprMem):
+            return False
+        if p.wd.value == 0:
+            e = ExprMem(e.arg, 32)
+        else:
+            e = ExprMem(e.arg, 16)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        p = self.parent
+        p.wd.value = 0
+        v_cand, segm, ok = expr2modrm(e, p, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_m80(x86_rm_arg):
+    msize = 80
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        # print "aaa", xx
+        e = modrm2expr(xx, p, 1)
+        if not isinstance(e, ExprMem):
+            return False
+        e = ExprMem(e.arg, self.msize)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if isinstance(e, ExprInt):
+            raise StopIteration
+        if not isinstance(e, ExprMem) or e.size != self.msize:
+            raise StopIteration
+        p = self.parent
+        mode = p.mode
+        if mode == 64:
+            mode = 32
+        e = ExprMem(e.arg, mode)
+        v_cand, segm, ok = expr2modrm(e, p, 1)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_m08(x86_rm_arg):
+    msize = 8
+
+    def decode(self, v):
+        p = self.parent
+        xx = self.get_modrm()
+        e = modrm2expr(xx, p, 0)
+        self.expr = e
+        return e is not None
+
+    def encode(self):
+        e = self.expr
+        if e.size != 8:
+            raise StopIteration
+        """
+        if not isinstance(e, ExprMem) or e.size != self.msize:
+            raise StopIteration
+        """
+        p = self.parent
+        mode = p.mode
+        # if mode == 64:
+        #    mode = 32
+        # e = ExprMem(e.arg, mode)
+        v_cand, segm, ok = expr2modrm(e, p, 0)
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_m16(x86_rm_m80):
+    msize = 16
+
+
+class x86_rm_m64(x86_rm_m80):
+    msize = 64
+
+
+class x86_rm_reg_noarg(object):
+    prio = default_prio + 1
+
+    parser = gpreg
+
+    def fromstring(self, s, parser_result=None):
+        # print 'parsing reg', s, opmode
+        if not hasattr(self.parent, 'sx') and hasattr(self.parent, "w8"):
+            self.parent.w8.value = 1
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+            # print 'reg result', e, start, stop
+            if e is None:
+                return None, None
+            self.expr = e
+            if self.expr.size == 8:
+                if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'):
+                    return None, None
+                self.parent.w8.value = 0
+            return start, stop
+        try:
+            v, start, stop = self.parser.scanString(s).next()
+        except StopIteration:
+            return None, None
+        self.expr = v[0]
+        if self.expr.size == 0:
+            if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'):
+                return None, None
+            self.parent.w8.value = 0
+
+        # print 'parsed', s, self.expr
+        return start, stop
+
+    def getrexsize(self):
+        return self.parent.rex_r.value
+
+    def setrexsize(self, v):
+        self.parent.rex_r.value = v
+
+    def decode(self, v):
+        v = v & self.lmask
+        p = self.parent
+        opmode = p.v_opmode()
+        # if hasattr(p, 'sx'):
+        #    opmode = 16
+        if not hasattr(p, 'sx') and (hasattr(p, 'w8') and p.w8.value == 0):
+            opmode = 8
+        r = size2gpregs[opmode]
+        if p.mode == 64 and self.getrexsize():
+            v |= 0x8
+        # print "XXX", p.v_opmode(), p.rex_p.value
+        if p.v_opmode() == 64 or p.rex_p.value == 1:
+            if not hasattr(p, 'sx') and (hasattr(p, 'w8') and p.w8.value == 0):
+            # if (hasattr(p, 'w8') and p.w8.value == 0):
+                r = gpregs08_64
+        """
+        if v < 8:
+            self.expr = r.expr[v]
+        else:
+            self.expr = size2gpregs[64].expr[v]
+        """
+        if hasattr(p, "xmm") or hasattr(p, "xmmreg"):
+            e = gpregs_xmm.expr[v]
+        elif hasattr(p, "mm") or hasattr(p, "mmreg"):
+            e = gpregs_mm.expr[v]
+        else:
+            e = r.expr[v]
+        self.expr = e
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprId):
+            return False
+        if self.expr in gpregs64.expr and not hasattr(self.parent, 'stk'):
+            self.parent.rex_w.value = 1
+        # print self.parent.opmode
+        # fd
+        opmode = self.parent.v_opmode()
+        # if hasattr(self.parent, 'sx'):
+        #    opmode = 16
+        # print 'reg encode', self.expr, opmode
+        if not hasattr(self.parent, 'sx') and hasattr(self.parent, 'w8'):
+            self.parent.w8.value = 1
+        if self.expr.size == 8:
+            if hasattr(self.parent, 'sx') or not hasattr(self.parent, 'w8'):
+                return False
+            self.parent.w8.value = 0
+            opmode = 8
+        r = size2gpregs[opmode]
+        # print "YYY", opmode, self.expr
+        if ((hasattr(self.parent, 'xmm') or hasattr(self.parent, 'xmmreg'))
+            and self.expr in gpregs_xmm.expr):
+            i = gpregs_xmm.expr.index(self.expr)
+        elif ((hasattr(self.parent, 'mm') or hasattr(self.parent, 'mmreg'))
+            and self.expr in gpregs_mm.expr):
+            i = gpregs_mm.expr.index(self.expr)
+        elif self.expr in r.expr:
+            i = r.expr.index(self.expr)
+        elif (opmode == 8 and self.parent.mode == 64 and
+            self.expr in gpregs08_64.expr):
+            i = gpregs08_64.expr.index(self.expr)
+            self.parent.rex_p.value = 1
+        else:
+            log.debug("cannot encode reg %r" % self.expr)
+            return False
+        # print "zzz", opmode, self.expr, i, self.parent.mode
+        if self.parent.v_opmode() == 64:
+            if i > 7:
+                self.setrexsize(1)
+                i -= 8
+        elif self.parent.mode == 64 and i > 7:
+            i -= 8
+            # print 'rrr', self.getrexsize()
+            # self.parent.rex_b.value = 1
+            self.setrexsize(1)
+        if hasattr(self.parent, 'xmm') or hasattr(self.parent, 'mm'):
+            if i > 7:
+                i -= 8
+        self.value = i
+        if self.value > self.lmask:
+            log.debug("cannot encode field value %x %x" %
+                      (self.value, self.lmask))
+            return False
+        # print 'RR ok'
+        return True
+
+
+class x86_rm_reg(x86_rm_reg_noarg, m_arg):
+    pass
+
+
+class x86_reg(x86_rm_reg):
+
+    def getrexsize(self):
+        return self.parent.rex_b.value
+
+    def setrexsize(self, v):
+        self.parent.rex_b.value = v
+
+
+class x86_reg_noarg(x86_rm_reg_noarg):
+
+    def getrexsize(self):
+        return self.parent.rex_b.value
+
+    def setrexsize(self, v):
+        self.parent.rex_b.value = v
+
+
+class x86_rm_segm(reg_noarg, m_arg):
+    prio = default_prio + 1
+    reg_info = segmreg
+    parser = reg_info.parser
+
+
+class x86_rm_cr(reg_noarg, m_arg):
+    prio = default_prio + 1
+    reg_info = crregs
+    parser = reg_info.parser
+
+
+class x86_rm_dr(reg_noarg, m_arg):
+    prio = default_prio + 1
+    reg_info = drregs
+    parser = reg_info.parser
+
+
+class x86_rm_flt(reg_noarg, m_arg):
+    prio = default_prio + 1
+    reg_info = fltregs
+    parser = reg_info.parser
+
+
+class bs_fbit(bsi):
+
+    def decode(self, v):
+        # value already decoded in pre_dis_info
+        # print "jj", self.value
+        return True
+
+
+class bs_cl1(bsi, m_arg):
+    parser = cl_or_imm
+
+    def decode(self, v):
+        if v == 1:
+            self.expr = regs08_expr[1]
+        else:
+            self.expr = ExprInt8(1)
+        return True
+
+    def encode(self):
+        if self.expr == regs08_expr[1]:
+            self.value = 1
+        elif isinstance(self.expr, ExprInt) and int(self.expr.arg) == 1:
+            self.value = 0
+        else:
+            return False
+        return True
+
+
+def sib_cond(cls, mode, v):
+        if admode_prefix((mode, v["opmode"], v["admode"])) == 16:
+            return None
+        if v['mod'] == 0b11:
+            return None
+        elif v['rm'] == 0b100:
+            return cls.ll
+        else:
+            return None
+        return v['rm'] == 0b100
+
+
+class bs_cond_scale(bs_cond):
+    # cond must return field len
+    ll = 2
+
+    @classmethod
+    def flen(cls, mode, v):
+        return sib_cond(cls, mode, v)
+
+    def encode(self):
+        if self.value is None:
+            self.value = 0
+            self.l = 0
+            return True
+        return super(bs_cond, self).encode()
+
+    def decode(self, v):
+        self.value = v
+        return True
+
+
+class bs_cond_index(bs_cond_scale):
+    ll = 3
+
+    @classmethod
+    def flen(cls, mode, v):
+        return sib_cond(cls, mode, v)
+
+
+class bs_cond_disp(bs_cond):
+    # cond must return field len
+
+    @classmethod
+    def flen(cls, mode, v):
+        # print 'disp cond', mode,
+        # print v, v_admode_info(mode, v['opmode'], v['admode'])
+        # if v_admode_info(mode, v['opmode'], v['admode']) ==16:
+        if admode_prefix((mode, v['opmode'], v['admode'])) == 16:
+            if v['mod'] == 0b00:
+                if v['rm'] == 0b110:
+                    return 16
+                else:
+                    return None
+            elif v['mod'] == 0b01:
+                return 8
+            elif v['mod'] == 0b10:
+                return 16
+            return None
+        # 32, 64
+        if 'sib_base' in v and v['sib_base'] == 0b101:
+            if v['mod'] == 0b00:
+                return 32
+            elif v['mod'] == 0b01:
+                return 8
+            elif v['mod'] == 0b10:
+                return 32
+            else:
+                return None
+
+        if v['mod'] == 0b00:
+            if v['rm'] == 0b101:
+                return 32
+            else:
+                return None
+        elif v['mod'] == 0b01:
+            return 8
+        elif v['mod'] == 0b10:
+            return 32
+        else:
+            return None
+
+    def encode(self):
+        if self.value is None:
+            self.value = 0
+            self.l = 0
+            return True
+        self.value = swap_uint(self.l, self.value)
+        return True
+
+    def decode(self, v):
+        admode = self.parent.v_admode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, admode)
+        v = ExprInt_fromsize(admode, v)
+        self.expr = v
+        return True
+
+
+class bs_cond_imm(bs_cond_scale, m_arg):
+    parser = int_or_expr
+    max_size = 32
+
+    def fromstring(self, s, parser_result=None):
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+        else:
+            try:
+                e, start, stop = self.parser.scanString(s).next()
+            except StopIteration:
+                e = None
+        self.expr = e
+
+        if len(self.parent.args) > 1:
+            l = self.parent.args[0].expr.size
+        else:
+            l = self.parent.v_opmode()
+        # l = min(l, self.max_size)
+        # l = offsize(self.parent)
+        if isinstance(self.expr, ExprInt):
+            v = int(self.expr.arg)
+            mask = ((1 << l) - 1)
+            v = v & mask
+            e = ExprInt_fromsize(l, v)
+            self.expr = e
+
+        if self.expr is None:
+            log.debug('cannot fromstring int %r' % s)
+            return None, None
+        return start, stop
+
+    @classmethod
+    def flen(cls, mode, v):
+        if 'w8' not in v or v['w8'] == 1:
+            if 'se' in v and v['se'] == 1:
+                return 8
+            else:
+                # osize = v_opmode_info(mode, v['opmode'], v['admode'])
+                # osize = opmode_prefix((mode, v['opmode'], v['admode']))
+                osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+                osize = min(osize, cls.max_size)
+                return osize
+        return 8
+
+    def getmaxlen(self):
+        return 32
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            raise StopIteration
+        arg0_expr = self.parent.args[0].expr
+        self.parent.rex_w.value = 0
+        # special case for push
+        if len(self.parent.args) == 1:
+            v = int(self.expr.arg)
+            l = self.parent.v_opmode()
+            l = min(l, self.max_size)
+
+            self.l = l
+            mask = ((1 << self.l) - 1)
+            # print 'ext', self.l, l, hex(v), hex(sign_ext(v & ((1<<self.l)-1),
+            # self.l, l))
+            if v != sign_ext(v & mask, self.l, l):
+                raise StopIteration
+            self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+            # print hex(self.value)
+            yield True
+            raise StopIteration
+
+        # assume 2 args; use first arg to guess op size
+        if arg0_expr.size == 64:
+            self.parent.rex_w.value = 1
+
+        l = self.parent.v_opmode()  # self.parent.args[0].expr.size
+        # print 'imm enc', l, self.parent.rex_w.value
+        v = int(self.expr.arg)
+        # print "imms size", l, hex(v), arg0_expr.size
+        if arg0_expr.size == 8:
+            if not hasattr(self.parent, 'w8'):
+                raise StopIteration
+            self.parent.w8.value = 0
+            l = 8
+            if hasattr(self.parent, 'se'):
+                self.parent.se.value = 0
+        elif hasattr(self.parent, 'se'):
+            if hasattr(self.parent, 'w8'):
+                self.parent.w8.value = 1
+            # print 'test', 8, hex(v),
+            # print hex(sign_ext(v & 0xFF, 8, arg0_expr.size))
+            # try to generate signed extended version
+            if v == sign_ext(v & 0xFF, 8, arg0_expr.size):
+                # print 'setse'
+                self.parent.se.value = 1
+                self.l = 8
+                self.value = v & 0xFF
+                yield True
+            self.parent.se.value = 0
+        else:
+            if hasattr(self.parent, 'w8'):
+                self.parent.w8.value = 1
+        if l == 64:
+            self.l = self.getmaxlen()
+        else:
+            self.l = l
+        # l = min(l, self.max_size)
+
+        mask = ((1 << self.l) - 1)
+        # print 'ext', self.l, l, hex(v), hex(sign_ext(v & ((1<<self.l)-1),
+        # self.l, l))
+        if v != sign_ext(v & mask, self.l, l):
+            raise StopIteration
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        # print hex(self.value)
+        yield True
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        l_out = opmode
+        if hasattr(self.parent, 'w8') and self.parent.w8.value == 0:
+            l_out = 8
+        v = sign_ext(v, self.l, l_out)
+        v = ExprInt_fromsize(l_out, v)
+        self.expr = v
+        # print self.expr, repr(self.expr)
+        return True
+
+
+class bs_cond_imm64(bs_cond_imm):
+    max_size = 64
+
+    def getmaxlen(self):
+        return 64
+
+    @classmethod
+    def flen(cls, mode, v):
+        if 'w8' not in v or v['w8'] == 1:
+            if 'se' in v and v['se'] == 1:
+                return 8
+            else:
+                osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+                return osize
+        else:
+            return 8
+
+
+class bs_rel_off(bs_cond_imm):  # m_arg):
+    parser = int_or_expr
+
+    def fromstring(self, s, parser_result=None):
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+        else:
+            try:
+                e, start, stop = self.parser.scanString(s).next()
+            except StopIteration:
+                e = None
+        self.expr = e
+        l = self.parent.mode
+        if isinstance(self.expr, ExprInt):
+            v = int(self.expr.arg)
+            mask = ((1 << l) - 1)
+            v = v & mask
+            e = ExprInt_fromsize(l, v)
+            self.expr = e
+        return start, stop
+
+    @classmethod
+    def flen(cls, mode, v):
+        osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+        if osize == 16:
+            return 16
+        else:
+            return 32
+
+    def encode(self):
+        if not isinstance(self.expr, ExprInt):
+            raise StopIteration
+        arg0_expr = self.parent.args[0].expr
+        if self.l != 0:
+            l = self.l
+        else:
+            l = self.parent.v_opmode()  # self.parent.args[0].expr.size
+            self.l = l
+            # if l == 16:
+            #    self.l = 16
+            # else:
+            #    self.l = 32
+        l = offsize(self.parent)
+
+        # l = self.parent.v_opmode()#self.parent.args[0].expr.size
+        # print 'imm enc', l, self.parent.rex_w.value
+        v = int(self.expr.arg)
+        mask = ((1 << self.l) - 1)
+        # print 'ext', self.l, l, hex(v), hex(sign_ext(v & ((1<<self.l)-1),
+        # self.l, l))
+        if self.l > l:
+            raise StopIteration
+        if v != sign_ext(v & mask, self.l, l):
+            raise StopIteration
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        # print hex(self.value)
+        yield True
+
+    def decode(self, v):
+        v = swap_uint(self.l, v)
+        size = offsize(self.parent)
+        v = sign_ext(v, self.l, size)
+        v = ExprInt_fromsize(size, v)
+        self.expr = v
+        # print self.expr, repr(self.expr)
+        return True
+
+
+class bs_rel_off08(bs_rel_off):
+
+    @classmethod
+    def flen(cls, mode, v):
+        return 8
+
+
+class bs_moff(bsi):
+
+    @classmethod
+    def flen(cls, mode, v):
+        osize = v_opmode_info(mode, v['opmode'], v['rex_w'], 0)
+        if osize == 16:
+            return 16
+        else:
+            return 32
+
+    def encode(self):
+        if not hasattr(self.parent, "mseg"):
+            raise StopIteration
+        m = self.parent.mseg.expr
+        if (not (isinstance(m, ExprMem) and m.is_op_segm() and
+            isinstance(m.arg.args[0], ExprInt))):
+            raise StopIteration
+        l = self.parent.v_opmode()  # self.parent.args[0].expr.size
+        if l == 16:
+            self.l = 16
+        else:
+            self.l = 32
+        # print 'imm enc', l, self.parent.rex_w.value
+        v = int(m.arg.args[1].arg)
+        mask = ((1 << self.l) - 1)
+        # print 'ext', self.l, l, hex(v), hex(sign_ext(v & ((1<<self.l)-1),
+        # self.l, l))
+        if v != sign_ext(v & mask, self.l, l):
+            raise StopIteration
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        # print hex(self.value)
+        yield True
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        if opmode == 64:
+            return False
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, opmode)
+        v = ExprInt_fromsize(opmode, v)
+        self.expr = v
+        # print self.expr, repr(self.expr)
+        return True
+
+
+class bs_movoff(m_arg):
+    parser = deref_mem
+
+    def fromstring(self, s, parser_result=None):
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+            if e is None:
+                return None, None
+            # print 'fromstring', hex(e), self.int2expr
+            if not isinstance(e, ExprMem):
+                return None, None
+            self.expr = e
+            if self.expr is None:
+                return None, None
+            return start, stop
+        try:
+            v, start, stop = self.parser.scanString(s).next()
+        except StopIteration:
+            return None, None
+        if not isinstance(e, ExprMem):
+            return None, None
+        e = v[0]
+        if e is None:
+            log.debug('cannot fromstring int %r' % s)
+            return None, None
+        self.expr = e
+        return start, stop
+
+    @classmethod
+    def flen(cls, mode, v):
+        if mode == 64:
+            if v['admode']:
+                return 32
+            else:
+                return 64
+        asize = v_admode_info(mode, v['admode'])
+        return asize
+
+    def encode(self):
+        e = self.expr
+        p = self.parent
+        if not isinstance(e, ExprMem) or not isinstance(e.arg, ExprInt):
+            raise StopIteration
+        self.l = p.v_admode()
+        # print 'imm enc', l, self.parent.rex_w.value
+        v = int(e.arg.arg)
+        mask = ((1 << self.l) - 1)
+        if v != mask & v:
+            raise StopIteration
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            if self.parent.admode == 1:
+                l = 32
+            else:
+                l = 64
+        else:
+            l = self.parent.v_admode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, l)
+        v = ExprInt_fromsize(l, v)
+        size = self.parent.v_opmode()
+        if self.parent.w8.value == 0:
+            size = 8
+        self.expr = ExprMem(v, size)
+        # print self.expr, repr(self.expr)
+        return True
+
+    @staticmethod
+    def arg2str(e):
+        sz = {8: 'BYTE', 16: 'WORD', 32: 'DWORD', 64: 'QWORD', 80: 'TBYTE'}
+        o = sz[e.size] + ' PTR [%s]' % e.arg
+        return "%s" % o
+
+
+class bs_msegoff(m_arg):
+    parser = deref_ptr
+
+    def fromstring(self, s, parser_result=None):
+        if parser_result:
+            e, start, stop = parser_result[self.parser]
+            if e is None:
+                return None, None
+            self.expr = e
+            if self.expr is None:
+                return None, None
+            return start, stop
+        try:
+            v, start, stop = self.parser.scanString(s).next()
+        except StopIteration:
+            return None, None
+        e = v[0]
+        if e is None:
+            log.debug('cannot fromstring int %r' % s)
+            return None, None
+        self.expr = e
+        return start, stop
+
+    def encode(self):
+        if not (isinstance(self.expr, ExprMem) and self.expr.is_op_segm()):
+            raise StopIteration
+        if not isinstance(self.expr.arg.args[0], ExprInt):
+            raise StopIteration
+        if not isinstance(self.expr.arg.args[1], ExprInt):
+            raise StopIteration
+        l = self.parent.v_opmode()  # self.parent.args[0].expr.size
+        # print 'imm enc', l, self.parent.rex_w.value
+        v = int(self.expr.arg.args[0].arg)
+        mask = ((1 << self.l) - 1)
+        # print 'ext', self.l, l, hex(v), hex(sign_ext(v & ((1<<self.l)-1),
+        # self.l, l))
+        if v != sign_ext(v & mask, self.l, l):
+            raise StopIteration
+        self.value = swap_uint(self.l, v & ((1 << self.l) - 1))
+        yield True
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        v = swap_uint(self.l, v)
+        self.value = v
+        v = sign_ext(v, self.l, opmode)
+        v = ExprInt_fromsize(opmode, v)
+        e = ExprMem(ExprOp('segm', v, self.parent.off.expr))
+        self.expr = e
+        # print self.expr, repr(self.expr)
+        return True
+
+    @staticmethod
+    def arg2str(e):
+        return "%s:%s" % (e.arg.args[0], e.arg.args[1])
+
+
+d_rex_p = bs(l=0, cls=(bs_fbit,), fname="rex_p")
+d_rex_w = bs(l=0, cls=(bs_fbit,), fname="rex_w")
+d_rex_r = bs(l=0, cls=(bs_fbit,), fname="rex_r")
+d_rex_x = bs(l=0, cls=(bs_fbit,), fname="rex_x")
+d_rex_b = bs(l=0, cls=(bs_fbit,), fname="rex_b")
+
+d_g1 = bs(l=0, cls=(bs_fbit,), fname="g1")
+d_g2 = bs(l=0, cls=(bs_fbit,), fname="g2")
+
+
+d_cl1 = bs(l=1, cls=(bs_cl1,), fname="cl1")
+
+
+w8 = bs(l=1, fname="w8")
+se = bs(l=1, fname="se")
+
+sx = bs(l=0, fname="sx")
+sxd = bs(l=0, fname="sx")
+
+
+xmm = bs(l=0, fname="xmm")
+mm = bs(l=0, fname="mm")
+xmmreg = bs(l=0, fname="xmmreg")
+mmreg = bs(l=0, fname="mmreg")
+
+pref_f2 = bs(l=0, fname="prefixed", default="\xf2")
+pref_f3 = bs(l=0, fname="prefixed", default="\xf3")
+pref_66 = bs(l=0, fname="prefixed", default="\x66")
+no_xmm_pref = bs(l=0, fname="no_xmm_pref")
+
+sib_scale = bs(l=2, cls=(bs_cond_scale,), fname = "sib_scale")
+sib_index = bs(l=3, cls=(bs_cond_index,), fname = "sib_index")
+sib_base = bs(l=3, cls=(bs_cond_index,), fname = "sib_base")
+
+disp = bs(l=0, cls=(bs_cond_disp,), fname = "disp")
+
+
+u08 = bs(l=8, cls=(x86_08, m_arg))
+u07 = bs(l=7, cls=(x86_08, m_arg))
+u16 = bs(l=16, cls=(x86_16, m_arg))
+u32 = bs(l=32, cls=(x86_32, m_arg))
+s3264 = bs(l=32, cls=(x86_s32to64, m_arg))
+
+u08_3 = bs(l=0, cls=(x86_imm_fix, m_arg), ival = 3)
+
+d0 = bs("000", fname='reg')
+d1 = bs("001", fname='reg')
+d2 = bs("010", fname='reg')
+d3 = bs("011", fname='reg')
+d4 = bs("100", fname='reg')
+d5 = bs("101", fname='reg')
+d6 = bs("110", fname='reg')
+d7 = bs("111", fname='reg')
+
+sd = bs(l=1, fname="sd")
+wd = bs(l=1, fname="wd")
+
+stk = bs(l=0, fname="stk")
+
+
+class field_size:
+    prio = default_prio
+
+    def __init__(self, d=None):
+        if d is None:
+            d = {}
+        self.d = d
+
+    def get(self, opm, adm=None):
+        return self.d[opm]
+
+d_imm64 = bs(l=0, fname="imm64")
+
+# d_eax = bs_eax(l=0)
+d_eax = bs(l=0, cls=(bs_eax, ), fname='eax')
+d_edx = bs(l=0, cls=(bs_edx, ), fname='edx')
+d_st = bs(l=0, cls=(x86_reg_st, ), fname='st')
+# d_imm = bs(l=0, cls=(bs_cond_imm,), fname="imm")
+d_imm = bs(l=0, cls=(bs_cond_imm,), fname="imm")
+d_imm64 = bs(l=0, cls=(bs_cond_imm64,), fname="imm")
+d_ax = bs(l=0, cls=(r_ax, ), fname='ax')
+d_dx = bs(l=0, cls=(r_dx, ), fname='dx')
+d_cl = bs(l=0, cls=(r_cl, ), fname='cl')
+
+d_cs = bs(l=0, cls=(bs_cs, ), fname='cs')
+d_ds = bs(l=0, cls=(bs_ds, ), fname='ds')
+d_es = bs(l=0, cls=(bs_es, ), fname='es')
+d_ss = bs(l=0, cls=(bs_ss, ), fname='ss')
+d_fs = bs(l=0, cls=(bs_fs, ), fname='fs')
+d_gs = bs(l=0, cls=(bs_gs, ), fname='gs')
+
+rel_off = bs(l=0, cls=(bs_rel_off,), fname="off")
+rel_off08 = bs(l=8, cls=(bs_rel_off08,), fname="off")
+moff = bs(l=0, cls=(bs_moff,), fname="off")
+msegoff = bs(l=16, cls=(bs_msegoff,), fname="mseg")
+movoff = bs(l=0, cls=(bs_movoff,), fname="off")
+mod = bs(l=2, fname="mod")
+
+rmreg = bs(l=3, cls=(x86_rm_reg, ), order =1, fname = "reg")
+reg = bs(l=3, cls=(x86_reg, ), order =1, fname = "reg")
+regnoarg = bs(l=3, default_val="000", order=1, fname="reg")
+segm = bs(l=3, cls=(x86_rm_segm, ), order =1, fname = "reg")
+crreg = bs(l=3, cls=(x86_rm_cr, ), order =1, fname = "reg")
+drreg = bs(l=3, cls=(x86_rm_dr, ), order =1, fname = "reg")
+
+fltreg = bs(l=3, cls=(x86_rm_flt, ), order =1, fname = "reg")
+
+rm = bs(l=3, fname="rm")
+
+rm_arg = bs(l=0, cls=(x86_rm_arg,), fname='rmarg')
+rm_arg_w8 = bs(l=0, cls=(x86_rm_w8,), fname='rmarg')
+rm_arg_sx = bs(l=0, cls=(x86_rm_sx,), fname='rmarg')
+rm_arg_sxd = bs(l=0, cls=(x86_rm_sxd,), fname='rmarg')
+rm_arg_sd = bs(l=0, cls=(x86_rm_sd,), fname='rmarg')
+rm_arg_wd = bs(l=0, cls=(x86_rm_wd,), fname='rmarg')
+rm_arg_m80 = bs(l=0, cls=(x86_rm_m80,), fname='rmarg')
+rm_arg_m64 = bs(l=0, cls=(x86_rm_m64,), fname='rmarg')
+rm_arg_m08 = bs(l=0, cls=(x86_rm_m08,), fname='rmarg')
+rm_arg_m16 = bs(l=0, cls=(x86_rm_m16,), fname='rmarg')
+
+swapargs = bs_swapargs(l=1, fname="swap", mn_mod=range(1 << 1))
+
+
+cond_list = ["O", "NO", "B", "AE",
+             "Z", "NZ", "BE", "A",
+             "S", "NS", "PE", "NP",
+             #"L", "NL", "NG", "G"]
+             "L", "GE", "LE", "G"]
+cond = bs_mod_name(l=4, fname='cond', mn_mod=cond_list)
+
+
+def rmmod(r, rm_arg_x=rm_arg):
+    return [mod, r, rm, sib_scale, sib_index, sib_base, disp, rm_arg_x]
+
+#
+# mode | reg | rm #
+#
+
+#
+# scale | index | base #
+#
+
+#
+# Prefix | REX prefix | Opcode | mod/rm | sib | displacement | immediate #
+#
+
+
+def addop(name, fields, args=None, alias=False):
+    dct = {"fields": fields}
+    dct["alias"] = alias
+    if args is not None:
+        dct['args'] = args
+    type(name, (mn_x86,), dct)
+"""
+class ia32_aaa(mn_x86):
+    fields = [bs8(0x37)]
+"""
+addop("aaa", [bs8(0x37)])
+addop("aas", [bs8(0x3F)])
+addop("aad", [bs8(0xd5), u08])
+addop("aam", [bs8(0xd4), u08])
+
+addop("adc", [bs("0001010"), w8, d_eax, d_imm])
+addop("adc", [bs("100000"), se, w8] + rmmod(d2, rm_arg_w8) + [d_imm])
+addop("adc", [bs("000100"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("add", [bs("0000010"), w8, d_eax, d_imm])
+addop("add", [bs("100000"), se, w8] + rmmod(d0, rm_arg_w8) + [d_imm])
+addop("add", [bs("000000"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("and", [bs("0010010"), w8, d_eax, d_imm])
+addop("and", [bs("100000"), se, w8] + rmmod(d4, rm_arg_w8) + [d_imm])
+addop("and", [bs("001000"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("bsf", [bs8(0x0f), bs8(0xbc)] + rmmod(rmreg))
+addop("bsr", [bs8(0x0f), bs8(0xbd), mod,
+    rmreg, rm, sib_scale, sib_index, sib_base, disp, rm_arg])
+
+addop("bswap", [bs8(0x0f), bs('11001'), reg])
+
+addop("bt", [bs8(0x0f), bs8(0xa3)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("bt", [bs8(0x0f), bs8(0xba)] + rmmod(d4) + [u08])
+addop("btc", [bs8(0x0f), bs8(0xbb)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("btc", [bs8(0x0f), bs8(0xba)] + rmmod(d7) + [u08])
+
+
+addop("btr", [bs8(0x0f), bs8(0xb3)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("btr", [bs8(0x0f), bs8(0xba)] + rmmod(d6) + [u08])
+addop("bts", [bs8(0x0f), bs8(0xab)] + rmmod(rmreg), [rm_arg, rmreg])
+addop("bts", [bs8(0x0f), bs8(0xba)] + rmmod(d5) + [u08])
+
+addop("call", [bs8(0xe8), rel_off])
+addop("call", [bs8(0xff), stk] + rmmod(d2))
+addop("call", [bs8(0x9a), moff, msegoff])
+
+
+class bs_op_mode(bsi):
+
+    def decode(self, v):
+        opmode = self.parent.v_opmode()
+        # print "MODE", opmode, self.mode
+        return opmode == self.mode
+
+
+class bs_ad_mode(bsi):
+
+    def decode(self, v):
+        admode = self.parent.v_admode()
+        # print "MODE", opmode, self.mode
+        return admode == self.mode
+
+
+class bs_op_mode_no64(bsi):
+
+    def encode(self):
+        if self.parent.mode == 64:
+            return False
+        return super(bs_op_mode_no64, self).encode()
+
+    def decode(self, v):
+        if self.parent.mode == 64:
+            return False
+        opmode = self.parent.v_opmode()
+        # print "MODE", opmode, self.mode
+        return opmode == self.mode
+
+
+bs_opmode16 = bs(l=0, cls=(bs_op_mode,), mode = 16, fname="fopmode")
+bs_opmode32 = bs(l=0, cls=(bs_op_mode,), mode = 32, fname="fopmode")
+bs_opmode64 = bs(l=0, cls=(bs_op_mode,), mode = 64, fname="fopmode")
+
+
+bs_admode16 = bs(l=0, cls=(bs_ad_mode,), mode = 16, fname="fadmode")
+bs_admode32 = bs(l=0, cls=(bs_ad_mode,), mode = 32, fname="fadmode")
+bs_admode64 = bs(l=0, cls=(bs_ad_mode,), mode = 64, fname="fadmode")
+
+bs_opmode16_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 16, fname="fopmode")
+bs_opmode32_no64 = bs(l=0, cls=(bs_op_mode_no64,), mode = 32, fname="fopmode")
+
+# class ia32_call(mn_x86):
+#    fields = [bs8(0xff)] + rmmod(d3)
+# conv_name = {16:'CBW', 32:'CWDE', 64:'CDQE'}
+# bs_conv_name = bs_modname_size(l=0, name=conv_name)
+addop("cbw", [bs8(0x98), bs_opmode16])
+addop("cwde", [bs8(0x98), bs_opmode32])
+addop("cdqe", [bs8(0x98), bs_opmode64])
+
+addop("clc", [bs8(0xf8)])
+addop("cld", [bs8(0xfc)])
+addop("cli", [bs8(0xfa)])
+addop("clts", [bs8(0x0f), bs8(0x06)])
+addop("cmc", [bs8(0xf5)])
+
+addop("cmov", [bs8(0x0f), bs('0100'), cond] + rmmod(rmreg))
+
+addop("cmp", [bs("0011110"), w8, d_eax, d_imm])
+addop("cmp", [bs("100000"), se, w8] + rmmod(d7, rm_arg_w8) + [d_imm])
+addop("cmp", [bs("001110"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+
+addop("cmpsb", [bs8(0xa6)])
+# cmps_name = {16:'CMPSW', 32:'CMPSD', 64:'CMPSQ'}
+# bs_cmps_name = bs_modname_size(l=0, name=cmps_name)
+# addop("cmps", [bs8(0xa7), bs_cmps_name])
+addop("cmpsw", [bs8(0xa7), bs_opmode16])
+addop("cmpsd", [bs8(0xa7), bs_opmode32])
+addop("cmpsq", [bs8(0xa7), bs_opmode64])
+
+addop("cmpxchg", [bs8(0x0f), bs('1011000'), w8]
+      + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+# XXX TODO CMPXCHG8/16
+addop("cpuid", [bs8(0x0f), bs8(0xa2)])
+
+# convbis_name = {16:'CWD', 32:'CDQ', 64:'CQO'}
+# bs_convbis_name = bs_modname_size(l=0, name=convbis_name)
+# addop("convbis", [bs8(0x99), bs_convbis_name])
+addop("cwd", [bs8(0x99), bs_opmode16])
+addop("cdq", [bs8(0x99), bs_opmode32])
+addop("cqo", [bs8(0x99), bs_opmode64])
+
+
+addop("daa", [bs8(0x27)])
+addop("das", [bs8(0x2f)])
+addop("dec", [bs('1111111'), w8] + rmmod(d1, rm_arg_w8))
+addop("dec", [bs('01001'), reg])
+addop("div", [bs('1111011'), w8] + rmmod(d6, rm_arg_w8))
+addop("enter", [bs8(0xc8), u16, u08])
+
+# float #####
+addop("fwait", [bs8(0x9b)])
+
+addop("f2xm1", [bs8(0xd9), bs8(0xf0)])
+addop("fabs", [bs8(0xd9), bs8(0xe1)])
+
+addop("fadd", [bs("11011"), sd, bs("00")] + rmmod(d0, rm_arg_sd))
+addop("fadd", [bs("11011"), swapargs, bs("00"),
+      bs("11000"), d_st, fltreg], [d_st, fltreg])
+addop("faddp", [bs8(0xde), bs("11000"), fltreg, d_st])
+addop("fiadd", [bs("11011"), wd, bs("10")] + rmmod(d0, rm_arg_wd))
+
+addop("fbld", [bs8(0xdf)] + rmmod(d4, rm_arg_m80))
+addop("fbldp", [bs8(0xdf)] + rmmod(d6, rm_arg_m80))
+addop("fchs", [bs8(0xd9), bs8(0xe0)])
+# addop("fclex", [bs8(0x9b), bs8(0xdb), bs8(0xe2)])
+addop("fnclex", [bs8(0xdb), bs8(0xe2)])
+
+addop("fcmovb", [bs8(0xda), bs("11000"), d_st, fltreg])
+addop("fcmove", [bs8(0xda), bs("11001"), d_st, fltreg])
+addop("fcmovbe", [bs8(0xda), bs("11010"), d_st, fltreg])
+addop("fcmovu", [bs8(0xda), bs("11011"), d_st, fltreg])
+addop("fcmovnb", [bs8(0xdb), bs("11000"), d_st, fltreg])
+addop("fcmovne", [bs8(0xdb), bs("11001"), d_st, fltreg])
+addop("fcmovnbe", [bs8(0xdb), bs("11010"), d_st, fltreg])
+addop("fcmovnu", [bs8(0xdb), bs("11011"), d_st, fltreg])
+
+addop("fcom", [bs("11011"), sd, bs("00")] + rmmod(d2, rm_arg_sd))
+addop("fcom", [bs("11011"), swapargs, bs("00"),
+      bs("11010"), d_st, fltreg], [d_st, fltreg])
+addop("fcomp", [bs("11011"), sd, bs("00")] + rmmod(d3, rm_arg_sd))
+addop("fcomp",
+      [bs("11011"), swapargs, bs("00"), bs("11011"),
+      d_st, fltreg], [d_st, fltreg])
+addop("fcompp", [bs8(0xde), bs8(0xd9)])
+
+addop("fcomi", [bs8(0xdb), bs("11110"), d_st, fltreg])
+addop("fcomip", [bs8(0xdf), bs("11110"), d_st, fltreg])
+addop("fucomi", [bs8(0xdb), bs("11101"), d_st, fltreg])
+addop("fucomip", [bs8(0xdf), bs("11101"), d_st, fltreg])
+
+addop("fcos", [bs8(0xd9), bs8(0xff)])
+addop("fdecstp", [bs8(0xd9), bs8(0xf6)])
+
+
+addop("fdiv", [bs("11011"), sd, bs("00")] + rmmod(d6, rm_arg_sd))
+addop("fdiv", [bs8(0xd8), bs("11110"), d_st, fltreg])
+addop("fdiv", [bs8(0xdc), bs("11111"), fltreg, d_st])
+addop("fdivp", [bs8(0xde), bs("11111"), fltreg, d_st])
+addop("fidiv", [bs("11011"), wd, bs("10")] + rmmod(d6, rm_arg_wd))
+
+addop("fdivr", [bs("11011"), sd, bs("00")] + rmmod(d7, rm_arg_sd))
+addop("fdivr", [bs8(0xd8), bs("11111"), d_st, fltreg])
+addop("fdivr", [bs8(0xdc), bs("11110"), fltreg, d_st])
+addop("fdivrp", [bs8(0xde), bs("11110"), fltreg, d_st])
+addop("fidivr", [bs("11011"), wd, bs("10")] + rmmod(d7, rm_arg_wd))
+
+addop("ffree", [bs8(0xdd), bs("11000"), fltreg])
+addop("ficom", [bs("11011"), wd, bs("10")] + rmmod(d2, rm_arg_wd))
+addop("ficomp", [bs("11011"), wd, bs("10")] + rmmod(d3, rm_arg_wd))
+addop("fild", [bs("11011"), wd, bs("11")] + rmmod(d0, rm_arg_wd))
+addop("fild", [bs8(0xdf)] + rmmod(d5, rm_arg_m64))
+
+addop("fincstp", [bs8(0xd9), bs8(0xf7)])
+
+# addop("finit", [bs8(0x9b), bs8(0xdb), bs8(0xe3)])
+addop("fninit", [bs8(0xdb), bs8(0xe3)])
+
+addop("fist", [bs("11011"), wd, bs("11")] + rmmod(d2, rm_arg_wd))
+addop("fistp", [bs("11011"), wd, bs("11")] + rmmod(d3, rm_arg_wd))
+addop("fistp", [bs8(0xdf)] + rmmod(d7, rm_arg_m64))
+
+addop("fisttp", [bs("11011"), wd, bs("11")] + rmmod(d1, rm_arg_wd))
+addop("fisttp", [bs8(0xdd)] + rmmod(d1, rm_arg_m64))
+
+addop("fld", [bs("11011"), sd, bs("01")] + rmmod(d0, rm_arg_sd))
+addop("fld", [bs8(0xdb)] + rmmod(d5, rm_arg_m80))
+addop("fld", [bs8(0xd9), bs("11000"), fltreg])
+
+addop("fld1", [bs8(0xd9), bs8(0xe8)])
+addop("fldl2t", [bs8(0xd9), bs8(0xe9)])
+addop("fldl2e", [bs8(0xd9), bs8(0xea)])
+addop("fldpi", [bs8(0xd9), bs8(0xeb)])
+addop("fldlg2", [bs8(0xd9), bs8(0xec)])
+addop("fldln2", [bs8(0xd9), bs8(0xed)])
+addop("fldz", [bs8(0xd9), bs8(0xee)])
+
+addop("fldcw", [bs8(0xd9)] + rmmod(d5, rm_arg_m16))
+addop("fldenv", [bs8(0xd9)] + rmmod(d4, rm_arg_m80))  # XXX TODO: m14?
+
+addop("fmul", [bs("11011"), sd, bs("00")] + rmmod(d1, rm_arg_sd))
+addop("fmul", [bs("11011"), swapargs, bs("00"),
+      bs("11001"), d_st, fltreg], [d_st, fltreg])
+addop("fmulp", [bs8(0xde), bs("11001"), fltreg, d_st])
+addop("fimul", [bs("11011"), wd, bs("10")] + rmmod(d1, rm_arg_wd))
+
+addop("fnop", [bs8(0xd9), bs8(0xd0)])
+addop("fpatan", [bs8(0xd9), bs8(0xf3)])
+addop("fprem", [bs8(0xd9), bs8(0xf8)])
+addop("fprem1", [bs8(0xd9), bs8(0xf5)])
+addop("fptan", [bs8(0xd9), bs8(0xf2)])
+addop("frndint", [bs8(0xd9), bs8(0xfc)])
+addop("frstor", [bs8(0xdd)] + rmmod(d4, rm_arg_m80))  # XXX TODO: m94 ?
+# addop("fsave", [bs8(0x9b), bs8(0xdd)] + rmmod(d6, rm_arg_m80)) # XXX
+# TODO: m94 ?
+addop("fnsave", [bs8(0xdd)] + rmmod(d6, rm_arg_m80))  # XXX TODO: m94 ?
+
+addop("fscale", [bs8(0xd9), bs8(0xfd)])
+addop("fsin", [bs8(0xd9), bs8(0xfe)])
+addop("fsincos", [bs8(0xd9), bs8(0xfb)])
+addop("fsqrt", [bs8(0xd9), bs8(0xfa)])
+
+addop("fst", [bs("11011"), sd, bs("01")] + rmmod(d2, rm_arg_sd))
+addop("fst", [bs8(0xdd), bs("11010"), fltreg])
+addop("fstp", [bs("11011"), sd, bs("01")] + rmmod(d3, rm_arg_sd))
+addop("fstp", [bs8(0xdb)] + rmmod(d7, rm_arg_m80))
+addop("fstp", [bs8(0xdd), bs("11011"), fltreg])
+
+# addop("fstcw", [bs8(0x9b), bs8(0xd9)] + rmmod(d7, rm_arg_m16))
+addop("fnstcw", [bs8(0xd9)] + rmmod(d7, rm_arg_m16))
+# addop("fstenv", [bs8(0x9b), bs8(0xd9)] + rmmod(d6, rm_arg_m80)) # XXX
+# TODO: m14?
+addop("fnstenv", [bs8(0xd9)] + rmmod(d6, rm_arg_m80))  # XXX TODO: m14?
+# addop("fstsw", [bs8(0x9b), bs8(0xdd)] + rmmod(d7, rm_arg_m16))
+addop("fnstsw", [bs8(0xdd)] + rmmod(d7, rm_arg_m16))
+# addop("fstsw", [bs8(0x9b), bs8(0xdf), bs8(0xe0), d_ax])
+addop("fnstsw", [bs8(0xdf), bs8(0xe0), d_ax])
+
+addop("fsub", [bs("11011"), sd, bs("00")] + rmmod(d4, rm_arg_sd))
+addop("fsub", [bs8(0xd8), bs("11100"), d_st, fltreg])
+addop("fsub", [bs8(0xdc), bs("11101"), fltreg, d_st])
+addop("fsubp", [bs8(0xde), bs("11101"), fltreg, d_st])
+addop("fisub", [bs("11011"), wd, bs("10")] + rmmod(d4, rm_arg_wd))
+
+addop("fsubr", [bs("11011"), sd, bs("00")] + rmmod(d5, rm_arg_sd))
+addop("fsubr", [bs8(0xd8), bs("11101"), d_st, fltreg])
+addop("fsubr", [bs8(0xdc), bs("11100"), fltreg, d_st])
+addop("fsubrp", [bs8(0xde), bs("11100"), fltreg, d_st])
+addop("fisubr", [bs("11011"), wd, bs("10")] + rmmod(d5, rm_arg_wd))
+addop("ftst", [bs8(0xd9), bs8(0xe4)])
+
+
+addop("fucom", [bs8(0xdd), bs("11100"), fltreg])
+addop("fucomp", [bs8(0xdd), bs("11101"), fltreg])
+addop("fucompp", [bs8(0xda), bs8(0xe9)])
+
+addop("fxam", [bs8(0xd9), bs8(0xe5)])
+addop("fxch", [bs8(0xd9), bs("11001"), fltreg])
+addop("fxrstor", [bs8(0x0f), bs8(0xae)]
+      + rmmod(d1, rm_arg_m80))  # XXX TODO m512
+addop("fxsave", [bs8(0x0f), bs8(0xae)]
+      + rmmod(d0, rm_arg_m80))  # XXX TODO m512
+
+addop("fxtract", [bs8(0xd9), bs8(0xf4)])
+addop("fyl2x", [bs8(0xd9), bs8(0xf1)])
+addop("fyl2xp1", [bs8(0xd9), bs8(0xf9)])
+
+addop("hlt", [bs8(0xf4)])
+addop("icebp", [bs8(0xf1)])
+
+addop("idiv", [bs('1111011'), w8] + rmmod(d7, rm_arg_w8))
+
+addop("imul", [bs('1111011'), w8] + rmmod(d5, rm_arg_w8))
+addop("imul", [bs8(0x0f), bs8(0xaf)] + rmmod(rmreg))
+
+addop("imul", [bs("011010"), se, bs('1')] + rmmod(rmreg) + [d_imm])
+
+addop("in", [bs("1110010"), w8, d_eax, u08])
+addop("in", [bs("1110110"), w8, d_eax, d_edx])
+
+addop("inc", [bs('1111111'), w8] + rmmod(d0, rm_arg_w8))
+addop("inc", [bs('01000'), reg])
+
+addop("insb", [bs8(0x6c)])
+# ins_name = {16:'INSW', 32:'INSD', 64:'INSD'}
+# bs_ins_name = bs_modname_size(l=0, name=ins_name)
+# addop("ins", [bs8(0x6d), bs_ins_name])
+addop("insw", [bs8(0x6d), bs_opmode16])
+addop("insd", [bs8(0x6d), bs_opmode32])
+addop("insd", [bs8(0x6d), bs_opmode64])
+
+addop("int", [bs8(0xcc), u08_3])
+addop("int", [bs8(0xcd), u08])
+addop("into", [bs8(0xce)])
+addop("invd", [bs8(0x0f), bs8(0x08)])
+addop("invlpg", [bs8(0x0f), bs8(0x01)] + rmmod(d7))
+
+# iret_name = {16:'IRET', 32:'IRETD', 64:'IRETQ'}
+# bs_iret_name = bs_modname_size(l=0, name=iret_name)
+# addop("iret", [bs8(0xcf), stk, bs_iret_name])
+addop("iret", [bs8(0xcf), stk, bs_opmode16])
+addop("iretd", [bs8(0xcf), stk, bs_opmode32])
+addop("iretq", [bs8(0xcf), stk, bs_opmode64])
+
+addop("j", [bs('0111'), cond, rel_off08])
+# bs_jecxz_name = bs_modname_jecx(l=0)
+# addop("jecxz", [bs8(0xe3), rel_off08, bs_jecxz_name])
+
+addop("jcxz", [bs8(0xe3), rel_off08, bs_admode16])
+addop("jecxz", [bs8(0xe3), rel_off08, bs_admode32])
+addop("jrcxz", [bs8(0xe3), rel_off08, bs_admode64])
+
+addop("j", [bs8(0x0f), bs('1000'), cond, rel_off])
+addop("jmp", [bs8(0xeb), rel_off08])
+addop("jmp", [bs8(0xe9), rel_off])
+# TODO XXX replace stk force64?
+addop("jmp", [bs8(0xff), stk] + rmmod(d4))
+addop("jmp", [bs8(0xea), moff, msegoff])
+
+addop("jmpf", [bs8(0xff), stk] + rmmod(d5))
+
+addop("lahf", [bs8(0x9f)])
+addop("lar", [bs8(0x0f), bs8(0x02)] + rmmod(rmreg))
+
+# XXX TODO LDS LES ...
+addop("lea", [bs8(0x8d)] + rmmod(rmreg))
+addop("leave", [bs8(0xc9)])
+
+addop("lodsb", [bs8(0xac)])
+# lods_name = {16:'LODSW', 32:'LODSD', 64:'LODSQ'}
+# bs_lods_name = bs_modname_size(l=0, name=lods_name)
+# addop("lods", [bs8(0xad), bs_lods_name])
+addop("lodsw", [bs8(0xad), bs_opmode16])
+addop("lodsd", [bs8(0xad), bs_opmode32])
+addop("lodsq", [bs8(0xad), bs_opmode64])
+
+addop("loop", [bs8(0xe2), rel_off08])
+addop("loope", [bs8(0xe1), rel_off08])
+addop("loopne", [bs8(0xe0), rel_off08])
+addop("lsl", [bs8(0x0f), bs8(0x03)] + rmmod(rmreg))
+addop("monitor", [bs8(0x0f), bs8(0x01), bs8(0xc8)])
+
+addop("mov", [bs("100010"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("mov", [bs("100011"), swapargs, bs('0')] + rmmod(segm), [rm_arg, segm])
+addop("mov", [bs("101000"), swapargs, w8, d_eax, movoff], [d_eax, movoff])
+addop("mov", [bs("1011"), w8, reg, d_imm64])
+addop("mov", [bs("1100011"), w8] + rmmod(d0, rm_arg_w8) + [d_imm])
+addop("mov", [bs8(0x0f), bs("001000"), swapargs, bs('0')]
+      + rmmod(crreg), [rm_arg, crreg])
+addop("mov", [bs8(0x0f), bs("001000"), swapargs, bs('1')]
+      + rmmod(drreg), [rm_arg, drreg])
+addop("movsb", [bs8(0xa4)])
+# movs_name = {16:'MOVSW', 32:'MOVSD', 64:'MOVSQ'}
+# bs_movs_name = bs_modname_size(l=0, name=movs_name)
+# addop("movs", [bs8(0xa5), bs_movs_name])
+addop("movsw", [bs8(0xa5), bs_opmode16])
+addop("movsd", [bs8(0xa5), bs_opmode32])
+addop("movsq", [bs8(0xa5), bs_opmode64])
+
+addop("movsx", [bs8(0x0f), bs("1011111"), w8, sx] + rmmod(rmreg, rm_arg_sx))
+# addop("movsxd", [bs8(0x63), sxd] + rmmod(rmreg, rm_arg_sxd))
+type("movsxd", (mn_x86,), {
+     "fields": [bs8(0x63), sxd] + rmmod(rmreg, rm_arg_sxd),
+     "modes": [64], 'alias': False})
+
+addop("movups",
+      [bs8(0x0f), bs8(0x10), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
+addop("movsd", [bs8(0x0f), bs("0001000"), swapargs, xmm, pref_f2]
+      + rmmod(rmreg, rm_arg), [xmm, rm_arg])
+addop("movss", [bs8(0x0f), bs8(0x10), xmm, pref_f3] + rmmod(rmreg, rm_arg))
+addop("movupd", [bs8(0x0f), bs8(0x10), xmm, pref_66] + rmmod(rmreg, rm_arg))
+
+
+addop("addss", [bs8(0x0f), bs8(0x58), xmm, pref_f3] + rmmod(rmreg, rm_arg))
+addop("addsd", [bs8(0x0f), bs8(0x58), xmm, pref_f2] + rmmod(rmreg, rm_arg))
+
+addop("subss", [bs8(0x0f), bs8(0x5c), xmm, pref_f3] + rmmod(rmreg, rm_arg))
+addop("subsd", [bs8(0x0f), bs8(0x5c), xmm, pref_f2] + rmmod(rmreg, rm_arg))
+
+addop("mulss", [bs8(0x0f), bs8(0x59), xmm, pref_f3] + rmmod(rmreg, rm_arg))
+addop("mulsd", [bs8(0x0f), bs8(0x59), xmm, pref_f2] + rmmod(rmreg, rm_arg))
+
+addop("divss", [bs8(0x0f), bs8(0x5e), xmm, pref_f3] + rmmod(rmreg, rm_arg))
+addop("divsd", [bs8(0x0f), bs8(0x5e), xmm, pref_f2] + rmmod(rmreg, rm_arg))
+
+
+addop("pminsw", [bs8(0x0f), bs8(0xea), mm, no_xmm_pref] + rmmod(rmreg, rm_arg))
+addop("pminsw", [bs8(0x0f), bs8(0xea), xmm, pref_66] + rmmod(rmreg, rm_arg))
+
+
+addop("pxor", [bs8(0x0f), bs8(0xef), xmm] + rmmod(rmreg, rm_arg))
+
+addop("ucomiss",
+      [bs8(0x0f), bs8(0x2e), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
+addop("ucomisd", [bs8(0x0f), bs8(0x2e), xmm, pref_66] + rmmod(rmreg, rm_arg))
+
+addop("andps", [bs8(0x0f), bs8(0x54), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
+addop("andpd", [bs8(0x0f), bs8(0x54), xmm, pref_66] + rmmod(rmreg, rm_arg))
+
+
+addop("maxsd", [bs8(0x0f), bs8(0x5f), xmm, pref_f2] + rmmod(rmreg, rm_arg))
+
+addop("cvtsi2sd",
+      [bs8(0x0f), bs8(0x2a), xmmreg, pref_f2] + rmmod(rmreg, rm_arg))
+addop("cvtsi2ss",
+      [bs8(0x0f), bs8(0x2a), xmmreg, pref_f3] + rmmod(rmreg, rm_arg))
+
+
+addop("cvttsd2ss",
+      [bs8(0x0f), bs8(0x2c), xmmreg, pref_f2] + rmmod(rmreg, rm_arg))
+addop("cvttss2si",
+      [bs8(0x0f), bs8(0x2c), xmmreg, pref_f3] + rmmod(rmreg, rm_arg))
+
+
+# type("movupd", (mn_x86,), {"fields":[bs8(0x0f), bs8(0x10), xmm, pref_f2]
+# + rmmod(rmreg, rm_arg_sxd), 'prefixed':'\xf2'})
+
+addop("movzx", [bs8(0x0f), bs("1011011"), w8, sx] + rmmod(rmreg, rm_arg_sx))
+addop("mul", [bs('1111011'), w8] + rmmod(d4, rm_arg_w8))
+
+addop("neg", [bs('1111011'), w8] + rmmod(d3, rm_arg_w8))
+addop("nop", [bs8(0x0f), bs8(0x1f)] + rmmod(d0, rm_arg))  # XXX TODO m512
+addop("not", [bs('1111011'), w8] + rmmod(d2, rm_arg_w8))
+addop("or", [bs("0000110"), w8, d_eax, d_imm])
+addop("or", [bs("100000"), se, w8] + rmmod(d1, rm_arg_w8) + [d_imm])
+addop("or", [bs("000010"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("out", [bs("1110011"), w8, u08, d_eax])
+addop("out", [bs("1110111"), w8, d_edx, d_eax])
+
+addop("outsb", [bs8(0x6e)])
+# outs_name = {16:'OUTSW', 32:'OUTSD', 64:'OUTSD'}
+# bs_outs_name = bs_modname_size(l=0, name=outs_name)
+# addop("outs", [bs8(0x6f), bs_outs_name])
+addop("outsw", [bs8(0x6f), bs_opmode16])
+addop("outsd", [bs8(0x6f), bs_opmode32])
+addop("outsd", [bs8(0x6f), bs_opmode64])
+
+
+# addop("pause", [bs8(0xf3), bs8(0x90)])
+
+addop("pop", [bs8(0x8f), stk] + rmmod(d0))
+addop("pop", [bs("01011"), stk, reg])
+addop("pop", [bs8(0x1f), d_ds])
+addop("pop", [bs8(0x07), d_es])
+addop("pop", [bs8(0x17), d_ss])
+addop("pop", [bs8(0x0f), bs8(0xa1), d_fs])
+addop("pop", [bs8(0x0f), bs8(0xa9), d_gs])
+
+# popa_name = {16:'POPA', 32:'POPAD'}
+# bs_popa_name = bs_modname_size(l=0, name=popa_name)
+# addop("popa", [bs8(0x61), bs_popa_name])
+addop("popa", [bs8(0x61), bs_opmode16])
+addop("popad", [bs8(0x61), bs_opmode32])
+
+# popf_name = {16:'POPF', 32:'POPFD', 64:'POPFQ'}
+# bs_popf_name = bs_modname_size(l=0, name=popf_name)
+# addop("popf", [bs8(0x9d), bs_popf_name])
+addop("popf", [bs8(0x9d), bs_opmode16])
+addop("popfd", [bs8(0x9d), bs_opmode32])
+addop("popfq", [bs8(0x9d), bs_opmode64])
+
+addop("prefetch0", [bs8(0x0f), bs8(0x18)] + rmmod(d1, rm_arg_m08))
+addop("prefetch1", [bs8(0x0f), bs8(0x18)] + rmmod(d2, rm_arg_m08))
+addop("prefetch2", [bs8(0x0f), bs8(0x18)] + rmmod(d3, rm_arg_m08))
+addop("prefetchnta", [bs8(0x0f), bs8(0x18)] + rmmod(d0, rm_arg_m08))
+
+addop("push", [bs8(0xff), stk] + rmmod(d6))
+addop("push", [bs("01010"), stk, reg])
+addop("push", [bs8(0x6a), rel_off08, stk])
+addop("push", [bs8(0x68), d_imm, stk])
+addop("push", [bs8(0x0e), d_cs])
+addop("push", [bs8(0x16), d_ss])
+addop("push", [bs8(0x1e), d_ds])
+addop("push", [bs8(0x06), d_es])
+addop("push", [bs8(0x0f), bs8(0xa0), d_fs])
+addop("push", [bs8(0x0f), bs8(0xa8), d_gs])
+
+# pusha_name = {16:'PUSHA', 32:'PUSHAD'}
+# bs_pusha_name = bs_modname_size(l=0, name=pusha_name)
+# addop("pusha", [bs8(0x60), bs_pusha_name])
+addop("pusha", [bs8(0x60), bs_opmode16_no64])
+addop("pushad", [bs8(0x60), bs_opmode32_no64])
+
+
+# pushf_name = {16:'PUSHF', 32:'PUSHFD', 64:'PUSHFQ'}
+# bs_pushf_name = bs_modname_size(l=0, name=pushf_name)
+# addop("pushf", [bs8(0x9c), bs_pushf_name])
+addop("pushf", [bs8(0x9c), bs_opmode16])
+addop("pushfd", [bs8(0x9c), bs_opmode32])
+addop("pushfq", [bs8(0x9c), bs_opmode64])
+
+addop("rcl", [bs('110100'), d_cl1, w8] +
+      rmmod(d2, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("rcl", [bs('1100000'), w8] + rmmod(d2, rm_arg_w8) + [u08])
+addop("rcr", [bs('110100'), d_cl1, w8] +
+      rmmod(d3, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("rcr", [bs('1100000'), w8] + rmmod(d3, rm_arg_w8) + [u08])
+addop("rol", [bs('110100'), d_cl1, w8]
+      + rmmod(d0, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("rol", [bs('1100000'), w8] + rmmod(d0, rm_arg_w8) + [u08])
+addop("ror", [bs('110100'), d_cl1, w8]
+      + rmmod(d1, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("ror", [bs('1100000'), w8] + rmmod(d1, rm_arg_w8) + [u08])
+
+addop("rdmsr", [bs8(0x0f), bs8(0x32)])
+addop("rdpmc", [bs8(0x0f), bs8(0x33)])
+addop("rdtsc", [bs8(0x0f), bs8(0x31)])
+addop("ret", [bs8(0xc3), stk])
+addop("ret", [bs8(0xc2), stk, u16])
+addop("retf", [bs8(0xcb), stk])
+addop("retf", [bs8(0xca), stk, u16])
+
+addop("rsm", [bs8(0x0f), bs8(0xaa)])
+addop("sahf", [bs8(0x9e)])
+
+# XXX tipo in doc: /4 instead of /6
+addop("sal", [bs('110100'), d_cl1, w8] +
+      rmmod(d6, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("sal", [bs('1100000'), w8] + rmmod(d6, rm_arg_w8) + [u08])
+addop("sar", [bs('110100'), d_cl1, w8] +
+      rmmod(d7, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("sar", [bs('1100000'), w8] + rmmod(d7, rm_arg_w8) + [u08])
+
+addop("scasb", [bs8(0xae)])
+# scas_name = {16:'SCASW', 32:'SCASD', 64:'SCASQ'}
+# bs_scas_name = bs_modname_size(l=0, name=scas_name)
+# addop("scas", [bs8(0xaf), bs_scas_name])
+addop("scasw", [bs8(0xaf), bs_opmode16])
+addop("scasd", [bs8(0xaf), bs_opmode32])
+addop("scasq", [bs8(0xaf), bs_opmode64])
+
+addop("shl", [bs('110100'), d_cl1, w8]
+      + rmmod(d4, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("shl", [bs('1100000'), w8] + rmmod(d4, rm_arg_w8) + [u08])
+addop("shr", [bs('110100'), d_cl1, w8]
+      + rmmod(d5, rm_arg_w8), [rm_arg_w8, d_cl1])
+addop("shr", [bs('1100000'), w8] + rmmod(d5, rm_arg_w8) + [u08])
+
+addop("sbb", [bs("0001110"), w8, d_eax, d_imm])
+addop("sbb", [bs("100000"), se, w8] + rmmod(d3, rm_arg_w8) + [d_imm])
+addop("sbb", [bs("000110"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("set", [bs8(0x0f), bs('1001'), cond] + rmmod(regnoarg, rm_arg_m08))
+addop("sgdt", [bs8(0x0f), bs8(0x01)] + rmmod(d0))
+addop("shld", [bs8(0x0f), bs8(0xa4)] +
+      rmmod(rmreg) + [u08], [rm_arg, rmreg, u08])
+addop("shld", [bs8(0x0f), bs8(0xa5)] +
+      rmmod(rmreg) + [d_cl], [rm_arg, rmreg, d_cl])
+addop("shrd", [bs8(0x0f), bs8(0xac)] +
+      rmmod(rmreg) + [u08], [rm_arg, rmreg, u08])
+addop("shrd", [bs8(0x0f), bs8(0xad)] +
+      rmmod(rmreg) + [d_cl], [rm_arg, rmreg, d_cl])
+addop("sidt", [bs8(0x0f), bs8(0x01)] + rmmod(d1))
+addop("sldt", [bs8(0x0f), bs8(0x00)] + rmmod(d0))
+addop("smsw", [bs8(0x0f), bs8(0x01)] + rmmod(d4))
+addop("stc", [bs8(0xf9)])
+addop("std", [bs8(0xfd)])
+addop("sti", [bs8(0xfb)])
+addop("stosb", [bs8(0xaa)])
+# stos_name = {16:'STOSW', 32:'STOSD', 64:'STOSQ'}
+# bs_stos_name = bs_modname_size(l=0, name=stos_name)
+# addop("stos", [bs8(0xab), bs_stos_name])
+addop("stosw", [bs8(0xab), bs_opmode16])
+addop("stosd", [bs8(0xab), bs_opmode32])
+addop("stosq", [bs8(0xab), bs_opmode64])
+
+addop("str", [bs8(0x0f), bs8(0x00)] + rmmod(d1))
+
+addop("sub", [bs("0010110"), w8, d_eax, d_imm])
+addop("sub", [bs("100000"), se, w8] + rmmod(d5, rm_arg_w8) + [d_imm])
+addop("sub", [bs("001010"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("syscall", [bs8(0x0f), bs8(0x05)])
+addop("sysenter", [bs8(0x0f), bs8(0x34)])
+addop("sysexit", [bs8(0x0f), bs8(0x35)])
+addop("sysret", [bs8(0x0f), bs8(0x07)])
+addop("test", [bs("1010100"), w8, d_eax, d_imm])
+addop("test", [bs("1111011"), w8] + rmmod(d0, rm_arg_w8) + [d_imm])
+addop("test", [bs("1000010"), w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("ud2", [bs8(0x0f), bs8(0x0b)])
+addop("verr", [bs8(0x0f), bs8(0x00)] + rmmod(d4))
+addop("verw", [bs8(0x0f), bs8(0x00)] + rmmod(d5))
+addop("wbind", [bs8(0x0f), bs8(0x09)])
+addop("wrmsr", [bs8(0x0f), bs8(0x30)])
+addop("xadd", [bs8(0x0f), bs("1100000"), w8]
+      + rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+addop("nop", [bs8(0x90)], alias=True)
+
+addop("xchg", [bs('10010'), d_eax, reg])
+addop("xchg", [bs('1000011'), w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+addop("xlat", [bs8(0xd7)])
+
+
+addop("xor", [bs("0011010"), w8, d_eax, d_imm])
+addop("xor", [bs("100000"), se, w8] + rmmod(d6, rm_arg_w8) + [d_imm])
+addop("xor", [bs("001100"), swapargs, w8] +
+      rmmod(rmreg, rm_arg_w8), [rm_arg_w8, rmreg])
+
+
+# xorps_name = {16:'XORPD', 32:'XORPS', 64:'XORPS'}
+# bs_xorps_name = bs_modname_size(l=0, name=xorps_name)
+# addop("xorps", [bs8(0x0f), bs8(0x57), xmm] + rmmod(rmreg) + [
+# bs_xorps_name] )
+addop("xorpd", [bs8(0x0f), bs8(0x57), xmm] + rmmod(rmreg) + [bs_opmode16])
+addop("xorps", [bs8(0x0f), bs8(0x57), xmm] + rmmod(rmreg) + [bs_opmode32])
+addop("xorps", [bs8(0x0f), bs8(0x57), xmm] + rmmod(rmreg) + [bs_opmode64])
+
+# movaps_name = {16:'MOVAPD', 32:'MOVAPS', 64:'MOVAPS'}
+# bs_movaps_name = bs_modname_size(l=0, name=movaps_name)
+# addop("movaps", [bs8(0x0f), bs("0010100"), swapargs, xmm] + rmmod(rmreg,
+# rm_arg) + [ bs_movaps_name], [rmreg, rm_arg])
+addop("movapd", [bs8(0x0f), bs("0010100"), swapargs, xmm]
+      + rmmod(rmreg, rm_arg) + [bs_opmode16], [rmreg, rm_arg])
+addop("movaps", [bs8(0x0f), bs("0010100"), swapargs, xmm]
+      + rmmod(rmreg, rm_arg) + [bs_opmode32], [rmreg, rm_arg])
+addop("movaps", [bs8(0x0f), bs("0010100"), swapargs, xmm]
+      + rmmod(rmreg, rm_arg) + [bs_opmode64], [rmreg, rm_arg])
+
+mn_x86.bintree = factor_one_bit(mn_x86.bintree)
+# mn_x86.bintree = factor_fields_all(mn_x86.bintree)
+"""
+mod reg r/m
+ XX XXX XXX
+
+"""
+
+
+def print_size(e):
+    print e, e.size
+    return e
diff --git a/miasm2/arch/x86/disasm.py b/miasm2/arch/x86/disasm.py
new file mode 100644
index 00000000..7185a973
--- /dev/null
+++ b/miasm2/arch/x86/disasm.py
@@ -0,0 +1,51 @@
+from miasm2.core.asmbloc import asm_constraint, asm_label, disasmEngine
+from miasm2.expression.expression import ExprId
+from arch import mn_x86
+
+
+def cb_x86_callpop(mn, attrib, pool_bin, cur_bloc, offsets_to_dis, symbol_pool):
+    """
+    1000: call 1005
+    1005: pop
+    """
+    if len(cur_bloc.lines) < 1:
+        return
+    l = cur_bloc.lines[-1]
+    if l.name != 'CALL':
+        return
+    dst = l.args[0]
+    if not (isinstance(dst, ExprId) and isinstance(dst.name, asm_label)):
+        return
+    if dst.name.offset != l.offset + l.l:
+        return
+    l.name = 'PUSH'
+    # cur_bloc.bto.pop()
+    cur_bloc.bto[0].c_bto = asm_constraint.c_next
+
+
+cb_x86_funcs = [cb_x86_callpop]
+
+
+def cb_x86_disasm(mn, attrib, pool_bin, cur_bloc, offsets_to_dis, symbol_pool):
+    for func in cb_x86_funcs:
+        func(mn, attrib, pool_bin, cur_bloc, offsets_to_dis, symbol_pool)
+
+
+class dis_x86(disasmEngine):
+    attrib = None
+
+    def __init__(self, bs=None, **kwargs):
+        super(dis_x86, self).__init__(mn_x86, self.attrib, bs, **kwargs)
+        self.dis_bloc_callback = cb_x86_disasm
+
+
+class dis_x86_16(dis_x86):
+    attrib = 16
+
+
+class dis_x86_32(dis_x86):
+    attrib = 32
+
+
+class dis_x86_64(dis_x86):
+    attrib = 64
diff --git a/miasm2/arch/x86/ira.py b/miasm2/arch/x86/ira.py
new file mode 100644
index 00000000..04cb4cca
--- /dev/null
+++ b/miasm2/arch/x86/ira.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+from miasm2.expression.expression import *
+from miasm2.core.graph import DiGraph
+from miasm2.ir.ir import ir, irbloc
+from miasm2.ir.analysis import ira
+from miasm2.arch.x86.sem import ir_x86_16, ir_x86_32, ir_x86_64
+
+
+class ir_a_x86_16(ir_x86_16, ira):
+
+    def __init__(self, symbol_pool=None):
+        ir_x86_16.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.AX
+
+    # for test XXX TODO
+    def set_dead_regs(self, b):
+        b.rw[-1][1].add(self.arch.regs.zf)
+        b.rw[-1][1].add(self.arch.regs.of)
+        b.rw[-1][1].add(self.arch.regs.pf)
+        b.rw[-1][1].add(self.arch.regs.cf)
+        b.rw[-1][1].add(self.arch.regs.nf)
+        b.rw[-1][1].add(self.arch.regs.af)
+
+    def get_out_regs(self, b):
+        return set([self.ret_reg, self.sp])
+
+    def add_unused_regs(self):
+        leaves = [self.blocs[n] for n in self.g.leafs()]
+        for b in leaves:
+            self.set_dead_regs(b)
+
+    def call_effects(self, ad):
+        irs = [[ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)),
+                ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)),
+                ]]
+        return irs
+
+    def post_add_bloc(self, bloc, ir_blocs):
+        ir.post_add_bloc(self, bloc, ir_blocs)
+        if not bloc.lines:
+            return
+        l = bloc.lines[-1]
+        sub_call_dst = None
+        if not l.is_subcall():
+            return
+        sub_call_dst = l.args[0]
+        if self.ExprIsLabel(sub_call_dst):
+            sub_call_dst = sub_call_dst.name
+        for b in ir_blocs:
+            l = b.lines[-1]
+            sub_call_dst = None
+            if not l.is_subcall():
+                continue
+            sub_call_dst = l.args[0]
+            if self.ExprIsLabel(sub_call_dst):
+                sub_call_dst = sub_call_dst.name
+            lbl = bloc.get_next()
+            new_lbl = self.gen_label()
+            irs = self.call_effects(l.args[0])
+            nbloc = irbloc(new_lbl, ExprId(lbl, size=self.pc.size), irs)
+            nbloc.lines = [l]
+            self.blocs[new_lbl] = nbloc
+            b.dst = ExprId(new_lbl, size=self.pc.size)
+        return
+
+
+class ir_a_x86_32(ir_x86_32, ir_a_x86_16):
+
+    def __init__(self, symbol_pool=None):
+        ir_x86_32.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.EAX
+
+
+class ir_a_x86_64(ir_x86_64, ir_a_x86_16):
+
+    def __init__(self, symbol_pool=None):
+        ir_x86_64.__init__(self, symbol_pool)
+        self.ret_reg = self.arch.regs.RAX
+
+    def call_effects(self, ad):
+        irs = [[ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp,
+                                             self.arch.regs.RCX,
+                                             self.arch.regs.RDX,
+                                             self.arch.regs.R8,
+                                             self.arch.regs.R9,
+                                             )),
+                ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)),
+                ]]
+        return irs
diff --git a/miasm2/arch/x86/regs.py b/miasm2/arch/x86/regs.py
new file mode 100644
index 00000000..532b4f0c
--- /dev/null
+++ b/miasm2/arch/x86/regs.py
@@ -0,0 +1,405 @@
+from miasm2.expression.expression import *
+from miasm2.core.cpu import reg_info
+
+
+IP = ExprId('IP', 16)
+EIP = ExprId('EIP', 32)
+RIP = ExprId('RIP', 64)
+exception_flags = ExprId('exception_flags', 32)
+
+# GP
+
+
+regs08_str = ["AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"] + \
+    ["R%dB" % (i + 8) for i in xrange(8)]
+regs08_expr = [ExprId(x, 8) for x in regs08_str]
+
+regs08_64_str = ["AL", "CL", "DL", "BL", "SPL", "BPL", "SIL", "DIL"] + \
+    ["R%dB" % (i + 8) for i in xrange(8)]
+regs08_64_expr = [ExprId(x, 8) for x in regs08_64_str]
+
+
+regs16_str = ["AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"] + \
+    ["R%dW" % (i + 8) for i in xrange(8)]
+regs16_expr = [ExprId(x, 16) for x in regs16_str]
+
+regs32_str = ["EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"] + \
+    ["R%dD" % (i + 8) for i in xrange(8)]
+regs32_expr = [ExprId(x, 32) for x in regs32_str]
+
+regs64_str = ["RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
+              "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
+              "RIP"]
+regs64_expr = [ExprId(x, 64) for x in regs64_str]
+
+
+regs_xmm_str = ["XMM%d" % i for i in xrange(16)]
+regs_xmm_expr = [ExprId(x, 128) for x in regs_xmm_str]
+
+regs_mm_str = ["MM%d" % i for i in xrange(16)]
+regs_mm_expr = [ExprId(x, 64) for x in regs_mm_str]
+
+
+gpregs08 = reg_info(regs08_str, regs08_expr)
+gpregs08_64 = reg_info(regs08_64_str, regs08_64_expr)
+gpregs16 = reg_info(regs16_str, regs16_expr)
+gpregs32 = reg_info(regs32_str, regs32_expr)
+gpregs64 = reg_info(regs64_str, regs64_expr)
+
+gpregs_xmm = reg_info(regs_xmm_str, regs_xmm_expr)
+gpregs_mm = reg_info(regs_mm_str, regs_mm_expr)
+
+r08_eax = reg_info([regs08_str[0]], [regs08_expr[0]])
+r16_eax = reg_info([regs16_str[0]], [regs16_expr[0]])
+r32_eax = reg_info([regs32_str[0]], [regs32_expr[0]])
+r64_eax = reg_info([regs64_str[0]], [regs64_expr[0]])
+
+r08_ecx = reg_info([regs08_str[1]], [regs08_expr[1]])
+
+r_eax_all = reg_info(
+    [regs08_str[0], regs16_str[0], regs32_str[0], regs64_str[0]],
+    [regs08_expr[0], regs16_expr[0], regs32_expr[0], regs64_expr[0]])
+r_edx_all = reg_info(
+    [regs08_str[2], regs16_str[2], regs32_str[2], regs64_str[2]],
+    [regs08_expr[2], regs16_expr[2], regs32_expr[2], regs64_expr[2]])
+
+r16_edx = reg_info([regs16_str[2]], [regs16_expr[2]])
+
+
+selectr_str = ["ES", "CS", "SS", "DS", "FS", "GS"]
+selectr_expr = [ExprId(x, 16) for x in selectr_str]
+segmreg = reg_info(selectr_str, selectr_expr)
+
+crregs32_str = ["CR%d" % i for i in xrange(8)]
+crregs32_expr = [ExprId(x, 32) for x in crregs32_str]
+crregs = reg_info(crregs32_str, crregs32_expr)
+
+
+drregs32_str = ["DR%d" % i for i in xrange(8)]
+drregs32_expr = [ExprId(x, 32) for x in drregs32_str]
+drregs = reg_info(drregs32_str, drregs32_expr)
+
+
+fltregs32_str = ["ST(%d)" % i for i in xrange(8)]
+fltregs32_expr = [ExprId(x, 64) for x in fltregs32_str]
+fltregs = reg_info(fltregs32_str, fltregs32_expr)
+
+r_st_all = reg_info(['ST'],
+                    [ExprId('ST', 64)])
+
+r_cs_all = reg_info(['CS'],
+                    [ExprId('CS', 16)])
+r_ds_all = reg_info(['DS'],
+                    [ExprId('DS', 16)])
+r_es_all = reg_info(['ES'],
+                    [ExprId('ES', 16)])
+r_ss_all = reg_info(['SS'],
+                    [ExprId('SS', 16)])
+r_fs_all = reg_info(['FS'],
+                    [ExprId('FS', 16)])
+r_gs_all = reg_info(['GS'],
+                    [ExprId('GS', 16)])
+
+
+AL = regs08_expr[0]
+CL = regs08_expr[1]
+DL = regs08_expr[2]
+BL = regs08_expr[3]
+AH = regs08_expr[4]
+CH = regs08_expr[5]
+DH = regs08_expr[6]
+BH = regs08_expr[7]
+R8B = regs08_expr[8]
+R9B = regs08_expr[9]
+R10B = regs08_expr[10]
+R11B = regs08_expr[11]
+R12B = regs08_expr[12]
+R13B = regs08_expr[13]
+R14B = regs08_expr[14]
+R15B = regs08_expr[15]
+R15B = regs08_expr[15]
+
+SPL = regs08_64_expr[4]
+BPL = regs08_64_expr[5]
+SIL = regs08_64_expr[6]
+DIL = regs08_64_expr[7]
+
+
+AX = regs16_expr[0]
+CX = regs16_expr[1]
+DX = regs16_expr[2]
+BX = regs16_expr[3]
+SP = regs16_expr[4]
+BP = regs16_expr[5]
+SI = regs16_expr[6]
+DI = regs16_expr[7]
+R8W = regs16_expr[8]
+R9W = regs16_expr[9]
+R10W = regs16_expr[10]
+R11W = regs16_expr[11]
+R12W = regs16_expr[12]
+R13W = regs16_expr[13]
+R14W = regs16_expr[14]
+R15W = regs16_expr[15]
+
+
+EAX = regs32_expr[0]
+ECX = regs32_expr[1]
+EDX = regs32_expr[2]
+EBX = regs32_expr[3]
+ESP = regs32_expr[4]
+EBP = regs32_expr[5]
+ESI = regs32_expr[6]
+EDI = regs32_expr[7]
+R8D = regs32_expr[8]
+R9D = regs32_expr[9]
+R10D = regs32_expr[10]
+R11D = regs32_expr[11]
+R12D = regs32_expr[12]
+R13D = regs32_expr[13]
+R14D = regs32_expr[14]
+R15D = regs32_expr[15]
+
+
+RAX = regs64_expr[0]
+RCX = regs64_expr[1]
+RDX = regs64_expr[2]
+RBX = regs64_expr[3]
+RSP = regs64_expr[4]
+RBP = regs64_expr[5]
+RSI = regs64_expr[6]
+RDI = regs64_expr[7]
+R8 = regs64_expr[8]
+R9 = regs64_expr[9]
+R10 = regs64_expr[10]
+R11 = regs64_expr[11]
+R12 = regs64_expr[12]
+R13 = regs64_expr[13]
+R14 = regs64_expr[14]
+R15 = regs64_expr[15]
+
+
+reg_zf = 'zf'
+reg_nf = 'nf'
+reg_pf = 'pf'
+reg_of = 'of'
+reg_cf = 'cf'
+reg_tf = 'tf'
+reg_if = 'i_f'
+reg_df = 'df'
+reg_af = 'af'
+reg_iopl = 'iopl_f'
+reg_nt = 'nt'
+reg_rf = 'rf'
+reg_vm = 'vm'
+reg_ac = 'ac'
+reg_vif = 'vif'
+reg_vip = 'vip'
+reg_id = 'i_d'
+
+
+reg_es = "ES"
+reg_cs = "CS"
+reg_ss = "SS"
+reg_ds = "DS"
+reg_fs = "FS"
+reg_gs = "GS"
+
+reg_dr0 = 'DR0'
+reg_dr1 = 'DR1'
+reg_dr2 = 'DR2'
+reg_dr3 = 'DR3'
+reg_dr4 = 'DR4'
+reg_dr5 = 'DR5'
+reg_dr6 = 'DR6'
+reg_dr7 = 'DR7'
+
+reg_cr0 = 'CR0'
+reg_cr1 = 'CR1'
+reg_cr2 = 'CR2'
+reg_cr3 = 'CR3'
+reg_cr4 = 'CR4'
+reg_cr5 = 'CR5'
+reg_cr6 = 'CR6'
+reg_cr7 = 'CR7'
+
+reg_mm0 = 'MM0'
+reg_mm1 = 'MM1'
+reg_mm2 = 'MM2'
+reg_mm3 = 'MM3'
+reg_mm4 = 'MM4'
+reg_mm5 = 'MM5'
+reg_mm6 = 'MM6'
+reg_mm7 = 'MM7'
+
+
+reg_tsc1 = "tsc1"
+reg_tsc2 = "tsc2"
+
+reg_float_c0 = 'float_c0'
+reg_float_c1 = 'float_c1'
+reg_float_c2 = 'float_c2'
+reg_float_c3 = 'float_c3'
+reg_float_stack_ptr = "float_stack_ptr"
+reg_float_control = 'reg_float_control'
+reg_float_eip = 'reg_float_eip'
+reg_float_cs = 'reg_float_cs'
+reg_float_address = 'reg_float_address'
+reg_float_ds = 'reg_float_ds'
+
+
+reg_float_st0 = 'float_st0'
+reg_float_st1 = 'float_st1'
+reg_float_st2 = 'float_st2'
+reg_float_st3 = 'float_st3'
+reg_float_st4 = 'float_st4'
+reg_float_st5 = 'float_st5'
+reg_float_st6 = 'float_st6'
+reg_float_st7 = 'float_st7'
+
+
+dr0 = ExprId(reg_dr0)
+dr1 = ExprId(reg_dr1)
+dr2 = ExprId(reg_dr2)
+dr3 = ExprId(reg_dr3)
+dr4 = ExprId(reg_dr4)
+dr5 = ExprId(reg_dr5)
+dr6 = ExprId(reg_dr6)
+dr7 = ExprId(reg_dr7)
+
+cr0 = ExprId(reg_cr0)
+cr1 = ExprId(reg_cr1)
+cr2 = ExprId(reg_cr2)
+cr3 = ExprId(reg_cr3)
+cr4 = ExprId(reg_cr4)
+cr5 = ExprId(reg_cr5)
+cr6 = ExprId(reg_cr6)
+cr7 = ExprId(reg_cr7)
+
+mm0 = ExprId(reg_mm0, 64)
+mm1 = ExprId(reg_mm1, 64)
+mm2 = ExprId(reg_mm2, 64)
+mm3 = ExprId(reg_mm3, 64)
+mm4 = ExprId(reg_mm4, 64)
+mm5 = ExprId(reg_mm5, 64)
+mm6 = ExprId(reg_mm6, 64)
+mm7 = ExprId(reg_mm7, 64)
+
+
+# tmp1= ExprId(reg_tmp1)
+zf = ExprId(reg_zf, size=1)
+nf = ExprId(reg_nf, size=1)
+pf = ExprId(reg_pf, size=1)
+of = ExprId(reg_of, size=1)
+cf = ExprId(reg_cf, size=1)
+tf = ExprId(reg_tf, size=1)
+i_f = ExprId(reg_if, size=1)
+df = ExprId(reg_df, size=1)
+af = ExprId(reg_af, size=1)
+iopl = ExprId(reg_iopl, size=2)
+nt = ExprId(reg_nt, size=1)
+rf = ExprId(reg_rf, size=1)
+vm = ExprId(reg_vm, size=1)
+ac = ExprId(reg_ac, size=1)
+vif = ExprId(reg_vif, size=1)
+vip = ExprId(reg_vip, size=1)
+i_d = ExprId(reg_id, size=1)
+
+ES = ExprId(reg_es, size=16)
+CS = ExprId(reg_cs, size=16)
+SS = ExprId(reg_ss, size=16)
+DS = ExprId(reg_ds, size=16)
+FS = ExprId(reg_fs, size=16)
+GS = ExprId(reg_gs, size=16)
+
+tsc1 = ExprId(reg_tsc1, size=32)
+tsc2 = ExprId(reg_tsc2, size=32)
+
+float_c0 = ExprId(reg_float_c0, size=1)
+float_c1 = ExprId(reg_float_c1, size=1)
+float_c2 = ExprId(reg_float_c2, size=1)
+float_c3 = ExprId(reg_float_c3, size=1)
+float_stack_ptr = ExprId(reg_float_stack_ptr, size=3)
+float_control = ExprId(reg_float_control, 16)
+float_eip = ExprId(reg_float_eip)
+float_cs = ExprId(reg_float_cs, size=16)
+float_address = ExprId(reg_float_address)
+float_ds = ExprId(reg_float_ds, size=16)
+
+float_st0 = ExprId(reg_float_st0, 64)
+float_st1 = ExprId(reg_float_st1, 64)
+float_st2 = ExprId(reg_float_st2, 64)
+float_st3 = ExprId(reg_float_st3, 64)
+float_st4 = ExprId(reg_float_st4, 64)
+float_st5 = ExprId(reg_float_st5, 64)
+float_st6 = ExprId(reg_float_st6, 64)
+float_st7 = ExprId(reg_float_st7, 64)
+
+EAX_init = ExprId('EAX_init')
+EBX_init = ExprId('EBX_init')
+ECX_init = ExprId('ECX_init')
+EDX_init = ExprId('EDX_init')
+ESI_init = ExprId('ESI_init')
+EDI_init = ExprId('EDI_init')
+ESP_init = ExprId('ESP_init')
+EBP_init = ExprId('EBP_init')
+
+
+RAX_init = ExprId('RAX_init', 64)
+RBX_init = ExprId('RBX_init', 64)
+RCX_init = ExprId('RCX_init', 64)
+RDX_init = ExprId('RDX_init', 64)
+RSI_init = ExprId('RSI_init', 64)
+RDI_init = ExprId('RDI_init', 64)
+RSP_init = ExprId('RSP_init', 64)
+RBP_init = ExprId('RBP_init', 64)
+
+
+all_regs_ids = [
+    AL, CL, DL, BL, AH, CH, DH, BH,
+    R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B, R15B,
+    SPL, BPL, SIL, DIL,
+    AX, CX, DX, BX, SP, BP, SI, DI,
+    R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W,
+    IP,
+    EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
+    R8D, R9D, R10D, R11D, R12D, R13D, R14D, R15D,
+    EIP,
+
+    RAX, RBX, RCX, RDX, RSP, RBP, RIP, RSI, RDI,
+    R8, R9, R10, R11, R12, R13, R14, R15, R15,
+    zf, nf, pf, of, cf, af, df,
+    tf, i_f, iopl, nt, rf, vm, ac, vif, vip, i_d,
+    float_control, float_eip, float_cs, float_address, float_ds,
+    tsc1, tsc2,
+    ES, CS, SS, DS, FS, GS,
+    float_st0, float_st1, float_st2, float_st3,
+    float_st4, float_st5, float_st6, float_st7,
+    float_c0, float_c1, float_c2, float_c3,
+    cr0, cr3,
+    dr0, dr1, dr2, dr3, dr4, dr5, dr6, dr7,
+    float_stack_ptr,
+    mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+
+    exception_flags,
+] + fltregs32_expr
+
+all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids])
+
+all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids]
+
+regs_init = {}
+for i, r in enumerate(all_regs_ids):
+    all_regs_ids_init[i].is_term = True
+    regs_init[r] = all_regs_ids_init[i]
+
+
+mRAX = {16: AX, 32: EAX, 64: RAX}
+mRBX = {16: BX, 32: EBX, 64: RBX}
+mRCX = {16: CX, 32: ECX, 64: RCX}
+mRDX = {16: DX, 32: EDX, 64: RDX}
+mRSI = {16: SI, 32: ESI, 64: RSI}
+mRDI = {16: DI, 32: EDI, 64: RDI}
+mRBP = {16: BP, 32: EBP, 64: RBP}
+mRSP = {16: SP, 32: ESP, 64: RSP}
+mRIP = {16: IP, 32: EIP, 64: RIP}
diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py
new file mode 100644
index 00000000..4b8a357b
--- /dev/null
+++ b/miasm2/arch/x86/sem.py
@@ -0,0 +1,3029 @@
+#
+# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+from miasm2.expression.expression import *
+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.core.asmbloc import expr_is_int_or_label
+from miasm2.ir.ir import ir, irbloc
+import math
+import struct
+from regs import *
+
+# interrupt with eip update after instr
+EXCEPT_SOFT_BP = (1 << 1)
+EXCEPT_INT_XX = (1 << 2)
+
+EXCEPT_BREAKPOINT_INTERN = (1 << 10)
+
+EXCEPT_NUM_UPDT_EIP = (1 << 11)
+# interrupt with eip at instr
+EXCEPT_UNK_MEM_AD = (1 << 12)
+EXCEPT_THROW_SEH = (1 << 13)
+EXCEPT_UNK_EIP = (1 << 14)
+EXCEPT_ACCESS_VIOL = (1 << 14)
+EXCEPT_INT_DIV_BY_ZERO = (1 << 16)
+EXCEPT_PRIV_INSN = (1 << 17)
+EXCEPT_ILLEGAL_INSN = (1 << 18)
+EXCEPT_UNK_MNEMO = (1 << 19)
+
+
+"""
+http://www.emulators.com/docs/nx11_flags.htm
+
+CF(A+B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND NOT (A XOR B)) < 0)
+CF(A-B) = (((A XOR B) XOR D) < 0) XOR (((A XOR D) AND (A XOR B)) < 0)
+
+OF(A+B) = ((A XOR D) AND NOT (A XOR B)) < 0
+OF(A-B) = ((A XOR D) AND (A XOR B)) < 0
+"""
+
+
+float_list = [
+    float_st0,
+    float_st1,
+    float_st2,
+    float_st3,
+    float_st4,
+    float_st5,
+    float_st6,
+    float_st7,
+]
+
+
+# XXX TODO make default check against 0 or not 0 (same eq as in C)
+
+
+def update_flag_zf(a):
+    return [ExprAff(zf, ExprCond(a, ExprInt_from(zf, 0), ExprInt_from(zf, 1)))]
+
+
+def update_flag_nf(a):
+    return [ExprAff(nf, a.msb())]
+
+
+def update_flag_pf(a):
+    return [ExprAff(pf, ExprOp('parity', a & ExprInt_from(a, 0xFF)))]
+
+
+def update_flag_af(a):
+    return [ExprAff(af, ExprCond((a & ExprInt_from(a, 0x10)),
+                                 ExprInt_from(af, 1), ExprInt_from(af, 0)))]
+
+
+def update_flag_znp(a):
+    e = []
+    e += update_flag_zf(a)
+    e += update_flag_nf(a)
+    e += update_flag_pf(a)
+    return e
+
+
+def update_flag_logic(a):
+    e = []
+    e += update_flag_znp(a)
+    e.append(ExprAff(of, ExprInt_from(of, 0)))
+    e.append(ExprAff(cf, ExprInt_from(cf, 0)))
+    return e
+
+
+def update_flag_arith(a):
+    e = []
+    e += update_flag_znp(a)
+    return e
+
+
+def check_ops_msb(a, b, c):
+    if not a or not b or not c or a != b or a != c:
+        raise ValueError('bad ops size %s %s %s' % (a, b, c))
+
+
+def arith_flag(a, b, c):
+    a_s, b_s, c_s = a.size, b.size, c.size
+    check_ops_msb(a_s, b_s, c_s)
+    a_s, b_s, c_s = a.msb(), b.msb(), c.msb()
+    return a_s, b_s, c_s
+
+# checked: ok for adc add because b & c before +cf
+
+
+def update_flag_add_cf(a, b, c):
+    return ExprAff(cf, (((a ^ b) ^ c) ^ ((a ^ c) & (~(a ^ b)))).msb())
+
+
+def update_flag_add_of(a, b, c):
+    return ExprAff(of, (((a ^ c) & (~(a ^ b)))).msb())
+
+
+# checked: ok for sbb add because b & c before +cf
+def update_flag_sub_cf(a, b, c):
+    return ExprAff(cf, (((a ^ b) ^ c) ^ ((a ^ c) & (a ^ b))).msb())
+
+
+def update_flag_sub_of(a, b, c):
+    return ExprAff(of, (((a ^ c) & (a ^ b))).msb())
+
+# z = x+y (+cf?)
+
+
+def update_flag_add(x, y, z):
+    e = []
+    e.append(update_flag_add_cf(x, y, z))
+    e.append(update_flag_add_of(x, y, z))
+    return e
+
+# z = x-y (+cf?)
+
+
+def update_flag_sub(x, y, z):
+    e = []
+    e.append(update_flag_sub_cf(x, y, z))
+    e.append(update_flag_sub_of(x, y, z))
+    return e
+
+
+def set_float_cs_eip(instr):
+    e = []
+    # XXX TODO check float updt
+    e.append(ExprAff(float_eip, ExprInt_from(float_eip, instr.offset)))
+    e.append(ExprAff(float_cs, CS))
+    return e
+
+
+def mov(ir, instr, a, b):
+    if a in [ES, CS, SS, DS, FS, GS]:
+        b = b[:a.size]
+    if b in [ES, CS, SS, DS, FS, GS]:
+        b = b.zeroExtend(a.size)
+    e = [ExprAff(a, b)]
+    return None, e, []
+
+
+def xchg(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, b))
+    e.append(ExprAff(b, a))
+    return None, e, []
+
+
+def movzx(ir, instr, a, b):
+    e = [ExprAff(a, b.zeroExtend(a.size))]
+    return None, e, []
+
+
+def movsx(ir, instr, a, b):
+    e = [ExprAff(a, b.signExtend(a.size))]
+    return None, e, []
+
+
+def lea(ir, instr, a, b):
+    src = b.arg
+    if src.size > a.size:
+        src = src[:a.size]
+    e = [ExprAff(a, src)]
+    return None, e, []
+
+
+def add(ir, instr, a, b):
+    e = []
+    c = a + b
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+    e += update_flag_add(a, b, c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def xadd(ir, instr, a, b):
+    e = []
+    c = a + b
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+    e += update_flag_add(b, a, c)
+    e.append(ExprAff(b, a))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def adc(ir, instr, a, b):
+    e = []
+    c = a + (b + ExprCompose([(ExprInt_fromsize(a.size - 1, 0), 1, a.size),
+                              (cf, 0, 1)]))
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+    e += update_flag_add(a, b, c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def sub(ir, instr, a, b):
+    e = []
+    c = a - b
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+    e += update_flag_sub(a, b, c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+# a-(b+cf)
+
+
+def sbb(ir, instr, a, b):
+    e = []
+    c = a - (b + ExprCompose([(ExprInt_fromsize(a.size - 1, 0), 1, a.size),
+                              (cf, 0, 1)]))
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+    e += update_flag_sub(a, b, c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def neg(ir, instr, b):
+    e = []
+    a = ExprInt_from(b, 0)
+
+    c = a - b
+    e += update_flag_arith(c)
+    e += update_flag_sub(a, b, c)
+    e += update_flag_af(c)
+    e.append(ExprAff(b, c))
+    return None, e, []
+
+
+def l_not(ir, instr, b):
+    e = []
+    c = ~b
+    e.append(ExprAff(b, c))
+    return None, e, []
+
+
+def l_cmp(ir, instr, a, b):
+    e = []
+    c = a - b
+    e += update_flag_arith(c)
+    e += update_flag_sub(a, b, c)
+    e += update_flag_af(c)
+    return None, e, []
+
+
+def xor(ir, instr, a, b):
+    e = []
+    c = a ^ b
+    e += update_flag_logic(c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def l_or(ir, instr, a, b):
+    e = []
+    c = a | b
+    e += update_flag_logic(c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def l_and(ir, instr, a, b):
+    e = []
+    c = a & b
+    e += update_flag_logic(c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def l_test(ir, instr, a, b):
+    e = []
+    c = a & b
+    e += update_flag_logic(c)
+    return None, e, []
+
+
+def l_rol(ir, instr, a, b):
+    e = []
+    b = b.zeroExtend(a.size)
+    c = ExprOp('<<<', a, b)
+
+    new_cf = c[:1]
+    e.append(ExprAff(cf, new_cf))
+    # hack (only valid if b=1)
+    e.append(ExprAff(of, c.msb() ^ new_cf))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def l_ror(ir, instr, a, b):
+    e = []
+    b = b.zeroExtend(a.size)
+    c = ExprOp('>>>', a, b)
+
+    e.append(ExprAff(cf, c.msb()))
+    # hack (only valid if b=1): when count == 1: a = msb-1(dest)
+    e.append(ExprAff(of, (c ^ a).msb()))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def rcl(ir, instr, a, b):
+    e = []
+    b = b.zeroExtend(a.size)
+    c = ExprOp('<<<c_rez', a, b, cf.zeroExtend(a.size))
+    new_cf = ExprOp('<<<c_cf', a, b, cf.zeroExtend(a.size))[:1]
+
+    e.append(ExprAff(cf, new_cf))
+    # hack (only valid if b=1)
+    e.append(ExprAff(of, c.msb() ^ new_cf))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def rcr(ir, instr, a, b):
+    e = []
+    b = b.zeroExtend(a.size)
+    c = ExprOp('>>>c_rez', a, b, cf.zeroExtend(a.size))
+    new_cf = ExprOp('>>>c_cf', a, b, cf.zeroExtend(a.size))[:1]
+
+    e.append(ExprAff(cf, new_cf))
+    # hack (only valid if b=1)
+    e.append(ExprAff(of, (a ^ c).msb()))
+    e.append(ExprAff(a, c))
+
+    return None, e, []
+
+
+def get_shift(a, b):
+    # b.size must match a
+    b = b.zeroExtend(a.size)
+    if a.size == 64:
+        shift = b & ExprInt_from(b, 0x3f)
+    else:
+        shift = b & ExprInt_from(b, 0x1f)
+    shift = expr_simp(shift)
+    return shift
+
+
+def sar(ir, instr, a, b):
+
+    shifter = get_shift(a, b)
+    c = ExprOp('a>>', a, shifter)
+
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+
+    new_cf = ExprOp('a>>', a, (shifter - ExprInt_from(a, 1)))[:1]
+
+    e_do = [
+        ExprAff(cf, new_cf),
+        ExprAff(of, ExprInt_from(of, 0)),
+        ExprAff(a, c)
+    ]
+
+    e_do += update_flag_znp(c)
+
+    # dont generate conditional shifter on constant
+    if isinstance(shifter, ExprInt):
+        if int(shifter.arg) != 0:
+            return None, e_do, []
+        else:
+            raise NotImplementedError("TODO check me")
+
+    return ExprCond(shifter, lbl_do, lbl_skip),
+    [], [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def shr(ir, instr, a, b):
+    e = []
+    # TODO FIX AS SAR!
+    shifter = get_shift(a, b)
+    c = ExprOp('>>', a, shifter)
+
+    new_cf = ExprOp('>>', a, (shifter - ExprInt_from(a, 1)))[:1]
+    e.append(ExprAff(cf, ExprCond(shifter,
+                                  new_cf,
+                                  cf)
+                     )
+             )
+    e.append(ExprAff(of, a.msb()))
+    e += update_flag_znp(c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def shrd_cl(ir, instr, a, b):
+    e = []
+    opmode, admode = s, instr.v_admode()
+    shifter = mRCX[instr.mode][:8].zeroExtend(a.size) & ExprInt_from(a, 0x1f)
+    c = (a >> shifter) | (b << (ExprInt_from(a, a.size) - shifter))
+    new_cf = (a >> (shifter - ExprInt_from(a, 1)))[:1]
+    e.append(ExprAff(cf, ExprCond(shifter,
+                                  new_cf,
+                                  cf)
+                     )
+             )
+    e.append(ExprAff(of, a.msb()))
+    e += update_flag_znp(c)
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def shrd(ir, instr, a, b, c):
+    e = []
+    shifter = get_shift(a, c)
+
+    d = (a >> shifter) | (b << (ExprInt_from(a, a.size) - shifter))
+    new_cf = (a >> (shifter - ExprInt_from(a, 1)))[:1]
+    e.append(ExprAff(cf, ExprCond(shifter,
+                                  new_cf,
+                                  cf)
+                     )
+             )
+    e.append(ExprAff(of, a.msb()))
+    e += update_flag_znp(d)
+    e.append(ExprAff(a, d))
+    return None, e, []
+
+
+def sal(ir, instr, a, b):
+    e = []
+    shifter = get_shift(a, b)
+    c = ExprOp('a<<', a, shifter)
+    new_cf = (a >> (ExprInt_from(a, a.size) - shifter))[:1]
+    e.append(ExprAff(cf, ExprCond(shifter,
+                                  new_cf,
+                                  cf)
+                     )
+             )
+    e += update_flag_znp(c)
+    e.append(ExprAff(of, c.msb() ^ new_cf))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def shl(ir, instr, a, b):
+    e = []
+    shifter = get_shift(a, b)
+    c = a << shifter
+    new_cf = (a >> (ExprInt_from(a, a.size) - shifter))[:1]
+    e.append(ExprAff(cf, ExprCond(shifter,
+                                  new_cf,
+                                  cf)
+                     )
+             )
+    e += update_flag_znp(c)
+    e.append(ExprAff(of, c.msb() ^ new_cf))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def shld_cl(ir, instr, a, b):
+    return shld(ir, instr, a, b, ecx)
+
+
+def shld(ir, instr, a, b, c):
+    e = []
+    shifter = c.zeroExtend(a.size) & ExprInt_from(a, 0x1f)
+    c = ExprOp('|',
+               a << shifter,
+               b >> (ExprInt_from(a, a.size) - shifter)
+               )
+
+    new_cf = (a >> (ExprInt_from(a, a.size) - shifter))[:1]
+    e.append(ExprAff(cf, ExprCond(shifter,
+                                  new_cf,
+                                  cf)
+                     )
+             )
+    # XXX todo: don't update flag if shifter is 0
+    e += update_flag_znp(c)
+    e.append(ExprAff(of, c.msb() ^ new_cf))
+    e.append(ExprAff(a, ExprCond(shifter,
+                                 c,
+                                 a)))
+    return None, e, []
+
+
+# XXX todo ###
+def cmc(ir, instr):
+    e = [ExprAff(cf, ExprCond(cf, ExprInt_from(cf, 0), ExprInt_from(cf, 1)))]
+    return None, e, []
+
+
+def clc(ir, instr):
+    e = [ExprAff(cf, ExprInt_from(cf, 0))]
+    return None, e, []
+
+
+def stc(ir, instr):
+    e = [ExprAff(cf, ExprInt_from(cf, 1))]
+    return None, e, []
+
+
+def cld(ir, instr):
+    e = [ExprAff(df, ExprInt_from(df, 0))]
+    return None, e, []
+
+
+def std(ir, instr):
+    e = [ExprAff(df, ExprInt_from(df, 1))]
+    return None, e, []
+
+
+def cli(ir, instr):
+    e = [ExprAff(i_f, ExprInt_from(i_f, 0))]
+    return None, e, []
+
+
+def sti(ir, instr):
+    e = [ExprAff(exception_flags, ExprInt32(EXCEPT_PRIV_INSN))]
+    e = []  # XXX TODO HACK
+    return None, e, []
+
+
+def inc(ir, instr, a):
+    e = []
+    b = ExprInt_from(a, 1)
+    c = a + b
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+
+    e.append(update_flag_add_of(a, b, c))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def dec(ir, instr, a):
+    e = []
+    b = ExprInt_from(a, -1)
+    c = a + b
+    e += update_flag_arith(c)
+    e += update_flag_af(c)
+
+    e.append(update_flag_add_of(a, b, c))
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def push(ir, instr, a):
+    e = []
+    s = instr.mode
+    size = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    # special case segment regs
+    if a in [ES, CS, SS, DS, FS, GS]:
+        pass
+    if not s in [16, 32, 64]:
+        raise ValueError('bad size stacker!')
+    if isinstance(a, ExprInt):
+        a = ExprInt_fromsize(s, a.arg)
+
+    c = mRSP[instr.mode][:s] - ExprInt_fromsize(s, s / 8)
+    e.append(ExprAff(mRSP[instr.mode][:s], c))
+    # we sub vopmode to stack, but mem access is arg size wide
+    if ir.do_stk_segm:
+        c = ExprOp('segm', SS, c)
+    e.append(ExprAff(ExprMem(c, a.size), a))
+    return None, e, []
+
+
+def pop(ir, instr, a):
+    e = []
+    s = instr.mode
+    size = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    # special case segment regs
+    if a in [ES, CS, SS, DS, FS, GS]:
+        s = admode
+    if not s in [16, 32, 64]:
+        raise ValueError('bad size stacker!')
+    new_esp = mRSP[instr.mode][:s] + ExprInt_fromsize(s, s / 8)
+    e.append(ExprAff(mRSP[instr.mode][:s], new_esp))
+    # XXX FIX XXX for pop [esp]
+    if isinstance(a, ExprMem):
+        a = a.replace_expr({mRSP[instr.mode]: new_esp})
+    c = mRSP[instr.mode][:s]
+    if ir.do_stk_segm:
+        c = ExprOp('segm', SS, c)
+    e.append(ExprAff(a, ExprMem(c, a.size)))
+    return None, e, []
+
+
+def sete(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(zf, ExprInt_from(a, 1), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def setnz(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(zf, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def setl(ir, instr, a):
+    e = []
+    e.append(
+        ExprAff(a, ExprCond(nf - of, ExprInt_from(a, 1), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def setg(ir, instr, a):
+    e = []
+    a0 = ExprInt_from(a, 0)
+    a1 = ExprInt_from(a, 1)
+    e.append(ExprAff(a, ExprCond(zf, a0, a1) & ExprCond(nf - of, a0, a1)))
+    return None, e, []
+
+
+def setge(ir, instr, a):
+    e = []
+    e.append(
+        ExprAff(a, ExprCond(nf - of, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def seta(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(cf | zf,
+                                 ExprInt_from(a, 0),
+                                 ExprInt_from(a, 1))))
+
+    return None, e, []
+
+
+def setae(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(cf, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def setb(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(cf, ExprInt_from(a, 1), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def setbe(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(cf | zf,
+                                 ExprInt_from(a, 1),
+                                 ExprInt_from(a, 0)))
+             )
+    return None, e, []
+
+
+def setns(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(nf, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def sets(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(nf, ExprInt_from(a, 1), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def seto(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(of, ExprInt_from(a, 1), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def setp(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(pf, ExprInt_from(a, 1), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def setnp(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(pf, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def setle(ir, instr, a):
+    e = []
+    a0 = ExprInt_from(a, 0)
+    a1 = ExprInt_from(a, 1)
+    e.append(ExprAff(a, ExprCond(zf, a1, a0) | ExprCond(nf ^ of, a1, a0)))
+    return None, e, []
+
+
+def setna(ir, instr, a):
+    e = []
+    a0 = ExprInt_from(a, 0)
+    a1 = ExprInt_from(a, 1)
+    e.append(ExprAff(a, ExprCond(cf, a1, a0) & ExprCond(zf, a1, a0)))
+    return None, e, []
+
+
+def setnbe(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(cf | zf,
+                                 ExprInt_from(a, 0),
+                                 ExprInt_from(a, 1)))
+             )
+    return None, e, []
+
+
+def setno(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(of, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def setnb(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprCond(cf, ExprInt_from(a, 0), ExprInt_from(a, 1))))
+    return None, e, []
+
+
+def setalc(ir, instr):
+    a = mRAX[instr.mode][0:8]
+    e = []
+    e.append(
+        ExprAff(a, ExprCond(cf, ExprInt_from(a, 0xff), ExprInt_from(a, 0))))
+    return None, e, []
+
+
+def bswap(ir, instr, a):
+    e = []
+    if a.size == 16:
+        c = ExprCompose([(a[:8],        8, 16),
+                         (a[8:16],      0,  8),
+                         ])
+    elif a.size == 32:
+        c = ExprCompose([(a[:8],      24, 32),
+                         (a[8:16],    16, 24),
+                         (a[16:24],   8, 16),
+                         (a[24:32],   0, 8),
+                         ])
+    elif a.size == 64:
+        c = ExprCompose([(a[:8],      56, 64),
+                         (a[8:16],    48, 56),
+                         (a[16:24],   40, 48),
+                         (a[24:32],   32, 40),
+                         (a[32:40],   24, 32),
+                         (a[40:48],   16, 24),
+                         (a[48:56],    8, 16),
+                         (a[56:64],    0, 8),
+                         ])
+    else:
+        raise ValueError('the size DOES matter')
+    e.append(ExprAff(a, c))
+    return None, e, []
+
+
+def cmps(ir, instr, size):
+    lbl_cmp = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_0 = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_1 = ExprId(ir.gen_label(), instr.mode)
+    lbl_next = ExprId(ir.get_next_label(instr), instr.mode)
+
+    s = instr.v_admode()
+    a = ExprMem(mRDI[instr.mode][:s], size)
+    b = ExprMem(mRSI[instr.mode][:s], size)
+
+    dummy, e, extra = l_cmp(ir, instr, a, b)
+
+    e0 = []
+    e0.append(ExprAff(a.arg, a.arg + ExprInt_from(a.arg, size / 8)))
+    e0.append(ExprAff(b.arg, b.arg + ExprInt_from(b.arg, size / 8)))
+    e0 = irbloc(lbl_df_0.name, lbl_next, [e0])
+
+    e1 = []
+    e1.append(ExprAff(a.arg, a.arg - ExprInt_from(a.arg, size / 8)))
+    e1.append(ExprAff(b.arg, b.arg - ExprInt_from(b.arg, size / 8)))
+    e1 = irbloc(lbl_df_1.name, lbl_next, [e1])
+
+    return ExprCond(df, lbl_df_1, lbl_df_0), e, [e0, e1]
+
+
+def scas(ir, instr, size):
+    lbl_cmp = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_0 = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_1 = ExprId(ir.gen_label(), instr.mode)
+    lbl_next = ExprId(ir.get_next_label(instr), instr.mode)
+
+    s = instr.v_admode()
+    a = ExprMem(mRDI[instr.mode][:s], size)
+
+    dummy, e, extra = l_cmp(ir, instr, mRAX[instr.mode][:size], a)
+
+    e0 = []
+    e0.append(ExprAff(a.arg, a.arg + ExprInt_from(a.arg, size / 8)))
+    e0 = irbloc(lbl_df_0.name, lbl_next, [e0])
+
+    e1 = []
+    e1.append(ExprAff(a.arg, a.arg - ExprInt_from(a.arg, size / 8)))
+    e1 = irbloc(lbl_df_1.name, lbl_next, [e1])
+
+    return ExprCond(df, lbl_df_1, lbl_df_0), e, [e0, e1]
+
+
+def compose_eflag(s=32):
+    args = []
+
+    regs = [cf, ExprInt1(1), pf, ExprInt1(
+        0), af, ExprInt1(0), zf, nf, tf, i_f, df, of]
+    for i in xrange(len(regs)):
+        args.append((regs[i], i, i + 1))
+
+    args.append((iopl, 12, 14))
+
+    if s == 32:
+        regs = [nt, ExprInt1(0), rf, vm, ac, vif, vip, i_d]
+    elif s == 16:
+        regs = [nt, ExprInt1(0)]
+    else:
+        raise ValueError('unk size')
+    for i in xrange(len(regs)):
+        args.append((regs[i], i + 14, i + 15))
+    if s == 32:
+        args.append((ExprInt_fromsize(10, 0), 22, 32))
+    return ExprCompose(args)
+
+
+def pushfd(ir, instr):
+    return push(ir, instr, compose_eflag())
+
+
+def pushfw(ir, instr):
+    return push(ir, instr, compose_eflag(16))
+
+
+def popfd(ir, instr):
+    tmp = ExprMem(mRSP[instr.mode])
+    e = []
+    e.append(ExprAff(cf, ExprSlice(tmp, 0, 1)))
+    e.append(ExprAff(pf, ExprSlice(tmp, 2, 3)))
+    e.append(ExprAff(af, ExprSlice(tmp, 4, 5)))
+    e.append(ExprAff(zf, ExprSlice(tmp, 6, 7)))
+    e.append(ExprAff(nf, ExprSlice(tmp, 7, 8)))
+    e.append(ExprAff(tf, ExprSlice(tmp, 8, 9)))
+    e.append(ExprAff(i_f, ExprSlice(tmp, 9, 10)))
+    e.append(ExprAff(df, ExprSlice(tmp, 10, 11)))
+    e.append(ExprAff(of, ExprSlice(tmp, 11, 12)))
+    e.append(ExprAff(iopl, ExprSlice(tmp, 12, 14)))
+    e.append(ExprAff(nt, ExprSlice(tmp, 14, 15)))
+    e.append(ExprAff(rf, ExprSlice(tmp, 16, 17)))
+    e.append(ExprAff(vm, ExprSlice(tmp, 17, 18)))
+    e.append(ExprAff(ac, ExprSlice(tmp, 18, 19)))
+    e.append(ExprAff(vif, ExprSlice(tmp, 19, 20)))
+    e.append(ExprAff(vip, ExprSlice(tmp, 20, 21)))
+    e.append(ExprAff(i_d, ExprSlice(tmp, 21, 22)))
+    e.append(ExprAff(mRSP[instr.mode], mRSP[instr.mode] + ExprInt32(4)))
+    e.append(ExprAff(exception_flags,
+                     ExprCond(ExprSlice(tmp, 8, 9),
+                              ExprInt32(EXCEPT_SOFT_BP),
+                              exception_flags
+                              )
+                     )
+             )
+    return None, e, []
+
+
+def popfw(ir, instr):
+    tmp = ExprMem(esp)
+    e = []
+    e.append(ExprAff(cf, ExprSlice(tmp, 0, 1)))
+    e.append(ExprAff(pf, ExprSlice(tmp, 2, 3)))
+    e.append(ExprAff(af, ExprSlice(tmp, 4, 5)))
+    e.append(ExprAff(zf, ExprSlice(tmp, 6, 7)))
+    e.append(ExprAff(nf, ExprSlice(tmp, 7, 8)))
+    e.append(ExprAff(tf, ExprSlice(tmp, 8, 9)))
+    e.append(ExprAff(i_f, ExprSlice(tmp, 9, 10)))
+    e.append(ExprAff(df, ExprSlice(tmp, 10, 11)))
+    e.append(ExprAff(of, ExprSlice(tmp, 11, 12)))
+    e.append(ExprAff(iopl, ExprSlice(tmp, 12, 14)))
+    e.append(ExprAff(nt, ExprSlice(tmp, 14, 15)))
+    e.append(ExprAff(esp, esp + ExprInt32(2)))
+    return None, e, []
+
+
+def pushad(ir, instr):
+    e = []
+    s = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    if not s in [16, 32, 64]:
+        raise ValueError('bad size stacker!')
+
+    regs = [
+        mRAX[instr.mode][:s], mRCX[instr.mode][
+            :s], mRDX[instr.mode][:s], mRBX[instr.mode][:s],
+        mRSP[instr.mode][:s], mRBP[instr.mode][:s],
+        mRSI[instr.mode][:s], mRDI[instr.mode][:s]]
+
+    for i in xrange(len(regs)):
+        c = mRSP[instr.mode][:s] + ExprInt_fromsize(s, -(s / 8) * (i + 1))
+        e.append(ExprAff(ExprMem(c, s), regs[i]))
+    e.append(ExprAff(mRSP[instr.mode][:s], c))
+    return None, e, []
+
+
+def popad(ir, instr):
+    e = []
+    s = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    if not s in [16, 32, 64]:
+        raise ValueError('bad size stacker!')
+    regs = [
+        mRAX[instr.mode][:s], mRCX[instr.mode][
+            :s], mRDX[instr.mode][:s], mRBX[instr.mode][:s],
+        mRSP[instr.mode][:s], mRBP[instr.mode][:s],
+        mRSI[instr.mode][:s], mRDI[instr.mode][:s]]
+    myesp = mRSP[instr.mode][:s]
+    regs.reverse()
+    for i in xrange(len(regs)):
+        if regs[i] == myesp:
+            continue
+        c = myesp + ExprInt_from(myesp, ((s / 8) * i))
+        e.append(ExprAff(regs[i], ExprMem(c, s)))
+
+    c = myesp + ExprInt_from(myesp, ((s / 8) * (i + 1)))
+    e.append(ExprAff(myesp, c))
+
+    return None, e, []
+
+
+def call(ir, instr, dst):
+    e = []
+    # opmode, admode = instr.opmode, instr.admode
+    s = dst.size
+    meip = mRIP[instr.mode]
+    opmode, admode = s, instr.v_admode()
+    myesp = mRSP[instr.mode][:opmode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+
+    c = myesp + ExprInt_fromsize(s, (-s / 8))
+    e.append(ExprAff(myesp, c))
+    if ir.do_stk_segm:
+        c = ExprOp('segm', SS, c)
+    e.append(ExprAff(ExprMem(c, size=s), n))
+    e.append(ExprAff(meip, dst.zeroExtend(instr.mode)))
+    if not expr_is_int_or_label(dst):
+        dst = meip
+    return dst, e, []
+
+
+def ret(ir, instr, a=None):
+    e = []
+    s = instr.mode
+    meip = mRIP[instr.mode]
+    opmode, admode = instr.v_opmode(), instr.v_admode()
+    s = opmode
+    myesp = mRSP[instr.mode][:s]
+
+    if a is None:
+        a = ExprInt_fromsize(s, 0)
+        e.append(ExprAff(myesp, (myesp + (ExprInt_fromsize(s, (s / 8))))))
+    else:
+        a = a.zeroExtend(s)
+        e.append(ExprAff(myesp, (myesp + (ExprInt_fromsize(s, (s / 8)) + a))))
+    c = myesp
+    if ir.do_stk_segm:
+        c = ExprOp('segm', SS, c)
+    e.append(ExprAff(meip, ExprMem(c, size=s).zeroExtend(s)))
+    return meip, e, []
+
+
+def retf(ir, instr, a=None):
+    e = []
+    s = instr.mode
+    meip = mRIP[instr.mode]
+    opmode, admode = instr.v_opmode(), instr.v_admode()
+    if a is None:
+        a = ExprInt_fromsize(s, 0)
+    s = opmode
+    myesp = mRSP[instr.mode][:s]
+
+    a = a.zeroExtend(s)
+
+    e.append(ExprAff(myesp, (myesp + (ExprInt_fromsize(s, (s / 8)) + a))))
+
+    c = myesp
+    if ir.do_stk_segm:
+        c = ExprOp('segm', SS, c)
+    e.append(ExprAff(meip, ExprMem(c, size=s).zeroExtend(s)))
+    # e.append(ExprAff(meip, ExprMem(c, size = s)))
+    c = myesp + ExprInt_fromsize(s, (s / 8))
+    if ir.do_stk_segm:
+        c = ExprOp('segm', SS, c)
+    e.append(ExprAff(CS, ExprMem(c, size=16)))
+
+    return meip, e, []
+
+
+def leave(ir, instr):
+    opmode, admode = instr.v_opmode(), instr.v_admode()
+    s = opmode
+    myesp = mRSP[instr.mode]
+
+    e = []
+    e.append(ExprAff(mRBP[s], ExprMem(mRBP[instr.mode], size=s)))
+    e.append(ExprAff(myesp,
+    ExprInt_fromsize(instr.mode, instr.mode / 8) + mRBP[instr.mode]))
+    return None, e, []
+
+
+def enter(ir, instr, a, b):
+    opmode, admode = instr.v_opmode(), instr.v_admode()
+    s = opmode
+    myesp = mRSP[instr.mode][:s]
+    myebp = mRBP[instr.mode][:s]
+
+    a = a.zeroExtend(s)
+
+    e = []
+    esp_tmp = myesp - ExprInt_fromsize(s, s / 8)
+    e.append(ExprAff(ExprMem(esp_tmp,
+                             size=s),
+                     myebp))
+    e.append(ExprAff(myebp, esp_tmp))
+    e.append(ExprAff(myesp, myesp - (a + ExprInt_fromsize(s, s / 8))))
+    return None, e, []
+
+
+def jmp(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    e.append(ExprAff(meip, dst))  # dst.zeroExtend(instr.mode)))
+    if isinstance(dst, ExprMem):
+        dst = meip
+    return dst, e, []
+
+
+def jmpf(ir, instr, a):
+    e = []
+    meip = mRIP[instr.mode]
+    assert(isinstance(a, ExprMem) and
+           isinstance(a.arg, ExprOp) and
+           a.arg.op == "segm")
+    segm = a.arg.args[0]
+    base = a.arg.args[1]
+    s = instr.mode
+    print segm, base
+    m1 = ExprMem(ExprOp('segm', segm, base), 16)
+    m2 = ExprMem(ExprOp('segm', segm, base + ExprInt_from(base, 2)), s)
+
+    e.append(ExprAff(meip, m1))
+    e.append(ExprAff(CS, m2))
+    return meip, e, []
+
+
+def jz(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(zf, dst, n).zeroExtend(instr.mode)
+    e = [ExprAff(meip, dst_o)]
+    return dst_o, e, []
+
+
+def jcxz(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(mRCX[instr.mode][:16], n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jecxz(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(mRCX[instr.mode][:32], n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jrcxz(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(mRCX[instr.mode], n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jnz(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(zf, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jp(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(pf, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jnp(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(pf, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def ja(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(cf | zf, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jae(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(cf, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jb(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(cf, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jbe(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(cf | zf, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jge(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(nf - of, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jg(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(zf | (nf - of), n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jl(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(nf - of, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jle(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(zf | (nf - of), dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def js(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(nf, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jns(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(nf, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jo(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(of, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def jno(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    dst_o = ExprCond(of, n, dst).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+    return dst_o, e, []
+
+
+def loop(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    s = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    myecx = mRCX[instr.mode][:admode]
+
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    c = myecx - ExprInt_from(myecx, 1)
+    e.append(ExprAff(myecx, c))
+    e.append(ExprAff(meip, ExprCond(c, dst, n).zeroExtend(instr.mode)))
+    dst_o = ExprCond(myecx, dst, n).zeroExtend(instr.mode)
+    return dst_o, e, []
+
+
+def loopne(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    s = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    myecx = mRCX[instr.mode][:admode]
+
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+
+    c = ExprOp('==',
+               mRCX[instr.mode][:s] - ExprInt_fromsize(s, 1),
+               ExprInt_fromsize(s, 0)) ^ ExprInt1(1)
+    c &= zf ^ ExprInt1(1)
+
+    e.append(ExprAff(myecx, myecx - ExprInt_from(myecx, 1)))
+    e.append(ExprAff(meip, ExprCond(c, dst, n).zeroExtend(instr.mode)))
+
+    # for dst, ecx has been modified!
+    c = ExprOp('==',
+               mRCX[instr.mode][:s],
+               ExprInt_fromsize(s, 0)) ^ ExprInt1(1)
+    c &= zf ^ ExprInt1(1)
+    dst_o = ExprCond(c, dst, n).zeroExtend(instr.mode)
+    return dst_o, e, []
+
+
+def loope(ir, instr, dst):
+    e = []
+    meip = mRIP[instr.mode]
+    s = instr.v_opmode()
+    opmode, admode = s, instr.v_admode()
+    myecx = mRCX[instr.mode][:admode]
+
+    n = ExprId(ir.get_next_label(instr), instr.mode)
+    c = ExprOp('==',
+               mRCX[instr.mode][:s] - ExprInt_fromsize(s, 1),
+               ExprInt_fromsize(s, 0)) ^ ExprInt1(1)
+    c &= zf
+    e.append(ExprAff(myecx, myecx - ExprInt_from(myecx, 1)))
+    dst_o = ExprCond(c, dst, n).zeroExtend(instr.mode)
+    e.append(ExprAff(meip, dst_o))
+
+    # for dst, ecx has been modified!
+    c = ExprOp('==',
+               mRCX[instr.mode][:s],
+               ExprInt_fromsize(s, 0)) ^ ExprInt1(1)
+    c &= zf
+    dst_o = ExprCond(c, dst, n).zeroExtend(instr.mode)
+    return dst_o, e, []
+
+
+# XXX size to do; eflag
+def div(ir, instr, a):
+    e = []
+    s = a.size
+    if s == 8:
+        b = mRAX[instr.mode][:16]
+    elif s == 16:
+        s1, s2 = mRDX[instr.mode][:16], mRAX[instr.mode][:16]
+        b = ExprCompose([(s1, 0, 16),
+                         (s1, 16, 32)])
+    elif s == 32:
+        s1, s2 = mRDX[instr.mode][:32], mRAX[instr.mode][:32]
+        b = ExprCompose([(s2, 0, 32),
+                         (s1, 32, 64)])
+    elif s == 64:
+        s1, s2 = mRDX[instr.mode], mRAX[instr.mode]
+        b = ExprCompose([(s2, 0, 64),
+                         (s1, 64, 128)])
+    else:
+        raise ValueError('div arg not impl', a)
+
+    c_d = ExprOp('udiv', b, a.zeroExtend(b.size))
+    c_r = ExprOp('umod', b, a.zeroExtend(b.size))
+
+    # if 8 bit div, only ax is affected
+    if s == 8:
+        e.append(ExprAff(b, ExprCompose([(c_d[:8], 0, 8),
+                                         (c_r[:8], 8, 16)])))
+    else:
+        e.append(ExprAff(s1, c_r[:s]))
+        e.append(ExprAff(s2, c_d[:s]))
+    return None, e, []
+
+# XXX size to do; eflag
+
+
+def idiv(ir, instr, a):
+    e = []
+    s = a.size
+
+    if s == 8:
+        b = mRAX[instr.mode][:16]
+    elif s == 16:
+        s1, s2 = mRDX[instr.mode][:16], mRAX[instr.mode][:16]
+        b = ExprCompose([(s1, 0, 16),
+                         (s1, 16, 32)])
+    elif s == 32:
+        s1, s2 = mRDX[instr.mode][:32], mRAX[instr.mode][:32]
+        b = ExprCompose([(s2, 0, 32),
+                         (s1, 32, 64)])
+    else:
+        raise ValueError('div arg not impl', a)
+
+    c_d = ExprOp('idiv', b, a.signExtend(b.size))
+    c_r = ExprOp('imod', b, a.signExtend(b.size))
+
+    # if 8 bit div, only ax is affected
+    if s == 8:
+        e.append(ExprAff(b, ExprCompose([(c_d[:8], 0, 8),
+                                         (c_r[:8], 8, 16)])))
+    else:
+        e.append(ExprAff(s1, c_r[:s]))
+        e.append(ExprAff(s2, c_d[:s]))
+    return None, e, []
+
+# XXX size to do; eflag
+
+
+def mul(ir, instr, a):
+    e = []
+    size = a.size
+    if a.size in [16, 32, 64]:
+        result = ExprOp('*',
+                        mRAX[instr.mode][:size].zeroExtend(size * 2),
+                        a.zeroExtend(size * 2))
+        e.append(ExprAff(mRAX[instr.mode][:size], result[:size]))
+        e.append(ExprAff(mRDX[instr.mode][:size], result[size:size * 2]))
+
+    elif a.size == 8:
+        result = ExprOp('*',
+                        mRAX[instr.mode][:8].zeroExtend(16),
+                        a.zeroExtend(16))
+        e.append(ExprAff(mRAX[instr.mode][:16], result))
+    else:
+        raise ValueError('unknow size')
+
+    e.append(ExprAff(of, ExprCond(result[size:size * 2],
+                                  ExprInt1(1),
+                                  ExprInt1(0))))
+    e.append(ExprAff(cf, ExprCond(result[size:size * 2],
+                                  ExprInt1(1),
+                                  ExprInt1(0))))
+
+    return None, e, []
+
+
+def imul(ir, instr, a, b=None, c=None):
+    e = []
+    size = a.size
+    if b is None:
+        if size in [16, 32, 64]:
+            result = ExprOp('*',
+                            mRAX[instr.mode][:size].signExtend(size * 2),
+                            a.signExtend(size * 2))
+            e.append(ExprAff(mRAX[instr.mode][:size], result[:size]))
+            e.append(ExprAff(mRDX[instr.mode][:size], result[size:size * 2]))
+        elif size == 8:
+            dst = mRAX[instr.mode][:16]
+            result = ExprOp('*',
+                            mRAX[instr.mode][:8].signExtend(16),
+                            a.signExtend(16))
+
+            e.append(ExprAff(dst, result))
+        e.append(
+            ExprAff(cf, ExprCond(result - result[:size].signExtend(size * 2),
+                                 ExprInt1(1),
+                    ExprInt1(0))))
+        e.append(
+            ExprAff(of, ExprCond(result - result[:size].signExtend(size * 2),
+                                 ExprInt1(1),
+                    ExprInt1(0))))
+
+    else:
+        if c is None:
+            c = b
+            b = a
+        result = ExprOp('*',
+                        b.signExtend(size * 2),
+                        c.signExtend(size * 2))
+        e.append(ExprAff(a, result[:size]))
+
+        e.append(
+            ExprAff(cf, ExprCond(result - result[:size].signExtend(size * 2),
+                                 ExprInt1(1),
+                    ExprInt1(0))))
+        e.append(
+            ExprAff(of, ExprCond(result - result[:size].signExtend(size * 2),
+                                 ExprInt1(1),
+                    ExprInt1(0))))
+    return None, e, []
+
+
+def cbw(ir, instr):
+    e = []
+    tempAL = mRAX[instr.mode][:8]
+    tempAX = mRAX[instr.mode][:16]
+    e.append(ExprAff(tempAX, tempAL.signExtend(16)))
+    return None, e, []
+
+
+def cwde(ir, instr):
+    e = []
+    tempAX = mRAX[instr.mode][:16]
+    tempEAX = mRAX[instr.mode][:32]
+    e.append(ExprAff(tempEAX, tempAX.signExtend(32)))
+    return None, e, []
+
+
+def cdqe(ir, instr):
+    e = []
+    tempEAX = mRAX[instr.mode][:32]
+    tempRAX = mRAX[instr.mode][:64]
+    e.append(ExprAff(tempRAX, tempEAX.signExtend(64)))
+    return None, e, []
+
+
+def cwd(ir, instr):
+    e = []
+    tempAX = mRAX[instr.mode][:16]
+    tempDX = mRDX[instr.mode][:16]
+    c = tempAX.signExtend(32)
+    e.append(ExprAff(tempAX, c[:16]))
+    e.append(ExprAff(tempDX, c[16:32]))
+    return None, e, []
+
+
+def cdq(ir, instr):
+    e = []
+    tempEAX = mRAX[instr.mode][:32]
+    tempEDX = mRDX[instr.mode][:32]
+    c = tempEAX.signExtend(64)
+    e.append(ExprAff(tempEAX, c[:32]))
+    e.append(ExprAff(tempEDX, c[32:64]))
+    return None, e, []
+
+
+def cqo(ir, instr):
+    e = []
+    tempRAX = mRAX[instr.mode][:64]
+    tempRDX = mRDX[instr.mode][:64]
+    c = tempEAX.signExtend(128)
+    e.append(ExprAff(tempRAX, c[:64]))
+    e.append(ExprAff(tempRDX, c[64:127]))
+    return None, e, []
+
+
+def stos(ir, instr, size):
+    lbl_df_0 = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_1 = ExprId(ir.gen_label(), instr.mode)
+    lbl_next = ExprId(ir.get_next_label(instr), instr.mode)
+
+    s = instr.v_admode()
+
+    addr_o = mRDI[instr.mode][:s]
+    addr = addr_o
+    addr_p = addr + ExprInt_from(addr, size / 8)
+    addr_m = addr - ExprInt_from(addr, size / 8)
+    if ir.do_str_segm:
+        mss = ES
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        addr = ExprOp('segm', mss, addr)
+
+    b = mRAX[instr.mode][:size]
+
+    e0 = []
+    e0.append(ExprAff(addr_o, addr_p))
+    e0 = irbloc(lbl_df_0.name, lbl_next, [e0])
+
+    e1 = []
+    e1.append(ExprAff(addr_o, addr_m))
+    e1 = irbloc(lbl_df_1.name, lbl_next, [e1])
+
+    e = []
+    e.append(ExprAff(ExprMem(addr, size), b))
+
+    return ExprCond(df, lbl_df_1, lbl_df_0), e, [e0, e1]
+
+
+def lods(ir, instr, size):
+    lbl_df_0 = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_1 = ExprId(ir.gen_label(), instr.mode)
+    lbl_next = ExprId(ir.get_next_label(instr), instr.mode)
+    e = []
+    s = instr.v_admode()
+
+    addr_o = mRSI[instr.mode][:s]
+    addr = addr_o
+    addr_p = addr + ExprInt_from(addr, size / 8)
+    addr_m = addr - ExprInt_from(addr, size / 8)
+    if ir.do_str_segm:
+        mss = DS
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        addr = ExprOp('segm', mss, addr)
+
+    b = mRAX[instr.mode][:size]
+
+    e0 = []
+    e0.append(ExprAff(addr_o, addr_p))
+    e0 = irbloc(lbl_df_0.name, lbl_next, [e0])
+
+    e1 = []
+    e1.append(ExprAff(addr_o, addr_m))
+    e1 = irbloc(lbl_df_1.name, lbl_next, [e1])
+
+    e = []
+    e.append(ExprAff(b, ExprMem(addr, size)))
+
+    return ExprCond(df, lbl_df_1, lbl_df_0), e, [e0, e1]
+
+
+def movs(ir, instr, size):
+    lbl_df_0 = ExprId(ir.gen_label(), instr.mode)
+    lbl_df_1 = ExprId(ir.gen_label(), instr.mode)
+    lbl_next = ExprId(ir.get_next_label(instr), instr.mode)
+
+    s = instr.v_admode()
+    # a = ExprMem(mRDI[instr.mode][:s], size)
+    # b = ExprMem(mRSI[instr.mode][:s], size)
+
+    a = mRDI[instr.mode][:s]
+    b = mRSI[instr.mode][:s]
+
+    e = []
+    src = b
+    dst = a
+    if ir.do_str_segm:
+        if instr.additional_info.g2.value:
+            raise NotImplementedError("add segm support")
+        src = ExprOp('segm', DS, src)
+        dst = ExprOp('segm', ES, dst)
+    e.append(ExprAff(ExprMem(dst, size), ExprMem(src, size)))
+
+    e0 = []
+    e0.append(ExprAff(a, a + ExprInt_from(a, size / 8)))
+    e0.append(ExprAff(b, b + ExprInt_from(b, size / 8)))
+    e0 = irbloc(lbl_df_0.name, lbl_next, [e0])
+
+    e1 = []
+    e1.append(ExprAff(a, a - ExprInt_from(a, size / 8)))
+    e1.append(ExprAff(b, b - ExprInt_from(b, size / 8)))
+    e1 = irbloc(lbl_df_1.name, lbl_next, [e1])
+
+    return ExprCond(df, lbl_df_1, lbl_df_0), e, [e0, e1]
+
+
+def float_prev(flt):
+    if not flt in float_list:
+        return None
+    i = float_list.index(flt)
+    if i == 0:
+        raise ValueError('broken index')
+    flt = float_list[i - 1]
+    return flt
+
+
+def float_pop(avoid_flt=None):
+    avoid_flt = float_prev(avoid_flt)
+    e = []
+    if avoid_flt != float_st0:
+        e.append(ExprAff(float_st0, float_st1))
+    if avoid_flt != float_st1:
+        e.append(ExprAff(float_st1, float_st2))
+    if avoid_flt != float_st2:
+        e.append(ExprAff(float_st2, float_st3))
+    if avoid_flt != float_st3:
+        e.append(ExprAff(float_st3, float_st4))
+    if avoid_flt != float_st4:
+        e.append(ExprAff(float_st4, float_st5))
+    if avoid_flt != float_st5:
+        e.append(ExprAff(float_st5, float_st6))
+    if avoid_flt != float_st6:
+        e.append(ExprAff(float_st6, float_st7))
+    if avoid_flt != float_st7:
+        e.append(ExprAff(float_st7, ExprInt_from(float_st7, 0)))
+    e.append(
+        ExprAff(float_stack_ptr, float_stack_ptr - ExprInt_fromsize(3, 1)))
+    return e
+
+# XXX TODO
+
+
+def fcom(ir, instr, a, b):
+    e = []
+    """
+    if isinstance(a, ExprMem):
+        src = ExprOp('mem_%.2d_to_double'%a.size, a)
+    else:
+        src = a
+    """
+    src = b
+    e.append(ExprAff(float_c0, ExprOp('fcom_c0', a, src.zeroExtend(a.size))))
+    e.append(ExprAff(float_c1, ExprOp('fcom_c1', a, src.zeroExtend(a.size))))
+    e.append(ExprAff(float_c2, ExprOp('fcom_c2', a, src.zeroExtend(a.size))))
+    e.append(ExprAff(float_c3, ExprOp('fcom_c3', a, src.zeroExtend(a.size))))
+
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def ficom(ir, instr, a):
+    e = []
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fcomi(ir, instr, a):
+    # Invalid emulation
+    InvalidEmulation
+
+
+def fcomip(ir, instr, a):
+    # Invalid emulation
+    InvalidEmulation
+
+
+def fucomi(ir, instr, a):
+    # Invalid emulation
+    InvalidEmulation
+
+
+def fucomip(ir, instr, a):
+    # Invalid emulation, only read/write analysis is valid
+    cond = ExprOp('fcomp', float_st0, a)
+    e = []
+    e.append(
+        ExprAff(zf, ExprCond(cond, ExprInt_from(zf, 0), ExprInt_from(zf, 1))))
+    e.append(
+        ExprAff(pf, ExprCond(cond, ExprInt_from(zf, 0), ExprInt_from(zf, 1))))
+    e.append(
+        ExprAff(cf, ExprCond(cond, ExprInt_from(zf, 0), ExprInt_from(zf, 1))))
+    return None, e, []
+
+
+def fcomp(ir, instr, a, b):
+    dst, e, extra = fcom(ir, instr, a, b)
+    e += float_pop()
+    e += set_float_cs_eip(instr)
+    return dst, e, extra
+
+
+def fld(ir, instr, a):
+    if isinstance(a, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % a.size, a)
+    else:
+        src = a
+
+    e = []
+    e.append(ExprAff(float_st7, float_st6))
+    e.append(ExprAff(float_st6, float_st5))
+    e.append(ExprAff(float_st5, float_st4))
+    e.append(ExprAff(float_st4, float_st3))
+    e.append(ExprAff(float_st3, float_st2))
+    e.append(ExprAff(float_st2, float_st1))
+    e.append(ExprAff(float_st1, float_st0))
+    e.append(ExprAff(float_st0, src))
+    e.append(
+        ExprAff(float_stack_ptr, float_stack_ptr + ExprInt_fromsize(3, 1)))
+
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fst(ir, instr, a):
+    e = []
+    if isinstance(a, ExprMem):
+        src = ExprOp('double_to_mem_%2d' % a.size, float_st0)
+    else:
+        src = float_st0
+    e.append(ExprAff(a, src))
+
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fstp(ir, instr, a):
+    dst, e, extra = fst(ir, instr, a)
+    e += float_pop(a)
+    return dst, e, extra
+
+
+def fist(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprOp('double_to_int_%d' % a.size, float_st0)))
+
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fistp(ir, instr, a):
+    dst, e, extra = fist(ir, instr, a)
+    e += float_pop(a)
+    return dst, e, extra
+
+
+def fild(ir, instr, a):
+    # XXXXX
+    src = ExprOp('int_%.2d_to_double' % a.size, a)
+    e = []
+    e += set_float_cs_eip(instr)
+    dst, e_fld, extra = fld(ir, instr, src)
+    e += e_fld
+    return dst, e, extra
+
+
+def fldz(ir, instr):
+    return fld(ir, instr, ExprOp('int_32_to_double', ExprInt32(0)))
+
+
+def fld1(ir, instr):
+    return fld(ir, instr, ExprOp('int_32_to_double', ExprInt32(1)))
+
+
+def fldl2e(ir, instr):
+    x = struct.pack('d', 1 / math.log(2))
+    x = struct.unpack('Q', x)[0]
+    return fld(ir, instr, ExprOp('mem_64_to_double', ExprInt64(x)))
+
+
+def fldlg2(ir, instr):
+    x = struct.pack('d', math.log10(2))
+    x = struct.unpack('Q', x)[0]
+    return fld(ir, instr, ExprOp('mem_64_to_double', ExprInt64(x)))
+
+
+def fadd(ir, instr, a, b=None):
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(a, ExprOp('fadd', a, src)))
+
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def faddp(ir, instr, a, b=None):
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(float_prev(a), ExprOp('fadd', a, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(a)
+    return None, e, []
+
+
+def fninit(ir, instr):
+    e = []
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fnstenv(ir, instr, a):
+    e = []
+    # XXX TODO tag word, ...
+    status_word = ExprCompose([(ExprInt8(0), 0, 8),
+                               (float_c0,           8, 9),
+                               (float_c1,           9, 10),
+                               (float_c2,           10, 11),
+                               (float_stack_ptr,    11, 14),
+                               (float_c3,           14, 15),
+                               (ExprInt1(0), 15, 16),
+                               ])
+
+    s = instr.mode
+    ad = ExprMem(a.arg, size=16)
+    e.append(ExprAff(ad, float_control))
+    ad = ExprMem(a.arg + ExprInt_from(a.arg, s / 8 * 1), size=16)
+    e.append(ExprAff(ad, status_word))
+    ad = ExprMem(a.arg + ExprInt_from(a.arg, s / 8 * 3), size=s)
+    e.append(ExprAff(ad, float_eip[:s]))
+    ad = ExprMem(a.arg + ExprInt_from(a.arg, s / 8 * 4), size=16)
+    e.append(ExprAff(ad, float_cs))
+    ad = ExprMem(a.arg + ExprInt_from(a.arg, s / 8 * 5), size=s)
+    e.append(ExprAff(ad, float_address[:s]))
+    ad = ExprMem(a.arg + ExprInt_from(a.arg, s / 8 * 6), size=16)
+    e.append(ExprAff(ad, float_ds))
+    return None, e, []
+
+
+def fsub(ir, instr, a, b=None):
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(a, ExprOp('fsub', a, src)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fmul(ir, instr, a, b=None):
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(a, ExprOp('fmul', a, src)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fdiv(ir, instr, a, b=None):
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(a, ExprOp('fdiv', a, src)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fdivr(ir, instr, a, b=None):
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(a, ExprOp('fdiv', src, a)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fdivp(ir, instr, a, b=None):
+    # Invalid emulation
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(float_prev(a), ExprOp('fdiv', a, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(a)
+    return None, e, []
+
+
+def fmulp(ir, instr, a, b=None):
+    # Invalid emulation
+    if b is None:
+        b = a
+        a = float_st0
+    e = []
+    if isinstance(b, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % b.size, b)
+    else:
+        src = b
+    e.append(ExprAff(float_prev(a), ExprOp('fmul', a, src)))
+    e += set_float_cs_eip(instr)
+    e += float_pop(a)
+    return None, e, []
+
+
+def ftan(ir, instr, a):
+    e = []
+    if isinstance(a, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % a.size, a)
+    else:
+        src = a
+    e.append(ExprAff(float_st0, ExprOp('ftan', src)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fxch(ir, instr, a):
+    e = []
+    if isinstance(a, ExprMem):
+        src = ExprOp('mem_%.2d_to_double' % a.size, a)
+    else:
+        src = a
+    e.append(ExprAff(float_st0, src))
+    e.append(ExprAff(src, float_st0))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fptan(ir, instr):
+    e = []
+    e.append(ExprAff(float_st7, float_st6))
+    e.append(ExprAff(float_st6, float_st5))
+    e.append(ExprAff(float_st5, float_st4))
+    e.append(ExprAff(float_st4, float_st3))
+    e.append(ExprAff(float_st3, float_st2))
+    e.append(ExprAff(float_st2, float_st1))
+    e.append(ExprAff(float_st1, ExprOp('ftan', float_st0)))
+    e.append(ExprAff(float_st0, ExprOp('int_32_to_double', ExprInt32(1))))
+    e.append(
+        ExprAff(float_stack_ptr, float_stack_ptr + ExprInt_fromsize(3, 1)))
+    return None, e, []
+
+
+def frndint(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('frndint', float_st0)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fsin(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('fsin', float_st0)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fcos(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('fcos', float_st0)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fscale(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('fscale', float_st0, float_st1)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def f2xm1(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('f2xm1', float_st0)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fsqrt(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('fsqrt', float_st0)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fabs(ir, instr):
+    e = []
+    e.append(ExprAff(float_st0, ExprOp('fabs', float_st0)))
+    e += set_float_cs_eip(instr)
+    return None, e, []
+
+
+def fnstsw(ir, instr, dst):
+    args = [(ExprInt8(0),        0, 8),
+            (float_c0,           8, 9),
+            (float_c1,           9, 10),
+            (float_c2,           10, 11),
+            (float_stack_ptr,    11, 14),
+            (float_c3,           14, 15),
+            (ExprInt1(0), 15, 16)]
+    e = [ExprAff(dst, ExprCompose(args))]
+    return None, e, []
+
+
+def fnstcw(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, float_control))
+    return None, e, []
+
+
+def fldcw(ir, instr, a):
+    e = []
+    e.append(ExprAff(float_control, a))
+    return None, e, []
+
+
+def fwait(ir, instr):
+    return None, [], None
+
+
+def nop(ir, instr, a=None):
+    return None, [], []
+
+
+def hlt(ir, instr):
+    e = []
+    except_int = EXCEPT_PRIV_INSN
+    e.append(ExprAff(exception_flags, ExprInt32(except_int)))
+    return None, e, []
+
+
+def rdtsc(ir, instr):
+    e = []
+    myEAX = mRAX[instr.mode]
+    myEDX = mRDX[instr.mode]
+    e.append(ExprAff(tsc1, tsc1 + ExprInt32(1)))
+    e.append(ExprAff(myEAX, tsc1))
+    e.append(ExprAff(myEDX, tsc2))
+    return None, e, []
+
+
+# XXX TODO
+def daa(ir, instr):
+    return None, [], None
+
+
+def aam(ir, instr, a):
+    e = []
+    tempAL = mRAX[instr.mode][0:8]
+    newEAX = ExprCompose([
+                         (tempAL % a,           0,  8),
+                        (tempAL / a,           8,  16),
+                        (mRAX[instr.mode][16:], 16, mRAX[instr.mode].size),
+                         ])
+    e += [ExprAff(mRAX[instr.mode], newEAX)]
+    e += update_flag_arith(newEAX)
+    return None, e, []
+
+
+def aad(ir, instr, a):
+    e = []
+    tempAL = mRAX[instr.mode][0:8]
+    tempAH = mRAX[instr.mode][8:16]
+    newEAX = ExprCompose([
+                         ((tempAL + (tempAH * a)) & ExprInt8(0xFF), 0,  8),
+                        (ExprInt8(0),                              8,  16),
+                        (mRAX[instr.mode][16:],
+                         16, mRAX[instr.mode].size),
+                         ])
+    e += [ExprAff(mRAX[instr.mode], newEAX)]
+    e += update_flag_arith(newEAX)
+    return None, e, []
+
+
+def aaa(ir, instr, ):
+    e = []
+    c = (mRAX[instr.mode][:8] & ExprInt8(0xf)) - ExprInt8(9)
+
+    c = ExprCond(c.msb(),
+                 ExprInt1(0),
+                 ExprInt1(1)) & \
+        ExprCond(c,
+                 ExprInt1(1),
+                 ExprInt1(0))
+
+    c |= af & ExprInt1(1)
+    # set AL
+    m_al = ExprCond(c,
+                   (mRAX[instr.mode][:8] + ExprInt8(6)) & ExprInt8(0xF),
+                    mRAX[instr.mode][:8] & ExprInt8(0xF))
+    m_ah = ExprCond(c,
+                    mRAX[instr.mode][8:16] + ExprInt8(1),
+                    mRAX[instr.mode][8:16])
+
+    e.append(ExprAff(mRAX[instr.mode], ExprCompose([
+        (m_al, 0, 8), (m_ah, 8, 16),
+        (mRAX[instr.mode][16:], 16, mRAX[instr.mode].size)])))
+    e.append(ExprAff(af, c))
+    e.append(ExprAff(cf, c))
+    return None, e, []
+
+
+def aas(ir, instr, ):
+    e = []
+    c = (mRAX[instr.mode][:8] & ExprInt8(0xf)) - ExprInt8(9)
+
+    c = ExprCond(c.msb(),
+                 ExprInt1(0),
+                 ExprInt1(1)) & \
+        ExprCond(c,
+                 ExprInt1(1),
+                 ExprInt1(0))
+
+    c |= af & ExprInt1(1)
+    # set AL
+    m_al = ExprCond(c,
+                   (mRAX[instr.mode][:8] - ExprInt8(6)) & ExprInt8(0xF),
+                    mRAX[instr.mode][:8] & ExprInt8(0xF))
+    m_ah = ExprCond(c,
+                    mRAX[instr.mode][8:16] - ExprInt8(1),
+                    mRAX[instr.mode][8:16])
+
+    e.append(ExprAff(mRAX[instr.mode], ExprCompose([
+        (m_al, 0, 8), (m_ah, 8, 16),
+        (mRAX[instr.mode][16:], 16, mRAX[instr.mode].size)])))
+    e.append(ExprAff(af, c))
+    e.append(ExprAff(cf, c))
+    return None, e, []
+
+
+def bsf(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+
+    e = [ExprAff(zf, ExprCond(b, ExprInt_from(zf, 0), ExprInt_from(zf, 1)))]
+
+    e_do = []
+    e_do.append(ExprAff(a, ExprOp('bsf', b)))
+    return ExprCond(b,
+    lbl_do, lbl_skip), e, [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def bsr(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+
+    e = [ExprAff(zf, ExprCond(b, ExprInt_from(zf, 0), ExprInt_from(zf, 1)))]
+
+    e_do = []
+    e_do.append(ExprAff(a, ExprOp('bsr', b)))
+    return ExprCond(b,
+    lbl_do, lbl_skip), e, [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def arpl(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(exception_flags, ExprInt32(1 << 7)))
+    return None, e, []
+
+
+def ins(ir, instr, size):
+    e = []
+    e.append(ExprAff(exception_flags, ExprInt32(1 << 7)))
+    return None, e, []
+
+
+def sidt(ir, instr, a):
+    e = []
+    if not isinstance(a, ExprMem) or a.size != 32:
+        raise ValueError('not exprmem 32bit instance!!')
+    b = a.arg
+    print "DEFAULT SIDT ADDRESS %s!!" % str(a)
+    e.append(ExprAff(ExprMem(b, 32), ExprInt32(0xe40007ff)))
+    e.append(
+        ExprAff(ExprMem(ExprOp("+", b,
+        ExprInt_from(b, 4)), 16), ExprInt16(0x8245)))
+    return None, e, []
+
+
+def sldt(ir, instr, a):
+    # XXX TOOD
+    e = [ExprAff(exception_flags, ExprInt32(EXCEPT_PRIV_INSN))]
+    return None, e, []
+
+
+def cmovz(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+
+    dum, e_do, extra_irs = mov(ir, instr, a, b)
+    return ExprCond(zf,
+    lbl_do, lbl_skip), [], [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def cmovnz(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond(zf, a, b)))
+    return None, e, []
+
+
+def cmovge(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond(nf ^ of, a, b)))
+    return None, e, []
+
+
+def cmovg(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond(zf | (nf ^ of), a, b)))
+    return None, e, []
+
+
+def cmovl(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond(nf ^ of, b, a)))
+    return None, e, []
+
+
+def cmovle(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond((nf ^ of) | zf, b, a)))
+    return None, e, []
+
+
+def cmova(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+    dum, e_do, extra_irs = mov(ir, instr, a, b)
+    return ExprCond(cf | zf,
+    lbl_skip, lbl_do), [], [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def cmovae(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+    dum, e_do, extra_irs = mov(ir, instr, a, b)
+    return ExprCond(cf,
+    lbl_skip, lbl_do), [], [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def cmovbe(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+    dum, e_do, extra_irs = mov(ir, instr, a, b)
+    return ExprCond(cf | zf,
+    lbl_do, lbl_skip), [], [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def cmovb(ir, instr, a, b):
+    lbl_do = ExprId(ir.gen_label(), instr.mode)
+    lbl_skip = ExprId(ir.get_next_label(instr), instr.mode)
+    dum, e_do, extra_irs = mov(ir, instr, a, b)
+    return ExprCond(cf,
+    lbl_do, lbl_skip), [], [irbloc(lbl_do.name, lbl_skip, [e_do])]
+
+
+def cmovo(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond(of, b, a)))
+    return None, e, []
+
+
+def cmovno(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond(of, a, b)))
+    return None, e, []
+
+
+def cmovs(ir, instr, a, b):
+    e = []
+    # SF is called nf in miasm
+    e.append(ExprAff(a, ExprCond(nf, b, a)))
+    return None, e, []
+
+
+def cmovns(ir, instr, a, b):
+    e = []
+    # SF is called nf in miasm
+    e.append(ExprAff(a, ExprCond(nf, a, b)))
+    return None, e, []
+
+
+def icebp(ir, instr):
+    e = []
+    e.append(ExprAff(exception_flags,
+                     ExprInt32(EXCEPT_PRIV_INSN)))
+    return None, e, []
+# XXX
+
+
+def l_int(ir, instr, a):
+    e = []
+    # XXX
+    if a.arg in [1, 3]:
+        except_int = EXCEPT_SOFT_BP
+    else:
+        except_int = EXCEPT_INT_XX
+    e.append(ExprAff(exception_flags,
+                     ExprInt32(except_int)))
+    return None, e, []
+
+
+def l_sysenter(ir, instr):
+    e = []
+    e.append(ExprAff(exception_flags,
+                     ExprInt32(EXCEPT_PRIV_INSN)))
+    return None, e, []
+
+# XXX
+
+
+def l_out(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(exception_flags,
+                     ExprInt32(EXCEPT_PRIV_INSN)))
+    return None, e, []
+
+# XXX
+
+
+def l_outs(ir, instr, size):
+    e = []
+    e.append(ExprAff(exception_flags,
+                     ExprInt32(EXCEPT_PRIV_INSN)))
+    return None, e, []
+
+# XXX actually, xlat performs al = (ds:[e]bx + ZeroExtend(al))
+
+
+def xlat(ir, instr):
+    e = []
+    a = ExprCompose([(ExprInt_fromsize(24, 0), 8, 32),
+                     (mRAX[instr.mode][0:8], 0, 8)])
+    b = ExprMem(ExprOp('+', mRBX[instr.mode], a), 8)
+    e.append(ExprAff(mRAX[instr.mode][0:8], b))
+    return None, e, []
+
+
+def cpuid(ir, instr):
+    e = []
+    e.append(
+        ExprAff(mRAX[instr.mode],
+        ExprOp('cpuid', mRAX[instr.mode], ExprInt32(0))))
+    e.append(
+        ExprAff(mRBX[instr.mode],
+        ExprOp('cpuid', mRAX[instr.mode], ExprInt32(1))))
+    e.append(
+        ExprAff(mRCX[instr.mode],
+        ExprOp('cpuid', mRAX[instr.mode], ExprInt32(2))))
+    e.append(
+        ExprAff(mRDX[instr.mode],
+        ExprOp('cpuid', mRAX[instr.mode], ExprInt32(3))))
+    return None, e, []
+
+
+def bittest_get(a, b):
+    b = b.zeroExtend(a.size)
+    if isinstance(a, ExprMem):
+        off_bit = ExprOp('&', b, ExprInt_from(a, a.size - 1))
+        off_byte = (b >> ExprInt_from(a, 3)) & \
+            ExprOp('!', ExprInt_from(a, a.size / 8 - 1))
+
+        d = ExprMem(a.arg + off_byte, a.size)
+        # d = ExprOp('>>', mem, off_bit)
+    else:
+        off_bit = ExprOp('&', b, ExprInt_from(a, a.size - 1))
+        d = a
+        # d = ExprOp('>>', a, off_bit)
+    return d, off_bit
+
+
+def bt(ir, instr, a, b):
+    e = []
+    b = b.zeroExtend(a.size)
+    d, off_bit = bittest_get(a, b)
+    d = d >> off_bit
+    e.append(ExprAff(cf, d[:1]))
+    return None, e, []
+
+
+def btc(ir, instr, a, b):
+    e = []
+    d, off_bit = bittest_get(a, b)
+    e.append(ExprAff(cf, (d >> off_bit)[:1]))
+
+    m = ExprInt_from(a, 1) << off_bit
+    e.append(ExprAff(d, d ^ m))
+
+    return None, e, []
+
+
+def bts(ir, instr, a, b):
+    e = []
+    d, off_bit = bittest_get(a, b)
+    e.append(ExprAff(cf, (d >> off_bit)[:1]))
+    m = ExprInt_from(a, 1) << off_bit
+    e.append(ExprAff(d, d | m))
+
+    return None, e, []
+
+
+def btr(ir, instr, a, b):
+    e = []
+    d, off_bit = bittest_get(a, b)
+    e.append(ExprAff(cf, (d >> off_bit)[:1]))
+    m = ~(ExprInt_from(a, 1) << off_bit)
+    e.append(ExprAff(d, d & m))
+
+    return None, e, []
+
+
+def into(ir, instr):
+    return None, [], None
+
+
+def l_in(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(exception_flags,
+                     ExprInt32(EXCEPT_PRIV_INSN)))
+    return None, e, []
+
+
+def cmpxchg(ir, instr, a, b):
+    e = []
+
+    c = mRAX[instr.mode][:a.size]
+    cond = c - a
+    e.append(
+        ExprAff(zf, ExprCond(cond, ExprInt_from(zf, 0), ExprInt_from(zf, 1))))
+    e.append(ExprAff(a, ExprCond(cond,
+                                 b,
+                                 a)
+                     ))
+    e.append(ExprAff(c, ExprCond(cond,
+                                 a,
+                                 c)
+                     ))
+    return None, e, []
+
+
+def lds(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprMem(b.arg, size=a.size)))
+    e.append(ExprAff(ds, ExprMem(b.arg + ExprInt_from(a, 2),
+                                 size=16)))
+    return None, e, []
+
+
+def les(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprMem(b.arg, size=a.size)))
+    e.append(ExprAff(es, ExprMem(b.arg + ExprInt_from(a, 2),
+                                 size=16)))
+    return None, e, []
+
+
+def lss(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprMem(b.arg, size=a.size)))
+    e.append(ExprAff(ss, ExprMem(b.arg + ExprInt_from(a, 2),
+                                 size=16)))
+    return None, e, []
+
+
+def lahf(ir, instr):
+    e = []
+    args = []
+    regs = [cf, ExprInt1(1), pf, ExprInt1(0), af, ExprInt1(0), zf, nf]
+    for i in xrange(len(regs)):
+        args.append((regs[i], i, i + 1))
+    e.append(ExprAff(mRAX[instr.mode][8:16], ExprCompose(args)))
+    return None, e, []
+
+
+def sahf(ir, instr):
+    tmp = mRAX[instr.mode][8:16]
+    e = []
+    e.append(ExprAff(cf, tmp[0:1]))
+    e.append(ExprAff(pf, tmp[2:3]))
+    e.append(ExprAff(af, tmp[4:5]))
+    e.append(ExprAff(zf, tmp[6:7]))
+    e.append(ExprAff(nf, tmp[7:8]))
+    return None, e, []
+
+
+def lar(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprOp('access_segment', b)))
+    e.append(ExprAff(zf, ExprOp('access_segment_ok', b)))
+    return None, e, []
+
+
+def lsl(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprOp('load_segment_limit', b)))
+    e.append(ExprAff(zf, ExprOp('load_segment_limit_ok', b)))
+    return None, e, []
+
+
+def fclex(ir, instr):
+    # XXX TODO
+    return None, [], None
+
+
+def fnclex(ir, instr):
+    # XXX TODO
+    return None, [], None
+
+
+def l_str(ir, instr, a):
+    e = []
+    e.append(ExprAff(a, ExprOp('load_tr_segment_selector', ExprInt32(0))))
+    return None, e, []
+
+
+def movd(ir, instr, a, b):
+    e = []
+    if a.size == 64:
+        e.append(ExprAff(a, ExprCompose([(ExprInt32(0), 32, 64), (b, 0, 32)])))
+    else:
+        e.append(ExprAff(a, b[0:32]))
+    return None, e, []
+
+
+def xorps(ir, instr, a, b):
+    e = []
+    if isinstance(b, ExprMem):
+        b = ExprMem(b.arg, a.size)
+    e.append(ExprAff(a, ExprOp('xorps', a, b)))
+    return None, e, []
+
+
+def movaps(ir, instr, a, b):
+    e = []
+    if isinstance(a, ExprMem):
+        a = ExprMem(a.arg, b.size)
+    if isinstance(b, ExprMem):
+        b = ExprMem(b.arg, a.size)
+    e.append(ExprAff(a, b))
+    return None, e, []
+
+
+def pminsw(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a, ExprCond((a - b).msb(), a, b)))
+    return None, e, []
+
+
+def cvtsi2sd(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a[:b.size], ExprOp('cvtsi2sd', b)))
+    return None, e, []
+
+
+def movss(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(a[:b.size], ExprOp('movss', b)))
+    return None, e, []
+
+
+def ucomiss(ir, instr, a, b):
+    e = []
+    e.append(ExprAff(zf, ExprOp('ucomiss_zf', a[:32], b[:32])))
+    e.append(ExprAff(pf, ExprOp('ucomiss_pf', a[:32], b[:32])))
+    e.append(ExprAff(cf, ExprOp('ucomiss_cf', a[:32], b[:32])))
+
+    e.append(ExprAff(of, ExprInt1(0)))
+    e.append(ExprAff(af, ExprInt1(0)))
+    e.append(ExprAff(nf, ExprInt1(0)))
+
+    return None, e, []
+
+mnemo_func = {'mov': mov,
+              'xchg': xchg,
+              'movzx': movzx,
+              'movsx': movsx,
+              'movsxd': movsx,
+              'lea': lea,
+              'add': add,
+              'xadd': xadd,
+              'adc': adc,
+              'sub': sub,
+              'sbb': sbb,
+              'neg': neg,
+              'not': l_not,
+              'cmp': l_cmp,
+              'xor': xor,
+              'or': l_or,
+              'and': l_and,
+              'test': l_test,
+              'rol': l_rol,
+              'ror': l_ror,
+              'rcl': rcl,
+              'rcr': rcr,
+              'sar': sar,
+              'shr': shr,
+              'shrd_cl': shrd_cl,
+              'sal': sal,
+              'shl': shl,
+              'shld_cl': shld_cl,
+              'shld': shld,
+              'cmc': cmc,
+              'clc': clc,
+              'stc': stc,
+              'cld': cld,
+              'std': std,
+              'cli': cli,
+              'sti': sti,
+              'bsf': bsf,
+              'bsr': bsr,
+              'inc': inc,
+              'dec': dec,
+              'push': push,
+              'pop': pop,
+              'sete': sete,
+              'setnz': setnz,
+              'setl': setl,
+              'setg': setg,
+              'setge': setge,
+              'seta': seta,
+              'setae': setae,
+              'setb': setb,
+              'setbe': setbe,
+              'setns': setns,
+              'sets': sets,
+              'seto': seto,
+              'setp': setp,
+              'setpe': setp,
+              'setnp': setnp,
+              'setpo': setnp,
+              'setle': setle,
+              'setng': setle,
+              'setna': setna,
+              'setnbe': setnbe,
+              'setno': setno,
+              'setnc': setnb,
+              'setz': sete,
+              'setne': setnz,
+              'setnb': setae,
+              'setnae': setb,
+              'setc': setb,
+              'setnge': setl,
+              'setnl': setge,
+              'setnle': setg,
+              'setalc': setalc,
+              'bswap': bswap,
+              'cmpsb': lambda ir, instr: cmps(ir, instr, 8),
+              'cmpsw': lambda ir, instr: cmps(ir, instr, 16),
+              'cmpsd': lambda ir, instr: cmps(ir, instr, 32),
+              'scasb': lambda ir, instr: scas(ir, instr, 8),
+              'scasw': lambda ir, instr: scas(ir, instr, 16),
+              'scasd': lambda ir, instr: scas(ir, instr, 32),
+              'pushfd': pushfd,
+              'pushfw': pushfw,
+              'popfd': popfd,
+              'popfw': popfw,
+              'pushad': pushad,
+              'pusha': pushad,
+              'popad': popad,
+              'popa': popad,
+              'call': call,
+              'ret': ret,
+              'retf': retf,
+              'leave': leave,
+              'enter': enter,
+              'jmp': jmp,
+              'jmpf': jmpf,
+              'jz': jz,
+              'je': jz,
+              'jcxz': jcxz,
+              'jecxz': jecxz,
+              'jrcxz': jrcxz,
+              'jnz': jnz,
+              'jp': jp,
+              'jpe': jp,
+              'jnp': jnp,
+              'ja': ja,
+              'jae': jae,
+              'jb': jb,
+              'jbe': jbe,
+              'jg': jg,
+              'jge': jge,
+              'jl': jl,
+              'jle': jle,
+              'js': js,
+              'jns': jns,
+              'jo': jo,
+              'jno': jno,
+              'jecxz': jecxz,
+              'loop': loop,
+              'loopne': loopne,
+              'loope': loope,
+              'div': div,
+              'mul': mul,
+              'imul': imul,
+              'idiv': idiv,
+
+              'cbw': cbw,
+              'cwde': cwde,
+              'cdqe': cdqe,
+
+              'cwd': cwd,
+              'cdq': cdq,
+              'cqo': cqo,
+
+              'daa': daa,
+              'aam': aam,
+              'aad': aad,
+              'aaa': aaa,
+              'aas': aas,
+              'shrd': shrd,
+              'stosb': lambda ir, instr: stos(ir, instr, 8),
+              'stosw': lambda ir, instr: stos(ir, instr, 16),
+              'stosd': lambda ir, instr: stos(ir, instr, 32),
+              'stosq': lambda ir, instr: stos(ir, instr, 64),
+
+              'lodsb': lambda ir, instr: lods(ir, instr, 8),
+              'lodsw': lambda ir, instr: lods(ir, instr, 16),
+              'lodsd': lambda ir, instr: lods(ir, instr, 32),
+
+              'movsb': lambda ir, instr: movs(ir, instr, 8),
+              'movsw': lambda ir, instr: movs(ir, instr, 16),
+              'movsd': lambda ir, instr: movs(ir, instr, 32),
+              'movsq': lambda ir, instr: movs(ir, instr, 64),
+              'fcomp': fcomp,
+              'nop': nop,
+              'fnop': nop,  # XXX
+              'hlt': hlt,
+              'rdtsc': rdtsc,
+              'fst': fst,
+              'fstp': fstp,
+              'fist': fist,
+              'fistp': fistp,
+              'fld': fld,
+              'fldz': fldz,
+              'fld1': fld1,
+              'fldl2e': fldl2e,
+              'fldlg2': fldlg2,
+              'fild': fild,
+              'fadd': fadd,
+              'fninit': fninit,
+              'faddp': faddp,
+              'fsub': fsub,
+              'fmul': fmul,
+              'fmulp': fmulp,
+              'fdiv': fdiv,
+              'fdivr': fdivr,
+              'fdivp': fdivp,
+              'fxch': fxch,
+              'fptan': fptan,
+              'frndint': frndint,
+              'fsin': fsin,
+              'fcos': fcos,
+              'fscale': fscale,
+              'f2xm1': f2xm1,
+              'fsqrt': fsqrt,
+              'fabs': fabs,
+              'fnstsw': fnstsw,
+              'fnstcw': fnstcw,
+              'fldcw': fldcw,
+              'fwait': fwait,
+              'fnstenv': fnstenv,
+              'sidt': sidt,
+              'sldt': sldt,
+              'arpl': arpl,
+              'cmovz': cmovz,
+              'cmove': cmovz,
+              'cmovnz': cmovnz,
+              'cmovge': cmovge,
+              'cmovnl': cmovge,
+              'cmovg': cmovg,
+              'cmovl': cmovl,
+              'cmova': cmova,
+              'cmovae': cmovae,
+              'cmovbe': cmovbe,
+              'cmovb': cmovb,
+              'cmovnge': cmovl,
+              'cmovle': cmovle,
+              'cmovng': cmovle,
+              'cmovo': cmovo,
+              'cmovno': cmovno,
+              'cmovs': cmovs,
+              'cmovns': cmovns,
+              'icebp': icebp,
+              'int': l_int,
+              'xlat': xlat,
+              'bt': bt,
+              'cpuid': cpuid,
+              'jo': jo,
+              'fcom': fcom,
+              'ficom': ficom,
+              'fcomi': fcomi,
+              'fcomip': fcomip,
+              'fucomi': fucomi,
+              'fucomip': fucomip,
+              'insb': lambda ir, instr: ins(ir, instr, 8),
+              'insw': lambda ir, instr: ins(ir, instr, 16),
+              'insd': lambda ir, instr: ins(ir, instr, 32),
+              'btc': btc,
+              'bts': bts,
+              'btr': btr,
+              'into': into,
+              'in': l_in,
+              'outsb': lambda ir, instr: l_outs(ir, instr, 8),
+              'outsw': lambda ir, instr: l_outs(ir, instr, 16),
+              'outsd': lambda ir, instr: l_outs(ir, instr, 32),
+
+              'out': l_out,
+              "sysenter": l_sysenter,
+              "cmpxchg": cmpxchg,
+              "lds": lds,
+              "les": les,
+              "lss": lss,
+              "lahf": lahf,
+              "sahf": sahf,
+              "lar": lar,
+              "lsl": lsl,
+              "fclex": fclex,
+              "fnclex": fnclex,
+              "str": l_str,
+              "movd": movd,
+              "movaps": movaps,
+              "xorps": xorps,
+
+              "pminsw": pminsw,
+              "cvtsi2sd": cvtsi2sd,
+              "movss": movss,
+
+              "ucomiss": ucomiss,
+              }
+
+
+class ir_x86_16(ir):
+
+    def __init__(self, symbol_pool=None):
+        ir.__init__(self, mn_x86, 16, symbol_pool)
+        self.do_stk_segm = False
+        self.do_ds_segm = False
+        self.do_str_segm = False
+        self.do_all_segm = False
+        self.pc = IP
+        self.sp = SP
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        pass
+
+    def get_ir(self, instr):
+        args = instr.args[:]
+        my_ss = None
+        if self.do_ds_segm:
+            my_ss = DS
+        if self.do_all_segm and instr.additional_info.g2.value:
+            my_ss = {1: CS, 2: SS, 3: DS, 4: ES, 5: FS, 6: GS}[
+                instr.additional_info.g2.value]
+        if my_ss is not None:
+            for i, a in enumerate(args):
+                if isinstance(a, ExprMem) and not a.is_op_segm():
+                    args[i] = ExprMem(ExprOp('segm', my_ss, a.arg), a.size)
+
+        dst, instr_ir, extra_ir = mnemo_func[
+            instr.name.lower()](self, instr, *args)
+        self.mod_pc(instr, instr_ir, extra_ir)
+
+        self.mod_pc(instr, instr_ir, extra_ir)
+        instr.additional_info.except_on_instr = False
+        if instr.additional_info.g1.value & 6 == 0 or \
+                not instr.name in repeat_mn:
+            return dst, instr_ir, extra_ir
+        instr.additional_info.except_on_instr = True
+        # get instruction size
+        s = {"B": 8, "W": 16, "D": 32, 'Q': 64}[instr.name[-1]]
+        size = instr.v_opmode()
+        c_reg = mRCX[instr.mode][:size]
+        out_ir = []
+        zf_val = None
+        # set if zf is tested (cmps, scas)
+        for e in instr_ir:  # +[updt_c]:
+            if e.dst == zf:
+                zf_val = e.src
+
+        # end condition
+        if zf_val is None:
+            c_cond = ExprCond(c_reg, ExprInt1(0), ExprInt1(1))
+        elif instr.additional_info.g1.value & 2:  # REPNE
+            # c_cond = ExprCond(c_reg, ExprInt1(0), ExprInt1(1)) | (zf_val)
+            c_cond = ExprCond(c_reg, ExprInt1(0), ExprInt1(1)) | (zf)
+        elif instr.additional_info.g1.value & 4:  # REP
+            # c_cond = ExprCond(c_reg, ExprInt1(0), ExprInt1(1)) |
+            # (zf_val^ExprInt32(1))
+            c_cond = ExprCond(
+                c_reg, ExprInt1(0), ExprInt1(1)) | (zf ^ ExprInt1(1))
+
+        # gen while
+        lbl_do = ExprId(self.gen_label(), instr.mode)
+        lbl_end = ExprId(self.gen_label(), instr.mode)
+        lbl_skip = ExprId(self.get_next_label(instr), instr.mode)
+        lbl_next = ExprId(self.get_next_label(instr), instr.mode)
+
+        for b in extra_ir:
+            # print repr(b)
+            # print b
+            # self.replace_expr_in_ir(b, {lbl_next:lbl_end})
+            b.dst = b.dst.replace_expr({lbl_next: lbl_end})
+            # print b
+
+        cond_bloc = []
+        cond_bloc.append(ExprAff(c_reg, c_reg - ExprInt_from(c_reg, 1)))
+        cond_bloc = irbloc(
+            lbl_end.name, ExprCond(c_cond, lbl_skip, lbl_do), [cond_bloc])
+        e_do = instr_ir
+
+        c = irbloc(lbl_do.name, dst, [e_do])
+        c.except_automod = False
+        return ExprCond(c_reg, lbl_do, lbl_skip), [], [cond_bloc, c] + extra_ir
+
+    def expr_fix_regs_for_mode(self, e, mode=64):
+        return e.replace_expr(replace_regs[mode])
+
+    def expraff_fix_regs_for_mode(self, e, mode=64):
+        dst = self.expr_fix_regs_for_mode(e.dst, mode)
+        src = self.expr_fix_regs_for_mode(e.src, mode)
+        return ExprAff(dst, src)
+
+    def irbloc_fix_regs_for_mode(self, irbloc, mode=64):
+        for irs in irbloc.irs:
+            for i, e in enumerate(irs):
+                """
+                special case for 64 bits:
+                if destination is a 32 bit reg, zero extend the 64 bit reg
+                """
+                if mode == 64:
+                    if (isinstance(e.dst, ExprId) and e.dst.size == 32 and
+                            e.dst in replace_regs[64]):
+                        src = self.expr_fix_regs_for_mode(e.src, mode)
+                        dst = replace_regs[64][e.dst].arg
+                        e = ExprAff(dst, src.zeroExtend(64))
+                irs[i] = self.expr_fix_regs_for_mode(e, mode)
+        irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst, mode)
+
+
+class ir_x86_32(ir_x86_16):
+
+    def __init__(self, symbol_pool=None):
+        ir.__init__(self, mn_x86, 32, symbol_pool)
+        self.do_stk_segm = False
+        self.do_ds_segm = False
+        self.do_str_segm = False
+        self.do_all_segm = False
+        self.pc = EIP
+        self.sp = ESP
+
+
+class ir_x86_64(ir_x86_16):
+
+    def __init__(self, symbol_pool=None):
+        ir.__init__(self, mn_x86, 64, symbol_pool)
+        self.do_stk_segm = False
+        self.do_ds_segm = False
+        self.do_str_segm = False
+        self.do_all_segm = False
+        self.pc = RIP
+        self.sp = RSP
+
+    def mod_pc(self, instr, instr_ir, extra_ir):
+        # fix RIP for 64 bit
+        for i, x in enumerate(instr_ir):
+            if x.dst != self.pc:
+                x.dst = x.dst.replace_expr(
+                    {self.pc: ExprInt64(instr.offset + instr.l)})
+            x = ExprAff(x.dst, x.src.replace_expr(
+                {self.pc: ExprInt64(instr.offset + instr.l)}))
+            instr_ir[i] = x
+        for b in extra_ir:
+            for irs in b.irs:
+                for i, x in enumerate(irs):
+                    if x.dst != self.pc:
+                        x.dst = x.dst.replace_expr(
+                            {self.pc: ExprInt64(instr.offset + instr.l)})
+                    x = ExprAff(x.dst, x.src.replace_expr(
+                        {self.pc: ExprInt64(instr.offset + instr.l)}))
+                    irs[i] = x