public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] gas/x86-64: properly distinguish low and high register ranges
@ 2012-07-24 14:14 Jan Beulich
       [not found] ` <CAMe9rOrY+ECKpfYM23heJB4Ma1BT9aFd2+-z1oVdhq3EiXwdRQ@mail.gmail.com>
  0 siblings, 1 reply; 9+ messages in thread
From: Jan Beulich @ 2012-07-24 14:14 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 4805 bytes --]

There were several cases where the registers in the REX encoded range
got treated identically to the ones in the base range, due to not
paying attention to the fact that reg_entry's reg_num field doesn't
fully specify the register number (reg_flags also needs to be checked
for RegRex). This patch introduces and uses a new (inline) function to
obtain the full register number, and uses it to fix all those cases.

2012-07-24  Jan Beulich <jbeulich@suse.com>

	* config/tc-i386.c (register_number): New function.
	(build_vex_prefix, process_immext, process_operands,
	build_modrm_byte, i386_index_check): Use it.

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1758,6 +1758,17 @@ operand_type_register_match (i386_operan
 }
 
 static INLINE unsigned int
+register_number (const reg_entry *r)
+{
+  unsigned int nr = r->reg_num;
+
+  if (r->reg_flags & RegRex)
+    nr += 8;
+
+  return nr;
+}
+
+static INLINE unsigned int
 mode_from_disp_size (i386_operand_type t)
 {
   if (t.bitfield.disp8)
@@ -2830,12 +2841,7 @@ build_vex_prefix (const insn_template *t
 
   /* Check register specifier.  */
   if (i.vex.register_specifier)
-    {
-      register_specifier = i.vex.register_specifier->reg_num;
-      if ((i.vex.register_specifier->reg_flags & RegRex))
-	register_specifier += 8;
-      register_specifier = ~register_specifier & 0xf;
-    }
+    register_specifier = ~register_number (i.vex.register_specifier) & 0xf;
   else
     register_specifier = 0xf;
 
@@ -2976,14 +2982,13 @@ process_immext (void)
 
   if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0)
     {
-      /* SSE3 Instructions have the fixed operands with an opcode
-	 suffix which is coded in the same place as an 8-bit immediate
-	 field would be.  Here we check those operands and remove them
-	 afterwards.  */
+      /* MONITOR/MWAIT have fixed operands with an opcode suffix which
+	 is coded in the same place as an 8-bit immediate field would be.
+	 Here we check those operands and remove them afterwards.  */
       unsigned int x;
 
       for (x = 0; x < i.operands; x++)
-	if (i.op[x].regs->reg_num != x)
+	if (register_number (i.op[x].regs) != x)
 	  as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
 		  register_prefix, i.op[x].regs->reg_name, x + 1,
 		  i.tm.name);
@@ -5075,7 +5080,7 @@ process_operands (void)
 	{
 	  /* The first operand is implicit and must be xmm0.  */
 	  gas_assert (operand_type_equal (&i.types[0], &regxmm));
-	  if (i.op[0].regs->reg_num != 0)
+	  if (register_number (i.op[0].regs) != 0)
 	    return bad_implicit_operand (1);
 
 	  if (i.tm.opcode_modifier.vexsources == VEX3SOURCES)
@@ -5149,7 +5154,7 @@ duplicate:
       gas_assert (i.reg_operands
 		  && (operand_type_equal (&i.types[0], &regxmm)
 		      || operand_type_equal (&i.types[0], &regymm)));
-      if (i.op[0].regs->reg_num != 0)
+      if (register_number (i.op[0].regs) != 0)
 	return bad_implicit_operand (i.types[0].bitfield.regxmm);
 
       for (j = 1; j < i.operands; j++)
@@ -5352,10 +5357,7 @@ build_modrm_byte (void)
                       || operand_type_equal (&i.tm.operand_types[reg_slot],
                                              &regymm));
           exp->X_op = O_constant;
-          exp->X_add_number
-              = ((i.op[reg_slot].regs->reg_num
-                  + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0))
-		 << 4);
+          exp->X_add_number = register_number (i.op[reg_slot].regs) << 4;
         }
       else
         {
@@ -5399,9 +5401,7 @@ build_modrm_byte (void)
 		      || operand_type_equal (&i.tm.operand_types[reg_slot],
 					     &regymm));
           i.op[imm_slot].imms->X_add_number
-              |= ((i.op[reg_slot].regs->reg_num
-                   + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0))
-		  << 4);
+              |= register_number (i.op[reg_slot].regs) << 4;
         }
 
       gas_assert (operand_type_equal (&i.tm.operand_types[nds], &regxmm)
@@ -7314,7 +7314,7 @@ i386_index_check (const char *operand_st
 		   ? i.base_reg->reg_type.bitfield.reg32
 		   : i.base_reg->reg_type.bitfield.reg16))
 	ok = 0;
-      else if (i.base_reg->reg_num != expected)
+      else if (register_number (i.base_reg) != expected)
 	ok = -1;
 
       if (ok < 0)
@@ -7329,7 +7329,7 @@ i386_index_check (const char *operand_st
 		 : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
 		   ? i386_regtab[j].reg_type.bitfield.reg32
 		   : i386_regtab[j].reg_type.bitfield.reg16)
-		&& i386_regtab[j].reg_num == expected)
+		&& register_number(i386_regtab + j) == expected)
 	      break;
 	  gas_assert (j < i386_regtab_size);
 	  as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"),



[-- Attachment #2: binutils-mainline-x86-register-number.patch --]
[-- Type: text/plain, Size: 4801 bytes --]

There were several cases where the registers in the REX encoded range
got treated identically to the ones in the base range, due to not
paying attention to the fact that reg_entry's reg_num field doesn't
fully specify the register number (reg_flags also needs to be checked
for RegRex). This patch introduces and uses a new (inline) function to
obtain the full register number, and uses it to fix all those cases.

2012-07-24  Jan Beulich <jbeulich@suse.com>

	* config/tc-i386.c (register_number): New function.
	(build_vex_prefix, process_immext, process_operands,
	build_modrm_byte, i386_index_check): Use it.

--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -1758,6 +1758,17 @@ operand_type_register_match (i386_operan
 }
 
 static INLINE unsigned int
+register_number (const reg_entry *r)
+{
+  unsigned int nr = r->reg_num;
+
+  if (r->reg_flags & RegRex)
+    nr += 8;
+
+  return nr;
+}
+
+static INLINE unsigned int
 mode_from_disp_size (i386_operand_type t)
 {
   if (t.bitfield.disp8)
@@ -2830,12 +2841,7 @@ build_vex_prefix (const insn_template *t
 
   /* Check register specifier.  */
   if (i.vex.register_specifier)
-    {
-      register_specifier = i.vex.register_specifier->reg_num;
-      if ((i.vex.register_specifier->reg_flags & RegRex))
-	register_specifier += 8;
-      register_specifier = ~register_specifier & 0xf;
-    }
+    register_specifier = ~register_number (i.vex.register_specifier) & 0xf;
   else
     register_specifier = 0xf;
 
@@ -2976,14 +2982,13 @@ process_immext (void)
 
   if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0)
     {
-      /* SSE3 Instructions have the fixed operands with an opcode
-	 suffix which is coded in the same place as an 8-bit immediate
-	 field would be.  Here we check those operands and remove them
-	 afterwards.  */
+      /* MONITOR/MWAIT have fixed operands with an opcode suffix which
+	 is coded in the same place as an 8-bit immediate field would be.
+	 Here we check those operands and remove them afterwards.  */
       unsigned int x;
 
       for (x = 0; x < i.operands; x++)
-	if (i.op[x].regs->reg_num != x)
+	if (register_number (i.op[x].regs) != x)
 	  as_bad (_("can't use register '%s%s' as operand %d in '%s'."),
 		  register_prefix, i.op[x].regs->reg_name, x + 1,
 		  i.tm.name);
@@ -5075,7 +5080,7 @@ process_operands (void)
 	{
 	  /* The first operand is implicit and must be xmm0.  */
 	  gas_assert (operand_type_equal (&i.types[0], &regxmm));
-	  if (i.op[0].regs->reg_num != 0)
+	  if (register_number (i.op[0].regs) != 0)
 	    return bad_implicit_operand (1);
 
 	  if (i.tm.opcode_modifier.vexsources == VEX3SOURCES)
@@ -5149,7 +5154,7 @@ duplicate:
       gas_assert (i.reg_operands
 		  && (operand_type_equal (&i.types[0], &regxmm)
 		      || operand_type_equal (&i.types[0], &regymm)));
-      if (i.op[0].regs->reg_num != 0)
+      if (register_number (i.op[0].regs) != 0)
 	return bad_implicit_operand (i.types[0].bitfield.regxmm);
 
       for (j = 1; j < i.operands; j++)
@@ -5352,10 +5357,7 @@ build_modrm_byte (void)
                       || operand_type_equal (&i.tm.operand_types[reg_slot],
                                              &regymm));
           exp->X_op = O_constant;
-          exp->X_add_number
-              = ((i.op[reg_slot].regs->reg_num
-                  + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0))
-		 << 4);
+          exp->X_add_number = register_number (i.op[reg_slot].regs) << 4;
         }
       else
         {
@@ -5399,9 +5401,7 @@ build_modrm_byte (void)
 		      || operand_type_equal (&i.tm.operand_types[reg_slot],
 					     &regymm));
           i.op[imm_slot].imms->X_add_number
-              |= ((i.op[reg_slot].regs->reg_num
-                   + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0))
-		  << 4);
+              |= register_number (i.op[reg_slot].regs) << 4;
         }
 
       gas_assert (operand_type_equal (&i.tm.operand_types[nds], &regxmm)
@@ -7314,7 +7314,7 @@ i386_index_check (const char *operand_st
 		   ? i.base_reg->reg_type.bitfield.reg32
 		   : i.base_reg->reg_type.bitfield.reg16))
 	ok = 0;
-      else if (i.base_reg->reg_num != expected)
+      else if (register_number (i.base_reg) != expected)
 	ok = -1;
 
       if (ok < 0)
@@ -7329,7 +7329,7 @@ i386_index_check (const char *operand_st
 		 : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX]
 		   ? i386_regtab[j].reg_type.bitfield.reg32
 		   : i386_regtab[j].reg_type.bitfield.reg16)
-		&& i386_regtab[j].reg_num == expected)
+		&& register_number(i386_regtab + j) == expected)
 	      break;
 	  gas_assert (j < i386_regtab_size);
 	  as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"),

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-08-07 13:56 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-24 14:14 [PATCH] gas/x86-64: properly distinguish low and high register ranges Jan Beulich
     [not found] ` <CAMe9rOrY+ECKpfYM23heJB4Ma1BT9aFd2+-z1oVdhq3EiXwdRQ@mail.gmail.com>
2012-07-25  6:56   ` Jan Beulich
2012-07-30 16:05     ` H.J. Lu
2012-07-31  6:24       ` Jan Beulich
2012-07-31 15:49         ` H.J. Lu
2012-07-31 16:28           ` Jan Beulich
2012-07-31 18:45             ` H.J. Lu
2012-08-07 10:29               ` [PATCH, v2] " Jan Beulich
2012-08-07 14:02                 ` H.J. Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).