Merge branch 'avx512'
[platform/upstream/nasm.git] / disasm.c
index 724d0bf..9a5f9ad 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -1,13 +1,42 @@
-/* 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 licence given in the file "Licence"
- * 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"
+
 #include <stdio.h>
 #include <string.h>
 #include <limits.h>
@@ -17,8 +46,8 @@
 #include "disasm.h"
 #include "sync.h"
 #include "insns.h"
-
-#include "names.c"
+#include "tables.h"
+#include "regdis.h"
 
 /*
  * Flags that go into the `segment' field of `insn' structures
@@ -34,8 +63,6 @@
 #define SEG_SIGNED     128
 #define SEG_64BIT      256
 
-#include "regdis.c"
-
 /*
  * Prefix information
  */
@@ -46,12 +73,18 @@ 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 rex;               /* Rex 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 */
+    uint32_t rex;              /* REX prefix present */
 };
 
 #define getu8(x) (*(uint8_t *)(x))
-#if defined(__i386__) || defined(__x86_64__)
+#if X86_MEMORY
 /* Littleendian CPU which can handle unaligned references */
 #define getu16(x) (*(uint16_t *)(x))
 #define getu32(x) (*(uint32_t *)(x))
@@ -77,118 +110,91 @@ 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 (!(REG_CS & ~regflags))
-        return (regval == 1) ? R_CS : 0;
-    if (!(REG_DESS & ~regflags))
-        return (regval == 0 || regval == 2
-                || regval == 3 ? rd_sreg[regval] : 0);
-    if (!(REG_FSGS & ~regflags))
-        return (regval == 4 || regval == 5 ? rd_sreg[regval] : 0);
-    if (!(REG_SEG67 & ~regflags))
-        return (regval == 6 || regval == 7 ? 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)
-           return rd_reg8_rex[regval];
+       if (rex & (REX_P|REX_NH))
+           return nasm_rd_reg8_rex[regval];
        else
-           return rd_reg8[regval];
+           return nasm_rd_reg8[regval];
     }
     if (!(REG16 & ~regflags))
-        return rd_reg16[regval];
+        return nasm_rd_reg16[regval];
     if (!(REG32 & ~regflags))
-        return rd_reg32[regval];
+        return nasm_rd_reg32[regval];
     if (!(REG64 & ~regflags))
-        return rd_reg64[regval];
+        return nasm_rd_reg64[regval];
     if (!(REG_SREG & ~regflags))
-        return rd_sreg[regval & 7]; /* Ignore REX */
+        return nasm_rd_sreg[regval & 7]; /* Ignore REX */
     if (!(REG_CREG & ~regflags))
-        return rd_creg[regval];
+        return nasm_rd_creg[regval];
     if (!(REG_DREG & ~regflags))
-        return rd_dreg[regval];
+        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 rd_treg[regval];
+        return nasm_rd_treg[regval];
     }
     if (!(FPUREG & ~regflags))
-        return rd_fpureg[regval & 7]; /* Ignore REX */
+        return nasm_rd_fpureg[regval & 7]; /* Ignore REX */
     if (!(MMXREG & ~regflags))
-        return rd_mmxreg[regval & 7]; /* Ignore REX */
+        return nasm_rd_mmxreg[regval & 7]; /* Ignore REX */
     if (!(XMMREG & ~regflags))
-        return rd_xmmreg[regval];
+        return nasm_rd_xmmreg[regval];
+    if (!(YMMREG & ~regflags))
+        return nasm_rd_ymmreg[regval];
 
     return 0;
 }
 
-static const char *whichcond(int condval)
-{
-    static int conds[] = {
-        C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
-        C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
-    };
-    return conditions[conds[condval]];
-}
-
-/*
- * 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;
@@ -197,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 */
@@ -213,7 +214,7 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
         return data;
     }
 
