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.
This commit is contained in:
Alice Carlotti 2026-01-29 12:17:24 +00:00
parent 328a34f0db
commit 6095ea2efc
6 changed files with 25 additions and 63 deletions

View file

@ -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;
}
logsz = get_log2 (aarch64_get_qualifier_esize (opd1_qlf));
unsigned logsz = 0;
unsigned max_logsz;
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

View file

@ -0,0 +1,2 @@
#as: -march=armv8-a
#error_output: reloc-invalid-qualifiers.l

View file

@ -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\]

View file

@ -0,0 +1,4 @@
label:
# Test error handling for an incorrect register size
ldrb x0, [x0, #:lo12:label]

View file

@ -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 *);

View file

@ -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,