about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorFabrice Desclaux <fabrice.desclaux@cea.fr>2015-08-15 13:13:02 +0200
committerFabrice Desclaux <fabrice.desclaux@cea.fr>2015-08-24 13:05:08 +0200
commit2bdfaab649a1f9c6fc02b3a15d52df11f0ba07f3 (patch)
tree3c216b1cae931f3b76295445ab8e90eba5041d19
parent4d93231e77a8af094c198a8b3b3733b0250cd45a (diff)
downloadmiasm-2bdfaab649a1f9c6fc02b3a15d52df11f0ba07f3.tar.gz
miasm-2bdfaab649a1f9c6fc02b3a15d52df11f0ba07f3.zip
Arch/x86: fix xmm encoding/decoding
-rw-r--r--miasm2/arch/x86/arch.py653
1 files changed, 380 insertions, 273 deletions
diff --git a/miasm2/arch/x86/arch.py b/miasm2/arch/x86/arch.py
index f966c860..a382a4bd 100644
--- a/miasm2/arch/x86/arch.py
+++ b/miasm2/arch/x86/arch.py
@@ -279,21 +279,25 @@ WORD = Literal('WORD')
 DWORD = Literal('DWORD')
 QWORD = Literal('QWORD')
 TBYTE = Literal('TBYTE')
+XMMWORD = Literal('XMMWORD')
 
+MEMPREFIX2SIZE = {'BYTE': 8, 'WORD': 16, 'DWORD': 32,
+                  'QWORD': 64, 'TBYTE': 80, 'XMMWORD': 128}
+
+SIZE2MEMPREFIX = dict((x[1], x[0]) for x in MEMPREFIX2SIZE.items())
 
 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]])
+        return ExprMem(ptr, MEMPREFIX2SIZE[s[0]])
     elif len(t) == 3:
         s, segm, ptr = t
-        return ExprMem(ExprOp('segm', segm[0], ptr), sz[s[0]])
+        return ExprMem(ExprOp('segm', segm[0], ptr), MEMPREFIX2SIZE[s[0]])
     else:
         raise ValueError('len(t) > 3')
 
-mem_size = Group(BYTE | DWORD | QWORD | WORD | TBYTE)
+mem_size = Group(BYTE | DWORD | QWORD | WORD | TBYTE | XMMWORD)
 deref_mem = Group(mem_size + PTR + Optional(Group(int_or_expr + COLON))
                   + deref_mem_ad).setParseAction(parse_deref_mem)
 
@@ -593,8 +597,7 @@ class instruction_x86(instruction):
         if isinstance(e, ExprId) or isinstance(e, ExprInt):
             o = str(e)
         elif isinstance(e, ExprMem):
-            sz = {8: 'BYTE', 16: 'WORD', 32: 'DWORD',
-                  64: 'QWORD', 80: 'TBYTE'}[e.size]
+            sz = SIZE2MEMPREFIX[e.size]
             segm = ""
             if e.is_op_segm():
                 segm = "%s:" % e.arg.args[0]
@@ -1742,151 +1745,169 @@ def exprfindmod(e, o=None):
             raise ValueError('bad op')
     return None
 
+def test_addr_size(ptr, size):
+    if isinstance(ptr, ExprInt):
+        return ptr.arg < (1 << size)
+    else:
+        return ptr.size == size
+
+SIZE2XMMREG = {64:gpregs_mm,
+               128:gpregs_xmm}
+
+def parse_mem(expr, parent, w8, sx=0, xmm=0, mm=0):
+    dct_expr = {}
+    opmode = parent.v_opmode()
+    if expr.is_op_segm() and isinstance(expr.arg.args[0], ExprInt):
+        return None, None, False
+
+    if expr.is_op_segm():
+        segm = expr.arg.args[0]
+        ptr = expr.arg.args[1]
+    else:
+        segm = None
+        ptr = expr.arg
+
+    dct_expr[f_isad] = True
+    ad_size = ptr.size
+    admode = parent.v_admode()
+    if not test_addr_size(ptr, admode):
+        return None, None, False
+
+    if (w8 == 1 and expr.size != opmode and not sx and
+        not (hasattr(parent, 'sd') or hasattr(parent, 'wd'))):
+        return None, None, False
 