-    op->addr_size = 0;
+    op->disp_size = 0;
     op->eaflags = 0;
 
     if (asize == 16) {
@@ -223,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) {
@@ -258,7 +263,7 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
         if (rm == 6 && mod == 0) {      /* special case */
             op->basereg = -1;
             if (segsize != 16)
-                op->addr_size = 16;
+                op->disp_size = 16;
             mod = 2;            /* fake disp16 */
         }
         switch (mod) {
@@ -293,9 +298,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
         op->indexreg = -1;
 
        if (a64)
-           op->basereg = rd_reg64[rm | ((rex & REX_B) ? 8 : 0)];
+           op->basereg = nasm_rd_reg64[rm | ((rex & REX_B) ? 8 : 0)];
        else
-           op->basereg = rd_reg32[rm | ((rex & REX_B) ? 8 : 0)];
+           op->basereg = nasm_rd_reg32[rm | ((rex & REX_B) ? 8 : 0)];
 
         if (rm == 5 && mod == 0) {
            if (segsize == 64) {
@@ -305,12 +310,13 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
            }
 
            if (asize != 64)
-               op->addr_size = asize;
+               op->disp_size = asize;
 
            op->basereg = -1;
            mod = 2;            /* fake disp32 */
         }
 
+
         if (rm == 4) {          /* process SIB */
             scale = (sib >> 6) & 03;
             index = (sib >> 3) & 07;
@@ -318,23 +324,32 @@ 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)
-               op->indexreg = rd_reg64[index | ((rex & REX_X) ? 8 : 0)];
+           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 = rd_reg64[index | ((rex & REX_X) ? 8 : 0)];
+               op->indexreg = nasm_rd_reg32[index | ((rex & REX_X) ? 8 : 0)];
 
            if (base == 5 && mod == 0) {
                op->basereg = -1;
                mod = 2;        /* Fake disp32 */
            } else if (a64)
-               op->basereg = rd_reg64[base | ((rex & REX_B) ? 8 : 0)];
+               op->basereg = nasm_rd_reg64[base | ((rex & REX_B) ? 8 : 0)];
            else
-               op->basereg = rd_reg32[base | ((rex & REX_B) ? 8 : 0)];
+               op->basereg = nasm_rd_reg32[base | ((rex & REX_B) ? 8 : 0)];
 
-           if (segsize != 32)
-               op->addr_size = 32;
+           if (segsize == 16)
+               op->disp_size = 32;
+        } else if (type != EA_SCALAR) {
+            /* Can't have VSIB without SIB */
+            return NULL;
         }
 
         switch (mod) {
@@ -348,7 +363,7 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
             break;
         case 2:
             op->segment |= SEG_DISP32;
-            op->offset = getu32(data);
+            op->offset = gets32(data);
            data += 4;
             break;
         }
@@ -360,318 +375,576 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
  * Determine whether the instruction template in t corresponds to the data
  * stream in data. Return the number of bytes matched if so.
  */
+#define case4(x) case (x): case (x)+1: case (x)+2: case (x)+3
+
 static int matches(const struct itemplate *t, uint8_t *data,
                   const struct prefix_info *prefix, int segsize, insn *ins)
 {
     uint8_t *r = (uint8_t *)(t->code);
     uint8_t *origdata = data;
-    int a_used = FALSE, o_used = FALSE;
+    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;
+    int i, c;
+    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].addr_size =
+       ins->oprs[i].segment = ins->oprs[i].disp_size =
            (segsize == 64 ? SEG_64BIT : segsize == 32 ? SEG_32BIT : 0);
     }
     ins->condition = -1;
     ins->rex = prefix->rex;
+    memset(ins->prefixes, 0, sizeof ins->prefixes);
 
     if (t->flags & (segsize == 64 ? IF_NOLONG : IF_LONG))
-        return FALSE;
+        return false;
 
     if (prefix->rep == 0xF2)
         drep = P_REPNE;
     else if (prefix->rep == 0xF3)
         drep = P_REP;
 
