[binutils-gdb] aarch64: Fix ldst_lo12_determine_real_reloc_type

Alice Carlotti via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6095ea2efce173ec8d91e2452485f63a6ba78abe

commit 6095ea2efce173ec8d91e2452485f63a6ba78abe
Author: Alice Carlotti <[email protected]>
Date:   Thu Jan 29 12:17:24 2026 +0000

    aarch64: Fix ldst_lo12_determine_real_reloc_type
    
    Add fallback handling for an invalid choice of opd0_qlf, instead of
    hitting an assert when trying to use X registers in byte or half
    instructions.
    
    Additionally, simplify the code by inlining the relevant parts of
    aarch64_get_expected_qualifer, and by deducing the array index directly
    from the qualifier enum values (instead of looking up the element size
    and computing its log).
    
    This makes aarch64_get_expected_qualifier unused, so remove it.

Diff:
---
 gas/config/tc-aarch64.c                            | 25 ++++++-----
 .../gas/aarch64/reloc-invalid-qualifiers.d         |  2 +
 .../gas/aarch64/reloc-invalid-qualifiers.l         |  4 ++
 .../gas/aarch64/reloc-invalid-qualifiers.s         |  4 ++
 include/opcode/aarch64.h                           |  4 --
 opcodes/aarch64-opc.c                              | 49 ----------------------
 6 files changed, 25 insertions(+), 63 deletions(-)

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index b3b73daca47..b851868d3ff 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -6621,10 +6621,6 @@ process_movw_reloc_info (void)
 static inline bfd_reloc_code_real_type
 ldst_lo12_determine_real_reloc_type (void)
 {
-  unsigned logsz, max_logsz;
-  enum aarch64_opnd_qualifier opd0_qlf = inst.base.operands[0].qualifier;
-  enum aarch64_opnd_qualifier opd1_qlf = inst.base.operands[1].qualifier;
-
   const bfd_reloc_code_real_type reloc_ldst_lo12[5][5] = {
     {
       BFD_RELOC_AARCH64_LDST8_LO12,
@@ -6673,13 +6669,22 @@ ldst_lo12_determine_real_reloc_type (void)
 		  == BFD_RELOC_AARCH64_TLSLE_LDST_TPREL_LO12_NC));
   gas_assert (inst.base.opcode->operands[1] == AARCH64_OPND_ADDR_UIMM12);
 
-  if (opd1_qlf == AARCH64_OPND_QLF_NIL)
-    opd1_qlf =
-      aarch64_get_expected_qualifier (inst.base.opcode->qualifiers_list,
-				      1, opd0_qlf, 0);
-  gas_assert (opd1_qlf != AARCH64_OPND_QLF_NIL);
+  enum aarch64_opnd_qualifier opd0_qlf = inst.base.operands[0].qualifier;
+  enum aarch64_opnd_qualifier opd1_qlf = AARCH64_OPND_QLF_NIL;
+  const aarch64_opnd_qualifier_seq_t *qseq_list
+    = inst.base.opcode->qualifiers_list;
+  for (int i = 0; i < AARCH64_MAX_QLF_SEQ_NUM; ++i)
+    if (qseq_list[i][0] == opd0_qlf)
+      {
+	opd1_qlf = qseq_list[i][1];
+	break;
+      }
+
+  unsigned logsz = 0;
+  unsigned max_logsz;
 
-  logsz = get_log2 (aarch64_get_qualifier_esize (opd1_qlf));
+  if (opd1_qlf >= AARCH64_OPND_QLF_S_B && opd1_qlf <= AARCH64_OPND_QLF_S_Q)
+      logsz = opd1_qlf - AARCH64_OPND_QLF_S_B;
 
   if (inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12
       || inst.reloc.type == BFD_RELOC_AARCH64_TLSLD_LDST_DTPREL_LO12_NC
diff --git a/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.d b/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.d
new file mode 100644
index 00000000000..f36ede6e856
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.d
@@ -0,0 +1,2 @@
+#as: -march=armv8-a
+#error_output: reloc-invalid-qualifiers.l
diff --git a/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.l b/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.l
new file mode 100644
index 00000000000..1c77162c079
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.l
@@ -0,0 +1,4 @@
+[^ :]+: Assembler messages:
+[^ :]+:[0-9]+: Error: operand mismatch -- `ldrb x0,\[x0,#:lo12:label\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	ldrb w0, \[x0\]
diff --git a/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.s b/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.s
new file mode 100644
index 00000000000..f0c030a530c
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.s
@@ -0,0 +1,4 @@
+
+label:
+# Test error handling for an incorrect register size
+  ldrb	x0, [x0, #:lo12:label]
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index a604a66c573..8f0d1fb0c1f 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -2097,10 +2097,6 @@ aarch64_print_operand (char *, size_t, bfd_vma, const aarch64_opcode *,
 extern int
 aarch64_operand_index (const enum aarch64_opnd *, enum aarch64_opnd);
 
-extern aarch64_opnd_qualifier_t
-aarch64_get_expected_qualifier (const aarch64_opnd_qualifier_seq_t *, int,
-				const aarch64_opnd_qualifier_t, int);
-
 extern bool
 aarch64_is_destructive_by_operands (const aarch64_opcode *);
 
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index a1560a40eb3..589e6a49395 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -713,55 +713,6 @@ aarch64_zero_register_p (const aarch64_opnd_info *operand)
 	  && operand->reg.regno == 31);
 }
 
-/* Given qualifier sequence list QSEQ_LIST and the known qualifier KNOWN_QLF
-   for operand KNOWN_IDX, return the expected qualifier for operand IDX.
-
-   Return NIL if more than one expected qualifiers are found.  */
-
-aarch64_opnd_qualifier_t
-aarch64_get_expected_qualifier (const aarch64_opnd_qualifier_seq_t *qseq_list,
-				int idx,
-				const aarch64_opnd_qualifier_t known_qlf,
-				int known_idx)
-{
-  int i, saved_i;
-
-  /* Special case.
-
-     When the known qualifier is NIL, we have to assume that there is only
-     one qualifier sequence in the *QSEQ_LIST and return the corresponding
-     qualifier directly.  One scenario is that for instruction
-	PRFM <prfop>, [<Xn|SP>, #:lo12:<symbol>]
-     which has only one possible valid qualifier sequence
-	NIL, S_D
-     the caller may pass NIL in KNOWN_QLF to obtain S_D so that it can
-     determine the correct relocation type (i.e. LDST64_LO12) for PRFM.
-
-     Because the qualifier NIL has dual roles in the qualifier sequence:
-     it can mean no qualifier for the operand, or the qualifer sequence is
-     not in use (when all qualifiers in the sequence are NILs), we have to
-     handle this special case here.  */
-  if (known_qlf == AARCH64_OPND_QLF_NIL)
-    {
-      assert (qseq_list[0][known_idx] == AARCH64_OPND_QLF_NIL);
-      return qseq_list[0][idx];
-    }
-
-  for (i = 0, saved_i = -1; i < AARCH64_MAX_QLF_SEQ_NUM; ++i)
-    {
-      if (qseq_list[i][known_idx] == known_qlf)
-	{
-	  if (saved_i != -1)
-	    /* More than one sequences are found to have KNOWN_QLF at
-	       KNOWN_IDX.  */
-	    return AARCH64_OPND_QLF_NIL;
-	  saved_i = i;
-	}
-    }
-
-  return qseq_list[saved_i][idx];
-}
-
 enum operand_qualifier_kind
 {
   OQK_NIL,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.