This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]