Disassembly of section .text:
-0+000 <foo>:
- 0: 9b 26 67 d9 3c[ ]+fstcw[ ]+%es:\(%si\)
- 5: 9b df e0 [ ]*fstsw %ax
- 8: 9b df e0 [ ]*fstsw %ax
- b: 9b 67 df e0 [ ]*addr16 fstsw %ax
- f: 36 67 66 f3 a7 [ ]*repz cmpsw %es:\(%di\),%ss:\(%si\)
- 14: 26 9b[ ]*es fwait
+0+ <foo>:
+[ ]*[a-f0-9]+: 9b 26 67 d9 3c fstcw %es:\(%si\)
+[ ]*[a-f0-9]+: 9b df e0 fstsw %ax
+[ ]*[a-f0-9]+: 9b df e0 fstsw %ax
+[ ]*[a-f0-9]+: 9b 67 df e0 addr16 fstsw %ax
+[ ]*[a-f0-9]+: 36 67 66 f3 a7 repz cmpsw %es:\(%di\),%ss:\(%si\)
+[ ]*[a-f0-9]+: 26 9b es fwait
+[ ]*[a-f0-9]+: 66 f2 0f 38 17 data16 \(bad\)
+[ ]*[a-f0-9]+: f2 66 0f 54 repnz \(bad\)
+[ ]*[a-f0-9]+: f2 0f 54 repnz \(bad\)
+[ ]*[a-f0-9]+: f2 66 0f 11 22 data16 movsd %xmm4,\(%edx\)
+[ ]*[a-f0-9]+: f2 67 66 0f 11 22 data16 movsd %xmm4,\(%bp,%si\)
+[ ]*[a-f0-9]+: f2 67 f0 66 0f 11 22 lock data16 movsd %xmm4,\(%bp,%si\)
+[ ]*[a-f0-9]+: f3 66 0f 11 22 data16 movss %xmm4,\(%edx\)
+[ ]*[a-f0-9]+: f3 67 f0 66 0f 11 22 lock data16 movss %xmm4,\(%bp,%si\)
+[ ]*[a-f0-9]+: f3 67 f2 66 0f 11 22 repz data16 movsd %xmm4,\(%bp,%si\)
+[ ]*[a-f0-9]+: f3 66 3e 0f 11 22 data16 movss %xmm4,%ds:\(%edx\)
+[ ]*[a-f0-9]+: f2 66 36 0f 11 22 data16 movsd %xmm4,%ss:\(%edx\)
+[ ]*[a-f0-9]+: f3 f0 f2 66 36 0f 11 22 repz lock data16 movsd %xmm4,%ss:\(%edx\)
+[ ]*[a-f0-9]+: f2 66 3e 36 0f 11 22 data16 ds movsd %xmm4,%ss:\(%edx\)
+[ ]*[a-f0-9]+: f2 67 66 3e 36 0f 11 22 data16 ds movsd %xmm4,%ss:\(%bp,%si\)
+[ ]*[a-f0-9]+: f2 67 f0 66 3e 36 0f 11 22 lock data16 ds movsd %xmm4,%ss:\(%bp,%si\)
+[ ]*[a-f0-9]+: f3 66 3e 36 0f 11 22 data16 ds movss %xmm4,%ss:\(%edx\)
+[ ]*[a-f0-9]+: f3 f0 66 3e 36 0f 11 22 lock data16 ds movss %xmm4,%ss:\(%edx\)
+[ ]*[a-f0-9]+: f3 67 f2 66 3e 36 0f 11 22 repz data16 ds movsd %xmm4,%ss:\(%bp,%si\)
+[ ]*[a-f0-9]+: f2 66 90 repnz xchg %ax,%ax
+[ ]*[a-f0-9]+: f2 67 66 90 repnz addr16 xchg %ax,%ax
+[ ]*[a-f0-9]+: f2 67 f0 66 90 repnz addr16 lock xchg %ax,%ax
+[ ]*[a-f0-9]+: f3 66 90 data16 pause
+[ ]*[a-f0-9]+: f3 67 f0 66 90 addr16 lock data16 pause
+[ ]*[a-f0-9]+: f3 67 f2 66 90 repz addr16 repnz xchg %ax,%ax
+[ ]*[a-f0-9]+: f2 3e 90 repnz ds nop
+[ ]*[a-f0-9]+: f2 f0 67 3e 90 repnz lock addr16 ds nop
+[ ]*[a-f0-9]+: f3 3e 90 ds pause
+[ ]*[a-f0-9]+: f3 66 3e 90 data16 ds pause
+[ ]*[a-f0-9]+: f3 f0 3e 90 lock ds pause
+[ ]*[a-f0-9]+: f3 f0 67 3e 90 lock addr16 ds pause
+[ ]*[a-f0-9]+: f3 f2 67 3e 90 repz repnz addr16 ds nop
+[ ]*[a-f0-9]+: 66 f0 36 90 lock ss xchg %ax,%ax
+[ ]*[a-f0-9]+: f2 36 90 repnz ss nop
+[ ]*[a-f0-9]+: f2 66 36 90 repnz ss xchg %ax,%ax
+[ ]*[a-f0-9]+: f2 f0 36 90 repnz lock ss nop
+[ ]*[a-f0-9]+: f2 f0 67 36 90 repnz lock addr16 ss nop
+[ ]*[a-f0-9]+: f3 36 90 ss pause
+[ ]*[a-f0-9]+: f3 67 36 90 addr16 ss pause
+[ ]*[a-f0-9]+: f3 f0 67 36 90 lock addr16 ss pause
+[ ]*[a-f0-9]+: f3 f2 36 90 repz repnz ss nop
+[ ]*[a-f0-9]+: f3 f2 67 36 90 repz repnz addr16 ss nop
+[ ]*[a-f0-9]+: f3 f0 f2 66 36 90 repz lock repnz ss xchg %ax,%ax
+[ ]*[a-f0-9]+: 66 3e 36 90 ds ss xchg %ax,%ax
+[ ]*[a-f0-9]+: 67 66 3e 36 90 addr16 ds ss xchg %ax,%ax
+[ ]*[a-f0-9]+: 67 f0 66 3e 36 90 addr16 lock ds ss xchg %ax,%ax
+[ ]*[a-f0-9]+: f3 66 3e 36 90 data16 ds ss pause
+[ ]*[a-f0-9]+: f3 f0 66 3e 36 90 lock data16 ds ss pause
+[ ]*[a-f0-9]+: f3 f2 67 3e 36 90 repz repnz addr16 ds ss nop
+[ ]*[a-f0-9]+: f3 67 f2 66 3e 36 90 repz addr16 repnz ds ss xchg %ax,%ax
#pass
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
+static const unsigned char twobyte_has_mandatory_prefix[256] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* ------------------------------- */
+ /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */
+ /* 10 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */
+ /* 20 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0, /* 2f */
+ /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */
+ /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */
+ /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */
+ /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */
+ /* 70 */ 1,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1, /* 7f */
+ /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */
+ /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */
+ /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */
+ /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */
+ /* c0 */ 0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0, /* cf */
+ /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */
+ /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */
+ /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */
+ /* ------------------------------- */
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+};
+
static char obuf[100];
static char *obufp;
static char *mnemonicendp;
static unsigned char *start_codep;
static unsigned char *insn_codep;
static unsigned char *codep;
+static unsigned char *end_codep;
static int last_lock_prefix;
static int last_repz_prefix;
static int last_repnz_prefix;
static int last_addr_prefix;
static int last_rex_prefix;
static int last_seg_prefix;
+/* The PREFIX_REPZ/PREFIX_REPNZ/PREFIX_DATA prefix is mandatory. */
+static int mandatory_prefix;
+/* The active segment register prefix. */
+static int active_seg_prefix;
#define MAX_CODE_LENGTH 15
/* We can up to 14 prefixes since the maximum instruction length is
15bytes. */
last_addr_prefix = -1;
last_rex_prefix = -1;
last_seg_prefix = -1;
+ active_seg_prefix = 0;
for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++)
all_prefixes[i] = 0;
i = 0;
case 0x2e:
prefixes |= PREFIX_CS;
last_seg_prefix = i;
+ active_seg_prefix = PREFIX_CS;
break;
case 0x36:
prefixes |= PREFIX_SS;
last_seg_prefix = i;
+ active_seg_prefix = PREFIX_SS;
break;
case 0x3e:
prefixes |= PREFIX_DS;
last_seg_prefix = i;
+ active_seg_prefix = PREFIX_DS;
break;
case 0x26:
prefixes |= PREFIX_ES;
last_seg_prefix = i;
+ active_seg_prefix = PREFIX_ES;
break;
case 0x64:
prefixes |= PREFIX_FS;
last_seg_prefix = i;
+ active_seg_prefix = PREFIX_FS;
break;
case 0x65:
prefixes |= PREFIX_GS;
last_seg_prefix = i;
+ active_seg_prefix = PREFIX_GS;
break;
case 0x66:
prefixes |= PREFIX_DATA;
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 the name of the prefix byte PREF, or NULL if PREF is not a
prefix byte. */
}
else
{
+ int last_prefix = -1;
+ int prefix = 0;
vindex = 0;
- used_prefixes |= (prefixes & PREFIX_REPZ);
- if (prefixes & PREFIX_REPZ)
- {
- vindex = 1;
- all_prefixes[last_repz_prefix] = 0;
- }
- else
+ /* We check PREFIX_REPNZ and PREFIX_REPZ before PREFIX_DATA.
+ When there are multiple PREFIX_REPNZ and PREFIX_REPZ, the
+ last one wins. */
+ if ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) != 0)
{
- /* We should check PREFIX_REPNZ and PREFIX_REPZ before
- PREFIX_DATA. */
- used_prefixes |= (prefixes & PREFIX_REPNZ);
- if (prefixes & PREFIX_REPNZ)
+ if (last_repz_prefix > last_repnz_prefix)
{
- vindex = 3;
- all_prefixes[last_repnz_prefix] = 0;
+ vindex = 1;
+ prefix = PREFIX_REPZ;
+ last_prefix = last_repz_prefix;
}
else
{
- used_prefixes |= (prefixes & PREFIX_DATA);
- if (prefixes & PREFIX_DATA)
- {
- vindex = 2;
- all_prefixes[last_data_prefix] = 0;
- }
+ vindex = 3;
+ prefix = PREFIX_REPNZ;
+ last_prefix = last_repnz_prefix;
}
+
+ /* Ignore the invalid index if it isn't mandatory. */
+ if (!mandatory_prefix
+ && (prefix_table[dp->op[1].bytemode][vindex].name
+ == NULL)
+ && (prefix_table[dp->op[1].bytemode][vindex].op[0].bytemode
+ == 0))
+ vindex = 0;
+ }
+
+ if (vindex == 0 && (prefixes & PREFIX_DATA) != 0)
+ {
+ vindex = 2;
+ prefix = PREFIX_DATA;
+ last_prefix = last_data_prefix;
+ }
+
+ if (vindex != 0)
+ {
+ used_prefixes |= prefix;
+ all_prefixes[last_prefix] = 0;
}
}
dp = &prefix_table[dp->op[1].bytemode][vindex];
FETCH_DATA (info, codep + 2);
vindex = *codep++;
dp = &three_byte_table[dp->op[1].bytemode][vindex];
+ end_codep = codep;
modrm.mod = (*codep >> 6) & 3;
modrm.reg = (*codep >> 3) & 7;
modrm.rm = *codep & 7;
vindex = *codep++;
dp = &xop_table[vex_table_index][vindex];
+ end_codep = codep;
FETCH_DATA (info, codep + 1);
modrm.mod = (*codep >> 6) & 3;
modrm.reg = (*codep >> 3) & 7;
codep++;
vindex = *codep++;
dp = &vex_table[vex_table_index][vindex];
+ end_codep = codep;
/* There is no MODRM byte for VEX [82|77]. */
if (vindex != 0x77 && vindex != 0x82)
{
codep++;
vindex = *codep++;
dp = &vex_table[dp->op[1].bytemode][vindex];
+ end_codep = codep;
/* There is no MODRM byte for VEX [82|77]. */
if (vindex != 0x77 && vindex != 0x82)
{
codep++;
vindex = *codep++;
dp = &evex_table[vex_table_index][vindex];
+ end_codep = codep;
FETCH_DATA (info, codep + 1);
modrm.mod = (*codep >> 6) & 3;
modrm.reg = (*codep >> 3) & 7;
threebyte = *++codep;
dp = &dis386_twobyte[threebyte];
need_modrm = twobyte_has_modrm[*codep];
+ mandatory_prefix = twobyte_has_mandatory_prefix[*codep];
codep++;
}
else
{
dp = &dis386[*codep];
need_modrm = onebyte_has_modrm[*codep];
+ mandatory_prefix = 0;
codep++;
}
- if ((prefixes & PREFIX_REPZ))
- used_prefixes |= PREFIX_REPZ;
- if ((prefixes & PREFIX_REPNZ))
- used_prefixes |= PREFIX_REPNZ;
- if ((prefixes & PREFIX_LOCK))
- used_prefixes |= PREFIX_LOCK;
-
default_prefixes = 0;
if (prefixes & PREFIX_ADDR)
{
}
}
+ end_codep = codep;
if (need_modrm)
{
FETCH_DATA (info, codep + 1);
}
}
- /* 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 | default_prefixes)) != 0)
- {
- 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;
- }
- }
-
/* Check if the REX prefix is used. */
if (rex_ignored == 0 && (rex ^ rex_used) == 0 && last_rex_prefix >= 0)
all_prefixes[last_rex_prefix] = 0;
/* Check if the SEG prefix is 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)
+ && (used_prefixes & active_seg_prefix) != 0)
all_prefixes[last_seg_prefix] = 0;
/* Check if the ADDR prefix is used. */
&& (used_prefixes & PREFIX_ADDR) != 0)
all_prefixes[last_addr_prefix] = 0;
- /* Check if the DATA prefix is used. */
- if ((prefixes & PREFIX_DATA) != 0
- && (used_prefixes & PREFIX_DATA) != 0)
- all_prefixes[last_data_prefix] = 0;
+ /* Check if the DATA prefix is used. Restore the DFLAG bit in
+ sizeflag if the DATA prefix is unused. */
+ if ((prefixes & PREFIX_DATA) != 0)
+ {
+ if ((used_prefixes & PREFIX_DATA) != 0)
+ all_prefixes[last_data_prefix] = 0;
+ else if ((default_prefixes & PREFIX_DATA) == 0)
+ sizeflag ^= DFLAG;
+ }
prefix_length = 0;
for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++)
(*info->fprintf_func) (info->stream, "%s ", name);
}
+ /* If the mandatory PREFIX_REPZ/PREFIX_REPNZ/PREFIX_DATA prefix is
+ unused, opcode is invalid. Since the PREFIX_DATA prefix may be
+ used by putop and MMX/SSE operand and may be overriden by the
+ PREFIX_REPZ/PREFIX_REPNZ fix, we check the PREFIX_DATA prefix
+ separately. */
+ if (mandatory_prefix
+ && dp != &bad_opcode
+ && (((prefixes
+ & (PREFIX_REPZ | PREFIX_REPNZ)) != 0
+ && (used_prefixes
+ & (PREFIX_REPZ | PREFIX_REPNZ)) == 0)
+ || ((((prefixes
+ & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA))
+ == PREFIX_DATA)
+ && (used_prefixes & PREFIX_DATA) == 0))))
+ {
+ (*info->fprintf_func) (info->stream, "(bad)");
+ return end_codep - priv.the_buffer;
+ }
+
/* Check maximum code length. */
if ((codep - start_codep) > MAX_CODE_LENGTH)
{
static void
append_seg (void)
{
- if (prefixes & PREFIX_CS)
+ /* Only print the active segment register. */
+ if (!active_seg_prefix)
+ return;
+
+ used_prefixes |= active_seg_prefix;
+ switch (active_seg_prefix)
{
- used_prefixes |= PREFIX_CS;
+ case PREFIX_CS:
oappend_maybe_intel ("%cs:");
- }
- if (prefixes & PREFIX_DS)
- {
- used_prefixes |= PREFIX_DS;
+ break;
+ case PREFIX_DS:
oappend_maybe_intel ("%ds:");
- }
- if (prefixes & PREFIX_SS)
- {
- used_prefixes |= PREFIX_SS;
+ break;
+ case PREFIX_SS:
oappend_maybe_intel ("%ss:");
- }
- if (prefixes & PREFIX_ES)
- {
- used_prefixes |= PREFIX_ES;
+ break;
+ case PREFIX_ES:
oappend_maybe_intel ("%es:");
- }
- if (prefixes & PREFIX_FS)
- {
- used_prefixes |= PREFIX_FS;
+ break;
+ case PREFIX_FS:
oappend_maybe_intel ("%fs:");
- }
- if (prefixes & PREFIX_GS)
- {
- used_prefixes |= PREFIX_GS;
+ break;
+ case PREFIX_GS:
oappend_maybe_intel ("%gs:");
+ break;
+ default:
+ break;
}
}
{
if (modrm.mod != 0 || base == 5)
{
- if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
- | PREFIX_ES | PREFIX_FS | PREFIX_GS))
- ;
- else
+ if (!active_seg_prefix)
{
oappend (names_seg[ds_reg - es_reg]);
oappend (":");
}
else if (intel_syntax)
{
- if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
- | PREFIX_ES | PREFIX_FS | PREFIX_GS))
- ;
- else
+ if (!active_seg_prefix)
{
oappend (names_seg[ds_reg - es_reg]);
oappend (":");
if (intel_syntax)
{
- if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
- | PREFIX_ES | PREFIX_FS | PREFIX_GS)))
+ if (!active_seg_prefix)
{
oappend (names_seg[ds_reg - es_reg]);
oappend (":");
if (intel_syntax)
{
- if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS
- | PREFIX_ES | PREFIX_FS | PREFIX_GS)))
+ if (!active_seg_prefix)
{
oappend (names_seg[ds_reg - es_reg]);
oappend (":");
intel_operand_size (b_mode, sizeflag);
}
}
- if ((prefixes
- & (PREFIX_CS
- | PREFIX_DS
- | PREFIX_SS
- | PREFIX_ES
- | PREFIX_FS
- | PREFIX_GS)) == 0)
- prefixes |= PREFIX_DS;
+ /* Set active_seg_prefix to PREFIX_DS if it is unset so that the
+ default segment register DS is printed. */
+ if (!active_seg_prefix)
+ active_seg_prefix = PREFIX_DS;
append_seg ();
ptr_reg (code, sizeflag);
}