This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: PR binutils/4218: objdump on AMD64 fails to decode prefixed 0x90 opcode properly.
- From: "H. J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Wed, 21 Mar 2007 12:15:44 -0700
- Subject: PATCH: PR binutils/4218: objdump on AMD64 fails to decode prefixed 0x90 opcode properly.
The assembler doesn't use the shorter 0x90 opcode for xchg in 64bit
mode and the disassembler fails to proper decode the REX byte before
0x90. Also nop (0f 1f) takes both register and memory operand.
This patch fixes those.
H.J.
-----
gas/
2003-03-21 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/4218
* config/tc-i386.c (match_template): Properly handle 64bit mode
"xchg %eax, %eax".
gas/testsuite/
2003-03-21 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/4218
* gas/i386/nops.s: Add testcases for nop r/m.
* gas/i386/x86-64-nops.s: Likewise.
* gas/i386/x86-64-opcode.s: Add testcases for xchg with %ax,
%eax and %rax.
* gas/i386/nops.d: Updated.
* gas/i386/x86-64-nops.d: Likewise.
* gas/i386/x86-64-opcode.d: Likewise.
opcodes/
2003-03-21 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/4218
* i386-dis.c (PREGRP38): New.
(dis386): Use PREGRP38 for 0x90.
(prefix_user_table): Add PREGRP38.
(print_insn): Set uses_REPZ_prefix to 1 for pause.
(NOP_Fixup1): Properly handle REX bits.
(NOP_Fixup2): Likewise.
* i386-opc.c (i386_optab): Allow %eax with xchg in 64bit.
Allow register with nop.
--- binutils/gas/config/tc-i386.c.nop 2007-03-21 08:53:36.000000000 -0700
+++ binutils/gas/config/tc-i386.c 2007-03-21 10:45:27.000000000 -0700
@@ -2621,6 +2621,15 @@ match_template (void)
continue;
break;
case 2:
+ /* xchg %eax, %eax is a special case. It is an aliase for nop
+ only in 32bit mode and we can use opcode 0x90. In 64bit
+ mode, we can't use 0x90 for xchg %eax, %eax since it should
+ zero-extend %eax to %rax. */
+ if (flag_code == CODE_64BIT
+ && t->base_opcode == 0x90
+ && i.types [0] == (Acc | Reg32)
+ && i.types [1] == (Acc | Reg32))
+ continue;
case 3:
case 4:
overlap1 = i.types[1] & operand_types[1];
--- binutils/gas/testsuite/gas/i386/nops.d.nop 2006-06-12 11:59:35.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/nops.d 2007-03-21 09:16:58.000000000 -0700
@@ -14,4 +14,11 @@ Disassembly of section .text:
[ ]*19:[ ]+0f 1f 84 00 00 00 00 00[ ]+nopl[ ]+0x0\(%eax,%eax,1\)
[ ]*21:[ ]+66 0f 1f 84 00 00 00 00 00[ ]+nopw[ ]+0x0\(%eax,%eax,1\)
[ ]*2a:[ ]+66 2e 0f 1f 84 00 00 00 00 00[ ]+nopw[ ]+%cs:0x0\(%eax,%eax,1\)
+[ ]*34:[ ]+0f 1f 00[ ]+nopl[ ]+\(%eax\)
+[ ]*37:[ ]+0f 1f c0[ ]+nop[ ]+%eax
+[ ]*3a:[ ]+66 0f 1f c0[ ]+nop[ ]+%ax
+[ ]*3e:[ ]+0f 1f 00[ ]+nopl[ ]+\(%eax\)
+[ ]*41:[ ]+66 0f 1f 00[ ]+nopw[ ]+\(%eax\)
+[ ]*45:[ ]+0f 1f c0[ ]+nop[ ]+%eax
+[ ]*48:[ ]+66 0f 1f c0[ ]+nop[ ]+%ax
#pass
--- binutils/gas/testsuite/gas/i386/nops.s.nop 2006-06-12 11:59:35.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/nops.s 2007-03-21 09:10:52.000000000 -0700
@@ -9,4 +9,12 @@
.byte 0x66, 0x0f, 0x1f, 0x84, 0x0, 0x0, 0x0, 0x0, 0x0
.byte 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x0, 0x0, 0x0, 0x0, 0x0
+ nop (%eax)
+ nop %eax
+ nop %ax
+ nopl (%eax)
+ nopw (%eax)
+ nopl %eax
+ nopw %ax
+
.p2align 4
--- binutils/gas/testsuite/gas/i386/x86-64-nops.d.nop 2006-06-12 11:59:35.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/x86-64-nops.d 2007-03-21 11:31:17.000000000 -0700
@@ -14,4 +14,24 @@ Disassembly of section .text:
[ ]*19:[ ]+0f 1f 84 00 00 00 00 00[ ]+nopl[ ]+0x0\(%rax,%rax,1\)
[ ]*21:[ ]+66 0f 1f 84 00 00 00 00 00[ ]+nopw[ ]+0x0\(%rax,%rax,1\)
[ ]*2a:[ ]+66 2e 0f 1f 84 00 00 00 00 00[ ]+nopw[ ]+%cs:0x0\(%rax,%rax,1\)
+[ ]*34:[ ]+0f 1f 00[ ]+nopl[ ]+\(%rax\)
+[ ]*37:[ ]+48 0f 1f c0[ ]+nop[ ]+%rax
+[ ]*3b:[ ]+0f 1f c0[ ]+nop[ ]+%eax
+[ ]*3e:[ ]+66 0f 1f c0[ ]+nop[ ]+%ax
+[ ]*42:[ ]+48 0f 1f 00[ ]+nopq[ ]+\(%rax\)
+[ ]*46:[ ]+0f 1f 00[ ]+nopl[ ]+\(%rax\)
+[ ]*49:[ ]+66 0f 1f 00[ ]+nopw[ ]+\(%rax\)
+[ ]*4d:[ ]+48 0f 1f c0[ ]+nop[ ]+%rax
+[ ]*51:[ ]+0f 1f c0[ ]+nop[ ]+%eax
+[ ]*54:[ ]+66 0f 1f c0[ ]+nop[ ]+%ax
+[ ]*58:[ ]+41 0f 1f 02[ ]+nopl[ ]+\(%r10\)
+[ ]*5c:[ ]+49 0f 1f c2[ ]+nop[ ]+%r10
+[ ]*60:[ ]+41 0f 1f c2[ ]+nop[ ]+%r10d
+[ ]*64:[ ]+66 41 0f 1f c2[ ]+nop[ ]+%r10w
+[ ]*69:[ ]+49 0f 1f 02[ ]+nopq[ ]+\(%r10\)
+[ ]*6d:[ ]+41 0f 1f 02[ ]+nopl[ ]+\(%r10\)
+[ ]*71:[ ]+66 41 0f 1f 02[ ]+nopw[ ]+\(%r10\)
+[ ]*76:[ ]+49 0f 1f c2[ ]+nop[ ]+%r10
+[ ]*7a:[ ]+41 0f 1f c2[ ]+nop[ ]+%r10d
+[ ]*7e:[ ]+66 41 0f 1f c2[ ]+nop[ ]+%r10w
#pass
--- binutils/gas/testsuite/gas/i386/x86-64-nops.s.nop 2006-06-12 11:59:35.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/x86-64-nops.s 2007-03-21 09:12:36.000000000 -0700
@@ -9,4 +9,25 @@
.byte 0x66, 0x0f, 0x1f, 0x84, 0x0, 0x0, 0x0, 0x0, 0x0
.byte 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x0, 0x0, 0x0, 0x0, 0x0
+ nop (%rax)
+ nop %rax
+ nop %eax
+ nop %ax
+ nopq (%rax)
+ nopl (%rax)
+ nopw (%rax)
+ nopq %rax
+ nopl %eax
+ nopw %ax
+ nop (%r10)
+ nop %r10
+ nop %r10d
+ nop %r10w
+ nopq (%r10)
+ nopl (%r10)
+ nopw (%r10)
+ nopq %r10
+ nopl %r10d
+ nopw %r10w
+
.p2align 4
--- binutils/gas/testsuite/gas/i386/x86-64-opcode.d.nop 2006-09-20 04:35:11.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/x86-64-opcode.d 2007-03-21 12:06:10.000000000 -0700
@@ -274,6 +274,16 @@ Disassembly of section .text:
[ ]*[0-9a-f]+:[ ]+90[ ]+nop[ ]*(#.*)*
[ ]*[0-9a-f]+:[ ]+48 90[ ]+rex64 nop[ ]*(#.*)*
[ ]*[0-9a-f]+:[ ]+49 90[ ]+xchg[ ]+%rax,%r8[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+41 90[ ]+xchg[ ]+%eax,%r8d[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+41 90[ ]+xchg[ ]+%eax,%r8d[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+41 91[ ]+xchg[ ]+%eax,%r9d[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+41 91[ ]+xchg[ ]+%eax,%r9d[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+93[ ]+xchg[ ]+%eax,%ebx[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+93[ ]+xchg[ ]+%eax,%ebx[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+66 41 90[ ]+xchg[ ]+%ax,%r8w[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+66 41 90[ ]+xchg[ ]+%ax,%r8w[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+66 41 91[ ]+xchg[ ]+%ax,%r9w[ ]*(#.*)*
+[ ]*[0-9a-f]+:[ ]+66 41 91[ ]+xchg[ ]+%ax,%r9w[ ]*(#.*)*
[ ]*[0-9a-f]+:[ ]+48 0f 01 e0[ ]+smsw[ ]+%rax[ ]*(#.*)*
[ ]*[0-9a-f]+:[ ]+0f 01 e0[ ]+smsw[ ]+%eax[ ]*(#.*)*
[ ]*[0-9a-f]+:[ ]+66 0f 01 e0[ ]+smsw[ ]+%ax[ ]*(#.*)*
--- binutils/gas/testsuite/gas/i386/x86-64-opcode.s.nop 2006-07-18 13:25:40.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/x86-64-opcode.s 2007-03-21 12:04:51.000000000 -0700
@@ -397,6 +397,16 @@
xchg %rax,%rax # -- -- -- -- 90
rex64 xchg %rax,%rax # -- -- -- 48 90
xchg %rax,%r8 # -- -- -- 49 90
+ xchg %eax,%r8d # -- -- -- 41 90
+ xchg %r8d,%eax # -- -- -- 41 90
+ xchg %eax,%r9d # -- -- -- 41 91
+ xchg %r9d,%eax # -- -- -- 41 91
+ xchg %ebx,%eax # -- -- -- 93
+ xchg %eax,%ebx # -- -- -- 93
+ xchg %ax,%r8w # -- -- -- 66 41 90
+ xchg %r8w,%ax # -- -- -- 66 41 90
+ xchg %ax,%r9w # -- -- -- 66 41 91
+ xchg %r9w,%ax # -- -- -- 66 41 91
smsw %rax # -- -- -- 48 0F 01 e0
smsw %eax # -- -- -- -- 0F 01 e0
--- binutils/opcodes/i386-dis.c.nop 2007-03-15 07:46:25.000000000 -0700
+++ binutils/opcodes/i386-dis.c 2007-03-21 11:36:00.000000000 -0700
@@ -467,6 +467,7 @@ fetch_data (struct disassemble_info *inf
#define PREGRP35 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 35 } }
#define PREGRP36 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 36 } }
#define PREGRP37 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 37 } }
+#define PREGRP38 NULL, { { NULL, USE_PREFIX_USER_TABLE }, { NULL, 38 } }
#define X86_64_0 NULL, { { NULL, X86_64_SPECIAL }, { NULL, 0 } }
@@ -692,7 +693,7 @@ static const struct dis386 dis386[] = {
{ "movD", { Sw, Sv } },
{ "popU", { stackEv } },
/* 90 */
- { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+ { PREGRP38 },
{ "xchgS", { RMeCX, eAX } },
{ "xchgS", { RMeDX, eAX } },
{ "xchgS", { RMeBX, eAX } },
@@ -2017,6 +2018,14 @@ static const struct dis386 prefix_user_t
{ "(bad)", { XX } },
{ "(bad)", { XX } },
},
+
+ /* PREGRP38 */
+ {
+ { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+ { "pause", { XX } },
+ { "xchgS", { { NOP_Fixup1, eAX_reg }, { NOP_Fixup2, eAX_reg } } },
+ { "(bad)", { XX } },
+ },
};
static const struct dis386 x86_64_table[][2] = {
@@ -3091,7 +3100,8 @@ print_insn (bfd_vma pc, disassemble_info
need_modrm = onebyte_has_modrm[*codep];
uses_DATA_prefix = 0;
uses_REPNZ_prefix = 0;
- uses_REPZ_prefix = 0;
+ /* pause is 0xf3 0x90. */
+ uses_REPZ_prefix = *codep == 0x90;
uses_LOCK_prefix = 0;
codep++;
}
@@ -5284,17 +5294,15 @@ OP_0fae (int bytemode, int sizeflag)
}
/* NOP is an alias of "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in
- 32bit mode and "xchg %rax,%rax" in 64bit mode. NOP with REPZ prefix
- is called PAUSE. We display "xchg %ax,%ax" instead of "data16 nop".
- */
+ 32bit mode and "xchg %rax,%rax" in 64bit mode. */
static void
NOP_Fixup1 (int bytemode, int sizeflag)
{
- if (prefixes == PREFIX_REPZ)
- strcpy (obuf, "pause");
- else if (prefixes == PREFIX_DATA
- || ((rex & REX_MODE64) && rex != 0x48))
+ if ((prefixes & PREFIX_DATA) != 0
+ || (rex != 0
+ && rex != 0x48
+ && address_mode == mode_64bit))
OP_REG (bytemode, sizeflag);
else
strcpy (obuf, "nop");
@@ -5303,8 +5311,10 @@ NOP_Fixup1 (int bytemode, int sizeflag)
static void
NOP_Fixup2 (int bytemode, int sizeflag)
{
- if (prefixes == PREFIX_DATA
- || ((rex & REX_MODE64) && rex != 0x48))
+ if ((prefixes & PREFIX_DATA) != 0
+ || (rex != 0
+ && rex != 0x48
+ && address_mode == mode_64bit))
OP_IMREG (bytemode, sizeflag);
}
--- binutils/opcodes/i386-opc.c.nop 2007-03-15 10:32:27.000000000 -0700
+++ binutils/opcodes/i386-opc.c 2007-03-21 10:26:30.000000000 -0700
@@ -144,12 +144,10 @@ const template i386_optab[] =
xchg commutes: we allow both operand orders.
In the 64bit code, xchg rax, rax is reused for new nop instruction. */
-{"xchg", 2, 0x90, X, CpuNo64, wl_Suf|ShortForm, { WordReg, Acc, 0 } },
-{"xchg", 2, 0x90, X, CpuNo64, wl_Suf|ShortForm, { Acc, WordReg, 0 } },
-{"xchg", 2, 0x90, X, Cpu64, wq_Suf|ShortForm, { Reg16|Reg64, Acc, 0 } },
-{"xchg", 2, 0x90, X, Cpu64, wq_Suf|ShortForm, { Acc, Reg16|Reg64, 0 } },
-{"xchg", 2, 0x86, X, 0, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } },
-{"xchg", 2, 0x86, X, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, Reg, 0 } },
+{"xchg", 2, 0x90, X, 0, wlq_Suf|ShortForm, { WordReg, Acc, 0 } },
+{"xchg", 2, 0x90, X, 0, wlq_Suf|ShortForm, { Acc, WordReg, 0 } },
+{"xchg", 2, 0x86, X, 0, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } },
+{"xchg", 2, 0x86, X, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, Reg, 0 } },
/* In/out from ports. */
/* XXX should reject %rax */
@@ -517,7 +515,7 @@ const template i386_optab[] =
{"hlt", 0, 0xf4, X, 0, NoSuf, { 0, 0, 0} },
-{"nop", 1, 0x0f1f, X, Cpu686, wl_Suf|Modrm, { WordMem, 0, 0} },
+{"nop", 1, 0x0f1f, 0, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, 0, 0} },
/* nop is actually "xchg %ax,%ax" in 16bit mode, "xchg %eax,%eax" in
32bit mode and "xchg %rax,%rax" in 64bit mode. */