This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH v2] x86: ignore high register select bit(s) in 32- and 16-bit modes
- From: "Jan Beulich" <JBeulich at suse dot com>
- To: <binutils at sourceware dot org>
- Cc: "H.J. Lu" <hjl dot tools at gmail dot com>
- Date: Wed, 15 Nov 2017 00:57:30 -0700
- Subject: [PATCH v2] x86: ignore high register select bit(s) in 32- and 16-bit modes
- Authentication-results: sourceware.org; auth=none
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
---
v2: Parts of the test were moved to earlier, already approved (and
committed) patches.
gas/
2017-11-15 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.
opcodes/
2017-11-15 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.
--- 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 \$(0x)?1,%xmm0,%xmm0
+[ ]*[a-f0-9]+: 8f e8 78 c0 00 01 vprotb \$(0x)?1,\(%eax\),%xmm0
+[ ]*[a-f0-9]+: 8f e9 78 90 c0 vprotb %xmm0,%xmm0,%xmm0
+[ ]*[a-f0-9]+: 8f e9 78 90 00 vprotb %xmm0,\(%eax\),%xmm0
+[ ]*[a-f0-9]+: 8f e9 f8 90 00 vprotb \(%eax\),%xmm0,%xmm0
+[ ]*[a-f0-9]+: 8f c8 78 c0 c0 01 vprotb \$(0x)?1,%xmm0,%xmm0
+[ ]*[a-f0-9]+: 8f c8 78 c0 00 01 vprotb \$(0x)?1,\(%eax\),%xmm0
+[ ]*[a-f0-9]+: 8f c9 b8 90 c0 vprotb %xmm0,%xmm0,%xmm0
+[ ]*[a-f0-9]+: 8f c9 78 90 00 vprotb %xmm0,\(%eax\),%xmm0
+[ ]*[a-f0-9]+: 8f e9 38 90 c0 vprotb %xmm0,%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 \$(0x)?0,%xmm0,\(%eax\),%xmm0,%xmm0
+[ ]*[a-f0-9]+: c4 e3 39 48 00 00 vpermil2ps \$(0x)?0,%xmm0,\(%eax\),%xmm0,%xmm0
+[ ]*[a-f0-9]+: c4 e3 79 48 00 80 vpermil2ps \$(0x)?0,%xmm0,\(%eax\),%xmm0,%xmm0
[ ]*[a-f0-9]+: c3 ret[ ]*
#pass
--- a/gas/testsuite/gas/i386/noextreg.s
+++ b/gas/testsuite/gas/i386/noextreg.s
@@ -1,24 +1,79 @@
.intel_syntax noprefix
.text
ix86:
+ vpand xmm0, xmm0, xmm0
+ .code64
+ vpand xmm0, xmm0, xmm8
+ vpand xmm0, xmm8, xmm8
+ .code32
+
+ vpandd xmm0, xmm0, xmm0
+ .code64
+ vpandd xmm0, xmm0, xmm8
+ vpandd xmm0, xmm8, xmm0
+ vpandd xmm0, xmm16, xmm0
+ .code32
+
+ vpblendvb xmm0, xmm0, xmm0, xmm0
+ .code64
+ vpblendvb xmm0, xmm0, xmm8, xmm0
+ vpblendvb xmm0, xmm8, xmm0, xmm0
+ vpblendvb xmm0, xmm0, xmm0, xmm8
+ .code32
+
+ vpgatherdd xmm1{k7}, [eax+xmm0]
+ .code64
+ vpgatherdd xmm1{k7}, [r8+xmm0]
+ vpgatherdd xmm1{k7}, [rax+xmm16]
+ .code32
+
andn eax, eax, [eax]
.code64
+ andn eax, r8d, [rax]
+ andn eax, eax, [r8]
andn rax, rax, [rax]
.code32
tzmsk eax, [eax]
.code64
+ tzmsk eax, [r8]
+ tzmsk r8d, [rax]
tzmsk rax, [rax]
.code32
llwpcb eax
.code64
+ llwpcb r8d
llwpcb rax
.code32
+ vprotb xmm0, xmm0, 1
+ vprotb xmm0, [eax], 1
+ vprotb xmm0, xmm0, xmm0
+ vprotb xmm0, [eax], xmm0
+ vprotb xmm0, xmm0, [eax]
+ .code64
+ vprotb xmm0, xmm8, 1
+ vprotb xmm0, [r8], 1
+ .byte 0x8f, 0xc9, 0xb8, 0x90, 0xc0 # vprotb xmm0, xmm8, xmm0
+ vprotb xmm0, [r8], xmm0
+ vprotb xmm0, xmm0, xmm8
+ vprotb xmm0, xmm0, [r8]
+ .code32
+
vfmaddps xmm0, xmm0, [eax], xmm0
+ .code64
+ vfmaddps xmm0, xmm8, [rax], xmm0
+ vfmaddps xmm0, xmm0, [rax], xmm8
+ .code32
.byte 0xc4, 0xe3, 0x79, 0x68, 0x00, 0x0f # vfmaddps xmm0, xmm0, [eax], xmm0
+ vpermil2ps xmm0, xmm0, [eax], xmm0, 0
+ .code64
+ vpermil2ps xmm0, xmm8, [rax], xmm0, 0
+ vpermil2ps xmm0, xmm0, [rax], xmm8, 0
+ .code32
+
ret
.type ix86, @function
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -12809,11 +12809,6 @@ get_valid_dis386 (const struct dis386 *d
{
/* 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 *d
{
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 *d
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 *d
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 ATTRI
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
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 sizefla
}
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 sizefla
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
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