-def expr2modrm(e, p, w8, sx=0, xmm=0, mm=0):
-    o = {}
-    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'):
+    if hasattr(parent, 'wd'):
+        if expr.size == 16:
+            parent.wd.value = 1
+        elif expr.size == 32:
             pass
-        elif hasattr(p, 'stk'):
+        else:
+            return None, None, False
+
+    if (parent.mode == 64 and ptr.size == 32 and
+        parent.admode != 1):
+        return None, None, False
+    dct_expr = {f_isad: True}
+    disp = exprfindmod(ptr, dct_expr)
+    out = []
+    if disp is None:
+        # add 0 disp
+        disp = ExprInt32(0)
+    if disp is not None:
+        for signed, encoding, cast_int in [(True, f_s08, ExprInt8),
+                                           (True, f_s16, ExprInt16),
+                                           (True, f_s32, ExprInt32),
+                                           (False, f_u08, ExprInt8),
+                                           (False, f_u16, ExprInt16),
+                                           (False, f_u32, ExprInt32)]:
+            value = cast_int(int(disp.arg))
+            if admode < value.size:
+                if signed:
+                    if int(disp.arg) != sign_ext(int(value.arg), admode, disp.size):
+                        continue
+                else:
+                    if int(disp.arg) != int(value.arg):
+                        continue
+            else:
+                if int(disp.arg) != sign_ext(int(value.arg), value.size, admode):
+                    continue
+            x1 = dict(dct_expr)
+            x1[f_imm] = (encoding, value)
+            out.append(x1)
+    else:
+        out = [dct_expr]
+    return out, segm, True
+
+def expr2modrm(expr, parent, w8, sx=0, xmm=0, mm=0):
+    dct_expr = {f_isad : False}
+
+    if mm or xmm:
+        if mm and expr.size != 64:
+            return None, None, False
+        elif xmm and expr.size != 128:
+            return None, None, False
+
+        if isinstance(expr, ExprId):
+            selreg = SIZE2XMMREG[expr.size]
+            if not expr in selreg.expr:
+                return None, None, False
+            i = selreg.expr.index(expr)
+            dct_expr[i] = 1
+            return [dct_expr], None, True
+        else:
+            return parse_mem(expr, parent, w8, sx, xmm, mm)
+
+    elif expr.size == 64 and not expr in gpregs_mm.expr:
+        if hasattr(parent, 'sd'):
+            parent.sd.value = 1
+        elif hasattr(parent, 'wd'):
+            pass
+        elif hasattr(parent, 'stk'):
             pass
         else:
-            p.rex_w.value = 1
-    opmode = p.v_opmode()
+            parent.rex_w.value = 1
+    opmode = parent.v_opmode()
     if sx == 1:
         opmode = 16
     if sx == 2:
         opmode = 32
-    if e.size == 8 and w8 != 0:
+    if expr.size == 8 and w8 != 0:
         return None, None, False
 
-    if w8 == 0 and e.size != 8:
+    if w8 == 0 and expr.size != 8:
         return None, None, False
 
-    if not isinstance(e, ExprMem):
-        o[f_isad] = False
+    if not isinstance(expr, ExprMem):
+        dct_expr[f_isad] = False
         if xmm:
-            if e in gpregs_xmm.expr:
-                i = gpregs_xmm.expr.index(e)
-                o[i] = 1
-                return [o], None, True
+            if expr in gpregs_xmm.expr:
+                i = gpregs_xmm.expr.index(expr)
+                dct_expr[i] = 1
+                return [dct_expr], 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
+            if expr in gpregs_mm.expr:
+                i = gpregs_mm.expr.index(expr)
+                dct_expr[i] = 1
+                return [dct_expr], 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:
+            if parent.mode == 64 and expr in gpregs08_64.expr:
                 r = gpregs08_64
