This is the mail archive of the binutils-cvs@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]

[binutils-gdb] x86: ignore high register select bit(s) in 32- and 16-bit modes


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5f847646eeb0107cb8c5e44c8bca3a4c88c91673

commit 5f847646eeb0107cb8c5e44c8bca3a4c88c91673
Author: Jan Beulich <jbeulich@novell.com>
Date:   Thu Nov 16 13:56:45 2017 +0100

    x86: ignore high register select bit(s) in 32- and 16-bit modes
    
    While commits 9889cbb14e ("Check invalid mask registers") and
    abfcb414b9 ("X86: Ignore REX_B bit for 32-bit XOP instructions") went a
    bit into the right direction, this wasn't quite enough:
    - VEX.vvvv has its high bit ignored
    - EVEX.vvvv has its high bit ignored together with EVEX.v'
    - the high bits of {,E}VEX.vvvv should not be prematurely zapped, to
      allow proper checking of them when the fields has to hold al ones
    - when the high bits of an immediate specify a register, bit 7 is
      ignored

Diff:
---
 gas/ChangeLog                     |  6 ++++
 gas/testsuite/gas/i386/noextreg.d | 35 +++++++++++++++++++++
 gas/testsuite/gas/i386/noextreg.s | 45 ++++++++++++++++++++++++---
 opcodes/ChangeLog                 | 11 +++++++
 opcodes/i386-dis.c                | 64 ++++++++++++++++++++++-----------------
 5 files changed, 129 insertions(+), 32 deletions(-)

diff --git a/gas/ChangeLog b/gas/ChangeLog
index e1aacff..de1b63d 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,11 @@
 2017-11-16  Jan Beulich  <jbeulich@suse.com>
 
+	* testsuite/gas/i386/noextreg.s: Add tests with register index
+	bit 3 set.
+	* testsuite/gas/i386/noextreg.d: Adjust expectations.
+
+2017-11-16  Jan Beulich  <jbeulich@suse.com>
+
 	* config/tc-i386.c (process_suffix): Ignore .no_qsuf outside of
 	64-bit mode.
 	* testsuite/gas/i386/ptwrite.s: Add test for memory operand
diff --git a/gas/testsuite/gas/i386/noextreg.d b/gas/testsuite/gas/i386/noextreg.d
index 4b7f45d..99579c9 100644
--- a/gas/testsuite/gas/i386/noextreg.d
+++ b/gas/testsuite/gas/i386/noextreg.d
@@ -6,13 +6,48 @@
 Disassembly of section .text:
 
 0+ <ix86>:
+[ 	]*[a-f0-9]+:	c5 f9 db c0          	vpand  %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 c1 79 db c0       	vpand  %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 c1 39 db c0       	vpand  %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	62 f1 7d 08 db c0    	vpandd %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	62 d1 7d 08 db c0    	vpandd %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	62 f1 3d 08 db c0    	vpandd %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	62 f1 7d 00 db c0    	vpandd %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 79 4c c0 00    	vpblendvb %xmm0,%xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 c3 79 4c c0 00    	vpblendvb %xmm0,%xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 39 4c c0 00    	vpblendvb %xmm0,%xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 79 4c c0 80    	vpblendvb %xmm0,%xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	62 f2 7d 0f 90 0c 00 	vpgatherdd \(%eax,%xmm0,1\),%xmm1\{%k7\}
+[ 	]*[a-f0-9]+:	62 d2 7d 0f 90 0c 00 	vpgatherdd \(%eax,%xmm0,1\),%xmm1\{%k7\}
+[ 	]*[a-f0-9]+:	62 f2 7d 07 90 0c 00 	vpgatherdd \(%eax,%xmm0,1\),%xmm1\{%k7\}
 [ 	]*[a-f0-9]+:	c4 e2 78 f2 00       	andn   \(%eax\),%eax,%eax
+[ 	]*[a-f0-9]+:	c4 e2 38 f2 00       	andn   \(%eax\),%eax,%eax
+[ 	]*[a-f0-9]+:	c4 c2 78 f2 00       	andn   \(%eax\),%eax,%eax
 [ 	]*[a-f0-9]+:	c4 e2 f8 f2 00       	andn   \(%eax\),%eax,%eax
 [ 	]*[a-f0-9]+:	8f e9 78 01 20       	tzmsk  \(%eax\),%eax
