diff options
author | Maciej W. Rozycki <macro@imgtec.com> | 2017-04-27 00:47:15 +0100 |
---|---|---|
committer | Maciej W. Rozycki <macro@imgtec.com> | 2017-04-27 00:50:57 +0100 |
commit | ce8ad8721313d288a05a95b62d95ca43db584ebb (patch) | |
tree | 4eb66ffed394520ed4396ce21f46a113ee62dbdd /gas/config | |
parent | 97d343d40012b1030f1fd219f91efcab180fb3ef (diff) | |
download | gdb-ce8ad8721313d288a05a95b62d95ca43db584ebb.zip gdb-ce8ad8721313d288a05a95b62d95ca43db584ebb.tar.gz gdb-ce8ad8721313d288a05a95b62d95ca43db584ebb.tar.bz2 |
MIPS/GAS: Fix `.option picX' handling with relaxation
Correct the handling of `.option pic0' and `.option pic2' GAS pseudo-ops
in relaxation and use the setting of `mips_pic' (which these directives
control) as at the time a relaxed frag has been created rather than the
final `mips_pic' setting at the end of the source file processed.
To do so record whether `mips_pic' is NO_PIC or not in the frag itself
and use this information throughout relaxation instead of `mips_pic' to
decide which of NO_PIC or SVR4_PIC to produce machine code for, fixing
code generation and removing a possible fatal failure reproducible with:
$ as -32 --relax-branch -o option-pic-relax-3.o option-pic-relax-3.s
option-pic-relax-3.s: Assembler messages:
option-pic-relax-3.s:7: Warning: relaxed out-of-range branch into a jump
option-pic-relax-3.s: Internal error in cvt_frag_to_fill at .../gas/write.c:490.
Please report this bug.
$
using the test source included, due to a buffer overrun in filling the
variable part of a frag.
Likewise use the `fx_tcbit2' flag of a BFD_RELOC_16_PCREL_S2 fixup to
handle the simple case of substituting an out of range unconditional
branch with an equivalent absolute jump in NO_PIC code.
Retain the current way of VXWORKS_PIC use, which commit 41a1578ed17c
("MIPS/GAS: Sanitize `.option picX' pseudo-op") has forbidden the use of
`.option picX' with.
gas/
* config/tc-mips.c (RELAX_ENCODE): Add `PIC' flag.
(RELAX_PIC): New macro.
(RELAX_USE_SECOND, RELAX_SECOND_LONGER, RELAX_NOMACRO)
(RELAX_DELAY_SLOT, RELAX_DELAY_SLOT_16BIT)
(RELAX_DELAY_SLOT_SIZE_FIRST, RELAX_DELAY_SLOT_SIZE_SECOND):
Shift bits.
(RELAX_BRANCH_ENCODE): Add `pic' flag.
(RELAX_BRANCH_UNCOND, RELAX_BRANCH_LIKELY, RELAX_BRANCH_LINK)
(RELAX_BRANCH_TOOFAR): Shift bits.
(RELAX_BRANCH_PIC): New macro.
(RELAX_MICROMIPS_ENCODE): Add `pic' flag.
(RELAX_MICROMIPS_PIC): New macro.
(RELAX_MICROMIPS_UNCOND, RELAX_MICROMIPS_COMPACT)
(RELAX_MICROMIPS_LINK, RELAX_MICROMIPS_NODS)
(RELAX_MICROMIPS_RELAX32): Shift bits.
(relax_close_frag): Pass `mips_pic' setting to RELAX_ENCODE.
(append_insn): Pass `mips_pic' setting to RELAX_BRANCH_ENCODE
and RELAX_MICROMIPS_ENCODE, and record it in `fx_tcbit2' of the
first fixup created.
(md_apply_fix) <BFD_RELOC_16_PCREL_S2>: Use `fx_tcbit2' of the
fixup processed rather than `mips_pic' in choosing to relax an
out of range branch to a jump.
(relaxed_branch_length): Use the `pic' flag of the relaxed frag
rather than `mips_pic'.
(relaxed_micromips_32bit_branch_length): Likewise.
(md_estimate_size_before_relax): Likewise.
(md_convert_frag): Likewise.
* testsuite/gas/mips/option-pic-relax-0.d: New test.
* testsuite/gas/mips/option-pic-relax-1.d: New test.
* testsuite/gas/mips/option-pic-relax-2.d: New test.
* testsuite/gas/mips/option-pic-relax-3.d: New test.
* testsuite/gas/mips/option-pic-relax-3a.d: New test.
* testsuite/gas/mips/option-pic-relax-4.d: New test.
* testsuite/gas/mips/option-pic-relax-5.d: New test.
* testsuite/gas/mips/option-pic-relax-2.l: New stderr output.
* testsuite/gas/mips/option-pic-relax-3.l: New stderr output.
* testsuite/gas/mips/option-pic-relax-4.l: New stderr output.
* testsuite/gas/mips/option-pic-relax-5.l: New stderr output.
* testsuite/gas/mips/option-pic-relax-0.s: New test source.
* testsuite/gas/mips/option-pic-relax-1.s: New test source.
* testsuite/gas/mips/option-pic-relax-2.s: New test source.
* testsuite/gas/mips/option-pic-relax-3.s: New test source.
* testsuite/gas/mips/option-pic-relax-4.s: New test source.
* testsuite/gas/mips/option-pic-relax-5.s: New test source.
* testsuite/gas/mips/mips.exp: Run the new tests.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-mips.c | 120 |
1 files changed, 68 insertions, 52 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index da8e9ab..1df1f86 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -967,6 +967,9 @@ static bfd_boolean mips_ignore_branch_isa; can be extracted using RELAX_FIRST() and RELAX_SECOND(). In addition, the subtype has the following flags: + RELAX_PIC + Set if generating PIC code. + RELAX_USE_SECOND Set if it has been decided that we should use the second sequence instead of the first. @@ -1008,17 +1011,19 @@ static bfd_boolean mips_ignore_branch_isa; The code and fixups for the unwanted alternative are discarded by md_convert_frag. */ -#define RELAX_ENCODE(FIRST, SECOND) (((FIRST) << 8) | (SECOND)) +#define RELAX_ENCODE(FIRST, SECOND, PIC) \ + (((FIRST) << 8) | (SECOND) | ((PIC) ? 0x10000 : 0)) #define RELAX_FIRST(X) (((X) >> 8) & 0xff) #define RELAX_SECOND(X) ((X) & 0xff) -#define RELAX_USE_SECOND 0x10000 -#define RELAX_SECOND_LONGER 0x20000 -#define RELAX_NOMACRO 0x40000 -#define RELAX_DELAY_SLOT 0x80000 -#define RELAX_DELAY_SLOT_16BIT 0x100000 -#define RELAX_DELAY_SLOT_SIZE_FIRST 0x200000 -#define RELAX_DELAY_SLOT_SIZE_SECOND 0x400000 +#define RELAX_PIC(X) (((X) & 0x10000) != 0) +#define RELAX_USE_SECOND 0x20000 +#define RELAX_SECOND_LONGER 0x40000 +#define RELAX_NOMACRO 0x80000 +#define RELAX_DELAY_SLOT 0x100000 +#define RELAX_DELAY_SLOT_16BIT 0x200000 +#define RELAX_DELAY_SLOT_SIZE_FIRST 0x400000 +#define RELAX_DELAY_SLOT_SIZE_SECOND 0x800000 /* Branch without likely bit. If label is out of range, we turn: @@ -1087,19 +1092,22 @@ static bfd_boolean mips_ignore_branch_isa; but it's not clear that it would actually improve performance. */ -#define RELAX_BRANCH_ENCODE(at, uncond, likely, link, toofar) \ +#define RELAX_BRANCH_ENCODE(at, pic, \ + uncond, likely, link, toofar) \ ((relax_substateT) \ (0xc0000000 \ | ((at) & 0x1f) \ - | ((toofar) ? 0x20 : 0) \ - | ((link) ? 0x40 : 0) \ - | ((likely) ? 0x80 : 0) \ - | ((uncond) ? 0x100 : 0))) + | ((pic) ? 0x20 : 0) \ + | ((toofar) ? 0x40 : 0) \ + | ((link) ? 0x80 : 0) \ + | ((likely) ? 0x100 : 0) \ + | ((uncond) ? 0x200 : 0))) #define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000) -#define RELAX_BRANCH_UNCOND(i) (((i) & 0x100) != 0) -#define RELAX_BRANCH_LIKELY(i) (((i) & 0x80) != 0) -#define RELAX_BRANCH_LINK(i) (((i) & 0x40) != 0) -#define RELAX_BRANCH_TOOFAR(i) (((i) & 0x20) != 0) +#define RELAX_BRANCH_UNCOND(i) (((i) & 0x200) != 0) +#define RELAX_BRANCH_LIKELY(i) (((i) & 0x100) != 0) +#define RELAX_BRANCH_LINK(i) (((i) & 0x80) != 0) +#define RELAX_BRANCH_TOOFAR(i) (((i) & 0x40) != 0) +#define RELAX_BRANCH_PIC(i) (((i) & 0x20) != 0) #define RELAX_BRANCH_AT(i) ((i) & 0x1f) /* For mips16 code, we use an entirely different form of relaxation. @@ -1164,36 +1172,38 @@ static bfd_boolean mips_ignore_branch_isa; instructions is enabled, and whether the displacement of a branch is too large to fit as an immediate argument of a 16-bit and a 32-bit branch, respectively. */ -#define RELAX_MICROMIPS_ENCODE(type, at, insn32, \ +#define RELAX_MICROMIPS_ENCODE(type, at, insn32, pic, \ uncond, compact, link, nods, \ relax32, toofar16, toofar32) \ (0x40000000 \ | ((type) & 0xff) \ | (((at) & 0x1f) << 8) \ | ((insn32) ? 0x2000 : 0) \ - | ((uncond) ? 0x4000 : 0) \ - | ((compact) ? 0x8000 : 0) \ - | ((link) ? 0x10000 : 0) \ - | ((nods) ? 0x20000 : 0) \ - | ((relax32) ? 0x40000 : 0) \ - | ((toofar16) ? 0x80000 : 0) \ - | ((toofar32) ? 0x100000 : 0)) + | ((pic) ? 0x4000 : 0) \ + | ((uncond) ? 0x8000 : 0) \ + | ((compact) ? 0x10000 : 0) \ + | ((link) ? 0x20000 : 0) \ + | ((nods) ? 0x40000 : 0) \ + | ((relax32) ? 0x80000 : 0) \ + | ((toofar16) ? 0x100000 : 0) \ + | ((toofar32) ? 0x200000 : 0)) #define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000) #define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff) #define RELAX_MICROMIPS_AT(i) (((i) >> 8) & 0x1f) #define RELAX_MICROMIPS_INSN32(i) (((i) & 0x2000) != 0) -#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x4000) != 0) -#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x8000) != 0) -#define RELAX_MICROMIPS_LINK(i) (((i) & 0x10000) != 0) -#define RELAX_MICROMIPS_NODS(i) (((i) & 0x20000) != 0) -#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x40000) != 0) - -#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x80000) != 0) -#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x80000) -#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x80000) -#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x100000) != 0) -#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x100000) -#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x100000) +#define RELAX_MICROMIPS_PIC(i) (((i) & 0x4000) != 0) +#define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x8000) != 0) +#define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x10000) != 0) +#define RELAX_MICROMIPS_LINK(i) (((i) & 0x20000) != 0) +#define RELAX_MICROMIPS_NODS(i) (((i) & 0x40000) != 0) +#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x80000) != 0) + +#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x100000) != 0) +#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x100000) +#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x100000) +#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x200000) != 0) +#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x200000) +#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x200000) /* Sign-extend 16-bit value X. */ #define SEXT_16BIT(X) ((((X) + 0x8000) & 0xffff) - 0x8000) @@ -4345,7 +4355,8 @@ relax_close_frag (void) { mips_macro_warning.first_frag = frag_now; frag_var (rs_machine_dependent, 0, 0, - RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1]), + RELAX_ENCODE (mips_relax.sizes[0], mips_relax.sizes[1], + mips_pic != NO_PIC), mips_relax.symbol, 0, (char *) mips_relax.first_fixup); memset (&mips_relax.sizes, 0, sizeof (mips_relax.sizes)); @@ -7332,7 +7343,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, : branch_likely_p (ip) ? 1 : 0)), 4, RELAX_BRANCH_ENCODE - (AT, + (AT, mips_pic != NO_PIC, uncond_branch_p (ip), branch_likely_p (ip), pinfo & INSN_WRITE_GPR_31, @@ -7369,6 +7380,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, length32 = relaxed_micromips_32bit_branch_length (NULL, NULL, uncond); add_relaxed_insn (ip, length32, relax16 ? 2 : 4, RELAX_MICROMIPS_ENCODE (type, AT, mips_opts.insn32, + mips_pic != NO_PIC, uncond, compact, al, nods, relax32, 0, 0), address_expr->X_add_symbol, @@ -7490,6 +7502,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, address_expr, howto0 && howto0->pc_relative, final_type[0]); + /* Record non-PIC mode in `fx_tcbit2' for `md_apply_fix'. */ + ip->fixp[0]->fx_tcbit2 = mips_pic == NO_PIC; /* Tag symbols that have a R_MIPS16_26 relocation against them. */ if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy) @@ -15582,7 +15596,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) insn |= (*valP >> 2) & 0xffff; write_insn (buf, insn); } - else if (mips_pic == NO_PIC + else if (fixP->fx_tcbit2 && fixP->fx_done && fixP->fx_frag->fr_address >= text_section->vma && (fixP->fx_frag->fr_address @@ -17339,6 +17353,7 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update) if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype)) fragp->fr_subtype = RELAX_BRANCH_ENCODE (RELAX_BRANCH_AT (fragp->fr_subtype), + RELAX_BRANCH_PIC (fragp->fr_subtype), RELAX_BRANCH_UNCOND (fragp->fr_subtype), RELAX_BRANCH_LIKELY (fragp->fr_subtype), RELAX_BRANCH_LINK (fragp->fr_subtype), @@ -17350,7 +17365,7 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update) if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0)) length += 8; - if (mips_pic != NO_PIC) + if (!fragp || RELAX_BRANCH_PIC (fragp->fr_subtype)) { /* Additional space for PIC loading of target address. */ length += 8; @@ -17393,6 +17408,7 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) { bfd_boolean insn32 = TRUE; bfd_boolean nods = TRUE; + bfd_boolean pic = TRUE; bfd_boolean al = TRUE; int short_insn_size; bfd_boolean toofar; @@ -17402,6 +17418,7 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) { insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype); nods = RELAX_MICROMIPS_NODS (fragp->fr_subtype); + pic = RELAX_MICROMIPS_PIC (fragp->fr_subtype); al = RELAX_MICROMIPS_LINK (fragp->fr_subtype); } short_insn_size = insn32 ? 4 : 2; @@ -17464,7 +17481,7 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) # compact && (!PIC || insn32) 0: */ - if ((mips_pic == NO_PIC || insn32) && (!compact_known || compact)) + if ((!pic || insn32) && (!compact_known || compact)) length += short_insn_size; /* If assembling PIC code, we further turn: @@ -17477,12 +17494,12 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) d/addiu at, %lo(label) # 4 bytes jr/c at # 2/4 bytes */ - if (mips_pic != NO_PIC) + if (pic) length += 4 + short_insn_size; /* Add an extra nop if the jump has no compact form and we need to fill the delay slot. */ - if ((mips_pic == NO_PIC || al) && nods) + if ((!pic || al) && nods) length += (fragp ? frag_branch_delay_slot_size (fragp, al, short_insn_size) : short_insn_size); @@ -17597,15 +17614,13 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype) return length; } - if (mips_pic == NO_PIC) - change = nopic_need_relax (fragp->fr_symbol, 0); - else if (mips_pic == SVR4_PIC) - change = pic_need_relax (fragp->fr_symbol); - else if (mips_pic == VXWORKS_PIC) + if (mips_pic == VXWORKS_PIC) /* For vxworks, GOT16 relocations never have a corresponding LO16. */ change = 0; + else if (RELAX_PIC (fragp->fr_subtype)) + change = pic_need_relax (fragp->fr_symbol); else - abort (); + change = nopic_need_relax (fragp->fr_symbol, 0); if (change) { @@ -17988,7 +18003,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) } uncond: - if (mips_pic == NO_PIC) + if (!RELAX_BRANCH_PIC (fragp->fr_subtype)) { /* j or jal. */ insn = (RELAX_BRANCH_LINK (fragp->fr_subtype) @@ -18066,6 +18081,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype); bfd_boolean insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype); bfd_boolean nods = RELAX_MICROMIPS_NODS (fragp->fr_subtype); + bfd_boolean pic = RELAX_MICROMIPS_PIC (fragp->fr_subtype); bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype); int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype); bfd_boolean short_ds; @@ -18241,7 +18257,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) } } - if (mips_pic == NO_PIC) + if (!pic) { unsigned long jal = (short_ds || nods ? 0x74000000 : 0xf4000000); /* jal/s */ |