-    while (*r) {
-        int c = *r++;
+    dwait = prefix->wait ? P_WAIT : 0;
 
-       /* FIX: change this into a switch */
-       if (c >= 01 && c <= 03) {
+    while ((c = *r++) != 0) {
+       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;
-       } else if (c == 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;
-            }
-       } else if (c == 05) {
-            switch (*data++) {
-            case 0xA1:
-                ins->oprs[0].basereg = 4;
-                break;
-            case 0xA9:
-                ins->oprs[0].basereg = 5;
-                break;
-            default:
-                return FALSE;
-           }
-       } else if (c == 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;
-            }
-       } else if (c == 07) {
-            switch (*data++) {
-            case 0xA0:
-                ins->oprs[0].basereg = 4;
-                break;
-            case 0xA8:
-                ins->oprs[0].basereg = 5;
-                break;
-            default:
-                return FALSE;
-            }
-       } else if (c >= 010 && c <= 013) {
+                    return false;
+           break;
+
+       case 05:
+       case 06:
+       case 07:
+           opex = c;
+           break;
+
+       case4(010):
+       {
             int t = *r++, d = *data++;
             if (d < t || d > t + 7)
-                return FALSE;
+                return false;
             else {
-                ins->oprs[c - 010].basereg = (d-t)+
+                opx->basereg = (d-t)+
                    (ins->rex & REX_B ? 8 : 0);
-                ins->oprs[c - 010].segment |= SEG_RMREG;
+                opx->segment |= SEG_RMREG;
             }
-       } else if (c >= 014 && c <= 017) {
-            ins->oprs[c - 014].offset = (int8_t)*data++;
-            ins->oprs[c - 014].segment |= SEG_SIGNED;
-        } else if (c >= 020 && c <= 023) {
-            ins->oprs[c - 020].offset = *data++;
-       } else if (c >= 024 && c <= 027) {
-            ins->oprs[c - 024].offset = *data++;
-       } else if (c >= 030 && c <= 033) {
-            ins->oprs[c - 030].offset = getu16(data);
+           break;
+       }
+
+       case4(0274):
+            opx->offset = (int8_t)*data++;
+            opx->segment |= SEG_SIGNED;
+           break;
+
+       case4(020):
+            opx->offset = *data++;
+           break;
+
+       case4(024):
+            opx->offset = *data++;
+           break;
+
+       case4(030):
+            opx->offset = getu16(data);
            data += 2;
-        } else if (c >= 034 && c <= 037) {
+           break;
+
+       case4(034):
            if (osize == 32) {
-               ins->oprs[c - 034].offset = getu32(data);
+               opx->offset = getu32(data);
                data += 4;
            } else {
-               ins->oprs[c - 034].offset = getu16(data);
+               opx->offset = getu16(data);
                data += 2;
            }
             if (segsize != asize)
-                ins->oprs[c - 034].addr_size = asize;
-        } else if (c >= 040 && c <= 043) {
-            ins->oprs[c - 040].offset = getu32(data);
+                opx->disp_size = asize;
+           break;
+
+       case4(040):
+            opx->offset = getu32(data);
            data += 4;
-        } else if (c >= 044 && c <= 047) {
+           break;
+
+        case4(0254):
+            opx->offset = gets32(data);
+            data += 4;
+            break;
+
+       case4(044):
            switch (asize) {
            case 16:
-               ins->oprs[c - 044].offset = getu16(data);
+               opx->offset = getu16(data);
                data += 2;
+               if (segsize != 16)
+                   opx->disp_size = 16;
                break;
            case 32:
-               ins->oprs[c - 044].offset = getu32(data);
+               opx->offset = getu32(data);
                data += 4;
+               if (segsize == 16)
+                   opx->disp_size = 32;
                break;
            case 64:
-               ins->oprs[c - 044].offset = getu64(data);
+               opx->offset = getu64(data);
+               opx->disp_size = 64;
                data += 8;
                break;
            }
-            if (segsize != asize)
-                ins->oprs[c - 044].addr_size = asize;
-        } else if (c >= 050 && c <= 053) {
-            ins->oprs[c - 050].offset = gets8(data++);
-            ins->oprs[c - 050].segment |= SEG_RELATIVE;
-        } else if (c >= 054 && c <= 057) {
-           ins->oprs[c - 054].offset = getu64(data);
+           break;
+
+       case4(050):
+            opx->offset = gets8(data++);
+            opx->segment |= SEG_RELATIVE;
+           break;
+
+       case4(054):
+           opx->offset = getu64(data);
            data += 8;
-       } else if (c >= 060 && c <= 063) {
-            ins->oprs[c - 060].offset = gets16(data);
+           break;
+
+       case4(060):
+            opx->offset = gets16(data);
            data += 2;
-            ins->oprs[c - 060].segment |= SEG_RELATIVE;
-            ins->oprs[c - 060].segment &= ~SEG_32BIT;
-        } else if (c >= 064 && c <= 067) {
-           if (osize == 16) {
-               ins->oprs[c - 064].offset = getu16(data);
-               data += 2;
-                ins->oprs[c - 064].segment &= ~(SEG_32BIT|SEG_64BIT);
-           } else if (osize == 32) {
-               ins->oprs[c - 064].offset = getu32(data);
-               data += 4;
-                ins->oprs[c - 064].segment &= ~SEG_64BIT;
-                ins->oprs[c - 064].segment |= SEG_32BIT;
-           }   
-            if (segsize != osize) {
-                ins->oprs[c - 064].type =
-                    (ins->oprs[c - 064].type & ~SIZE_MASK)
-                    | ((osize == 16) ? BITS16 : BITS32);
+            opx->segment |= SEG_RELATIVE;
+            opx->segment &= ~SEG_32BIT;
+           break;
+
+       case4(064):  /* rel */
+            opx->segment |= SEG_RELATIVE;
+            /* 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;
             }
-        } else if (c >= 070 && c <= 073) {
-            ins->oprs[c - 070].offset = getu32(data);
-           data += 4;
-            ins->oprs[c - 070].segment |= SEG_32BIT | SEG_RELATIVE;
-        } else if (c >= 0100 && c < 0140) {
-            int modrm = *data++;
-            ins->oprs[c & 07].segment |= SEG_RMREG;
-            data = do_ea(data, modrm, asize, segsize,
-                        &ins->oprs[(c >> 3) & 07], ins);
-           if (!data)
-               return FALSE;
-            ins->oprs[c & 07].basereg = ((modrm >> 3)&7)+
-               (ins->rex & REX_R ? 8 : 0);
-        } else if (c >= 0140 && c <= 0143) {
-            ins->oprs[c - 0140].offset = getu16(data);
-           data += 2;
-        } else if (c >= 0150 && c <= 0153) {
-           ins->oprs[c - 0150].offset = getu32(data);
+           break;
+
+       case4(070):
+            opx->offset = gets32(data);
            data += 4;
-       } else if (c >= 0160 && c <= 0167) {
-           ins->rex |= (c & 4) ? REX_D|REX_OC : REX_D;
-           ins->drexdst = c & 3;
-        } else if (c == 0170) {
-            if (*data++)
-                return FALSE;
-       } else if (c == 0171) {
-           data = do_drex(data, ins);
+            opx->segment |= SEG_32BIT | SEG_RELATIVE;
+           break;
+
+       case4(0100):
+       case4(0110):
+       case4(0120):
+       case4(0130):
+       {
+           int modrm = *data++;
+            opx->segment |= SEG_RMREG;
+            data = do_ea(data, modrm, asize, segsize, eat, opy, ins);
            if (!data)
-               return FALSE;
-        } else if (c >= 0200 && c <= 0277) {
+               return false;
+            opx->basereg = ((modrm >> 3) & 7) + (ins->rex & REX_R ? 8 : 0);
+           break;
+       }
+
+       case 0172:
+       {
+           uint8_t ximm = *data++;
+           c = *r++;
+           ins->oprs[c >> 3].basereg = (ximm >> 4) & regmask;
+           ins->oprs[c >> 3].segment |= SEG_RMREG;
+           ins->oprs[c & 7].offset = ximm & 15;
+       }
+       break;
+
+       case 0173:
+       {
+           uint8_t ximm = *data++;
+           c = *r++;
+
+           if ((c ^ ximm) & 15)
+               return false;
+
+           ins->oprs[c >> 4].basereg = (ximm >> 4) & regmask;
+           ins->oprs[c >> 4].segment |= SEG_RMREG;
+       }
+       break;
+
+       case4(0174):
+       {
+           uint8_t ximm = *data++;
+
+           opx->basereg = (ximm >> 4) & regmask;
+           opx->segment |= SEG_RMREG;
+       }
+       break;
+
+       case4(0200):
+       case4(0204):
+       case4(0210):
+       case4(0214):
+       case4(0220):
+       case4(0224):
+       case4(0230):
+       case4(0234):
+       {
             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);
+                return false;   /* spare field doesn't match up */
+            data = do_ea(data, modrm, asize, segsize, eat, opy, ins);
            if (!data)
-               return FALSE;
-        } else if (c == 0310) {
+               return false;
+           break;
+       }
+
+       case4(0260):
+       case 0270:
+       {
+           int vexm   = *r++;
+           int vexwlp = *r++;
+
+           ins->rex |= REX_V;
+           if ((prefix->rex & (REX_V|REX_P)) != REX_V)
+               return false;
+
+           if ((vexm & 0x1f) != prefix->vex_m)
+               return false;
+
+           switch (vexwlp & 060) {
+           case 000:
+               if (prefix->rex & REX_W)
+                   return false;
+               break;
+           case 020:
+               if (!(prefix->rex & REX_W))
+                   return false;
+               ins->rex &= ~REX_W;
+               break;
+           case 040:           /* VEX.W is a don't care */
+               ins->rex &= ~REX_W;
+               break;
+           case 060:
+               break;
+           }
+
+           /* The 010 bit of vexwlp is set if VEX.L is ignored */
+           if ((vexwlp ^ prefix->vex_lp) & ((vexwlp & 010) ? 03 : 07))
+               return false;
+
+           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 0271:
+            if (prefix->rep == 0xF3)
+                drep = P_XRELEASE;
+            break;
+
+        case 0272:
+            if (prefix->rep == 0xF2)
+                drep = P_XACQUIRE;
+            else if (prefix->rep == 0xF3)
+                drep = P_XRELEASE;
+            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)
-                return FALSE;
+                return false;
             else
-                a_used = TRUE;
-        } else if (c == 0311) {
-            if (asize == 16)
-                return FALSE;
+                a_used = true;
+           break;
+
+       case 0311:
+            if (asize != 32)
+                return false;
             else
-                a_used = TRUE;
-        } else if (c == 0312) {
+                a_used = true;
+           break;
+
+       case 0312:
             if (asize != segsize)
-                return FALSE;
+                return false;
             else
-                a_used = TRUE;
-       } else if (c == 0313) {
+                a_used = true;
+           break;
+
+       case 0313:
            if (asize != 64)
-               return FALSE;
+               return false;
            else
-               a_used = TRUE;
-        } else if (c == 0320) {
+               a_used = true;
+           break;
+
+       case 0314:
+           if (prefix->rex & REX_B)
+               return false;
+           break;
+
+       case 0315:
+           if (prefix->rex & REX_X)
+               return false;
+           break;
+
+       case 0316:
+           if (prefix->rex & REX_R)
+               return false;
+           break;
+
+       case 0317:
+           if (prefix->rex & REX_W)
+               return false;
+           break;
+
+       case 0320:
             if (osize != 16)
-                return FALSE;
+                return false;
             else
-                o_used = TRUE;
-        } else if (c == 0321) {
+                o_used = true;
+           break;
+
+       case 0321:
             if (osize != 32)
-                return FALSE;
+                return false;
             else
-                o_used = TRUE;
-        } else if (c == 0322) {
+                o_used = true;
+           break;
+
+       case 0322:
             if (osize != (segsize == 16) ? 16 : 32)
-                return FALSE;
+                return false;
             else
-                o_used = TRUE;
-        } else if (c == 0323) {
+                o_used = true;
+           break;
+
+       case 0323:
            ins->rex |= REX_W;  /* 64-bit only instruction */
            osize = 64;
-       } else if (c == 0324) {
-           if (!(ins->rex & (REX_P|REX_W)) || osize != 64)
-               return FALSE;
-       } else if (c == 0330) {
+           o_used = true;
+           break;
+
+       case 0324:
+           if (osize != 64)
+               return false;
+           o_used = true;
+           break;
+
+       case 0325:
+           ins->rex |= REX_NH;
+           break;
+
+       case 0330:
+       {
             int t = *r++, d = *data++;
             if (d < t || d > t + 15)
-                return FALSE;
+                return false;
             else
                 ins->condition = d - t;
-        } else if (c == 0331) {
+           break;
+       }
+
+        case 0326:
+            if (prefix->rep == 0xF3)
+                return false;
+            break;
+
+       case 0331:
             if (prefix->rep)
-                return FALSE;
-       } else if (c == 0332) {
+                return false;
+           break;
+
+       case 0332:
            if (prefix->rep != 0xF2)
-               return FALSE;
-        } else if (c == 0333) {
+               return false;
+           drep = 0;
+           break;
+
+       case 0333:
             if (prefix->rep != 0xF3)
-                return FALSE;
+                return false;
             drep = 0;
-        } else if (c == 0334) {
+           break;
+
+       case 0334:
            if (lock) {
                ins->rex |= REX_R;
                lock = 0;
            }
-        } else if (c == 0335) {
+           break;
+
+       case 0335:
             if (drep == P_REP)
                 drep = P_REPE;
-       } else if (c == 0364) {
+           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;
+           break;
+
+       case 0361:
+           if (!prefix->osp || prefix->rep)
+               return false;
+           o_used = true;
+           break;
+
+       case 0364:
            if (prefix->osp)
-               return FALSE;
-       } else if (c == 0365) {
+               return false;
+           break;
+
+       case 0365:
            if (prefix->asp)
-               return FALSE;
-       } else if (c == 0366) {
+               return false;
+           break;
+
+       case 0366:
            if (!prefix->osp)
-               return FALSE;
-           o_used = TRUE;
-       } else if (c == 0367) {
+               return false;
+           o_used = true;
+           break;
+
+       case 0367:
            if (!prefix->asp)
-               return FALSE;
-           o_used = TRUE;
+               return false;
+           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 */
        }
     }
 