+[ 	]*[a-f0-9]+:	8f c9 78 01 20       	tzmsk  \(%eax\),%eax
+[ 	]*[a-f0-9]+:	8f e9 38 01 20       	tzmsk  \(%eax\),%eax
 [ 	]*[a-f0-9]+:	8f e9 f8 01 20       	tzmsk  \(%eax\),%eax
 [ 	]*[a-f0-9]+:	8f e9 78 12 c0       	llwpcb %eax
+[ 	]*[a-f0-9]+:	8f c9 78 12 c0       	llwpcb %eax
 [ 	]*[a-f0-9]+:	8f e9 f8 12 c0       	llwpcb %eax
+[ 	]*[a-f0-9]+:	8f e8 78 c0 c0 01    	vprotb \$0x1,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	8f c8 78 c0 c0 01    	vprotb \$0x1,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	8f e8 78 c0 00 01    	vprotb \$0x1,\(%eax\),%xmm0
+[ 	]*[a-f0-9]+:	8f c8 78 c0 00 01    	vprotb \$0x1,\(%eax\),%xmm0
+[ 	]*[a-f0-9]+:	8f e9 78 90 c0       	vprotb %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	8f c9 b8 90 c0       	vprotb %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	8f e9 38 90 c0       	vprotb %xmm0,%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	8f e9 78 90 00       	vprotb %xmm0,\(%eax\),%xmm0
+[ 	]*[a-f0-9]+:	8f c9 78 90 00       	vprotb %xmm0,\(%eax\),%xmm0
+[ 	]*[a-f0-9]+:	8f e9 f8 90 00       	vprotb \(%eax\),%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	8f c9 f8 90 00       	vprotb \(%eax\),%xmm0,%xmm0
 [ 	]*[a-f0-9]+:	c4 e3 79 68 00 00    	vfmaddps %xmm0,\(%eax\),%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 39 68 00 00    	vfmaddps %xmm0,\(%eax\),%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 79 68 00 80    	vfmaddps %xmm0,\(%eax\),%xmm0,%xmm0
 [ 	]*[a-f0-9]+:	c4 e3 79 68 00 0f    	vfmaddps %xmm0,\(%eax\),%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 79 48 00 00    	vpermil2ps \$0x0,%xmm0,\(%eax\),%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 39 48 00 00    	vpermil2ps \$0x0,%xmm0,\(%eax\),%xmm0,%xmm0
+[ 	]*[a-f0-9]+:	c4 e3 79 48 00 80    	vpermil2ps \$0x0,%xmm0,\(%eax\),%xmm0,%xmm0
 [ 	]*[a-f0-9]+:	c3                   	ret[ 	]*
 #pass
diff --git a/gas/testsuite/gas/i386/noextreg.s b/gas/testsuite/gas/i386/noextreg.s
index f1205ac..85fd26e 100644
--- a/gas/testsuite/gas/i386/noextreg.s
+++ b/gas/testsuite/gas/i386/noextreg.s
@@ -1,20 +1,57 @@
 	.intel_syntax noprefix
 	.text
 ix86:
+	vpand	xmm0, xmm0, xmm0
+	.byte	0xc4, 0xc1, 0x79, 0xdb, 0xc0
+	.byte	0xc4, 0xc1, 0x39, 0xdb, 0xc0
+
+	vpandd	xmm0, xmm0, xmm0
+	.byte	0x62, 0xd1, 0x7d, 0x08, 0xdb, 0xc0
+	.byte	0x62, 0xf1, 0x3d, 0x08, 0xdb, 0xc0
+	.byte	0x62, 0xf1, 0x7d, 0x00, 0xdb, 0xc0
+
+	vpblendvb xmm0, xmm0, xmm0, xmm0
+	.byte	0xc4, 0xc3, 0x79, 0x4c, 0xc0, 0x00
+	.byte	0xc4, 0xe3, 0x39, 0x4c, 0xc0, 0x00
+	.byte	0xc4, 0xe3, 0x79, 0x4c, 0xc0, 0x80
+
+	vpgatherdd xmm1{k7}, [eax+xmm0]
+	.byte	0x62, 0xd2, 0x7d, 0x0f, 0x90, 0x0c, 0x00
+	.byte	0x62, 0xf2, 0x7d, 0x07, 0x90, 0x0c, 0x00
+
 	andn	eax, eax, [eax]
