/* Flags for the prefixes for the current instruction. See below. */
static int prefixes;
+/* Flags for prefixes which we somehow handled when printing the
+ current instruction. */
+static int used_prefixes;
+
/* Flags stored in PREFIXES. */
#define PREFIX_REPZ 1
#define PREFIX_REPNZ 2
info);
if (status != 0)
{
- /* If we have found an fwait prefix and an fwait opcode, then
- print_insn_i386 will arrange to print an instruction after we
- longjmp, and we don't want to print an error message here.
- This hack is required because we treat fwait as a prefix, but
- since fwait is really an instruction we want to print a
- standalone fwait correctly. */
- if ((prefixes & PREFIX_FWAIT) == 0
- || memchr (priv->the_buffer, FWAIT_OPCODE,
- priv->max_fetched - priv->the_buffer) == NULL)
+ /* If we did manage to read at least one byte, then
+ print_insn_i386 will do something sensible. Otherwise, print
+ an error. We do that here because this is where we know
+ STATUS. */
+ if (priv->max_fetched == priv->the_buffer)
(*info->memory_error_func) (status, start, info);
longjmp (priv->bailout, 1);
}
static int get16 PARAMS ((void));
static int get32 PARAMS ((void));
static void ckprefix PARAMS ((void));
+static const char *prefix_name PARAMS ((int, int));
static void ptr_reg PARAMS ((int, int));
static void BadOp PARAMS ((void));
ckprefix ()
{
prefixes = 0;
+ used_prefixes = 0;
while (1)
{
FETCH_DATA (the_info, codep + 1);
}
}
+/* Return the name of the prefix byte PREF, or NULL if PREF is not a
+ prefix byte. */
+
+static const char *
+prefix_name (pref, sizeflag)
+ int pref;
+ int sizeflag;
+{
+ switch (pref)
+ {
+ case 0xf3:
+ return "repz";
+ case 0xf2:
+ return "repnz";
+ case 0xf0:
+ return "lock";
+ case 0x2e:
+ return "cs";
+ case 0x36:
+ return "ss";
+ case 0x3e:
+ return "ds";
+ case 0x26:
+ return "es";
+ case 0x64:
+ return "fs";
+ case 0x65:
+ return "gs";
+ case 0x66:
+ return (sizeflag & DFLAG) ? "data16" : "data32";
+ case 0x67:
+ return (sizeflag & AFLAG) ? "addr16" : "addr32";
+ case FWAIT_OPCODE:
+ return "fwait";
+ default:
+ return NULL;
+ }
+}
+
static char op1out[100], op2out[100], op3out[100];
static int op_ad, op_index[3];
static unsigned int op_address[3];
int needcomma;
unsigned char need_modrm;
unsigned char uses_f3_prefix;
- int sizeflag;
+ int sizeflag, orig_sizeflag;
struct dis_private priv;
bfd_byte *inbuf = priv.the_buffer;
sizeflag = 0;
else
abort ();
+ orig_sizeflag = sizeflag;
/* The output looks better if we put 6 bytes on a line, since that
puts most long word instructions on a single line. */
if (setjmp (priv.bailout) != 0)
{
+ const char *name;
+
/* Getting here means we tried for data but didn't get it. That
- means we have an incomplete instruction of some sort.
- However, we need to check at least one case here: fwait is a
- complete instruction, although we treat it as a prefix. */
- if (prefixes & PREFIX_FWAIT)
+ means we have an incomplete instruction of some sort. Just
+ print the first byte as a prefix or a .byte pseudo-op. */
+ if (codep > inbuf)
{
- unsigned char *p;
-
- p = memchr (inbuf, FWAIT_OPCODE, codep - inbuf);
- if (p != NULL)
+ name = prefix_name (inbuf[0], orig_sizeflag);
+ if (name != NULL)
+ (*info->fprintf_func) (info->stream, "%s", name);
+ else
{
- (*info->fprintf_func) (info->stream, "fwait");
- return (p + 1) - inbuf;
+ /* Just print the first byte as a .byte instruction. */
+ (*info->fprintf_func) (info->stream, ".byte 0x%x",
+ (unsigned int) inbuf[0]);
}
- }
- if (codep > inbuf)
- {
- /* This will at least let objdump print the bytes followed
- by the error message generated by fetch_data. */
- return codep - inbuf;
+ return 1;
}
return -1;
if ((prefixes & PREFIX_FWAIT)
&& ((*codep < 0xd8) || (*codep > 0xdf)))
{
- /* fwait not followed by floating point instruction. */
- (*info->fprintf_func) (info->stream, "fwait");
- /* There may be other prefixes. Skip any before the fwait. */
- return codep - inbuf;
+ const char *name;
+
+ /* fwait not followed by floating point instruction. Print the
+ first prefix, which is probably fwait itself. */
+ name = prefix_name (inbuf[0], orig_sizeflag);
+ if (name == NULL)
+ name = INTERNAL_DISASSEMBLER_ERROR;
+ (*info->fprintf_func) (info->stream, "%s", name);
+ return 1;
}
if (*codep == 0x0f)
codep++;
if (!uses_f3_prefix && (prefixes & PREFIX_REPZ))
- oappend ("repz ");
+ {
+ oappend ("repz ");
+ used_prefixes |= PREFIX_REPZ;
+ }
if (prefixes & PREFIX_REPNZ)
- oappend ("repnz ");
+ {
+ oappend ("repnz ");
+ used_prefixes |= PREFIX_REPNZ;
+ }
if (prefixes & PREFIX_LOCK)
- oappend ("lock ");
+ {
+ oappend ("lock ");
+ used_prefixes |= PREFIX_LOCK;
+ }
if (prefixes & PREFIX_DATA)
sizeflag ^= DFLAG;
oappend ("addr32 ");
else
oappend ("addr16 ");
+ used_prefixes |= PREFIX_ADDR;
}
if (need_modrm)
break;
case USE_PREFIX_USER_TABLE:
dp = &prefix_user_table[dp->bytemode1][prefixes & PREFIX_REPZ ? 1 : 0];
+ used_prefixes |= (prefixes & PREFIX_REPZ);
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
(*dp->op3)(dp->bytemode3, sizeflag);
}
+ /* See if any prefixes were not used. If so, print the first one
+ separately. If we don't do this, we'll wind up printing an
+ instruction stream which does not precisely correspond to the
+ bytes we are disassembling. */
+ if ((prefixes & ~used_prefixes) != 0)
+ {
+ const char *name;
+
+ name = prefix_name (inbuf[0], orig_sizeflag);
+ if (name == NULL)
+ name = INTERNAL_DISASSEMBLER_ERROR;
+ (*info->fprintf_func) (info->stream, "%s", name);
+ return 1;
+ }
+
obufp = obuf + strlen (obuf);
for (i = strlen (obuf); i < 6; i++)
oappend (" ");
case 'N':
if ((prefixes & PREFIX_FWAIT) == 0)
*obufp++ = 'n';
+ else
+ used_prefixes |= PREFIX_FWAIT;
break;
case 'P':
if (intel_syntax)
*obufp++ = 'l';
else
*obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
break;
case 'Q':
*obufp++ = 'l';
else
*obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
break;
case 'R':
else
*obufp++ = 'w';
}
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
case 'S':
if (intel_syntax)
*obufp++ = 'l';
else
*obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
#endif
break;
*obufp++ = 'w';
}
}
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
}
}
append_seg ()
{
if (prefixes & PREFIX_CS)
- oappend ("%cs:");
+ {
+ oappend ("%cs:");
+ used_prefixes |= PREFIX_CS;
+ }
if (prefixes & PREFIX_DS)
- oappend ("%ds:");
+ {
+ oappend ("%ds:");
+ used_prefixes |= PREFIX_DS;
+ }
if (prefixes & PREFIX_SS)
- oappend ("%ss:");
+ {
+ oappend ("%ss:");
+ used_prefixes |= PREFIX_SS;
+ }
if (prefixes & PREFIX_ES)
- oappend ("%es:");
+ {
+ oappend ("%es:");
+ used_prefixes |= PREFIX_ES;
+ }
if (prefixes & PREFIX_FS)
- oappend ("%fs:");
+ {
+ oappend ("%fs:");
+ used_prefixes |= PREFIX_FS;
+ }
if (prefixes & PREFIX_GS)
- oappend ("%gs:");
+ {
+ oappend ("%gs:");
+ used_prefixes |= PREFIX_GS;
+ }
}
static void
oappend (names32[rm]);
else
oappend (names16[rm]);
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
case 0:
if ( !(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */))
oappend (names32[reg]);
else
oappend (names16[reg]);
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
s = names32[code - eAX_reg];
else
s = names16[code - eAX_reg];
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
default:
s = INTERNAL_DISASSEMBLER_ERROR;
op = get32 ();
else
op = get16 ();
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
case w_mode:
op = get16 ();
if ((op & 0x8000) != 0)
op -= 0x10000;
}
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
case w_mode:
op = get16 ();
displacement is added! */
mask = 0xffff;
}
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
offset = get16 ();
seg = get16 ();
}
+ used_prefixes |= (prefixes & PREFIX_DATA);
sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset);
oappend (scratchbuf);
}
sprintf (scratchbuf, "cmp%s%cs",
simd_cmp_op[cmp_type],
prefixes & PREFIX_REPZ ? 's' : 'p');
+ used_prefixes |= (prefixes & PREFIX_REPZ);
oappend (scratchbuf);
}
else