about summary refs log tree commit diff stats
path: root/miasm2/arch/x86/arch.py
diff options
context:
space:
mode:
Diffstat (limited to 'miasm2/arch/x86/arch.py')
-rw-r--r--miasm2/arch/x86/arch.py3839
1 files changed, 3839 insertions, 0 deletions
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