-	# andn rax, rax, [rax]
+	.byte	0xc4, 0xe2, 0x38, 0xf2, 0x00
+	.byte	0xc4, 0xc2, 0x78, 0xf2, 0x00
 	.byte	0xc4, 0xe2, 0xf8, 0xf2, 0x00
 
 	tzmsk	eax, [eax]
-	# tzmsk rax, [rax]
+	.byte	0x8f, 0xc9, 0x78, 0x01, 0x20
+	.byte	0x8f, 0xe9, 0x38, 0x01, 0x20
 	.byte	0x8f, 0xe9, 0xf8, 0x01, 0x20
 
 	llwpcb	eax
-	# llwpcb rax
+	.byte	0x8f, 0xc9, 0x78, 0x12, 0xc0
 	.byte	0x8f, 0xe9, 0xf8, 0x12, 0xc0
 
+	vprotb	xmm0, xmm0, 1
+	.byte	0x8f, 0xc8, 0x78, 0xc0, 0xc0, 0x01
+	vprotb	xmm0, [eax], 1
+	.byte	0x8f, 0xc8, 0x78, 0xc0, 0x00, 0x01
+	vprotb	xmm0, xmm0, xmm0
+	.byte	0x8f, 0xc9, 0xb8, 0x90, 0xc0
+	.byte	0x8f, 0xe9, 0x38, 0x90, 0xc0
+	vprotb	xmm0, [eax], xmm0
+	.byte	0x8f, 0xc9, 0x78, 0x90, 0x00
+	vprotb	xmm0, xmm0, [eax]
+	.byte	0x8f, 0xc9, 0xf8, 0x90, 0x00
+
 	vfmaddps xmm0, xmm0, [eax], xmm0
-	# vfmaddps xmm0, xmm0, [eax], xmm0
+	.byte	0xc4, 0xe3, 0x39, 0x68, 0x00, 0x00
+	.byte	0xc4, 0xe3, 0x79, 0x68, 0x00, 0x80
 	.byte	0xc4, 0xe3, 0x79, 0x68, 0x00, 0x0f
 
+	vpermil2ps xmm0, xmm0, [eax], xmm0, 0
+	.byte	0xc4, 0xe3, 0x39, 0x48, 0x00, 0x00
+	.byte	0xc4, 0xe3, 0x79, 0x48, 0x00, 0x80
+
 	ret
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 2cc3594..6ea9c10 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,14 @@
+2017-11-16  Jan Beulich  <jbeulich@suse.com>
+
+	(get_valid_dis386): Never flag bad opcode when
+	vex.register_specifier is beyond 7. Always store all four
+	bits of it. Move 16-/32-bit override in EVEX handling after
+	all to be overridden bits have been set.
+	(OP_VEX): Mask vex.register_specifier outside of 64-bit mode.
+	Use rex to determine GPR register set.
+	(OP_EX_VexReg, OP_Vex_2src_1, OP_Vex_2src_2, OP_REG_VexI4,
+	OP_LWP_E): Mask vex.register_specifier outside of 64-bit mode.
+
 2017-11-15  Jan Beulich  <jbeulich@suse.com>
 
 	* i386-dis.c (OP_VEX, OP_LWPCB_E, OP_LWP_E): Use rex to
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index 78a685e..64b4702 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -12809,11 +12809,6 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info)
 	{
 	  /* In 16/32-bit mode REX_B is silently ignored.  */
 	  rex &= ~REX_B;
-	  if (vex.register_specifier > 0x7)
-	    {
-	      dp = &bad_opcode;
-	      return dp;
-	    }
 	}
 
       vex.length = (*codep & 0x4) ? 256 : 128;