-                p.rex_p.value = 1
+                parent.rex_p.value = 1
             else:
-                p.rex_p.value = 0
-                p.rex_x.value = 0
+                parent.rex_p.value = 0
+                parent.rex_x.value = 0
                 r = size2gpregs[8]
-            if not e in r.expr:
+            if not expr 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"
+            i = r.expr.index(expr)
+            dct_expr[i] = 1
+            return [dct_expr], None, True
+        if opmode != expr.size:
             return None, None, False
-        if not e in size2gpregs[opmode].expr:
+        if not expr in size2gpregs[opmode].expr:
             return None, None, False
-        i = size2gpregs[opmode].expr.index(e)
-        # print 'aaa', p.mode, i
+        i = size2gpregs[opmode].expr.index(expr)
         if i > 7:
-            if p.mode == 64:
-                # p.rex_b.value = 1
-                # i -=7
-                # print "SET REXB"
-                pass
-            else:
+            if parent.mode != 64:
                 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
-
+        dct_expr[i] = 1
+        return [dct_expr], None, True
+    return parse_mem(expr, parent, w8, sx, xmm, mm)
 
-def modrm2expr(m, p, w8, sx=0, xmm=0, mm=0):
+def modrm2expr(modrm, parent, 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 not modrm[f_isad]:
+        modrm_k = [x[0] for x in modrm.items() if x[1] == 1]
+        if len(modrm_k) != 1:
+            raise ValueError('strange reg encoding %r' % modrm)
+        modrm_k = modrm_k[0]
         if w8 == 0:
             opmode = 8
         elif sx == 1:
@@ -1894,38 +1915,28 @@ def modrm2expr(m, p, w8, sx=0, xmm=0, mm=0):
         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
+            opmode = parent.v_opmode()
         if xmm:
-            e = gpregs_xmm.expr[k]
+            e = gpregs_xmm.expr[modrm_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]
+            e = gpregs_mm.expr[modrm_k]
+        elif opmode == 8 and (parent.v_opmode() == 64 or parent.rex_p.value == 1):
+            e = gpregs08_64.expr[modrm_k]
         else:
-            e = size2gpregs[opmode].expr[k]
+            e = size2gpregs[opmode].expr[modrm_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
+    admode = parent.v_admode()
+    opmode = parent.v_opmode()
+    for modrm_k, scale in modrm.items():
+        if type(modrm_k) in [int, long]:
+            e = size2gpregs[admode].expr[modrm_k]
+            if scale != 1:
+                e = ExprInt_fromsize(admode, scale) * e
             o.append(e)
-    # print [str(x) for x in o]
-    if f_imm in m:
-        if p.disp.value is None:
+    if f_imm in modrm:
+        if parent.disp.value is None:
             return None
-        o.append(ExprInt_fromsize(admode, p.disp.expr.arg))
+        o.append(ExprInt_fromsize(admode, parent.disp.expr.arg))
     e = ExprOp('+', *o)
     if w8 == 0:
         opmode = 8
@@ -1933,8 +1944,12 @@ def modrm2expr(m, p, w8, sx=0, xmm=0, mm=0):
         opmode = 16
     elif sx == 2:
         opmode = 32
+    if xmm:
+        opmode = 128
+    elif mm:
+        opmode = 64
+
     e = ExprMem(e, size=opmode)
-    # print "mem size", opmode, e
     return e
 
 
@@ -1970,20 +1985,13 @@ class x86_rm_arg(m_arg):
             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)
+        e = modrm2expr(xx, p, 1)
         if e is None:
             return False
         self.expr = e
@@ -2016,6 +2024,7 @@ class x86_rm_arg(m_arg):
 
         out_c = []
         for v in v_cand:
+            # print 'UU', v
             disp = None
             # patch value in modrm
             if f_imm in v:
@@ -2029,7 +2038,7 @@ class x86_rm_arg(m_arg):
             v = v.items()
             v.sort()
             v = tuple(v)
-            # print "II", e, admode
+            # print "II", v, admode
             # print 'III', v
             # if (8, 1) in v:
             #    pass
@@ -2135,18 +2144,14 @@ class x86_rm_arg(m_arg):
 
     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)
