diff options
author | Maciej W. Rozycki <macro@imgtec.com> | 2016-06-25 00:49:10 +0100 |
---|---|---|
committer | Maciej W. Rozycki <macro@imgtec.com> | 2016-06-25 00:54:59 +0100 |
commit | 88a7ef1689279e498354094e123191926a801002 (patch) | |
tree | b0f603e9cac70bcaca933b4d1d1d3b4fe4413e5e /gas/config/tc-mips.c | |
parent | 2907f41490b2b5602f47c5acdf9ad7ae94eaeff9 (diff) | |
download | gdb-88a7ef1689279e498354094e123191926a801002.zip gdb-88a7ef1689279e498354094e123191926a801002.tar.gz gdb-88a7ef1689279e498354094e123191926a801002.tar.bz2 |
MIPS16/GAS: Restore unsupported relocation diagnostics
Correct a MIPS16 relocation handling regression in GAS introduced with:
commit 177b4a6ad0047c8995fbc55016bc4f4b68d53b4a
Author: Alexandre Oliva <aoliva@redhat.com>
Date: Mon Mar 18 18:56:18 2002 +0000
discussed at <https://sourceware.org/ml/binutils/2002-03/msg00345.html>,
which removed a preparatory call to `mips16_extended_frag' previously
made from `md_estimate_size_before_relax'. As a result the function is
never called with its `sec' parameter non-NULL and consequently all the
unsupported relocation checks within are dead and never trigger, causing
any unhandled relocations to silently resolve to 0. Unfortunately there
was no sufficient test suite coverage back then to catch this.
Remove all dead code then, and all the associated comments. Update the
remaining call to `mips16_extended_frag' from `mips_relax_frag' to pass
the relocation section as the `sec' parameter and use it to mark frags
which require an external relocation, as extended. Finally handle any
outstanding MIPS16 relocations in `md_convert_frag' and report an error
since we don't support any except with percent operators.
gas/
* config/tc-mips.c (append_insn): Use any `O_symbol' expression
unchanged with relaxed MIPS16 instructions.
(mips16_extended_frag): Adjust accordingly. Return 1 right
away if a relocation will be required for the symbol requested.
Remove dead first relaxation pass code.
(mips_relax_frag): Pass `sec' down to `mips16_extended_frag'.
(md_convert_frag): Adjust symbol value calculation. Raise an
error if a relocation is required for the symbol requested.
* testsuite/gas/mips/mips16@relax-swap3.d: Remove dump patterns,
add error output.
* testsuite/gas/mips/mips16@relax-swap3.l: New error output.
* testsuite/gas/mips/mips16-pcrel-relax-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-relax-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-relax-2.d: New test.
* testsuite/gas/mips/mips16-pcrel-relax-3.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-2.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-3.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-4.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-5.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-6.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-7.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-0.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-1.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-2.d: New test.
* testsuite/gas/mips/mips16-pcrel-addend-3.d: New test.
* testsuite/gas/mips/mips16-pcrel-absolute.d: New test.
* testsuite/gas/mips/mips16-branch-reloc-0.d: New test.
* testsuite/gas/mips/mips16-branch-reloc-1.d: New test.
* testsuite/gas/mips/mips16-branch-reloc-2.d: New test.
* testsuite/gas/mips/mips16-branch-reloc-3.d: New test.
* testsuite/gas/mips/mips16-branch-addend-0.d: New test.
* testsuite/gas/mips/mips16-branch-addend-1.d: New test.
* testsuite/gas/mips/mips16-branch-addend-2.d: New test.
* testsuite/gas/mips/mips16-branch-addend-3.d: New test.
* testsuite/gas/mips/mips16-branch-absolute.d: New test.
* testsuite/gas/mips/mips16-absolute-reloc-0.d: New test.
* testsuite/gas/mips/mips16-absolute-reloc-1.d: New test.
* testsuite/gas/mips/mips16-absolute-reloc-2.d: New test.
* testsuite/gas/mips/mips16-absolute-reloc-3.d: New test.
* testsuite/gas/mips/mips16-pcrel-reloc-2.l: New error output.
* testsuite/gas/mips/mips16-pcrel-reloc-3.l: New error output.
* testsuite/gas/mips/mips16-pcrel-reloc-6.l: New error output.
* testsuite/gas/mips/mips16-pcrel-reloc-7.l: New error output.
* testsuite/gas/mips/mips16-pcrel-addend-2.l: New error output.
* testsuite/gas/mips/mips16-pcrel-addend-3.l: New error output.
* testsuite/gas/mips/mips16-pcrel-absolute.l: New error output.
* testsuite/gas/mips/mips16-branch-reloc-2.l: New error output.
* testsuite/gas/mips/mips16-branch-reloc-3.l: New error output.
* testsuite/gas/mips/mips16-branch-addend-2.l: New error output.
* testsuite/gas/mips/mips16-branch-addend-3.l: New error output.
* testsuite/gas/mips/mips16-branch-absolute.l: New error output.
* testsuite/gas/mips/mips16-absolute-reloc-2.l: New error output.
* testsuite/gas/mips/mips16-absolute-reloc-3.l: New error output.
* testsuite/gas/mips/mips16-pcrel-relax-0.s: New test source.
* testsuite/gas/mips/mips16-pcrel-relax-2.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-0.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-1.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-2.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-3.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-4.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-5.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-6.s: New test source.
* testsuite/gas/mips/mips16-pcrel-reloc-7.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-0.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-1.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-2.s: New test source.
* testsuite/gas/mips/mips16-pcrel-addend-3.s: New test source.
* testsuite/gas/mips/mips16-pcrel-absolute.s: New test source.
* testsuite/gas/mips/mips16-branch-reloc-0.s: New test source.
* testsuite/gas/mips/mips16-branch-reloc-1.s: New test source.
* testsuite/gas/mips/mips16-branch-reloc-2.s: New test source.
* testsuite/gas/mips/mips16-branch-reloc-3.s: New test source.
* testsuite/gas/mips/mips16-branch-addend-0.s: New test source.
* testsuite/gas/mips/mips16-branch-addend-1.s: New test source.
* testsuite/gas/mips/mips16-branch-addend-2.s: New test source.
* testsuite/gas/mips/mips16-branch-addend-3.s: New test source.
* testsuite/gas/mips/mips16-branch-absolute.s: New test source.
* testsuite/gas/mips/mips16-absolute-reloc-0.s: New test source.
* testsuite/gas/mips/mips16-absolute-reloc-1.s: New test source.
* testsuite/gas/mips/mips16-absolute-reloc-2.s: New test source.
* testsuite/gas/mips/mips16-absolute-reloc-3.s: New test source.
* testsuite/gas/mips/mips.exp: Run the new tests.
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r-- | gas/config/tc-mips.c | 101 |
1 files changed, 48 insertions, 53 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index bbb604a..ab2ea0c 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -7307,15 +7307,31 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, } else if (mips_opts.mips16 && *reloc_type > BFD_RELOC_UNUSED) { + symbolS *symbol; + offsetT offset; + /* We need to set up a variant frag. */ gas_assert (address_expr != NULL); + /* Pass any `O_symbol' expression unchanged as an `expr_section' + symbol created by `make_expr_symbol' may not get a necessary + external relocation produced. */ + if (address_expr->X_op == O_symbol) + { + symbol = address_expr->X_add_symbol; + offset = address_expr->X_add_number; + } + else + { + symbol = make_expr_symbol (address_expr); + offset = 0; + } add_relaxed_insn (ip, 4, 0, RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED, forced_insn_length == 2, forced_insn_length == 4, delayed_branch_p (&history[0]), history[0].mips16_absolute_jump_p), - make_expr_symbol (address_expr), 0); + symbol, offset); } else if (mips_opts.mips16 && insn_length (ip) == 2) { @@ -16731,12 +16747,17 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch) if (RELAX_MIPS16_USER_EXT (fragp->fr_subtype)) return 1; + symsec = S_GET_SEGMENT (fragp->fr_symbol); type = RELAX_MIPS16_TYPE (fragp->fr_subtype); operand = mips16_immed_operand (type, FALSE); + if (S_FORCE_RELOC (fragp->fr_symbol, TRUE) + || (operand->root.type == OP_PCREL + ? sec != symsec + : !bfd_is_abs_section (symsec))) + return 1; sym_frag = symbol_get_frag (fragp->fr_symbol); - val = S_GET_VALUE (fragp->fr_symbol); - symsec = S_GET_SEGMENT (fragp->fr_symbol); + val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; if (operand->root.type == OP_PCREL) { @@ -16744,47 +16765,16 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch) addressT addr; offsetT maxtiny; - /* We won't have the section when we are called from - mips_relax_frag. However, we will always have been called - from md_estimate_size_before_relax first. If this is a - branch to a different section, we mark it as such. If SEC is - NULL, and the frag is not marked, then it must be a branch to - the same section. */ - pcrel_op = (const struct mips_pcrel_operand *) operand; - if (sec == NULL) - { - if (RELAX_MIPS16_LONG_BRANCH (fragp->fr_subtype)) - return 1; - } - else - { - /* Must have been called from md_estimate_size_before_relax. */ - if (symsec != sec) - { - fragp->fr_subtype = - RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype); - - /* FIXME: We should support this, and let the linker - catch branches and loads that are out of range. */ - as_bad_where (fragp->fr_file, fragp->fr_line, - _("unsupported PC relative reference to different section")); + if (RELAX_MIPS16_LONG_BRANCH (fragp->fr_subtype)) + return 1; - return 1; - } - if (fragp != sym_frag && sym_frag->fr_address == 0) - /* Assume non-extended on the first relaxation pass. - The address we have calculated will be bogus if this is - a forward branch to another frag, as the forward frag - will have fr_address == 0. */ - return 0; - } + pcrel_op = (const struct mips_pcrel_operand *) operand; - /* In this case, we know for sure that the symbol fragment is in - the same section. If the relax_marker of the symbol fragment - differs from the relax_marker of this fragment, we have not - yet adjusted the symbol fragment fr_address. We want to add - in STRETCH in order to get a better estimate of the address. - This particularly matters because of the shift bits. */ + /* If the relax_marker of the symbol fragment differs from the + relax_marker of this fragment, we have not yet adjusted the + symbol fragment fr_address. We want to add in STRETCH in + order to get a better estimate of the address. This + particularly matters because of the shift bits. */ if (stretch != 0 && sym_frag->relax_marker != fragp->relax_marker) { @@ -16844,9 +16834,8 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch) /* If any of the shifted bits are set, we must use an extended opcode. If the address depends on the size of this instruction, this can lead to a loop, so we arrange to always - use an extended opcode. We only check this when we are in - the main relaxation loop, when SEC is NULL. */ - if ((val & ((1 << operand->shift) - 1)) != 0 && sec == NULL) + use an extended opcode. */ + if ((val & ((1 << operand->shift) - 1)) != 0) { fragp->fr_subtype = RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype); @@ -16867,16 +16856,13 @@ mips16_extended_frag (fragS *fragp, asection *sec, long stretch) extended with the next value above maxtiny. */ maxtiny = mips_int_operand_max (operand); if (val == maxtiny + (1 << operand->shift) - && ! RELAX_MIPS16_EXTENDED (fragp->fr_subtype) - && sec == NULL) + && ! RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) { fragp->fr_subtype = RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype); return 1; } } - else if (symsec != absolute_section && sec != NULL) - as_bad_where (fragp->fr_file, fragp->fr_line, _("unsupported relocation")); return !mips16_immed_in_range_p (operand, BFD_RELOC_UNUSED, val); } @@ -17367,7 +17353,7 @@ mips_relax_frag (asection *sec, fragS *fragp, long stretch) if (! RELAX_MIPS16_P (fragp->fr_subtype)) return 0; - if (mips16_extended_frag (fragp, NULL, stretch)) + if (mips16_extended_frag (fragp, sec, stretch)) { if (RELAX_MIPS16_EXTENDED (fragp->fr_subtype)) return 0; @@ -17820,12 +17806,13 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) unsigned int user_length, length; unsigned long insn; bfd_boolean ext; + segT symsec; type = RELAX_MIPS16_TYPE (fragp->fr_subtype); operand = mips16_immed_operand (type, FALSE); ext = RELAX_MIPS16_EXTENDED (fragp->fr_subtype); - val = resolve_symbol_value (fragp->fr_symbol); + val = resolve_symbol_value (fragp->fr_symbol) + fragp->fr_offset; if (operand->root.type == OP_PCREL) { const struct mips_pcrel_operand *pcrel_op; @@ -17878,8 +17865,16 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) else user_length = 0; - mips16_immed (fragp->fr_file, fragp->fr_line, type, - BFD_RELOC_UNUSED, val, user_length, &insn); + symsec = S_GET_SEGMENT (fragp->fr_symbol); + if (S_FORCE_RELOC (fragp->fr_symbol, TRUE) + || (operand->root.type == OP_PCREL + ? asec != symsec + : !bfd_is_abs_section (symsec))) + as_bad_where (fragp->fr_file, fragp->fr_line, + _("unsupported relocation")); + else + mips16_immed (fragp->fr_file, fragp->fr_line, type, + BFD_RELOC_UNUSED, val, user_length, &insn); length = (ext ? 4 : 2); gas_assert (mips16_opcode_length (insn) == length); |