@@ -12872,16 +12867,15 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info)
 	{
 	  if (vex.w)
 	    rex |= REX_W;
-	  vex.register_specifier = (~(*codep >> 3)) & 0xf;
 	}
       else
 	{
 	  /* For the 3-byte VEX prefix in 32-bit mode, the REX_B bit
 	     is ignored, other REX bits are 0 and the highest bit in
-	     VEX.vvvv is also ignored.  */
+	     VEX.vvvv is also ignored (but we mustn't clear it here).  */
 	  rex = 0;
-	  vex.register_specifier = (~(*codep >> 3)) & 0x7;
 	}
+      vex.register_specifier = (~(*codep >> 3)) & 0xf;
       vex.length = (*codep & 0x4) ? 256 : 128;
       switch ((*codep & 0x3))
 	{
@@ -12996,14 +12990,6 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info)
 	rex |= REX_W;
 
       vex.register_specifier = (~(*codep >> 3)) & 0xf;
-      if (address_mode != mode_64bit)
-	{
-	  /* In 16/32-bit mode silently ignore following bits.  */
-	  rex &= ~REX_B;
-	  vex.r = 1;
-	  vex.v = 1;
-	  vex.register_specifier &= 0x7;
-	}
 
       /* The U bit.  */
       if (!(*codep & 0x4))
@@ -13036,6 +13022,14 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info)
       vex.mask_register_specifier = *codep & 0x7;
       vex.zeroing = *codep & 0x80;
 
+      if (address_mode != mode_64bit)
+	{
+	  /* In 16/32-bit mode silently ignore following bits.  */
+	  rex &= ~REX_B;
+	  vex.r = 1;
+	  vex.v = 1;
+	}
+
       need_vex = 1;
       need_vex_reg = 1;
       codep++;
@@ -17098,11 +17092,10 @@ OP_VEX (int bytemode, int sizeflag ATTRIBUTE_UNUSED)
     return;
 
   reg = vex.register_specifier;
-  if (vex.evex)
-    {
-      if (!vex.v)
-	reg += 16;
-    }
+  if (address_mode != mode_64bit)
+    reg &= 7;
+  else if (vex.evex && !vex.v)
+    reg += 16;
 
   if (bytemode == vex_scalar_mode)
     {
@@ -17287,8 +17280,8 @@ OP_EX_VexReg (int bytemode, int sizeflag, int reg)
 	  if (rex & REX_B)
 	    reg += 8;
 	}
-      else if (reg > 7 && address_mode != mode_64bit)
-	BadOp ();
+      if (address_mode != mode_64bit)
+	reg &= 7;
     }
 
   switch (vex.length)
@@ -17380,7 +17373,13 @@ OP_Vex_2src_1 (int bytemode, int sizeflag)
     }
 
   if (vex.w)
-    oappend (names_xmm[vex.register_specifier]);
+    {
+      unsigned int reg = vex.register_specifier;
+
+      if (address_mode != mode_64bit)
+	reg &= 7;
+      oappend (names_xmm[reg]);
+    }
   else
     OP_Vex_2src (bytemode, sizeflag);
 }
@@ -17391,7 +17390,13 @@ OP_Vex_2src_2 (int bytemode, int sizeflag)
   if (vex.w)
     OP_Vex_2src (bytemode, sizeflag);
   else
-    oappend (names_xmm[vex.register_specifier]);
+    {
+      unsigned int reg = vex.register_specifier;
+
+      if (address_mode != mode_64bit)
+	reg &= 7;
+      oappend (names_xmm[reg]);
+    }
 }
 
 static void
@@ -17434,8 +17439,8 @@ OP_REG_VexI4 (int bytemode, int sizeflag ATTRIBUTE_UNUSED)
     abort ();
 
   reg >>= 4;
-  if (reg > 7 && address_mode != mode_64bit)
-    BadOp ();
+  if (address_mode != mode_64bit)
+    reg &= 7;
 
   switch (vex.length)
     {
@@ -17775,13 +17780,16 @@ static void
 OP_LWP_E (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED)
 {
   const char **names;
+  unsigned int reg = vex.register_specifier;
 
   if (rex & REX_W)
     names = names64;
   else
     names = names32;
 
-  oappend (names[vex.register_specifier]);
+  if (address_mode != mode_64bit)
+    reg &= 7;
+  oappend (names[reg]);
 }
 
 static void


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