+        v_cand, segm, ok = expr2modrm(e, p, 1)
         if segm:
             p.g2.value = segm2enc[segm]
-        # print "REZ1", v_cand, ok
         for x in self.gen_cand(v_cand, admode):
             yield x
 
@@ -2282,10 +2287,33 @@ class x86_rm_wd(x86_rm_arg):
             yield x
 
 
+class x86_rm_m64(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
+        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
+        v_cand, segm, ok = expr2modrm(e, p, 0, 0, 0, 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):
+        # print 'TTTT'
         p = self.parent
         xx = self.get_modrm()
         # print "aaa", xx
@@ -2307,6 +2335,7 @@ class x86_rm_m80(x86_rm_arg):
         if mode == 64:
             mode = 32
         e = ExprMem(e.arg, mode)
+        # print "eEEE", e
         v_cand, segm, ok = expr2modrm(e, p, 1)
         for x in self.gen_cand(v_cand, p.v_admode()):
             yield x
@@ -2344,8 +2373,69 @@ class x86_rm_m16(x86_rm_m80):
     msize = 16
 
 
-class x86_rm_m64(x86_rm_m80):
+class x86_rm_mm(x86_rm_m80):
+    msize = 64
+    is_mm = True
+    is_xmm = False
+
+    def decode(self, v):
+        # print 'TTTT'
+        p = self.parent
+        xx = self.get_modrm()
+        # print "aaa", xx
+        #modrm2expr(m, p, w8, sx=0, xmm=0, mm=0):
+        expr = modrm2expr(xx, p, 0, 0, self.is_xmm, self.is_mm)
+        if isinstance(expr, ExprMem) and expr.size != self.msize:
+            expr = ExprMem(expr.arg, self.msize)
+        # print 'RRR', e
+        self.expr = expr
+        return True
+
+
+    def encode(self):
+        expr = self.expr
+        if isinstance(expr, ExprInt):
+            raise StopIteration
+        if isinstance(expr, ExprMem) and expr.size != self.msize:
+            raise StopIteration
+        p = self.parent
+        mode = p.mode
+        if mode == 64:
+            mode = 32
+        if isinstance(expr, ExprMem):
+            if self.is_xmm:
+                expr = ExprMem(expr.arg, 128)
+            elif self.is_mm:
+                expr = ExprMem(expr.arg, 64)
+
+        #expr2modrm(e, p, w8, sx=0, xmm=0, mm=0):
+        # print "eeeEEE", e
+        v_cand, segm, ok = expr2modrm(expr, p, 0, 0, self.is_xmm, self.is_mm)
+        # print v_cand, segm, p.v_admode()
+        for x in self.gen_cand(v_cand, p.v_admode()):
+            yield x
+
+
+class x86_rm_mm_m64(x86_rm_mm):
+    msize = 64
+    is_mm = True
+    is_xmm = False
+
+class x86_rm_xmm(x86_rm_mm):
+    msize = 128
+    is_mm = False
+    is_xmm = True
+
+
+class x86_rm_xmm_m32(x86_rm_mm):
+    msize = 32
+    is_mm = False
+    is_xmm = True
+
+class x86_rm_xmm_m64(x86_rm_mm):
     msize = 64
+    is_mm = False
+    is_xmm = True
 
 
 class x86_rm_reg_noarg(object):
@@ -2391,8 +2481,6 @@ class x86_rm_reg_noarg(object):
         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]
@@ -2401,20 +2489,8 @@ class x86_rm_reg_noarg(object):
         # 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]
+        e = r.expr[v]
         self.expr = e
         return True
 
@@ -2423,12 +2499,7 @@ class x86_rm_reg_noarg(object):
             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:
@@ -2437,14 +2508,7 @@ class x86_rm_reg_noarg(object):
             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:
+        if 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):
@@ -2453,28 +2517,49 @@ class x86_rm_reg_noarg(object):
         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_mm(x86_rm_reg_noarg, m_arg):
+    selreg = gpregs_mm
+    def decode(self, v):
+        if self.parent.mode == 64 and self.getrexsize():
+            v |= 0x8
+        e = self.selreg.expr[v]
+        self.expr = e
+        return True
+
+    def encode(self):
+        if not isinstance(self.expr, ExprId):
+            return False
+        if not self.expr in self.selreg.expr:
+            return False
+        i = self.selreg.expr.index(self.expr)
+        if self.parent.mode == 64 and i > 7:
+            i -= 8
+            self.setrexsize(1)
+        self.value = i
+        if self.value > self.lmask:
+            log.debug("cannot encode field value %x %x",
+                      self.value, self.lmask)
+            return False
+        return True
+
+class x86_rm_reg_xmm(x86_rm_reg_mm):
+    selreg = gpregs_xmm
+
 class x86_rm_reg(x86_rm_reg_noarg, m_arg):
     pass
 
@@ -3186,6 +3271,11 @@ 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")
 
+
+mm_reg = bs(l=3, cls=(x86_rm_reg_mm, ), order =1, fname = "reg")
+xmm_reg = bs(l=3, cls=(x86_rm_reg_xmm, ), order =1, fname = "reg")
+
+
 fltreg = bs(l=3, cls=(x86_rm_flt, ), order =1, fname = "reg")
 
 rm = bs(l=3, fname="rm")
@@ -3196,11 +3286,18 @@ 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_m80 = bs(l=0, cls=(x86_rm_m80,), 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')
 
+rm_arg_mm = bs(l=0, cls=(x86_rm_mm,), fname='rmarg')
+rm_arg_mm_m64 = bs(l=0, cls=(x86_rm_mm_m64,), fname='rmarg')
+
+rm_arg_xmm = bs(l=0, cls=(x86_rm_xmm,), fname='rmarg')
+rm_arg_xmm_m32 = bs(l=0, cls=(x86_rm_xmm_m32,), fname='rmarg')
+rm_arg_xmm_m64 = bs(l=0, cls=(x86_rm_xmm_m64,), fname='rmarg')
+
 swapargs = bs_swapargs(l=1, fname="swap", mn_mod=range(1 << 1))
 
 
@@ -3660,62 +3757,62 @@ addop("movsx", [bs8(0x0f), bs("1011111"), w8, sx] + rmmod(rmreg, rm_arg_sx))
 addop("movsxd", [bs8(0x63), sxd, bs_mode64] + rmmod(rmreg, rm_arg_sxd))
 
 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), bs("0001000"), swapargs, xmm, pref_f3] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
-addop("movupd", [bs8(0x0f), bs8(0x10), xmm, pref_66] + rmmod(rmreg, rm_arg))
+      [bs8(0x0f), bs8(0x10), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("movsd", [bs8(0x0f), bs("0001000"), swapargs, pref_f2]
+      + rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64])
+addop("movss", [bs8(0x0f), bs("0001000"), swapargs, pref_f3] +
+      rmmod(xmm_reg, rm_arg_xmm_m32), [xmm_reg, rm_arg_xmm_m32])
+addop("movupd", [bs8(0x0f), bs8(0x10), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 
-addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), mm, no_xmm_pref] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
-addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), xmm, pref_66] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg), [mm_reg, rm_arg])
+addop("movd", [bs8(0x0f), bs('011'), swapargs, bs('1110'), pref_66] +
+      rmmod(xmm_reg, rm_arg), [xmm_reg, rm_arg])
 