-    /* REX cannot be combined with DREX */
-    if ((ins->rex & REX_D) && (prefix->rex))
-       return FALSE;
+    if (!vex_ok && (ins->rex & REX_V))
+       return false;
+
+    /* REX cannot be combined with VEX */
+    if ((ins->rex & REX_V) && (prefix->rex & REX_P))
+       return false;
 
     /*
      * Check for unused rep or a/o prefixes.
      */
     for (i = 0; i < t->operands; i++) {
        if (ins->oprs[i].segment != SEG_RMREG)
-           a_used = TRUE;
+           a_used = true;
     }
 
-    ins->nprefix = 0;
-    if (lock)
-       ins->prefixes[ins->nprefix++] = P_LOCK;
-    if (drep)
-        ins->prefixes[ins->nprefix++] = drep;
-    if (!a_used && asize != segsize)
-        ins->prefixes[ins->nprefix++] = asize == 16 ? P_A16 : P_A32;
-    if (!o_used && osize == ((segsize == 16) ? 32 : 16))
-        ins->prefixes[ins->nprefix++] = osize == 16 ? P_O16 : P_O32;
+    if (lock) {
+       if (ins->prefixes[PPS_LOCK])
+           return false;
+       ins->prefixes[PPS_LOCK] = P_LOCK;
+    }
+    if (drep) {
+       if (ins->prefixes[PPS_REP])
+           return false;
+        ins->prefixes[PPS_REP] = drep;
+    }
+    ins->prefixes[PPS_WAIT] = dwait;
+    if (!o_used) {
+       if (osize != ((segsize == 16) ? 16 : 32)) {
+           enum prefixes pfx = 0;
+
+           switch (osize) {
+           case 16:
+               pfx = P_O16;
+               break;
+           case 32:
+               pfx = P_O32;
+               break;
+           case 64:
+               pfx = P_O64;
+               break;
+           }
+
+           if (ins->prefixes[PPS_OSIZE])
+               return false;
+           ins->prefixes[PPS_OSIZE] = pfx;
+       }
+    }
+    if (!a_used && asize != segsize) {
+       if (ins->prefixes[PPS_ASIZE])
+           return false;
+        ins->prefixes[PPS_ASIZE] = asize == 16 ? P_A16 : P_A32;
+    }
 
     /* Fix: check for redundant REX prefixes */
 
     return data - origdata;
 }
 
