Un-special-case "xchg rax,rax"; disassemble o64
authorH. Peter Anvin <hpa@zytor.com>
Tue, 13 Nov 2007 06:55:27 +0000 (22:55 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 13 Nov 2007 06:56:07 +0000 (22:56 -0800)
Un-special-case "xchg rax,rax"; allow it to be encoded as 48 90 for
orthogonality's sake.  It's a no-op, to be sure, but so are many other
instructions.

"xchg eax,eax" is still special-cased in 64-bit mode since it is not a
no-op; unadorned opcode 90 is now simply "nop" and nothing else.

Make the disassembler detect unused REX.W and display them as an "o64"
prefix.

disasm.c
insns.dat
test/nop.asm [new file with mode: 0644]

index b86c7f7..3554ca8 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -382,6 +382,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
     }
     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;
@@ -712,11 +713,13 @@ static int matches(const struct itemplate *t, uint8_t *data,
        case 0323:
            ins->rex |= REX_W;  /* 64-bit only instruction */
            osize = 64;
+           o_used = true;
            break;
 
        case 0324:
            if (!(ins->rex & (REX_P|REX_W)) || osize != 64)
                return false;
+           o_used = true;
            break;
 
        case 0330:
@@ -779,7 +782,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
        case 0367:
            if (!prefix->asp)
                return false;
-           o_used = true;
+           a_used = true;
            break;
 
        default:
@@ -809,10 +812,26 @@ static int matches(const struct itemplate *t, uint8_t *data,
            return false;
         ins->prefixes[PPS_LREP] = drep;
     }
-    if (!o_used && osize == ((segsize == 16) ? 32 : 16)) {
-       if (ins->prefixes[PPS_OSIZE])
-           return false;
-        ins->prefixes[PPS_OSIZE] = osize == 16 ? P_O16 : P_O32;
+    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])
@@ -1006,12 +1025,18 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
         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;
         }
index f54d6cc..fa04d12 100644 (file)
--- a/insns.dat
+++ b/insns.dat
@@ -848,7 +848,7 @@ PADDUSW             mmxreg,mmxrm            \2\x0F\xDD\110                  PENT,MMX,SM
 PADDW          mmxreg,mmxrm            \2\x0F\xFD\110                  PENT,MMX,SM
 PAND           mmxreg,mmxrm            \2\x0F\xDB\110                  PENT,MMX,SM
 PANDN          mmxreg,mmxrm            \2\x0F\xDF\110                  PENT,MMX,SM
-PAUSE          void                    \333\1\x90                      8086
+PAUSE          void                    \314\333\1\x90                  8086
 PAVEB          mmxreg,mmxrm            \2\x0F\x50\110                  PENT,MMX,SM,CYRIX
 PAVGUSB                mmxreg,mmxrm            \2\x0F\x0F\110\01\xBF           PENT,3DNOW,SM
 PCMPEQB                mmxreg,mmxrm            \2\x0F\x74\110                  PENT,MMX,SM
@@ -1271,12 +1271,13 @@ XBTS            reg32,mem               \321\2\x0F\xA6\110              386,SD,UNDOC,ND
 XBTS           reg32,reg32             \321\2\x0F\xA6\110              386,UNDOC,ND
 XCHG           reg_ax,reg16            \320\11\x90                     8086
 XCHG           reg_eax,reg32na         \321\11\x90                     386
-XCHG           reg_rax,reg64na         \324\11\x90                     X64
+XCHG           reg_rax,reg64           \324\11\x90                     X64
 XCHG           reg16,reg_ax            \320\10\x90                     8086
 XCHG           reg32na,reg_eax         \321\10\x90                     386
-XCHG           reg64na,reg_rax         \324\10\x90                     X64
+XCHG           reg64,reg_rax           \324\10\x90                     X64
+; This must be NOLONG since opcode 90 is NOP, and in 64-bit mode
+; "xchg eax,eax" is *not* a NOP.
 XCHG           reg_eax,reg_eax         \321\1\x90                      386,NOLONG
-XCHG           reg_rax,reg_rax         \323\1\x90                      X64
 XCHG           reg8,mem                \1\x86\110                      8086,SM
 XCHG           reg8,reg8               \1\x86\110                      8086
 XCHG           reg16,mem               \320\1\x87\110                  8086,SM
diff --git a/test/nop.asm b/test/nop.asm
new file mode 100644 (file)
index 0000000..3dabaa0
--- /dev/null
@@ -0,0 +1,14 @@
+       bits 64
+
+       nop
+       o64 nop
+       pause
+       o64 pause
+
+       xchg ax,ax
+       xchg eax,eax
+       xchg rax,rax
+       
+       rep xchg ax,ax
+       rep xchg eax,eax
+       rep xchg rax,rax