Un-special-case "xchg rax,rax"; disassemble o64

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.
This commit is contained in:
H. Peter Anvin 2007-11-12 22:55:27 -08:00
parent fb0c90cdbe
commit bb72f7f111
3 changed files with 49 additions and 9 deletions

View file

@ -382,6 +382,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
} }
ins->condition = -1; ins->condition = -1;
ins->rex = prefix->rex; ins->rex = prefix->rex;
memset(ins->prefixes, 0, sizeof ins->prefixes);
if (t->flags & (segsize == 64 ? IF_NOLONG : IF_LONG)) if (t->flags & (segsize == 64 ? IF_NOLONG : IF_LONG))
return false; return false;
@ -712,11 +713,13 @@ static int matches(const struct itemplate *t, uint8_t *data,
case 0323: case 0323:
ins->rex |= REX_W; /* 64-bit only instruction */ ins->rex |= REX_W; /* 64-bit only instruction */
osize = 64; osize = 64;
o_used = true;
break; break;
case 0324: case 0324:
if (!(ins->rex & (REX_P|REX_W)) || osize != 64) if (!(ins->rex & (REX_P|REX_W)) || osize != 64)
return false; return false;
o_used = true;
break; break;
case 0330: case 0330:
@ -779,7 +782,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
case 0367: case 0367:
if (!prefix->asp) if (!prefix->asp)
return false; return false;
o_used = true; a_used = true;
break; break;
default: default:
@ -809,10 +812,26 @@ static int matches(const struct itemplate *t, uint8_t *data,
return false; return false;
ins->prefixes[PPS_LREP] = drep; ins->prefixes[PPS_LREP] = drep;
} }
if (!o_used && osize == ((segsize == 16) ? 32 : 16)) { 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]) if (ins->prefixes[PPS_OSIZE])
return false; return false;
ins->prefixes[PPS_OSIZE] = osize == 16 ? P_O16 : P_O32; ins->prefixes[PPS_OSIZE] = pfx;
}
} }
if (!a_used && asize != segsize) { if (!a_used && asize != segsize) {
if (ins->prefixes[PPS_ASIZE]) if (ins->prefixes[PPS_ASIZE])
@ -1006,12 +1025,18 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
case P_A32: case P_A32:
slen += snprintf(output + slen, outbufsize - slen, "a32 "); slen += snprintf(output + slen, outbufsize - slen, "a32 ");
break; break;
case P_A64:
slen += snprintf(output + slen, outbufsize - slen, "a64 ");
break;
case P_O16: case P_O16:
slen += snprintf(output + slen, outbufsize - slen, "o16 "); slen += snprintf(output + slen, outbufsize - slen, "o16 ");
break; break;
case P_O32: case P_O32:
slen += snprintf(output + slen, outbufsize - slen, "o32 "); slen += snprintf(output + slen, outbufsize - slen, "o32 ");
break; break;
case P_O64:
slen += snprintf(output + slen, outbufsize - slen, "o64 ");
break;
default: default:
break; break;
} }

View file

@ -848,7 +848,7 @@ PADDUSW mmxreg,mmxrm \2\x0F\xDD\110 PENT,MMX,SM
PADDW mmxreg,mmxrm \2\x0F\xFD\110 PENT,MMX,SM PADDW mmxreg,mmxrm \2\x0F\xFD\110 PENT,MMX,SM
PAND mmxreg,mmxrm \2\x0F\xDB\110 PENT,MMX,SM PAND mmxreg,mmxrm \2\x0F\xDB\110 PENT,MMX,SM
PANDN mmxreg,mmxrm \2\x0F\xDF\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 PAVEB mmxreg,mmxrm \2\x0F\x50\110 PENT,MMX,SM,CYRIX
PAVGUSB mmxreg,mmxrm \2\x0F\x0F\110\01\xBF PENT,3DNOW,SM PAVGUSB mmxreg,mmxrm \2\x0F\x0F\110\01\xBF PENT,3DNOW,SM
PCMPEQB mmxreg,mmxrm \2\x0F\x74\110 PENT,MMX,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 XBTS reg32,reg32 \321\2\x0F\xA6\110 386,UNDOC,ND
XCHG reg_ax,reg16 \320\11\x90 8086 XCHG reg_ax,reg16 \320\11\x90 8086
XCHG reg_eax,reg32na \321\11\x90 386 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 reg16,reg_ax \320\10\x90 8086
XCHG reg32na,reg_eax \321\10\x90 386 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_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,mem \1\x86\110 8086,SM
XCHG reg8,reg8 \1\x86\110 8086 XCHG reg8,reg8 \1\x86\110 8086
XCHG reg16,mem \320\1\x87\110 8086,SM XCHG reg16,mem \320\1\x87\110 8086,SM

14
test/nop.asm Normal file
View file

@ -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