+/* Condition names for disassembly, sorted by x86 code */
+static const char * const condition_name[16] = {
+    "o", "no", "c", "nc", "z", "nz", "na", "a",
+    "s", "ns", "pe", "po", "l", "nl", "ng", "g"
+};
+
 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;
@@ -682,9 +955,10 @@ 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;
 
     memset(&ins, 0, sizeof ins);
 
@@ -696,36 +970,129 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
     prefix.osize = (segsize == 64) ? 32 : segsize;
     segover = NULL;
     origdata = data;
-    for (;;) {
-        if (*data == 0xF3 || *data == 0xF2)
+
+    ix = itable;
+
+    end_prefix = false;
+    while (!end_prefix) {
+       switch (*data) {
+       case 0xF2:
+       case 0xF3:
             prefix.rep = *data++;
-        else if (*data == 0xF0)
+           break;
+
+       case 0x9B:
+           prefix.wait = *data++;
+           break;
+
+       case 0xF0:
             prefix.lock = *data++;
-        else if (*data == 0x2E)
+           break;
+
+       case 0x2E:
            segover = "cs", prefix.seg = *data++;
-       else if (*data == 0x36)
+           break;
+       case 0x36:
            segover = "ss", prefix.seg = *data++;
-       else if (*data == 0x3E)
+           break;
+       case 0x3E:
            segover = "ds", prefix.seg = *data++;
-       else if (*data == 0x26)
+           break;
+       case 0x26:
            segover = "es", prefix.seg = *data++;
-       else if (*data == 0x64)
+           break;
+       case 0x64:
            segover = "fs", prefix.seg = *data++;
-       else if (*data == 0x65)
+           break;
+       case 0x65:
            segover = "gs", prefix.seg = *data++;
-       else if (*data == 0x66) {
+           break;
+
+       case 0x66:
            prefix.osize = (segsize == 16) ? 32 : 16;
            prefix.osp = *data++;
-       } else if (*data == 0x67) {
+           break;
+       case 0x67:
            prefix.asize = (segsize == 32) ? 16 : 32;
            prefix.asp = *data++;
-       } else if (segsize == 64 && (*data & 0xf0) == REX_P) {
-           prefix.rex = *data++;
-           if (prefix.rex & REX_W)
-               prefix.osize = 64;
-           break;              /* REX is always the last prefix */
-       } else {
-            break;
+           break;
+
+       case 0xC4:
+       case 0xC5:
+           if (segsize == 64 || (data[1] & 0xc0) == 0xc0) {
+               prefix.vex[0] = *data++;
+               prefix.vex[1] = *data++;
+
+               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];
+           }
+           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;
+
+               ix = itable_vex[RV_XOP][prefix.vex_m][prefix.vex_lp & 3];
+           }
+           end_prefix = true;
+           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) {
+               prefix.rex = *data++;
+               if (prefix.rex & REX_W)
+                   prefix.osize = 64;
+           }
+           end_prefix = true;
+           break;
+
+       default:
+           end_prefix = true;
+           break;
        }
     }
 