-addop("movq", [bs8(0x0f), bs('011'), swapargs, bs('1111'), mm, no_xmm_pref] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+addop("movq", [bs8(0x0f), bs('011'), swapargs, bs('1111'), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm_m64), [mm_reg, rm_arg_mm_m64])
 
-addop("movq", [bs8(0x0f), bs8(0x7e), xmm, pref_f3] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
-addop("movq", [bs8(0x0f), bs8(0xd6), xmm, pref_66] +
-      rmmod(rmreg, rm_arg), [rm_arg, rmreg])
+addop("movq", [bs8(0x0f), bs8(0x7e), pref_f3] +
+      rmmod(xmm_reg, rm_arg_xmm_m64), [xmm_reg, rm_arg_xmm_m64])
+addop("movq", [bs8(0x0f), bs8(0xd6), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm_m64), [rm_arg_xmm_m64, xmm_reg])
 
 
 
-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("addss", [bs8(0x0f), bs8(0x58), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("addsd", [bs8(0x0f), bs8(0x58), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
 
-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("subss", [bs8(0x0f), bs8(0x5c), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("subsd", [bs8(0x0f), bs8(0x5c), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
 
-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("mulss", [bs8(0x0f), bs8(0x59), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("mulsd", [bs8(0x0f), bs8(0x59), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
 
-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("divss", [bs8(0x0f), bs8(0x5e), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("divsd", [bs8(0x0f), bs8(0x5e), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
 
 
-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("pminsw", [bs8(0x0f), bs8(0xea), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("pminsw", [bs8(0x0f), bs8(0xea), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 
-addop("pxor", [bs8(0x0f), bs8(0xef), xmm] + rmmod(rmreg, rm_arg))
+addop("pxor", [bs8(0x0f), bs8(0xef), xmm] + rmmod(xmm_reg, rm_arg_xmm))
 
-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("ucomiss", [bs8(0x0f), bs8(0x2e), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm_m32))
+addop("ucomisd", [bs8(0x0f), bs8(0x2e), pref_66] + rmmod(xmm_reg, rm_arg_xmm_m64))
 
-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("andps", [bs8(0x0f), bs8(0x54), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("andpd", [bs8(0x0f), bs8(0x54), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 
-addop("maxsd", [bs8(0x0f), bs8(0x5f), xmm, pref_f2] + rmmod(rmreg, rm_arg))
+addop("maxsd", [bs8(0x0f), bs8(0x5f), pref_f2] + rmmod(xmm_reg, rm_arg_xmm_m64))
+addop("maxss", [bs8(0x0f), bs8(0x5f), pref_f3] + rmmod(xmm_reg, rm_arg_xmm_m32))
 
 addop("cvtsi2sd",
-      [bs8(0x0f), bs8(0x2a), xmmreg, pref_f2] + rmmod(rmreg, rm_arg))
+      [bs8(0x0f), bs8(0x2a), xmmreg, pref_f2] + rmmod(xmm_reg, rm_arg))
 addop("cvtsi2ss",
-      [bs8(0x0f), bs8(0x2a), xmmreg, pref_f3] + rmmod(rmreg, rm_arg))
+      [bs8(0x0f), bs8(0x2a), xmmreg, pref_f3] + rmmod(xmm_reg, rm_arg))
 
 
 addop("cvttsd2ss",
@@ -3724,7 +3821,7 @@ 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]
+# type("movupd", (mn_x86,), {"fields":[bs8(0x0f), bs8(0x10), pref_f2]
 # + rmmod(rmreg, rm_arg_sxd), 'prefixed':'\xf2'})
 
 addop("movzx", [bs8(0x0f), bs("1011011"), w8, sx] + rmmod(rmreg, rm_arg_sx))
@@ -3957,7 +4054,7 @@ addop("xor", [bs("001100"), swapargs, w8] +
 addop("xgetbv", [bs8(0x0f), bs8(0x01), bs8(0xd0)])
 
 
-#addop("pand", [bs8(0x0f), bs8(0xdb), xmm, pref_66])# + rmmod(rmreg, rm_arg))
+#addop("pand", [bs8(0x0f), bs8(0xdb), pref_66])# + rmmod(rmreg, rm_arg))
 
 #### MMX/SSE/AVX operations
 #### Categories are the same than here: https://software.intel.com/sites/landingpage/IntrinsicsGuide/
@@ -3973,54 +4070,64 @@ addop("xgetbv", [bs8(0x0f), bs8(0x01), bs8(0xd0)])
 # 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])
+      + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode16], [xmm_reg, rm_arg_xmm])
 addop("movaps", [bs8(0x0f), bs("0010100"), swapargs, xmm]
-      + rmmod(rmreg, rm_arg) + [bs_opmode32], [rmreg, rm_arg])
+      + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode32], [xmm_reg, rm_arg_xmm])
 addop("movaps", [bs8(0x0f), bs("0010100"), swapargs, xmm]
-      + rmmod(rmreg, rm_arg) + [bs_opmode64], [rmreg, rm_arg])
-addop("movdqu", [bs8(0x0f), bs("011"), swapargs, bs("1111"), xmm, pref_f3]
-      + rmmod(rmreg, rm_arg), [rmreg, rm_arg])
-addop("movdqa", [bs8(0x0f), bs("011"), swapargs, bs("1111"), xmm, pref_66]
-      + rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+      + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode64], [xmm_reg, rm_arg_xmm])
+addop("movdqu", [bs8(0x0f), bs("011"), swapargs, bs("1111"), pref_f3]
+      + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
+addop("movdqa", [bs8(0x0f), bs("011"), swapargs, bs("1111"), pref_66]
+      + rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
 
 
 
 ## Additions
 # SSE
-addop("paddb", [bs8(0x0f), bs8(0xfc), xmm, pref_66] + rmmod(rmreg, rm_arg))
-addop("paddw", [bs8(0x0f), bs8(0xfd), xmm, pref_66] + rmmod(rmreg, rm_arg))
-addop("paddd", [bs8(0x0f), bs8(0xfe), xmm, pref_66] + rmmod(rmreg, rm_arg))
-addop("paddq", [bs8(0x0f), bs8(0xd4), xmm, pref_66] + rmmod(rmreg, rm_arg))
+addop("paddb", [bs8(0x0f), bs8(0xfc), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("paddw", [bs8(0x0f), bs8(0xfd), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("paddd", [bs8(0x0f), bs8(0xfe), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("paddq", [bs8(0x0f), bs8(0xd4), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("paddb", [bs8(0x0f), bs8(0xfc), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("paddw", [bs8(0x0f), bs8(0xfd), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("paddd", [bs8(0x0f), bs8(0xfe), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("paddq", [bs8(0x0f), bs8(0xd4), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
 
 ## Substractions
 # SSE
-addop("psubb", [bs8(0x0f), bs8(0xf8), xmm, pref_66] + rmmod(rmreg, rm_arg))
-addop("psubw", [bs8(0x0f), bs8(0xf9), xmm, pref_66] + rmmod(rmreg, rm_arg))
-addop("psubd", [bs8(0x0f), bs8(0xfa), xmm, pref_66] + rmmod(rmreg, rm_arg))
-addop("psubq", [bs8(0x0f), bs8(0xfb), xmm, pref_66] + rmmod(rmreg, rm_arg))
+addop("psubb", [bs8(0x0f), bs8(0xf8), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("psubw", [bs8(0x0f), bs8(0xf9), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("psubd", [bs8(0x0f), bs8(0xfa), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+addop("psubq", [bs8(0x0f), bs8(0xfb), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
+
+addop("psubb", [bs8(0x0f), bs8(0xf8), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("psubw", [bs8(0x0f), bs8(0xf9), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("psubd", [bs8(0x0f), bs8(0xfa), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
+addop("psubq", [bs8(0x0f), bs8(0xfb), no_xmm_pref] + rmmod(mm_reg, rm_arg_mm))
 
 ### Arithmetic (floating-point)
 ###
 
 ## Additions
 # SSE
-addop("addps", [bs8(0x0f), bs8(0x58), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
-addop("addpd", [bs8(0x0f), bs8(0x58), xmm, pref_66] + rmmod(rmreg, rm_arg))
+addop("addps", [bs8(0x0f), bs8(0x58), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("addpd", [bs8(0x0f), bs8(0x58), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 ## Substractions
 # SSE
-addop("subps", [bs8(0x0f), bs8(0x5c), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
-addop("subpd", [bs8(0x0f), bs8(0x5c), xmm, pref_66] + rmmod(rmreg, rm_arg))
+addop("subps", [bs8(0x0f), bs8(0x5c), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("subpd", [bs8(0x0f), bs8(0x5c), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 ## Multiplications
 # SSE
-addop("mulps", [bs8(0x0f), bs8(0x59), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
-addop("mulpd", [bs8(0x0f), bs8(0x59), xmm, pref_66] + rmmod(rmreg, rm_arg))
+addop("mulps", [bs8(0x0f), bs8(0x59), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("mulpd", [bs8(0x0f), bs8(0x59), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 ## Divisions
 # SSE
-addop("divps", [bs8(0x0f), bs8(0x5e), xmm, no_xmm_pref] + rmmod(rmreg, rm_arg))
-addop("divpd", [bs8(0x0f), bs8(0x5e), xmm, pref_66] + rmmod(rmreg, rm_arg))
+addop("divps", [bs8(0x0f), bs8(0x5e), no_xmm_pref] + rmmod(xmm_reg, rm_arg_xmm))
+addop("divpd", [bs8(0x0f), bs8(0x5e), pref_66] + rmmod(xmm_reg, rm_arg_xmm))
 
 ### Logical (floating-point)
 ###
@@ -4031,25 +4138,25 @@ addop("divpd", [bs8(0x0f), bs8(0x5e), xmm, pref_66] + rmmod(rmreg, rm_arg))
 # 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])
+addop("xorpd", [bs8(0x0f), bs8(0x57), xmm] + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode16])
+addop("xorps", [bs8(0x0f), bs8(0x57), xmm] + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode32])
+addop("xorps", [bs8(0x0f), bs8(0x57), xmm] + rmmod(xmm_reg, rm_arg_xmm) + [bs_opmode64])
 
 ## AND
 # MMX
-addop("pand", [bs8(0x0f), bs8(0xdb), mm, no_xmm_pref] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+addop("pand", [bs8(0x0f), bs8(0xdb), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
 # SSE
-addop("pand", [bs8(0x0f), bs8(0xdb), xmm, pref_66] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+addop("pand", [bs8(0x0f), bs8(0xdb), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
 
 ## OR
 # MMX
-addop("por", [bs8(0x0f), bs8(0xeb), mm, no_xmm_pref] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+addop("por", [bs8(0x0f), bs8(0xeb), no_xmm_pref] +
+      rmmod(mm_reg, rm_arg_mm), [mm_reg, rm_arg_mm])
 # SSE
-addop("por", [bs8(0x0f), bs8(0xeb), xmm, pref_66] +
-      rmmod(rmreg, rm_arg), [rmreg, rm_arg])
+addop("por", [bs8(0x0f), bs8(0xeb), pref_66] +
+      rmmod(xmm_reg, rm_arg_xmm), [xmm_reg, rm_arg_xmm])
 
 ### Convert
 ### SS = single precision
@@ -4060,15 +4167,15 @@ addop("por", [bs8(0x0f), bs8(0xeb), xmm, pref_66] +
 ##
 
 # SSE
-addop("cvtss2sd", [bs8(0x0f), bs8(0x5a), xmm, pref_f3]
-      + rmmod(rmreg, rm_arg))
+addop("cvtss2sd", [bs8(0x0f), bs8(0x5a), pref_f3]
+      + rmmod(xmm_reg, rm_arg_xmm_m32))
 
 ## SD -> SS
 ##
 
 # SSE
-addop("cvtsd2ss", [bs8(0x0f), bs8(0x5a), xmm, pref_f2]
-      + rmmod(rmreg, rm_arg))
+addop("cvtsd2ss", [bs8(0x0f), bs8(0x5a), pref_f2]
+      + rmmod(xmm_reg, rm_arg_xmm_m64))
 
 
 mn_x86.bintree = factor_one_bit(mn_x86.bintree)