[binutils-gdb] x86: fix EVEX no-broadcast disassembly

Jan Beulich jbeulich@sourceware.org
Tue Sep 8 15:08:55 GMT 2026


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

commit 2ece447a4f3dcf1d96bcaca644dbf895e42194b8
Author: Rohan Shenoy <RohanRadhesh.Shenoy@amd.com>
Date:   Tue Sep 8 17:06:16 2026 +0200

    x86: fix EVEX no-broadcast disassembly
    
    - EVEX.W=1 alone does not make a valid broadcast. Hence we restrict it to
    x_mode operands only.
    - For the destination-memory-operand check, ins->obufp may not point to
      the start of op_out[0], hence we correct the position of this check.
    - VMOVDQU{8,16} (loads) were incorrectly marked as broadcastable.
    
    Suggested-by: Jan Beulich <jbeulich@suse.com>

Diff:
---
 gas/testsuite/gas/i386/bad-bcast-intel.d | 4 ++++
 gas/testsuite/gas/i386/bad-bcast.d       | 5 +++++
 gas/testsuite/gas/i386/bad-bcast.s       | 6 ++++++
 opcodes/i386-dis-evex-w.h                | 4 ++--
 opcodes/i386-dis.c                       | 9 ++++-----
 5 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/gas/testsuite/gas/i386/bad-bcast-intel.d b/gas/testsuite/gas/i386/bad-bcast-intel.d
index 29de3de299c..feb11e28c38 100644
--- a/gas/testsuite/gas/i386/bad-bcast-intel.d
+++ b/gas/testsuite/gas/i386/bad-bcast-intel.d
@@ -12,4 +12,8 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:[ 	]*66 90\s*xchg   ax,ax
 [ 	]*[a-f0-9]+:[ 	]*66 90\s*xchg   ax,ax
 [ 	]*[a-f0-9]+:[ 	]*62 c1 ff 38 2a 20\s*vcvtsi2sd xmm4,xmm0,\[eax\]{bad}
+[ 	]*[a-f0-9]+:[ 	]*62 f1 fe 58 7f 09\s*vmovdqu64 \[ecx\]{bad},zmm1
+[ 	]*[a-f0-9]+:[ 	]*62 f1 7f 58 6f 09\s*vmovdqu8 zmm1,\[ecx\]{bad}
+[ 	]*[a-f0-9]+:[ 	]*62 f1 ff 58 6f 09\s*vmovdqu16 zmm1,\[ecx\]{bad}
+[ 	]*[a-f0-9]+:[ 	]*62 f1 fe 58 6f 09\s*vmovdqu64 zmm1,\[ecx\]{bad}
 #pass
diff --git a/gas/testsuite/gas/i386/bad-bcast.d b/gas/testsuite/gas/i386/bad-bcast.d
index 4f829259994..bb819f48432 100644
--- a/gas/testsuite/gas/i386/bad-bcast.d
+++ b/gas/testsuite/gas/i386/bad-bcast.d
@@ -12,3 +12,8 @@ Disassembly of section .text:
  +[a-f0-9]+:	66 90\s+xchg   %ax,%ax
  +[a-f0-9]+:	66 90\s+xchg   %ax,%ax
  +[a-f0-9]+:	62 c1 ff 38 2a 20\s+vcvtsi2sd \(%eax\){bad},%xmm0,%xmm4
+ +[a-f0-9]+:	62 f1 fe 58 7f 09\s+vmovdqu64 %zmm1,\(%ecx\){bad}
+ +[a-f0-9]+:	62 f1 7f 58 6f 09\s+vmovdqu8 \(%ecx\){bad},%zmm1
+ +[a-f0-9]+:	62 f1 ff 58 6f 09\s+vmovdqu16 \(%ecx\){bad},%zmm1
+ +[a-f0-9]+:	62 f1 fe 58 6f 09\s+vmovdqu64 \(%ecx\){bad},%zmm1
+#pass
diff --git a/gas/testsuite/gas/i386/bad-bcast.s b/gas/testsuite/gas/i386/bad-bcast.s
index 6c55dcbbbd8..a85b38a0620 100644
--- a/gas/testsuite/gas/i386/bad-bcast.s
+++ b/gas/testsuite/gas/i386/bad-bcast.s
@@ -3,3 +3,9 @@
 	.byte 0x62, 0xc3, 0x8c, 0x1d, 0x66, 0x90, 0x66, 0x90, 0x66, 0x90
 # Invalid vcvtsi2sd with EVEX.b == 1.
 	.byte 0x62,0xc1,0xff,0x38,0x2a,0x20
+# Broadcast is invalid for stores.
+	.insn EVEX.f3.0f.W1 0x7f, %zmm1, (%ecx){1to8}
+# Invalid vmovdqu{8,16,64} with broadcast.
+	.insn EVEX.f2.0f.W0 0x6f, (%ecx){1to16}, %zmm1
+	.insn EVEX.f2.0f.W1 0x6f, (%ecx){1to8}, %zmm1
+	.insn EVEX.f3.0f.W1 0x6f, (%ecx){1to8}, %zmm1
diff --git a/opcodes/i386-dis-evex-w.h b/opcodes/i386-dis-evex-w.h
index e5b0cb805bb..f0f00e44143 100644
--- a/opcodes/i386-dis-evex-w.h
+++ b/opcodes/i386-dis-evex-w.h
@@ -41,8 +41,8 @@
   },
   /* EVEX_W_0F6F_P_3 */
   {
-    { "vmovdqu8",	{ XM, EXx }, 0 },
-    { "vmovdqu16",	{ XM, EXx }, 0 },
+    { "vmovdqu8",	{ XM, EXEvexXNoBcst }, 0 },
+    { "vmovdqu16",	{ XM, EXEvexXNoBcst }, 0 },
   },
   /* EVEX_W_0F70_P_2 */
   {
diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c
index ec1d149d9dc..44529d0aa82 100644
--- a/opcodes/i386-dis.c
+++ b/opcodes/i386-dis.c
@@ -12310,6 +12310,9 @@ OP_E_memory (instr_info *ins, int bytemode, int sizeflag)
   /* Handles EVEX other than APX EVEX-promoted instructions.  */
   if (ins->vex.evex && ins->evex_type == evex_default)
     {
+      /* Broadcast can only ever be valid for memory sources.  */
+      if (ins->vex.b && ins->obufp == ins->op_out[0])
+	ins->vex.no_broadcast = true;
 
       /* Zeroing-masking is invalid for memory destinations. Set the flag
 	 uniformly, as the consumer will inspect it only for the destination
@@ -12747,10 +12750,6 @@ OP_E_memory (instr_info *ins, int bytemode, int sizeflag)
     {
       ins->evex_used |= EVEX_b_used;
 
-      /* Broadcast can only ever be valid for memory sources.  */
-      if (ins->obufp == ins->op_out[0])
-	ins->vex.no_broadcast = true;
-
       if (!ins->vex.no_broadcast
 	  && (!ins->intel_syntax || !(ins->evex_used & EVEX_len_used)))
 	{
@@ -12774,7 +12773,7 @@ OP_E_memory (instr_info *ins, int bytemode, int sizeflag)
 	  else if (bytemode == q_mode
 		   || bytemode == ymmq_mode)
 	    ins->vex.no_broadcast = true;
-	  else if (ins->vex.w
+	  else if ((bytemode == x_mode && ins->vex.w)
 		   || bytemode == evex_half_bcst_xmmqdh_mode
 		   || bytemode == evex_half_bcst_xmmq_mode)
 	    {


More information about the Binutils-cvs mailing list