@@ -733,37 +1100,42 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
     best_p = NULL;
     best_pref = INT_MAX;
 
+    if (!ix)
+       return 0;               /* No instruction table at all... */
+
     dp = data;
-    ix = itable + *dp++;
-    while (ix->n == (size_t)-1) {
+    ix += *dp++;
+    while (ix->n == -1) {
        ix = (const struct disasm_index *)ix->p + *dp++;
     }
 
     p = (const struct itemplate * const *)ix->p;
     for (n = ix->n; n; n--, p++) {
         if ((length = matches(*p, data, &prefix, segsize, &tmp_ins))) {
-            works = TRUE;
+            works = true;
             /*
              * Final check to make sure the types of r/m match up.
             * XXX: Need to make sure this is actually correct.
              */
             for (i = 0; i < (*p)->operands; i++) {
-                if (!((*p)->opd[i] & SAME_AS) &&
-                   (
-                       /* If it's a mem-only EA but we have a register, die. */
+                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])) ||
-                       /* If it's a reg-only EA but we have a memory ref, die. */
+                        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) &&
                         !(REG_EA & ~(*p)->opd[i]) &&
                         !((*p)->opd[i] & REG_SMASK)) ||
-                       /* Register type mismatch (eg FS vs REG_DESS): die. */
+                       /* Register type mismatch (eg FS vs REG_DESS):
+                          die. */
                        ((((*p)->opd[i] & (REGISTER | FPUREG)) ||
                          (tmp_ins.oprs[i].segment & SEG_RMREG)) &&
                         !whichreg((*p)->opd[i],
                                   tmp_ins.oprs[i].basereg, tmp_ins.rex))
-                       )) {
-                    works = FALSE;
+                       ) {
+                    works = false;
                     break;
                 }
             }
