#include <setjmp.h>
-static int fetch_data (struct disassemble_info *, bfd_byte *);
-static void ckprefix (void);
-static const char *prefix_name (int, int);
static int print_insn (bfd_vma, disassemble_info *);
static void dofloat (int);
static void OP_ST (int, int);
static unsigned char *start_codep;
static unsigned char *insn_codep;
static unsigned char *codep;
-static const char *lock_prefix;
-static const char *data_prefix;
-static const char *addr_prefix;
-static const char *repz_prefix;
-static const char *repnz_prefix;
-static const char **all_prefixes[5];
+static int last_lock_prefix;
+static int last_repz_prefix;
+static int last_repnz_prefix;
+static int last_data_prefix;
+static int last_addr_prefix;
+static int last_rex_prefix;
+static int last_seg_prefix;
+#define MAX_CODE_LENGTH 15
+/* We can up to 14 prefixes since the maximum instruction length is
+ 15bytes. */
+static int all_prefixes[MAX_CODE_LENGTH - 1];
static disassemble_info *the_info;
static struct
{
#define INTERNAL_DISASSEMBLER_ERROR _("<internal disassembler error>")
-static void
+/* We use the high bit to indicate different name for the same
+ prefix. */
+#define ADDR16_PREFIX (0x67 | 0x100)
+#define ADDR32_PREFIX (0x67 | 0x200)
+#define DATA16_PREFIX (0x66 | 0x100)
+#define DATA32_PREFIX (0x66 | 0x200)
+#define REP_PREFIX (0xf3 | 0x100)
+
+static int
ckprefix (void)
{
- int newrex, i;
+ int newrex, i, length;
rex = 0;
rex_original = 0;
rex_ignored = 0;
prefixes = 0;
used_prefixes = 0;
rex_used = 0;
+ last_lock_prefix = -1;
+ last_repz_prefix = -1;
+ last_repnz_prefix = -1;
+ last_data_prefix = -1;
+ last_addr_prefix = -1;
+ last_rex_prefix = -1;
+ last_seg_prefix = -1;
for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++)
all_prefixes[i] = 0;
i = 0;
- while (1)
+ length = 0;
+ /* The maximum instruction length is 15bytes. */
+ while (length < MAX_CODE_LENGTH - 1)
{
FETCH_DATA (the_info, codep + 1);
newrex = 0;
case 0x4d:
case 0x4e:
case 0x4f:
- if (address_mode == mode_64bit)
- newrex = *codep;
- else
- return;
+ if (address_mode == mode_64bit)
+ newrex = *codep;
+ else
+ return 1;
+ last_rex_prefix = i;
break;
case 0xf3:
- if ((prefixes & PREFIX_REPZ) == 0)
- {
- all_prefixes[i] = &repz_prefix;
- i++;
- }
prefixes |= PREFIX_REPZ;
+ last_repz_prefix = i;
break;
case 0xf2:
- if ((prefixes & PREFIX_REPNZ) == 0)
- {
- all_prefixes[i] = &repnz_prefix;
- i++;
- }
prefixes |= PREFIX_REPNZ;
+ last_repnz_prefix = i;
break;
case 0xf0:
- if ((prefixes & PREFIX_LOCK) == 0)
- {
- all_prefixes[i] = &lock_prefix;
- i++;
- }
prefixes |= PREFIX_LOCK;
+ last_lock_prefix = i;
break;
case 0x2e:
prefixes |= PREFIX_CS;
+ last_seg_prefix = i;
break;
case 0x36:
prefixes |= PREFIX_SS;
+ last_seg_prefix = i;
break;
case 0x3e:
prefixes |= PREFIX_DS;
+ last_seg_prefix = i;
break;
case 0x26:
prefixes |= PREFIX_ES;
+ last_seg_prefix = i;
break;
case 0x64:
prefixes |= PREFIX_FS;
+ last_seg_prefix = i;
break;
case 0x65:
prefixes |= PREFIX_GS;
+ last_seg_prefix = i;
break;
case 0x66:
- if ((prefixes & PREFIX_DATA) == 0)
- {
- all_prefixes[i] = &data_prefix;
- i++;
- }
prefixes |= PREFIX_DATA;
+ last_data_prefix = i;
break;
case 0x67:
- if ((prefixes & PREFIX_ADDR) == 0)
- {
- all_prefixes[i] = &addr_prefix;
- i++;
- }
prefixes |= PREFIX_ADDR;
+ last_addr_prefix = i;
break;
case FWAIT_OPCODE:
/* fwait is really an instruction. If there are prefixes
{
prefixes |= PREFIX_FWAIT;
codep++;
- return;
+ return 1;
}
prefixes = PREFIX_FWAIT;
break;
default:
- return;
+ return 1;
}
/* Rex is ignored when followed by another prefix. */
if (rex)
{
rex_used = rex;
- return;
+ return 1;
}
+ if (*codep != FWAIT_OPCODE)
+ all_prefixes[i++] = *codep;
rex = newrex;
rex_original = rex;
codep++;
+ length++;
+ }
+ return 0;
+}
+
+static int
+seg_prefix (int pref)
+{
+ switch (pref)
+ {
+ case 0x2e:
+ return PREFIX_CS;
+ case 0x36:
+ return PREFIX_SS;
+ case 0x3e:
+ return PREFIX_DS;
+ case 0x26:
+ return PREFIX_ES;
+ case 0x64:
+ return PREFIX_FS;
+ case 0x65:
+ return PREFIX_GS;
+ default:
+ return 0;
}
}
return (sizeflag & AFLAG) ? "addr16" : "addr32";
case FWAIT_OPCODE:
return "fwait";
+ case ADDR16_PREFIX:
+ return "addr16";
+ case ADDR32_PREFIX:
+ return "addr32";
+ case DATA16_PREFIX:
+ return "data16";
+ case DATA32_PREFIX:
+ return "data32";
+ case REP_PREFIX:
+ return "rep";
default:
return NULL;
}
if (prefixes & PREFIX_REPZ)
{
index = 1;
- repz_prefix = NULL;
+ all_prefixes[last_repz_prefix] = 0;
}
else
{
if (prefixes & PREFIX_REPNZ)
{
index = 3;
- repnz_prefix = NULL;
+ all_prefixes[last_repnz_prefix] = 0;
}
else
{
if (prefixes & PREFIX_DATA)
{
index = 2;
- data_prefix = NULL;
+ all_prefixes[last_data_prefix] = 0;
}
}
}
const char *p;
struct dis_private priv;
unsigned char op;
- char prefix_obuf[32];
- char *prefix_obufp;
+ int prefix_length;
+ int default_prefixes;
if (info->mach == bfd_mach_x86_64_intel_syntax
|| info->mach == bfd_mach_x86_64
}
obufp = obuf;
- ckprefix ();
+ sizeflag = priv.orig_sizeflag;
+
+ if (!ckprefix () || rex_used)
+ {
+ /* Too many prefixes or unused REX prefixes. */
+ for (i = 0;
+ all_prefixes[i] && i < (int) ARRAY_SIZE (all_prefixes);
+ i++)
+ (*info->fprintf_func) (info->stream, "%s",
+ prefix_name (all_prefixes[i], sizeflag));
+ return 1;
+ }
insn_codep = codep;
- sizeflag = priv.orig_sizeflag;
FETCH_DATA (info, codep + 1);
two_source_ops = (*codep == 0x62) || (*codep == 0xc8);
if (((prefixes & PREFIX_FWAIT)
- && ((*codep < 0xd8) || (*codep > 0xdf)))
- || (rex && rex_used))
+ && ((*codep < 0xd8) || (*codep > 0xdf))))
{
- const char *name;
-
- /* fwait not followed by floating point instruction, or rex followed
- by other prefixes. Print the first prefix. */
- name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag);
- if (name == NULL)
- name = INTERNAL_DISASSEMBLER_ERROR;
- (*info->fprintf_func) (info->stream, "%s", name);
+ (*info->fprintf_func) (info->stream, "fwait");
return 1;
}
}
if ((prefixes & PREFIX_REPZ))
- {
- repz_prefix = "repz ";
- used_prefixes |= PREFIX_REPZ;
- }
- else
- repz_prefix = NULL;
-
+ used_prefixes |= PREFIX_REPZ;
if ((prefixes & PREFIX_REPNZ))
- {
- repnz_prefix = "repnz ";
- used_prefixes |= PREFIX_REPNZ;
- }
- else
- repnz_prefix = NULL;
-
+ used_prefixes |= PREFIX_REPNZ;
if ((prefixes & PREFIX_LOCK))
- {
- lock_prefix = "lock ";
- used_prefixes |= PREFIX_LOCK;
- }
- else
- lock_prefix = NULL;
+ used_prefixes |= PREFIX_LOCK;
- addr_prefix = NULL;
+ default_prefixes = 0;
if (prefixes & PREFIX_ADDR)
{
sizeflag ^= AFLAG;
if (dp->op[2].bytemode != loop_jcxz_mode || intel_syntax)
{
if ((sizeflag & AFLAG) || address_mode == mode_64bit)
- addr_prefix = "addr32 ";
+ all_prefixes[last_addr_prefix] = ADDR32_PREFIX;
else
- addr_prefix = "addr16 ";
- used_prefixes |= PREFIX_ADDR;
+ all_prefixes[last_addr_prefix] = ADDR16_PREFIX;
+ default_prefixes |= PREFIX_ADDR;
}
}
- data_prefix = NULL;
if ((prefixes & PREFIX_DATA))
{
sizeflag ^= DFLAG;
&& !intel_syntax)
{
if (sizeflag & DFLAG)
- data_prefix = "data32 ";
+ all_prefixes[last_data_prefix] = DATA32_PREFIX;
else
- data_prefix = "data16 ";
- used_prefixes |= PREFIX_DATA;
+ all_prefixes[last_data_prefix] = DATA16_PREFIX;
+ default_prefixes |= PREFIX_DATA;
+ }
+ else if (rex & REX_W)
+ {
+ /* REX_W will override PREFIX_DATA. */
+ default_prefixes |= PREFIX_DATA;
}
}
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)
+ if ((prefixes & ~(used_prefixes | default_prefixes)) != 0)
{
- const char *name;
-
- name = prefix_name (priv.the_buffer[0], priv.orig_sizeflag);
- if (name == NULL)
- name = INTERNAL_DISASSEMBLER_ERROR;
- (*info->fprintf_func) (info->stream, "%s", name);
- return 1;
- }
- if ((rex_original & ~rex_used) || rex_ignored)
- {
- const char *name;
- name = prefix_name (rex_original, priv.orig_sizeflag);
- if (name == NULL)
- name = INTERNAL_DISASSEMBLER_ERROR;
- (*info->fprintf_func) (info->stream, "%s ", name);
+ for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++)
+ if (all_prefixes[i])
+ {
+ const char *name;
+ name = prefix_name (all_prefixes[i], priv.orig_sizeflag);
+ if (name == NULL)
+ name = INTERNAL_DISASSEMBLER_ERROR;
+ (*info->fprintf_func) (info->stream, "%s", name);
+ return 1;
+ }
}
- prefix_obuf[0] = 0;
- prefix_obufp = prefix_obuf;
+ /* Check if the REX prefix used. */
+ if ((rex ^ rex_used) == 0)
+ all_prefixes[last_rex_prefix] = 0;
+
+ /* Check if the SEG prefix used. */
+ if ((prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS | PREFIX_ES
+ | PREFIX_FS | PREFIX_GS)) != 0
+ && (used_prefixes
+ & seg_prefix (all_prefixes[last_seg_prefix])) != 0)
+ all_prefixes[last_seg_prefix] = 0;
+
+ /* Check if the ADDR prefix used. */
+ if ((prefixes & PREFIX_ADDR) != 0
+ && (used_prefixes & PREFIX_ADDR) != 0)
+ all_prefixes[last_addr_prefix] = 0;
+
+ /* Check if the DATA prefix used. */
+ if ((prefixes & PREFIX_DATA) != 0
+ && (used_prefixes & PREFIX_DATA) != 0)
+ all_prefixes[last_data_prefix] = 0;
+
+ prefix_length = 0;
for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++)
- if (all_prefixes[i] && *all_prefixes[i])
- prefix_obufp = stpcpy (prefix_obufp, *all_prefixes[i]);
+ if (all_prefixes[i])
+ {
+ const char *name;
+ name = prefix_name (all_prefixes[i], sizeflag);
+ if (name == NULL)
+ abort ();
+ prefix_length += strlen (name) + 1;
+ (*info->fprintf_func) (info->stream, "%s ", name);
+ }
- if (prefix_obuf[0] != 0)
- (*info->fprintf_func) (info->stream, "%s", prefix_obuf);
+ /* Check maximum code length. */
+ if ((codep - start_codep) > MAX_CODE_LENGTH)
+ {
+ (*info->fprintf_func) (info->stream, "(bad)");
+ return MAX_CODE_LENGTH;
+ }
obufp = mnemonicendp;
- for (i = strlen (obuf) + strlen (prefix_obuf); i < 6; i++)
+ for (i = strlen (obuf) + prefix_length; i < 6; i++)
oappend (" ");
oappend (" ");
(*info->fprintf_func) (info->stream, "%s", obuf);
{
if (rex & REX_W)
*obufp++ = 'q';
- else if (sizeflag & DFLAG)
- *obufp++ = intel_syntax ? 'd' : 'l';
else
- *obufp++ = 'w';
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if (sizeflag & DFLAG)
+ *obufp++ = intel_syntax ? 'd' : 'l';
+ else
+ *obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
}
else
*obufp++ = 'w';
*obufp++ = 'l';
else
*obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
- used_prefixes |= (prefixes & PREFIX_DATA);
}
break;
case 'U':
*obufp++ = intel_syntax ? 'd' : 'l';
else
*obufp++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
- used_prefixes |= (prefixes & PREFIX_DATA);
}
}
else
else
*obufp++ = 's';
}
- else if (prefixes & PREFIX_DATA)
- *obufp++ = 'd';
else
- *obufp++ = 's';
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if (prefixes & PREFIX_DATA)
+ *obufp++ = 'd';
+ else
+ *obufp++ = 's';
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
case 'Y':
if (l == 0 && len == 1)
if (address_mode == mode_64bit && (sizeflag & DFLAG))
{
oappend ("QWORD PTR ");
- used_prefixes |= (prefixes & PREFIX_DATA);
break;
}
/* FALLTHRU */
USED_REX (REX_W);
if (rex & REX_W)
oappend ("QWORD PTR ");
- else if ((sizeflag & DFLAG) || bytemode == dq_mode)
- oappend ("DWORD PTR ");
else
- oappend ("WORD PTR ");
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if ((sizeflag & DFLAG) || bytemode == dq_mode)
+ oappend ("DWORD PTR ");
+ else
+ oappend ("WORD PTR ");
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
case z_mode:
if ((rex & REX_W) || (sizeflag & DFLAG))
if (address_mode == mode_64bit && (sizeflag & DFLAG))
{
names = names64;
- used_prefixes |= (prefixes & PREFIX_DATA);
break;
}
bytemode = v_mode;
USED_REX (REX_W);
if (rex & REX_W)
names = names64;
- else if ((sizeflag & DFLAG)
- || (bytemode != v_mode
- && bytemode != v_swap_mode))
- names = names32;
else
- names = names16;
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if ((sizeflag & DFLAG)
+ || (bytemode != v_mode
+ && bytemode != v_swap_mode))
+ names = names32;
+ else
+ names = names16;
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
case 0:
return;
}
}
else
- { /* 16 bit address mode */
+ {
+ /* 16 bit address mode */
+ used_prefixes |= prefixes & PREFIX_ADDR;
switch (modrm.mod)
{
case 0:
USED_REX (REX_W);
if (rex & REX_W)
oappend (names64[modrm.reg + add]);
- else if ((sizeflag & DFLAG) || bytemode != v_mode)
- oappend (names32[modrm.reg + add]);
else
- oappend (names16[modrm.reg + add]);
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if ((sizeflag & DFLAG) || bytemode != v_mode)
+ oappend (names32[modrm.reg + add]);
+ else
+ oappend (names16[modrm.reg + add]);
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
case m_mode:
if (address_mode == mode_64bit)
USED_REX (REX_W);
if (rex & REX_W)
s = names64[code - eAX_reg + add];
- else if (sizeflag & DFLAG)
- s = names32[code - eAX_reg + add];
else
- s = names16[code - eAX_reg + add];
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if (sizeflag & DFLAG)
+ s = names32[code - eAX_reg + add];
+ else
+ s = names16[code - eAX_reg + add];
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
default:
s = INTERNAL_DISASSEMBLER_ERROR;
USED_REX (REX_W);
if (rex & REX_W)
s = names64[code - eAX_reg];
- else if (sizeflag & DFLAG)
- s = names32[code - eAX_reg];
else
- s = names16[code - eAX_reg];
- used_prefixes |= (prefixes & PREFIX_DATA);
+ {
+ if (sizeflag & DFLAG)
+ s = names32[code - eAX_reg];
+ else
+ s = names16[code - eAX_reg];
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
case z_mode_ax_reg:
if ((rex & REX_W) || (sizeflag & DFLAG))
USED_REX (REX_W);
if (rex & REX_W)
op = get32s ();
- else if (sizeflag & DFLAG)
- {
- op = get32 ();
- mask = 0xffffffff;
- }
else
{
- op = get16 ();
- mask = 0xfffff;
+ if (sizeflag & DFLAG)
+ {
+ op = get32 ();
+ mask = 0xffffffff;
+ }
+ else
+ {
+ op = get16 ();
+ mask = 0xfffff;
+ }
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
- used_prefixes |= (prefixes & PREFIX_DATA);
break;
case w_mode:
mask = 0xfffff;
USED_REX (REX_W);
if (rex & REX_W)
op = get64 ();
- else if (sizeflag & DFLAG)
- {
- op = get32 ();
- mask = 0xffffffff;
- }
else
{
- op = get16 ();
- mask = 0xfffff;
+ if (sizeflag & DFLAG)
+ {
+ op = get32 ();
+ mask = 0xffffffff;
+ }
+ else
+ {
+ op = get16 ();
+ mask = 0xfffff;
+ }
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
- used_prefixes |= (prefixes & PREFIX_DATA);
break;
case w_mode:
mask = 0xfffff;
USED_REX (REX_W);
if (rex & REX_W)
op = get32s ();
- else if (sizeflag & DFLAG)
- {
- op = get32s ();
- mask = 0xffffffff;
- }
else
{
- mask = 0xffffffff;
- op = get16 ();
- if ((op & 0x8000) != 0)
- op -= 0x10000;
+ if (sizeflag & DFLAG)
+ {
+ op = get32s ();
+ mask = 0xffffffff;
+ }
+ else
+ {
+ mask = 0xffffffff;
+ op = get16 ();
+ if ((op & 0x8000) != 0)
+ op -= 0x10000;
+ }
+ used_prefixes |= (prefixes & PREFIX_DATA);
}
- used_prefixes |= (prefixes & PREFIX_DATA);
break;
case w_mode:
op = get16 ();
disp -= 0x100;
break;
case v_mode:
+ USED_REX (REX_W);
if ((sizeflag & DFLAG) || (rex & REX_W))
disp = get32s ();
else
segment = ((start_pc + codep - start_codep)
& ~((bfd_vma) 0xffff));
}
- used_prefixes |= (prefixes & PREFIX_DATA);
+ if (!(rex & REX_W))
+ used_prefixes |= (prefixes & PREFIX_DATA);
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
}
else if (address_mode != mode_64bit && (prefixes & PREFIX_LOCK))
{
- lock_prefix = NULL;
+ all_prefixes[last_lock_prefix] = 0;
used_prefixes |= PREFIX_LOCK;
add = 8;
}
else
{
/* Remove "addr16/addr32". */
- addr_prefix = NULL;
+ all_prefixes[last_addr_prefix] = 0;
op1_names = (address_mode != mode_32bit
? names32 : names16);
used_prefixes |= PREFIX_ADDR;
/* The 0xf3 prefix should be displayed as "rep" for ins, outs, movs,
lods and stos. */
if (prefixes & PREFIX_REPZ)
- repz_prefix = "rep ";
+ all_prefixes[last_repz_prefix] = REP_PREFIX;
switch (bytemode)
{
USED_REX (REX_W);
if (rex & REX_W)
*p++ = 'q';
- else if (sizeflag & DFLAG)
- *p++ = 'l';
- else
- *p++ = 'w';
- used_prefixes |= (prefixes & PREFIX_DATA);
+ else
+ {
+ if (sizeflag & DFLAG)
+ *p++ = 'l';
+ else
+ *p++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
{
if (rex & REX_W)
*p++ = 'q';
- else if (sizeflag & DFLAG)
- *p++ = 'l';
else
- *p++ = 'w';
+ {
+ if (sizeflag & DFLAG)
+ *p++ = 'l';
+ else
+ *p++ = 'w';
+ used_prefixes |= (prefixes & PREFIX_DATA);
+ }
}
- used_prefixes |= (prefixes & PREFIX_DATA);
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);