Merge branch 'avx512'
[platform/upstream/nasm.git] / disasm.c
index c02a3ad..9a5f9ad 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -1,11 +1,38 @@
-/* disasm.c   where all the _work_ gets done in the Netwide Disassembler
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 1996-2012 The NASM Authors - All Rights Reserved
+ *   See the file AUTHORS included with the NASM distribution for
+ *   the specific copyright holders.
  *
- * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
- * Julian Hall. All rights reserved. The software is
- * redistributable under the license given in the file "LICENSE"
- * distributed in the NASM archive.
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following
+ *   conditions are met:
  *
- * initial version 27/iii/95 by Simon Tatham
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *     
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* 
+ * disasm.c   where all the _work_ gets done in the Netwide Disassembler
  */
 
 #include "compiler.h"
@@ -46,8 +73,10 @@ struct prefix_info {
     uint8_t asp;               /* Address size prefix present */
     uint8_t rep;               /* Rep prefix present */
     uint8_t seg;               /* Segment override prefix present */
+    uint8_t wait;              /* WAIT "prefix" present */
     uint8_t lock;              /* Lock prefix present */
     uint8_t vex[3];            /* VEX prefix present */
+    uint8_t vex_c;             /* VEX "class" (VEX, XOP, ...) */
     uint8_t vex_m;             /* VEX.M field */
     uint8_t vex_v;
     uint8_t vex_lp;            /* VEX.LP fields */
@@ -81,59 +110,52 @@ static uint64_t getu64(uint8_t *data)
 #define gets64(x) ((int64_t)getu64(x))
 
 /* Important: regval must already have been adjusted for rex extensions */
-static enum reg_enum whichreg(int32_t regflags, int regval, int rex)
+static enum reg_enum whichreg(opflags_t regflags, int regval, int rex)
 {
+    size_t i;
+
+    static const struct {
+        opflags_t       flags;
+        enum reg_enum   reg;
+    } specific_registers[] = {
+        {REG_AL,  R_AL},
+        {REG_AX,  R_AX},
+        {REG_EAX, R_EAX},
+        {REG_RAX, R_RAX},
+        {REG_DL,  R_DL},
+        {REG_DX,  R_DX},
+        {REG_EDX, R_EDX},
+        {REG_RDX, R_RDX},
+        {REG_CL,  R_CL},
+        {REG_CX,  R_CX},
+        {REG_ECX, R_ECX},
+        {REG_RCX, R_RCX},
+        {FPU0,    R_ST0},
+        {XMM0,    R_XMM0},
+        {YMM0,    R_YMM0},
+        {REG_ES,  R_ES},
+        {REG_CS,  R_CS},
+        {REG_SS,  R_SS},
+        {REG_DS,  R_DS},
+        {REG_FS,  R_FS},
+        {REG_GS,  R_GS}
+    };
+
     if (!(regflags & (REGISTER|REGMEM)))
        return 0;               /* Registers not permissible?! */
 
     regflags |= REGISTER;
 
-    if (!(REG_AL & ~regflags))
-        return R_AL;
-    if (!(REG_AX & ~regflags))
-        return R_AX;
-    if (!(REG_EAX & ~regflags))
-        return R_EAX;
-    if (!(REG_RAX & ~regflags))
-       return R_RAX;
-    if (!(REG_DL & ~regflags))
-        return R_DL;
-    if (!(REG_DX & ~regflags))
-        return R_DX;
-    if (!(REG_EDX & ~regflags))
-        return R_EDX;
-    if (!(REG_RDX & ~regflags))
-        return R_RDX;
-    if (!(REG_CL & ~regflags))
-        return R_CL;
-    if (!(REG_CX & ~regflags))
-        return R_CX;
-    if (!(REG_ECX & ~regflags))
-        return R_ECX;
-    if (!(REG_RCX & ~regflags))
-        return R_RCX;
-    if (!(FPU0 & ~regflags))
-        return R_ST0;
-    if (!(XMM0 & ~regflags))
-       return R_XMM0;
-    if (!(YMM0 & ~regflags))
-       return R_YMM0;
-    if (!(REG_CS & ~regflags))
-        return (regval == 1) ? R_CS : 0;
-    if (!(REG_DESS & ~regflags))
-        return (regval == 0 || regval == 2
-                || regval == 3 ? nasm_rd_sreg[regval] : 0);
-    if (!(REG_FSGS & ~regflags))
-        return (regval == 4 || regval == 5 ? nasm_rd_sreg[regval] : 0);
-    if (!(REG_SEG67 & ~regflags))
-        return (regval == 6 || regval == 7 ? nasm_rd_sreg[regval] : 0);
+    for (i = 0; i < ARRAY_SIZE(specific_registers); i++)
+        if (!(specific_registers[i].flags & ~regflags))
+            return specific_registers[i].reg;
 
     /* All the entries below look up regval in an 16-entry array */
     if (regval < 0 || regval > 15)
         return 0;
 
     if (!(REG8 & ~regflags)) {
-       if (rex & REX_P)
+       if (rex & (REX_P|REX_NH))
            return nasm_rd_reg8_rex[regval];
        else
            return nasm_rd_reg8[regval];
@@ -151,7 +173,7 @@ static enum reg_enum whichreg(int32_t regflags, int regval, int rex)
     if (!(REG_DREG & ~regflags))
         return nasm_rd_dreg[regval];
     if (!(REG_TREG & ~regflags)) {
-       if (rex & REX_P)
+       if (regval > 7)
            return 0;           /* TR registers are ill-defined with rex */
         return nasm_rd_treg[regval];
     }
@@ -168,28 +190,11 @@ static enum reg_enum whichreg(int32_t regflags, int regval, int rex)
 }
 
 /*
- * Process a DREX suffix
- */
-static uint8_t *do_drex(uint8_t *data, insn *ins)
-{
-    uint8_t drex = *data++;
-    operand *dst = &ins->oprs[ins->drexdst];
-
-    if ((drex & 8) != ((ins->rex & REX_OC) ? 8 : 0))
-       return NULL;    /* OC0 mismatch */
-    ins->rex = (ins->rex & ~7) | (drex & 7);
-
-    dst->segment = SEG_RMREG;
-    dst->basereg = drex >> 4;
-    return data;
-}
-
-
-/*
  * Process an effective address (ModRM) specification.
  */
 static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
-                     int segsize, operand * op, insn *ins)
+                     int segsize, enum ea_type type,
+                      operand *op, insn *ins)
 {
     int mod, rm, scale, index, base;
     int rex;
@@ -198,14 +203,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
     mod = (modrm >> 6) & 03;
     rm = modrm & 07;
 
-    if (mod != 3 && rm == 4 && asize != 16)
+    if (mod != 3 && asize != 16 && rm == 4)
        sib = *data++;
 
-    if (ins->rex & REX_D) {
-       data = do_drex(data, ins);
-       if (!data)
-           return NULL;
-    }
     rex = ins->rex;
 
     if (mod == 3) {             /* pure register version */
@@ -224,6 +224,10 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
          * Exception: mod=0,rm=6 does not specify [BP] as one might
          * expect, but instead specifies [disp16].
          */
+
+        if (type != EA_SCALAR)
+            return NULL;
+
         op->indexreg = op->basereg = -1;
         op->scale = 1;          /* always, in 16 bits */
         switch (rm) {
@@ -312,6 +316,7 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
            mod = 2;            /* fake disp32 */
         }
 
+
         if (rm == 4) {          /* process SIB */
             scale = (sib >> 6) & 03;
             index = (sib >> 3) & 07;
@@ -319,9 +324,15 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
 
             op->scale = 1 << scale;
 
-           if (index == 4)
-               op->indexreg = -1; /* ESP/RSP/R12 cannot be an index */
-           else if (a64)
+           if (type == EA_XMMVSIB)
+               op->indexreg = nasm_rd_xmmreg[index | ((rex & REX_X) ? 8 : 0)];
+           else if (type == EA_YMMVSIB)
+               op->indexreg = nasm_rd_ymmreg[index | ((rex & REX_X) ? 8 : 0)];
+           else if (type == EA_ZMMVSIB)
+               op->indexreg = nasm_rd_zmmreg[index | ((rex & REX_X) ? 8 : 0)];
+           else if (index == 4 && !(rex & REX_X))
+               op->indexreg = -1; /* ESP/RSP cannot be an index */
+            else if (a64)
                op->indexreg = nasm_rd_reg64[index | ((rex & REX_X) ? 8 : 0)];
            else
                op->indexreg = nasm_rd_reg32[index | ((rex & REX_X) ? 8 : 0)];
@@ -336,6 +347,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
 
            if (segsize == 16)
                op->disp_size = 32;
+        } else if (type != EA_SCALAR) {
+            /* Can't have VSIB without SIB */
+            return NULL;
         }
 
         switch (mod) {
@@ -370,14 +384,17 @@ static int matches(const struct itemplate *t, uint8_t *data,
     uint8_t *origdata = data;
     bool a_used = false, o_used = false;
     enum prefixes drep = 0;
+    enum prefixes dwait = 0;
     uint8_t lock = prefix->lock;
     int osize = prefix->osize;
     int asize = prefix->asize;
     int i, c;
-    struct operand *opx;
-    int s_field_for = -1;      /* No 144/154 series code encountered */
+    int op1, op2;
+    struct operand *opx, *opy;
+    uint8_t opex = 0;
     bool vex_ok = false;
     int regmask = (segsize == 64) ? 15 : 7;
+    enum ea_type eat = EA_SCALAR;
 
     for (i = 0; i < MAX_OPERANDS; i++) {
        ins->oprs[i].segment = ins->oprs[i].disp_size =
@@ -395,77 +412,29 @@ static int matches(const struct itemplate *t, uint8_t *data,
     else if (prefix->rep == 0xF3)
         drep = P_REP;
 
+    dwait = prefix->wait ? P_WAIT : 0;
+
     while ((c = *r++) != 0) {
-       opx = &ins->oprs[c & 3];
+       op1 = (c & 3) + ((opex & 1) << 2);
+       op2 = ((c >> 3) & 3) + ((opex & 2) << 1);
+       opx = &ins->oprs[op1];
+       opy = &ins->oprs[op2];
+       opex = 0;
 
        switch (c) {
        case 01:
        case 02:
        case 03:
+       case 04:
             while (c--)
                 if (*r++ != *data++)
                     return false;
            break;
 
-       case 04:
-            switch (*data++) {
-            case 0x07:
-                ins->oprs[0].basereg = 0;
-                break;
-            case 0x17:
-                ins->oprs[0].basereg = 2;
-                break;
-            case 0x1F:
-                ins->oprs[0].basereg = 3;
-                break;
-            default:
-                return false;
-            }
-           break;
-
        case 05:
-            switch (*data++) {
-            case 0xA1:
-                ins->oprs[0].basereg = 4;
-                break;
-            case 0xA9:
-                ins->oprs[0].basereg = 5;
-                break;
-            default:
-                return false;
-           }
-           break;
-
        case 06:
-            switch (*data++) {
-            case 0x06:
-                ins->oprs[0].basereg = 0;
-                break;
-            case 0x0E:
-                ins->oprs[0].basereg = 1;
-                break;
-            case 0x16:
-                ins->oprs[0].basereg = 2;
-                break;
-            case 0x1E:
-                ins->oprs[0].basereg = 3;
-                break;
-            default:
-                return false;
-            }
-           break;
-
        case 07:
-            switch (*data++) {
-            case 0xA0:
-                ins->oprs[0].basereg = 4;
-                break;
-            case 0xA8:
-                ins->oprs[0].basereg = 5;
-                break;
-            default:
-                return false;
-            }
+           opex = c;
            break;
 
        case4(010):
@@ -481,7 +450,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
            break;
        }
 
-       case4(014):
+       case4(0274):
             opx->offset = (int8_t)*data++;
             opx->segment |= SEG_SIGNED;
            break;
@@ -516,6 +485,11 @@ static int matches(const struct itemplate *t, uint8_t *data,
            data += 4;
            break;
 
+        case4(0254):
+            opx->offset = gets32(data);
+            data += 4;
+            break;
+
        case4(044):
            switch (asize) {
            case 16:
@@ -555,22 +529,21 @@ static int matches(const struct itemplate *t, uint8_t *data,
             opx->segment &= ~SEG_32BIT;
            break;
 
-       case4(064):
+       case4(064):  /* rel */
             opx->segment |= SEG_RELATIVE;
-           if (osize == 16) {
-               opx->offset = gets16(data);
-               data += 2;
-                opx->segment &= ~(SEG_32BIT|SEG_64BIT);
-           } else if (osize == 32) {
-               opx->offset = gets32(data);
-               data += 4;
-                opx->segment &= ~SEG_64BIT;
-                opx->segment |= SEG_32BIT;
-           }
-            if (segsize != osize) {
-                opx->type =
-                    (opx->type & ~SIZE_MASK)
-                    | ((osize == 16) ? BITS16 : BITS32);
+            /* In long mode rel is always 32 bits, sign extended. */
+            if (segsize == 64 || osize == 32) {
+                opx->offset = gets32(data);
+                data += 4;
+                if (segsize != 64)
+                    opx->segment |= SEG_32BIT;
+                opx->type = (opx->type & ~SIZE_MASK)
+                    | (segsize == 64 ? BITS64 : BITS32);
+            } else {
+                opx->offset = gets16(data);
+                data += 2;
+                opx->segment &= ~SEG_32BIT;
+                opx->type = (opx->type & ~SIZE_MASK) | BITS16;
             }
            break;
 
@@ -587,58 +560,13 @@ static int matches(const struct itemplate *t, uint8_t *data,
        {
            int modrm = *data++;
             opx->segment |= SEG_RMREG;
-            data = do_ea(data, modrm, asize, segsize,
-                        &ins->oprs[(c >> 3) & 3], ins);
+            data = do_ea(data, modrm, asize, segsize, eat, opy, ins);
            if (!data)
                return false;
-            opx->basereg = ((modrm >> 3)&7)+
-               (ins->rex & REX_R ? 8 : 0);
+            opx->basereg = ((modrm >> 3) & 7) + (ins->rex & REX_R ? 8 : 0);
            break;
        }
 
-       case4(0140):
-           if (s_field_for == (c & 3)) {
-               opx->offset = gets8(data);
-               data++;
-           } else {
-               opx->offset = getu16(data);
-               data += 2;
-           }
-           break;
-
-       case4(0144):
-       case4(0154):
-           s_field_for = (*data & 0x02) ? c & 3 : -1;
-           if ((*data++ & ~0x02) != *r++)
-               return false;
-           break;
-
-       case4(0150):
-           if (s_field_for == (c & 3)) {
-               opx->offset = gets8(data);
-               data++;
-           } else {
-               opx->offset = getu32(data);
-               data += 4;
-           }
-           break;
-
-       case4(0160):
-           ins->rex |= REX_D;
-           ins->drexdst = c & 3;
-           break;
-
-       case4(0164):
-           ins->rex |= REX_D|REX_OC;
-           ins->drexdst = c & 3;
-           break;
-
-       case 0171:
-           data = do_drex(data, ins);
-           if (!data)
-               return false;
-           break;
-
        case 0172:
        {
            uint8_t ximm = *data++;
@@ -662,13 +590,12 @@ static int matches(const struct itemplate *t, uint8_t *data,
        }
        break;
 
-       case 0174:
+       case4(0174):
        {
            uint8_t ximm = *data++;
-           c = *r++;
 
-           ins->oprs[c].basereg = (ximm >> 4) & regmask;
-           ins->oprs[c].segment |= SEG_RMREG;
+           opx->basereg = (ximm >> 4) & regmask;
+           opx->segment |= SEG_RMREG;
        }
        break;
 
@@ -684,83 +611,77 @@ static int matches(const struct itemplate *t, uint8_t *data,
             int modrm = *data++;
             if (((modrm >> 3) & 07) != (c & 07))
                 return false;   /* spare field doesn't match up */
-            data = do_ea(data, modrm, asize, segsize,
-                         &ins->oprs[(c >> 3) & 07], ins);
+            data = do_ea(data, modrm, asize, segsize, eat, opy, ins);
            if (!data)
                return false;
            break;
        }
 
        case4(0260):
+       case 0270:
        {
            int vexm   = *r++;
            int vexwlp = *r++;
+
            ins->rex |= REX_V;
-           if ((prefix->rex & (REX_V|REX_D|REX_P)) != REX_V)
+           if ((prefix->rex & (REX_V|REX_P)) != REX_V)
                return false;
 
            if ((vexm & 0x1f) != prefix->vex_m)
                return false;
 
-           switch (vexwlp & 030) {
+           switch (vexwlp & 060) {
            case 000:
                if (prefix->rex & REX_W)
                    return false;
                break;
-           case 010:
+           case 020:
                if (!(prefix->rex & REX_W))
                    return false;
                ins->rex &= ~REX_W;
                break;
-           case 020:           /* VEX.W is a don't care */
+           case 040:           /* VEX.W is a don't care */
                ins->rex &= ~REX_W;
                break;
-           case 030:
+           case 060:
                break;
            }
 
-           if ((vexwlp & 007) != prefix->vex_lp)
+           /* The 010 bit of vexwlp is set if VEX.L is ignored */
+           if ((vexwlp ^ prefix->vex_lp) & ((vexwlp & 010) ? 03 : 07))
                return false;
 
-           opx->segment |= SEG_RMREG;
-           opx->basereg = prefix->vex_v;
+           if (c == 0270) {
+               if (prefix->vex_v != 0)
+                   return false;
+           } else {
+               opx->segment |= SEG_RMREG;
+               opx->basereg = prefix->vex_v;
+           }
            vex_ok = true;
            break;
        }
 
-       case 0270:
-       {
-           int vexm   = *r++;
-           int vexwlp = *r++;
-           ins->rex |= REX_V;
-           if ((prefix->rex & (REX_V|REX_D|REX_P)) != REX_V)
-               return false;
-
-           if ((vexm & 0x1f) != prefix->vex_m)
-               return false;
-
-           switch (vexwlp & 030) {
-           case 000:
-               if (ins->rex & REX_W)
-                   return false;
-               break;
-           case 010:
-               if (!(ins->rex & REX_W))
-                   return false;
-               break;
-           default:
-               break;          /* Need to do anything special here? */
-           }
-
-           if ((vexwlp & 007) != prefix->vex_lp)
-               return false;
+        case 0271:
+            if (prefix->rep == 0xF3)
+                drep = P_XRELEASE;
+            break;
 
-           if (prefix->vex_v != 0)
-               return false;
+        case 0272:
+            if (prefix->rep == 0xF2)
+                drep = P_XACQUIRE;
+            else if (prefix->rep == 0xF3)
+                drep = P_XRELEASE;
+            break;
 
-           vex_ok = true;
-           break;
-       }
+        case 0273:
+            if (prefix->lock == 0xF0) {
+                if (prefix->rep == 0xF2)
+                    drep = P_XACQUIRE;
+                else if (prefix->rep == 0xF3)
+                    drep = P_XRELEASE;
+            }
+            break;
 
        case 0310:
             if (asize != 16)
@@ -770,7 +691,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
            break;
 
        case 0311:
-            if (asize == 16)
+            if (asize != 32)
                 return false;
             else
                 a_used = true;
@@ -838,11 +759,15 @@ static int matches(const struct itemplate *t, uint8_t *data,
            break;
 
        case 0324:
-           if (!(ins->rex & (REX_P|REX_W)) || osize != 64)
+           if (osize != 64)
                return false;
            o_used = true;
            break;
 
+       case 0325:
+           ins->rex |= REX_NH;
+           break;
+
        case 0330:
        {
             int t = *r++, d = *data++;
@@ -853,6 +778,11 @@ static int matches(const struct itemplate *t, uint8_t *data,
            break;
        }
 
+        case 0326:
+            if (prefix->rep == 0xF3)
+                return false;
+            break;
+
        case 0331:
             if (prefix->rep)
                 return false;
@@ -882,9 +812,19 @@ static int matches(const struct itemplate *t, uint8_t *data,
                 drep = P_REPE;
            break;
 
+       case 0336:
+       case 0337:
+           break;
+
        case 0340:
            return false;
 
+       case 0341:
+           if (prefix->wait != 0x9B)
+               return false;
+           dwait = 0;
+           break;
+
        case 0360:
            if (prefix->osp || prefix->rep)
                return false;
@@ -896,18 +836,6 @@ static int matches(const struct itemplate *t, uint8_t *data,
            o_used = true;
            break;
 
-       case 0362:
-           if (prefix->osp || prefix->rep != 0xf2)
-               return false;
-           drep = 0;
-           break;
-
-       case 0363:
-           if (prefix->osp || prefix->rep != 0xf3)
-               return false;
-           drep = 0;
-           break;
-
        case 0364:
            if (prefix->osp)
                return false;
@@ -930,6 +858,22 @@ static int matches(const struct itemplate *t, uint8_t *data,
            a_used = true;
            break;
 
+        case 0370:
+        case 0371:
+            break;
+
+        case 0374:
+            eat = EA_XMMVSIB;
+            break;
+
+        case 0375:
+            eat = EA_YMMVSIB;
+            break;
+
+        case 0376:
+            eat = EA_ZMMVSIB;
+            break;
+
        default:
            return false;       /* Unknown code */
        }
@@ -938,8 +882,8 @@ static int matches(const struct itemplate *t, uint8_t *data,
     if (!vex_ok && (ins->rex & REX_V))
        return false;
 
-    /* REX cannot be combined with DREX or VEX */
-    if ((ins->rex & (REX_D|REX_V)) && (prefix->rex & REX_P))
+    /* REX cannot be combined with VEX */
+    if ((ins->rex & REX_V) && (prefix->rex & REX_P))
        return false;
 
     /*
@@ -951,15 +895,16 @@ static int matches(const struct itemplate *t, uint8_t *data,
     }
 
     if (lock) {
-       if (ins->prefixes[PPS_LREP])
+       if (ins->prefixes[PPS_LOCK])
            return false;
-       ins->prefixes[PPS_LREP] = P_LOCK;
+       ins->prefixes[PPS_LOCK] = P_LOCK;
     }
     if (drep) {
-       if (ins->prefixes[PPS_LREP])
+       if (ins->prefixes[PPS_REP])
            return false;
-        ins->prefixes[PPS_LREP] = drep;
+        ins->prefixes[PPS_REP] = drep;
     }
+    ins->prefixes[PPS_WAIT] = dwait;
     if (!o_used) {
        if (osize != ((segsize == 16) ? 16 : 32)) {
            enum prefixes pfx = 0;
@@ -999,7 +944,7 @@ static const char * const condition_name[16] = {
 };
 
 int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
-            int32_t offset, int autosync, uint32_t prefer)
+            int32_t offset, int autosync, iflags_t prefer)
 {
     const struct itemplate * const *p, * const *best_p;
     const struct disasm_index *ix;
@@ -1010,7 +955,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
     uint8_t *origdata;
     int works;
     insn tmp_ins, ins;
-    uint32_t goodness, best;
+    iflags_t goodness, best;
     int best_pref;
     struct prefix_info prefix;
     bool end_prefix;
@@ -1036,6 +981,10 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             prefix.rep = *data++;
            break;
 
+       case 0x9B:
+           prefix.wait = *data++;
+           break;
+
        case 0xF0:
             prefix.lock = *data++;
            break;
@@ -1073,24 +1022,47 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
            if (segsize == 64 || (data[1] & 0xc0) == 0xc0) {
                prefix.vex[0] = *data++;
                prefix.vex[1] = *data++;
-               if (prefix.vex[0] == 0xc4)
+
+               prefix.rex = REX_V;
+               prefix.vex_c = RV_VEX;
+
+               if (prefix.vex[0] == 0xc4) {
                    prefix.vex[2] = *data++;
+                   prefix.rex |= (~prefix.vex[1] >> 5) & 7; /* REX_RXB */
+                   prefix.rex |= (prefix.vex[2] >> (7-3)) & REX_W;
+                   prefix.vex_m = prefix.vex[1] & 0x1f;
+                   prefix.vex_v = (~prefix.vex[2] >> 3) & 15;
+                   prefix.vex_lp = prefix.vex[2] & 7;
+               } else {
+                   prefix.rex |= (~prefix.vex[1] >> (7-2)) & REX_R;
+                   prefix.vex_m = 1;
+                   prefix.vex_v = (~prefix.vex[1] >> 3) & 15;
+                   prefix.vex_lp = prefix.vex[1] & 7;
+               }
+
+               ix = itable_vex[RV_VEX][prefix.vex_m][prefix.vex_lp & 3];
            }
-           prefix.rex = REX_V;
-           if (prefix.vex[0] == 0xc4) {
+           end_prefix = true;
+           break;
+
+       case 0x8F:
+           if ((data[1] & 030) != 0 &&
+               (segsize == 64 || (data[1] & 0xc0) == 0xc0)) {
+               prefix.vex[0] = *data++;
+               prefix.vex[1] = *data++;
+               prefix.vex[2] = *data++;
+
+               prefix.rex = REX_V;
+               prefix.vex_c = RV_XOP;
+
                prefix.rex |= (~prefix.vex[1] >> 5) & 7; /* REX_RXB */
                prefix.rex |= (prefix.vex[2] >> (7-3)) & REX_W;
                prefix.vex_m = prefix.vex[1] & 0x1f;
                prefix.vex_v = (~prefix.vex[2] >> 3) & 15;
                prefix.vex_lp = prefix.vex[2] & 7;
-           } else {
-               prefix.rex |= (~prefix.vex[1] >> (7-2)) & REX_R;
-               prefix.vex_m = 1;
-               prefix.vex_v = (~prefix.vex[1] >> 3) & 15;
-               prefix.vex_lp = prefix.vex[1] & 7;
-           }
 
-           ix = itable_VEX[prefix.vex_m][prefix.vex_lp];
+               ix = itable_vex[RV_XOP][prefix.vex_m][prefix.vex_lp & 3];
+           }
            end_prefix = true;
            break;
 
@@ -1146,12 +1118,11 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             * XXX: Need to make sure this is actually correct.
              */
             for (i = 0; i < (*p)->operands; i++) {
-                if (!((*p)->opd[i] & SAME_AS) &&
-                   (
+                if (
                        /* If it's a mem-only EA but we have a
                           register, die. */
                        ((tmp_ins.oprs[i].segment & SEG_RMREG) &&
-                        !(MEMORY & ~(*p)->opd[i])) ||
+                        is_class(MEMORY, (*p)->opd[i])) ||
                        /* If it's a reg-only EA but we have a memory
                           ref, die. */
                        (!(tmp_ins.oprs[i].segment & SEG_RMREG) &&
@@ -1163,7 +1134,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
                          (tmp_ins.oprs[i].segment & SEG_RMREG)) &&
                         !whichreg((*p)->opd[i],
                                   tmp_ins.oprs[i].basereg, tmp_ins.rex))
-                       )) {
+                       ) {
                     works = false;
                     break;
                 }
@@ -1213,41 +1184,11 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
      *      the return value is "sane."  Maybe a macro wrapper could
      *      be used for that purpose.
      */
-    for (i = 0; i < MAXPREFIX; i++)
-        switch (ins.prefixes[i]) {
-       case P_LOCK:
-           slen += snprintf(output + slen, outbufsize - slen, "lock ");
-           break;
-        case P_REP:
-            slen += snprintf(output + slen, outbufsize - slen, "rep ");
-            break;
-        case P_REPE:
-            slen += snprintf(output + slen, outbufsize - slen, "repe ");
-            break;
-        case P_REPNE:
-            slen += snprintf(output + slen, outbufsize - slen, "repne ");
-            break;
-        case P_A16:
-            slen += snprintf(output + slen, outbufsize - slen, "a16 ");
-            break;
-        case P_A32:
-            slen += snprintf(output + slen, outbufsize - slen, "a32 ");
-            break;
-        case P_A64:
-            slen += snprintf(output + slen, outbufsize - slen, "a64 ");
-            break;
-        case P_O16:
-            slen += snprintf(output + slen, outbufsize - slen, "o16 ");
-            break;
-        case P_O32:
-            slen += snprintf(output + slen, outbufsize - slen, "o32 ");
-            break;
-        case P_O64:
-            slen += snprintf(output + slen, outbufsize - slen, "o64 ");
-            break;
-       default:
-           break;
-        }
+    for (i = 0; i < MAXPREFIX; i++) {
+       const char *prefix = prefix_name(ins.prefixes[i]);
+       if (prefix)
+           slen += snprintf(output+slen, outbufsize-slen, "%s ", prefix);
+    }
 
     i = (*p)->opcode;
     if (i >= FIRST_COND_OPCODE)
@@ -1264,11 +1205,6 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
        const operand *o = &ins.oprs[i];
        int64_t offs;
 
-       if (t & SAME_AS) {
-           o = &ins.oprs[t & ~SAME_AS];
-           t = (*p)->opd[t & ~SAME_AS];
-       }
-
         output[slen++] = (colon ? ':' : i == 0 ? ' ' : ',');
 
        offs = o->offset;
@@ -1344,7 +1280,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
                          o->disp_size == 32 ? "dword " :
                          o->disp_size == 16 ? "word " : ""), offs);
             segover = NULL;
-        } else if (!(REGMEM & ~t)) {
+        } else if (is_class(REGMEM, t)) {
             int started = false;
             if (t & BITS8)
                 slen +=
@@ -1367,6 +1303,9 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             if (t & BITS256)
                 slen +=
                     snprintf(output + slen, outbufsize - slen, "yword ");
+            if (t & BITS512)
+                slen +=
+                    snprintf(output + slen, outbufsize - slen, "zword ");
             if (t & FAR)
                 slen += snprintf(output + slen, outbufsize - slen, "far ");
             if (t & NEAR)
@@ -1475,8 +1414,86 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
     return length;
 }
 
-int32_t eatbyte(uint8_t *data, char *output, int outbufsize)
+/*
+ * This is called when we don't have a complete instruction.  If it
+ * is a standalone *single-byte* prefix show it as such, otherwise
+ * print it as a literal.
+ */
+int32_t eatbyte(uint8_t *data, char *output, int outbufsize, int segsize)
 {
-    snprintf(output, outbufsize, "db 0x%02X", *data);
+    uint8_t byte = *data;
+    const char *str = NULL;
+    
+    switch (byte) {
+    case 0xF2:
+       str = "repne";
+       break;
+    case 0xF3:
+       str = "rep";
+       break;
+    case 0x9B:
+       str = "wait";
+       break;
+    case 0xF0:
+       str = "lock";
+       break;
+    case 0x2E:
+       str = "cs";
+       break;
+    case 0x36:
+       str = "ss";
+       break;
+    case 0x3E:
+       str = "ss";
+       break;
+    case 0x26:
+       str = "es";
+       break;
+    case 0x64:
+       str = "fs";
+       break;
+    case 0x65:
+       str = "gs";
+       break;
+    case 0x66:
+       str = (segsize == 16) ? "o32" : "o16";
+       break;
+    case 0x67:
+       str = (segsize == 32) ? "a16" : "a32";
+       break;
+    case REX_P + 0x0:
+    case REX_P + 0x1:
+    case REX_P + 0x2:
+    case REX_P + 0x3:
+    case REX_P + 0x4:
+    case REX_P + 0x5:
+    case REX_P + 0x6:
+    case REX_P + 0x7:
+    case REX_P + 0x8:
+    case REX_P + 0x9:
+    case REX_P + 0xA:
+    case REX_P + 0xB:
+    case REX_P + 0xC:
+    case REX_P + 0xD:
+    case REX_P + 0xE:
+    case REX_P + 0xF:
+       if (segsize == 64) {
+           snprintf(output, outbufsize, "rex%s%s%s%s%s",
+                    (byte == REX_P) ? "" : ".",
+                    (byte & REX_W) ? "w" : "",
+                    (byte & REX_R) ? "r" : "",
+                    (byte & REX_X) ? "x" : "",
+                    (byte & REX_B) ? "b" : "");
+           break;
+       }
+       /* else fall through */
+    default:
+       snprintf(output, outbufsize, "db 0x%02x", byte);
+       break;
+    }
+
+    if (str)
+       snprintf(output, outbufsize, "%s", str);
+
     return 1;
 }