@@ -777,13 +1149,18 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             * selection.
             */
             if (works) {
+               int i, nprefix;
                 goodness = ((*p)->flags & IF_PFMASK) ^ prefer;
-                if (tmp_ins.nprefix < best_pref ||
-                   (tmp_ins.nprefix == best_pref && goodness < best)) {
+               nprefix = 0;
+               for (i = 0; i < MAXPREFIX; i++)
+                   if (tmp_ins.prefixes[i])
+                       nprefix++;
+                if (nprefix < best_pref ||
+                   (nprefix == best_pref && goodness < best)) {
                     /* This is the best one found so far */
                     best = goodness;
                     best_p = p;
-                   best_pref = tmp_ins.nprefix;
+                   best_pref = nprefix;
                     best_length = length;
                     ins = tmp_ins;
                 }
@@ -801,65 +1178,33 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
     slen = 0;
 
     /* TODO: snprintf returns the value that the string would have if
-     *      the buffer were long enough, and not the actual length of 
+     *      the buffer were long enough, and not the actual length of
      *      the returned string, so each instance of using the return
      *      value of snprintf should actually be checked to assure that
      *      the return value is "sane."  Maybe a macro wrapper could
      *      be used for that purpose.
      */
-    for (i = 0; i < ins.nprefix; 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_O16:
-            slen += snprintf(output + slen, outbufsize - slen, "o16 ");
-            break;
-        case P_O32:
-            slen += snprintf(output + slen, outbufsize - slen, "o32 ");
-            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);
+    }
 
-    for (i = 0; i < (int)elements(ico); i++)
-        if ((*p)->opcode == ico[i]) {
-            slen +=
-                snprintf(output + slen, outbufsize - slen, "%s%s", icn[i],
-                         whichcond(ins.condition));
-            break;
-        }
-    if (i >= (int)elements(ico))
-        slen +=
-            snprintf(output + slen, outbufsize - slen, "%s",
-                     insn_names[(*p)->opcode]);
-    colon = FALSE;
+    i = (*p)->opcode;
+    if (i >= FIRST_COND_OPCODE)
+       slen += snprintf(output + slen, outbufsize - slen, "%s%s",
+                        nasm_insn_names[i], condition_name[ins.condition]);
+    else
+        slen += snprintf(output + slen, outbufsize - slen, "%s",
+                        nasm_insn_names[i]);
+
+    colon = false;
     length += data - origdata;  /* fix up for prefixes */
     for (i = 0; i < (*p)->operands; i++) {
        opflags_t t = (*p)->opd[i];
        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;
@@ -870,6 +1215,9 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
              */
             if (!(o->segment & (SEG_32BIT|SEG_64BIT)))
                offs &= 0xffff;
+           else if (segsize != 64)
+               offs &= 0xffffffff;
+
             /*
              * add sync marker, if autosync is on
              */
@@ -878,9 +1226,9 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
         }
 
         if (t & COLON)
-            colon = TRUE;
+            colon = true;
         else
-            colon = FALSE;
+            colon = false;
 
         if ((t & (REGISTER | FPUREG)) ||
             (o->segment & SEG_RMREG)) {
@@ -889,7 +1237,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             if (t & TO)
                 slen += snprintf(output + slen, outbufsize - slen, "to ");
             slen += snprintf(output + slen, outbufsize - slen, "%s",
-                             reg_names[reg - EXPR_REG_START]);
+                             nasm_reg_names[reg-EXPR_REG_START]);
         } else if (!(UNITY & ~t)) {
             output[slen++] = '1';
         } else if (t & IMMEDIATE) {
@@ -924,15 +1272,16 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
                          offs);
         } else if (!(MEM_OFFS & ~t)) {
             slen +=
-                snprintf(output + slen, outbufsize - slen, "[%s%s%s0x%"PRIx64"]",
+                snprintf(output + slen, outbufsize - slen,
+                        "[%s%s%s0x%"PRIx64"]",
                          (segover ? segover : ""),
                          (segover ? ":" : ""),
-                         (o->addr_size ==
-                          32 ? "dword " : o->addr_size ==
-                          16 ? "word " : ""), offs);
+                        (o->disp_size == 64 ? "qword " :
+                         o->disp_size == 32 ? "dword " :
+                         o->disp_size == 16 ? "word " : ""), offs);
             segover = NULL;
-        } else if (!(REGMEM & ~t)) {
-            int started = FALSE;
+        } else if (is_class(REGMEM, t)) {
+            int started = false;
             if (t & BITS8)
                 slen +=
                     snprintf(output + slen, outbufsize - slen, "byte ");
@@ -948,17 +1297,26 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             if (t & BITS80)
                 slen +=
                     snprintf(output + slen, outbufsize - slen, "tword ");
+            if (t & BITS128)
+                slen +=
+                    snprintf(output + slen, outbufsize - slen, "oword ");
+            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)
                 slen +=
                     snprintf(output + slen, outbufsize - slen, "near ");
             output[slen++] = '[';
