mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2026-08-27 00:26:02 -04:00
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:
parent
328a34f0db
commit
6095ea2efc
6 changed files with 25 additions and 63 deletions
|
|
@ -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
|
||||
|
|
|
|||
2
gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.d
Normal file
2
gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.d
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#as: -march=armv8-a
|
||||
#error_output: reloc-invalid-qualifiers.l
|
||||
4
gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.l
Normal file
4
gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.l
Normal 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\]
|
||||
4
gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.s
Normal file
4
gas/testsuite/gas/aarch64/reloc-invalid-qualifiers.s
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
label:
|
||||
# Test error handling for an incorrect register size
|
||||
ldrb x0, [x0, #:lo12:label]
|
||||
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue