This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: PR binutils/3235: objdump on AMD64 - wrong output for prefixed offset operands
- From: "H. J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Fri, 22 Sep 2006 14:41:50 -0700
- Subject: PATCH: PR binutils/3235: objdump on AMD64 - wrong output for prefixed offset operands
This patch fixes x86-64 objdump for opcodes 0xa0, 0xa1, 0xa2, 0xa3 when
there is an address size prefix. We should use 32bit address offset
in this case.
While writing a testcase, assembler used opcodes 0x88, 0x89, 0x8a, 0x8b
instead of 0xa0, 0xa1, 0xa2, 0xa3 even if latter encoding is one byte
shorter. The problem is we failed to realize that address size prefix
would turn Disp64/Disp32/Disp16 operand into Disp32/Disp16/Disp32
operand. This patch also updates assembler to fix this issue.
H.J.
----
gas/
2006-09-22 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/3235
* config/tc-i386.c (match_template): Check address size prefix
to turn Disp64/Disp32/Disp16 operand into Disp32/Disp16/Disp32
operand.
gas/testsuite/
2006-09-22 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/3235
* gas/i386/addr16.d: New file.
* gas/i386/addr16.s: Likewise.
* gas/i386/addr32.d: Likewise.
* gas/i386/addr32.s: Likewise.
* gas/i386/i386.exp: Add "addr16" and "addr32".
* gas/i386/x86-64-addr32.s: Add tests for "add32 mov".
* gas/i386/x86-64-addr32.d: Updated.
opcodes/
2006-09-22 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/3235
* i386-dis.c (OP_OFF64): Get 32bit offset if there is an
address size prefix.
--- binutils/gas/config/tc-i386.c.moff 2006-09-22 12:44:41.000000000 -0700
+++ binutils/gas/config/tc-i386.c 2006-09-22 14:25:09.000000000 -0700
@@ -2571,6 +2571,8 @@ match_template ()
unsigned int overlap0, overlap1, overlap2;
unsigned int found_reverse_match;
int suffix_check;
+ unsigned int operand_types [3];
+ int addr_prefix_disp;
#define MATCH(overlap, given, template) \
((overlap & ~JumpAbsolute) \
@@ -2589,6 +2591,10 @@ match_template ()
overlap1 = 0;
overlap2 = 0;
found_reverse_match = 0;
+ operand_types [0] = 0;
+ operand_types [1] = 0;
+ operand_types [2] = 0;
+ addr_prefix_disp = -1;
suffix_check = (i.suffix == BYTE_MNEM_SUFFIX
? No_bSuf
: (i.suffix == WORD_MNEM_SUFFIX
@@ -2604,6 +2610,8 @@ match_template ()
for (t = current_templates->start; t < current_templates->end; t++)
{
+ addr_prefix_disp = -1;
+
/* Must have right number of operands. */
if (i.operands != t->operands)
continue;
@@ -2614,6 +2622,10 @@ match_template ()
&& (t->opcode_modifier & IgnoreSize)))
continue;
+ operand_types [0] = t->operand_types [0];
+ operand_types [1] = t->operand_types [1];
+ operand_types [2] = t->operand_types [2];
+
/* In general, don't allow 64-bit operands in 32-bit mode. */
if (i.suffix == QWORD_MNEM_SUFFIX
&& flag_code != CODE_64BIT
@@ -2621,8 +2633,8 @@ match_template ()
? (!(t->opcode_modifier & IgnoreSize)
&& !intel_float_operand (t->name))
: intel_float_operand (t->name) != 2)
- && (!(t->operand_types[0] & (RegMMX | RegXMM))
- || !(t->operand_types[t->operands > 1] & (RegMMX | RegXMM)))
+ && (!(operand_types[0] & (RegMMX | RegXMM))
+ || !(operand_types[t->operands > 1] & (RegMMX | RegXMM)))
&& (t->base_opcode != 0x0fc7
|| t->extension_opcode != 1 /* cmpxchg8b */))
continue;
@@ -2636,41 +2648,76 @@ match_template ()
break;
}
- overlap0 = i.types[0] & t->operand_types[0];
+ /* Address size prefix will turn Disp64/Disp32/Disp16 operand
+ into Disp32/Disp16/Disp32 operand. */
+ if (i.prefix[ADDR_PREFIX] != 0)
+ {
+ unsigned int j, DispOn = 0, DispOff = 0;
+
+ switch (flag_code)
+ {
+ case CODE_16BIT:
+ DispOn = Disp32;
+ DispOff = Disp16;
+ break;
+ case CODE_32BIT:
+ DispOn = Disp16;
+ DispOff = Disp32;
+ break;
+ case CODE_64BIT:
+ DispOn = Disp32;
+ DispOff = Disp64;
+ break;
+ }
+
+ for (j = 0; j < 3; j++)
+ {
+ /* There should be only one Disp operand. */
+ if ((operand_types[j] & DispOff))
+ {
+ addr_prefix_disp = j;
+ operand_types[j] |= DispOn;
+ operand_types[j] &= ~DispOff;
+ break;
+ }
+ }
+ }
+
+ overlap0 = i.types[0] & operand_types[0];
switch (t->operands)
{
case 1:
- if (!MATCH (overlap0, i.types[0], t->operand_types[0]))
+ if (!MATCH (overlap0, i.types[0], operand_types[0]))
continue;
break;
case 2:
case 3:
- overlap1 = i.types[1] & t->operand_types[1];
- if (!MATCH (overlap0, i.types[0], t->operand_types[0])
- || !MATCH (overlap1, i.types[1], t->operand_types[1])
+ overlap1 = i.types[1] & operand_types[1];
+ if (!MATCH (overlap0, i.types[0], operand_types[0])
+ || !MATCH (overlap1, i.types[1], operand_types[1])
/* monitor in SSE3 is a very special case. The first
register and the second register may have different
sizes. */
|| !((t->base_opcode == 0x0f01
&& t->extension_opcode == 0xc8)
|| CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
- t->operand_types[0],
+ operand_types[0],
overlap1, i.types[1],
- t->operand_types[1])))
+ operand_types[1])))
{
/* Check if other direction is valid ... */
if ((t->opcode_modifier & (D | FloatD)) == 0)
continue;
/* Try reversing direction of operands. */
- overlap0 = i.types[0] & t->operand_types[1];
- overlap1 = i.types[1] & t->operand_types[0];
- if (!MATCH (overlap0, i.types[0], t->operand_types[1])
- || !MATCH (overlap1, i.types[1], t->operand_types[0])
+ overlap0 = i.types[0] & operand_types[1];
+ overlap1 = i.types[1] & operand_types[0];
+ if (!MATCH (overlap0, i.types[0], operand_types[1])
+ || !MATCH (overlap1, i.types[1], operand_types[0])
|| !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
- t->operand_types[1],
+ operand_types[1],
overlap1, i.types[1],
- t->operand_types[0]))
+ operand_types[0]))
{
/* Does not match either direction. */
continue;
@@ -2686,12 +2733,12 @@ match_template ()
reverse match 3 operand instructions, and all 3
operand instructions only need to be checked for
register consistency between operands 2 and 3. */
- overlap2 = i.types[2] & t->operand_types[2];
- if (!MATCH (overlap2, i.types[2], t->operand_types[2])
+ overlap2 = i.types[2] & operand_types[2];
+ if (!MATCH (overlap2, i.types[2], operand_types[2])
|| !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1],
- t->operand_types[1],
+ operand_types[1],
overlap2, i.types[2],
- t->operand_types[2]))
+ operand_types[2]))
continue;
}
@@ -2719,7 +2766,7 @@ match_template ()
{
if (!intel_syntax
&& ((i.types[0] & JumpAbsolute)
- != (t->operand_types[0] & JumpAbsolute)))
+ != (operand_types[0] & JumpAbsolute)))
{
as_warn (_("indirect %s without `*'"), t->name);
}
@@ -2735,6 +2782,11 @@ match_template ()
/* Copy the template we found. */
i.tm = *t;
+
+ if (addr_prefix_disp != -1)
+ i.tm.operand_types[addr_prefix_disp]
+ = operand_types[addr_prefix_disp];
+
if (found_reverse_match)
{
/* If we found a reverse match we must alter the opcode
@@ -2743,8 +2795,8 @@ match_template ()
i.tm.base_opcode ^= found_reverse_match;
- i.tm.operand_types[0] = t->operand_types[1];
- i.tm.operand_types[1] = t->operand_types[0];
+ i.tm.operand_types[0] = operand_types[1];
+ i.tm.operand_types[1] = operand_types[0];
}
return 1;
--- binutils/gas/testsuite/gas/i386/addr16.d.moff 2006-09-22 14:13:12.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/addr16.d 2006-09-22 14:08:58.000000000 -0700
@@ -0,0 +1,15 @@
+#objdump: -drw
+#name: i386 16-bit addressing in 32-bit mode.
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ ]*0:[ ]+67 a0 98 08 [ ]+addr16[ ]+mov[ ]+0x898,%al
+[ ]*4:[ ]+67 66 a1 98 08 [ ]+addr16[ ]+mov[ ]+0x898,%ax
+[ ]*9:[ ]+67 a1 98 08 [ ]+addr16[ ]+mov[ ]+0x898,%eax
+[ ]*d:[ ]+67 a2 98 08 [ ]+addr16[ ]+mov[ ]+%al,0x898
+[ ]*11:[ ]+67 66 a3 98 08 [ ]+addr16[ ]+mov[ ]+%ax,0x898
+[ ]*16:[ ]+67 a3 98 08[ ]+addr16[ ]+mov[ ]+%eax,0x898
+#pass
--- binutils/gas/testsuite/gas/i386/addr16.s.moff 2006-09-22 14:13:12.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/addr16.s 2006-09-22 13:46:44.000000000 -0700
@@ -0,0 +1,7 @@
+ .text
+ addr16 mov 0x0898,%al
+ addr16 mov 0x0898,%ax
+ addr16 mov 0x0898,%eax
+ addr16 mov %al,0x0898
+ addr16 mov %ax,0x0898
+ addr16 mov %eax,0x0898
--- binutils/gas/testsuite/gas/i386/addr32.d.moff 2006-09-22 14:13:12.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/addr32.d 2006-09-22 14:10:00.000000000 -0700
@@ -0,0 +1,15 @@
+#objdump: -drw -mi8086
+#name: i386 32-bit addressing in 16-bit mode.
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ ]*0:[ ]+67 a0 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%al
+[ ]*6:[ ]+67 a1 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%ax
+[ ]*c:[ ]+67 66 a1 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%eax
+[ ]*13:[ ]+67 a2 98 08 60 00[ ]+addr32[ ]+mov[ ]+%al,0x600898
+[ ]*19:[ ]+67 a3 98 08 60 00[ ]+addr32[ ]+mov[ ]+%ax,0x600898
+[ ]*1f:[ ]+67 66 a3 98 08 60 00[ ]+addr32[ ]+mov[ ]+%eax,0x600898
+#pass
--- binutils/gas/testsuite/gas/i386/addr32.s.moff 2006-09-22 14:13:12.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/addr32.s 2006-09-22 14:06:16.000000000 -0700
@@ -0,0 +1,8 @@
+ .text
+ .code16
+ addr32 mov 0x600898,%al
+ addr32 mov 0x600898,%ax
+ addr32 mov 0x600898,%eax
+ addr32 mov %al,0x600898
+ addr32 mov %ax,0x600898
+ addr32 mov %eax,0x600898
--- binutils/gas/testsuite/gas/i386/i386.exp.moff 2006-09-21 13:55:33.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/i386.exp 2006-09-22 14:02:15.000000000 -0700
@@ -81,6 +81,8 @@ if [expr ([istarget "i*86-*-*"] || [ist
run_dump_test "nops-2"
run_dump_test "nops-2-i386"
run_dump_test "nops-2-merom"
+ run_dump_test "addr16"
+ run_dump_test "addr32"
# These tests require support for 8 and 16 bit relocs,
# so we only run them for ELF and COFF targets.
--- binutils/gas/testsuite/gas/i386/x86-64-addr32.d.moff 2006-09-21 13:55:33.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/x86-64-addr32.d 2006-09-22 13:44:25.000000000 -0700
@@ -11,4 +11,12 @@ Disassembly of section .text:
[ ]*8:[ ]+67 49 8d 80 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0\(%r8d?\),%rax.*
[ ]*10:[ ]+67 48 8d 05 00 00 00 00[ ]+addr32[ ]+lea[ ]+0\(%[re]ip\),%rax.*
[ ]*18:[ ]+67 48 8d 04 25 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0,%rax.*
+[ ]*21:[ ]+67 a0 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%al
+[ ]*27:[ ]+67 66 a1 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%ax
+[ ]*2e:[ ]+67 a1 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%eax
+[ ]*34:[ ]+67 48 a1 98 08 60 00[ ]+addr32[ ]+mov[ ]+0x600898,%rax
+[ ]*3b:[ ]+67 a2 98 08 60 00[ ]+addr32[ ]+mov[ ]+%al,0x600898
+[ ]*41:[ ]+67 66 a3 98 08 60 00[ ]+addr32[ ]+mov[ ]+%ax,0x600898
+[ ]*48:[ ]+67 a3 98 08 60 00[ ]+addr32[ ]+mov[ ]+%eax,0x600898
+[ ]*4e:[ ]+67 48 a3 98 08 60 00[ ]+addr32[ ]+mov[ ]+%rax,0x600898
#pass
--- binutils/gas/testsuite/gas/i386/x86-64-addr32.s.moff 2004-07-21 09:09:43.000000000 -0700
+++ binutils/gas/testsuite/gas/i386/x86-64-addr32.s 2006-09-22 13:39:49.000000000 -0700
@@ -3,3 +3,11 @@
lea symbol(%r8d), %rax
addr32 lea symbol(%rip), %rax
addr32 lea symbol, %rax
+ addr32 mov 0x600898,%al
+ addr32 mov 0x600898,%ax
+ addr32 mov 0x600898,%eax
+ addr32 mov 0x600898,%rax
+ addr32 mov %al,0x600898
+ addr32 mov %ax,0x600898
+ addr32 mov %eax,0x600898
+ addr32 mov %rax,0x600898
--- binutils/opcodes/i386-dis.c.moff 2006-09-21 13:55:24.000000000 -0700
+++ binutils/opcodes/i386-dis.c 2006-09-22 13:28:27.000000000 -0700
@@ -4693,7 +4693,8 @@ OP_OFF64 (int bytemode, int sizeflag)
{
bfd_vma off;
- if (address_mode != mode_64bit)
+ if (address_mode != mode_64bit
+ || (prefixes & PREFIX_ADDR))
{
OP_OFF (bytemode, sizeflag);
return;