-            if (o->addr_size)
+            if (o->disp_size)
                 slen += snprintf(output + slen, outbufsize - slen, "%s",
-                                 (o->addr_size == 64 ? "qword " :
-                                 o->addr_size == 32 ? "dword " :
-                                  o->addr_size == 16 ? "word " :
+                                 (o->disp_size == 64 ? "qword " :
+                                 o->disp_size == 32 ? "dword " :
+                                  o->disp_size == 16 ? "word " :
                                  ""));
            if (o->eaflags & EAF_REL)
                slen += snprintf(output + slen, outbufsize - slen, "rel ");
@@ -970,46 +1328,63 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
             }
             if (o->basereg != -1) {
                 slen += snprintf(output + slen, outbufsize - slen, "%s",
-                                 reg_names[(o->basereg -
-                                            EXPR_REG_START)]);
-                started = TRUE;
+                                 nasm_reg_names[(o->basereg-EXPR_REG_START)]);
+                started = true;
             }
             if (o->indexreg != -1) {
                 if (started)
                     output[slen++] = '+';
                 slen += snprintf(output + slen, outbufsize - slen, "%s",
-                                 reg_names[(o->indexreg -
-                                            EXPR_REG_START)]);
+                                 nasm_reg_names[(o->indexreg-EXPR_REG_START)]);
                 if (o->scale > 1)
                     slen +=
                         snprintf(output + slen, outbufsize - slen, "*%d",
                                  o->scale);
-                started = TRUE;
+                started = true;
             }
+
+
             if (o->segment & SEG_DISP8) {
-               int minus = 0;
-               int8_t offset = offs;
-               if (offset < 0) {
-                   minus = 1;
+               const char *prefix;
+               uint8_t offset = offs;
+               if ((int8_t)offset < 0) {
+                   prefix = "-";
                    offset = -offset;
+               } else {
+                   prefix = "+";
                }
                 slen +=
                     snprintf(output + slen, outbufsize - slen, "%s0x%"PRIx8"",
-                            minus ? "-" : "+", offset);
+                            prefix, offset);
             } else if (o->segment & SEG_DISP16) {
-               int minus = 0;
-               int16_t offset = offs;
-               if (offset < 0) {
-                   minus = 1;
+               const char *prefix;
+               uint16_t offset = offs;
+               if ((int16_t)offset < 0 && started) {
                    offset = -offset;
+                   prefix = "-";
+               } else {
+                   prefix = started ? "+" : "";
                }
                 slen +=
-                    snprintf(output + slen, outbufsize - slen, "%s0x%"PRIx16"",
-                            minus ? "-" : started ? "+" : "", offset);
+                    snprintf(output + slen, outbufsize - slen,
+                            "%s0x%"PRIx16"", prefix, offset);
             } else if (o->segment & SEG_DISP32) {
-                   char *prefix = "";
-                   int32_t offset = offs;
-                   if (offset < 0) {
+               if (prefix.asize == 64) {
+                   const char *prefix;
+                   uint64_t offset = (int64_t)(int32_t)offs;
+                   if ((int32_t)offs < 0 && started) {
+                       offset = -offset;
+                       prefix = "-";
+                   } else {
+                       prefix = started ? "+" : "";
+                   }
+                   slen +=
+                       snprintf(output + slen, outbufsize - slen,
+                                "%s0x%"PRIx64"", prefix, offset);
+               } else {
+                   const char *prefix;
+                   uint32_t offset = offs;
+                   if ((int32_t) offset < 0 && started) {
                        offset = -offset;
                        prefix = "-";
                    } else {
@@ -1018,6 +1393,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
                    slen +=
                        snprintf(output + slen, outbufsize - slen,
                                 "%s0x%"PRIx32"", prefix, offset);
+               }
             }
             output[slen++] = ']';
         } else {
@@ -1038,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;
 }