From 5f847646eeb0107cb8c5e44c8bca3a4c88c91673 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 16 Nov 2017 13:56:45 +0100 Subject: [PATCH] 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 --- 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 e1aacffd964..de1b63d46b4 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2017-11-16 Jan Beulich + + * 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 * config/tc-i386.c (process_suffix): Ignore .no_qsuf outside of diff --git a/gas/testsuite/gas/i386/noextreg.d b/gas/testsuite/gas/i386/noextreg.d index 4b7f45d46ed..99579c9c677 100644 --- a/gas/testsuite/gas/i386/noextreg.d +++ b/gas/testsuite/gas/i386/noextreg.d @@ -6,13 +6,48 @@ Disassembly of section .text: 0+ : +[ ]*[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 f1205acf227..85fd26ed5a4 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 2cc35947bd9..6ea9c100bfb 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,14 @@ +2017-11-16 Jan Beulich + + (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 * 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 78a685ee471..64b47028fd4 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 -- 2.30.2