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
This commit is contained in:
Jan Beulich 2017-11-16 13:56:45 +01:00 committed by Jan Beulich
parent 968a13f836
commit 5f847646ee
5 changed files with 129 additions and 32 deletions

View File

@ -1,3 +1,9 @@
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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