[binutils-gdb] aarch64: Fix ldst_lo12_determine_real_reloc_type

Alice Carlotti acarlotti@sourceware.org
Fri May 15 14:09:07 GMT 2026


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

commit 6095ea2efce173ec8d91e2452485f63a6ba78abe
Author: Alice Carlotti <alice.carlotti@arm.com>
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,


More information about the Binutils-cvs mailing list