From: Alice Carlotti Date: Thu, 29 Jan 2026 12:17:24 +0000 (+0000) Subject: aarch64: Fix ldst_lo12_determine_real_reloc_type X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6095ea2efce173ec8d91e2452485f63a6ba78abe;p=thirdparty%2Fbinutils-gdb.git 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 --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 , [, #:lo12:] - 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,