From 5919d0127e12dfe3d3190ba3468c71782cb16b02 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sat, 8 Feb 2003 17:05:55 +0000 Subject: gas/ * config/tc-mips.c (reloc_needs_lo_p): New function. (fixup_has_matching_lo_p): New function. (append_insn): Use reloc_needs_lo_p to check whether a relocation might need a matching %lo(). Reuse the head of mips_hi_fixup_list if that fixup already has a matching %lo(). Don't call frag_wane here. (macro): Call frag_wane here if the last unmatched hi was in the current frag. (pic_need_relax): New function, split out from... (md_estimate_size_before_relax): ...here. (mips_frob_file): Use reloc_needs_lo_p. Use pic_need_relax to test whether BFD_RELOC_MIPS_GOT16 fixups refer to global symbols. gas/testsuite/ * gas/mips/rel12.[sd], gas/mips/rel13.[sd]: New tests. * gas/mips/mips.exp: Run them. --- gas/ChangeLog | 14 +++ gas/config/tc-mips.c | 218 +++++++++++++++++++++++-------------- gas/testsuite/ChangeLog | 5 + gas/testsuite/gas/mips/elf-rel12.d | 11 ++ gas/testsuite/gas/mips/elf-rel12.s | 14 +++ gas/testsuite/gas/mips/elf-rel13.d | 17 +++ gas/testsuite/gas/mips/elf-rel13.s | 22 ++++ gas/testsuite/gas/mips/mips.exp | 2 + 8 files changed, 220 insertions(+), 83 deletions(-) create mode 100644 gas/testsuite/gas/mips/elf-rel12.d create mode 100644 gas/testsuite/gas/mips/elf-rel12.s create mode 100644 gas/testsuite/gas/mips/elf-rel13.d create mode 100644 gas/testsuite/gas/mips/elf-rel13.s (limited to 'gas') diff --git a/gas/ChangeLog b/gas/ChangeLog index 265d152..698a405 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +2003-02-08 Richard Sandiford + + * config/tc-mips.c (reloc_needs_lo_p): New function. + (fixup_has_matching_lo_p): New function. + (append_insn): Use reloc_needs_lo_p to check whether a relocation + might need a matching %lo(). Reuse the head of mips_hi_fixup_list + if that fixup already has a matching %lo(). Don't call frag_wane here. + (macro): Call frag_wane here if the last unmatched hi was in the + current frag. + (pic_need_relax): New function, split out from... + (md_estimate_size_before_relax): ...here. + (mips_frob_file): Use reloc_needs_lo_p. Use pic_need_relax to test + whether BFD_RELOC_MIPS_GOT16 fixups refer to global symbols. + 2003-02-07 Richard Sandiford * config/tc-mips.c (my_getSmallExpression): Rework bracket handling. diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 57c1196..4c0052b 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -801,6 +801,10 @@ static int mips_relax_branch; enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG }; +static inline bfd_boolean reloc_needs_lo_p + PARAMS ((bfd_reloc_code_real_type)); +static inline bfd_boolean fixup_has_matching_lo_p + PARAMS ((fixS *)); static int insn_uses_reg PARAMS ((struct mips_cl_insn *ip, unsigned int reg, enum mips_regclass class)); @@ -932,6 +936,8 @@ static void s_mips_file PARAMS ((int)); static void s_mips_loc PARAMS ((int)); +static bfd_boolean pic_need_relax + PARAMS ((symbolS *, asection *)); static int mips16_extended_frag PARAMS ((fragS *, asection *, long)); static int relaxed_branch_length (fragS *, asection *, int); @@ -1439,6 +1445,31 @@ md_assemble (str) } } +/* Return true if the given relocation might need a matching %lo(). + Note that R_MIPS_GOT16 relocations only need a matching %lo() when + applied to local symbols. */ + +static inline bfd_boolean +reloc_needs_lo_p (reloc) + bfd_reloc_code_real_type reloc; +{ + return (reloc == BFD_RELOC_HI16_S + || reloc == BFD_RELOC_MIPS_GOT16); +} + +/* Return true if the given fixup is followed by a matching R_MIPS_LO16 + relocation. */ + +static inline bfd_boolean +fixup_has_matching_lo_p (fixp) + fixS *fixp; +{ + return (fixp->fx_next != NULL + && fixp->fx_next->fx_r_type == BFD_RELOC_LO16 + && fixp->fx_addsy == fixp->fx_next->fx_addsy + && fixp->fx_offset == fixp->fx_next->fx_offset); +} + /* See whether instruction IP reads register REG. CLASS is the type of register. */ @@ -1593,14 +1624,12 @@ append_insn (place, ip, address_expr, reloc_type) char *f; fixS *fixp[3]; int nops = 0; - bfd_boolean unmatched_reloc_p; /* Mark instruction labels in mips16 mode. */ mips16_mark_labels (); prev_pinfo = prev_insn.insn_mo->pinfo; pinfo = ip->insn_mo->pinfo; - unmatched_reloc_p = FALSE; if (place == NULL && (! mips_opts.noreorder || prev_nop_frag != NULL)) { @@ -2144,17 +2173,22 @@ append_insn (place, ip, address_expr, reloc_type) || *reloc_type == BFD_RELOC_MIPS_RELGOT)) fixp[0]->fx_no_overflow = 1; - if (reloc_type[0] == BFD_RELOC_HI16_S) + if (reloc_needs_lo_p (*reloc_type)) { struct mips_hi_fixup *hi_fixup; - hi_fixup = ((struct mips_hi_fixup *) - xmalloc (sizeof (struct mips_hi_fixup))); + /* Reuse the last entry if it already has a matching %lo. */ + hi_fixup = mips_hi_fixup_list; + if (hi_fixup == 0 + || !fixup_has_matching_lo_p (hi_fixup->fixp)) + { + hi_fixup = ((struct mips_hi_fixup *) + xmalloc (sizeof (struct mips_hi_fixup))); + hi_fixup->next = mips_hi_fixup_list; + mips_hi_fixup_list = hi_fixup; + } hi_fixup->fixp = fixp[0]; hi_fixup->seg = now_seg; - hi_fixup->next = mips_hi_fixup_list; - mips_hi_fixup_list = hi_fixup; - unmatched_reloc_p = TRUE; } if (reloc_type[1] != BFD_RELOC_UNUSED) @@ -2706,16 +2740,6 @@ append_insn (place, ip, address_expr, reloc_type) /* We just output an insn, so the next one doesn't have a label. */ mips_clear_insn_labels (); - - /* We must ensure that a fixup associated with an unmatched %hi - reloc does not become a variant frag. Otherwise, the - rearrangement of %hi relocs in frob_file may confuse - tc_gen_reloc. */ - if (unmatched_reloc_p) - { - frag_wane (frag_now); - frag_new (0); - } } /* This function forgets that there was any previous instruction or @@ -4070,6 +4094,27 @@ macro (ip) expr1.X_add_symbol = NULL; expr1.X_add_number = 1; + /* Umatched fixups should not be put in the same frag as a relaxable + macro. For example, suppose we have: + + lui $4,%hi(l1) # 1 + la $5,l2 # 2 + addiu $4,$4,%lo(l1) # 3 + + If instructions 1 and 2 were put in the same frag, md_frob_file would + move the fixup for #1 after the fixups for the "unrelaxed" version of + #2. This would confuse tc_gen_reloc, which expects the relocations + for #2 to be the last for that frag. + + If it looks like this situation could happen, put the macro + in a new frag. */ + if (mips_hi_fixup_list != 0 + && mips_hi_fixup_list->fixp->fx_frag == frag_now) + { + frag_wane (frag_now); + frag_new (0); + } + switch (mask) { case M_DABS: @@ -10858,14 +10903,16 @@ mips_frob_file () segment_info_type *seginfo; int pass; - assert (l->fixp->fx_r_type == BFD_RELOC_HI16_S); + assert (reloc_needs_lo_p (l->fixp->fx_r_type)); - /* Check quickly whether the next fixup happens to be a matching - %lo. */ - if (l->fixp->fx_next != NULL - && l->fixp->fx_next->fx_r_type == BFD_RELOC_LO16 - && l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy - && l->fixp->fx_offset == l->fixp->fx_next->fx_offset) + /* If a GOT16 relocation turns out to be against a global symbol, + there isn't supposed to be a matching LO. */ + if (l->fixp->fx_r_type == BFD_RELOC_MIPS_GOT16 + && !pic_need_relax (l->fixp->fx_addsy, l->seg)) + continue; + + /* Check quickly whether the next fixup happens to be a matching %lo. */ + if (fixup_has_matching_lo_p (l->fixp)) continue; /* Look through the fixups for this segment for a matching %lo. @@ -10887,9 +10934,8 @@ mips_frob_file () && f->fx_offset == l->fixp->fx_offset && (pass == 1 || prev == NULL - || prev->fx_r_type != BFD_RELOC_HI16_S - || prev->fx_addsy != f->fx_addsy - || prev->fx_offset != f->fx_offset)) + || !reloc_needs_lo_p (prev->fx_r_type) + || !fixup_has_matching_lo_p (prev))) { fixS **pf; @@ -12672,6 +12718,64 @@ nopic_need_relax (sym, before_relaxing) return 1; } + +/* Return true if the given symbol should be considered local for SVR4 PIC. */ + +static bfd_boolean +pic_need_relax (sym, segtype) + symbolS *sym; + asection *segtype; +{ + asection *symsec; + bfd_boolean linkonce; + + /* Handle the case of a symbol equated to another symbol. */ + while (symbol_equated_reloc_p (sym)) + { + symbolS *n; + + /* It's possible to get a loop here in a badly written + program. */ + n = symbol_get_value_expression (sym)->X_add_symbol; + if (n == sym) + break; + sym = n; + } + + symsec = S_GET_SEGMENT (sym); + + /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */ + linkonce = FALSE; + if (symsec != segtype && ! S_IS_LOCAL (sym)) + { + if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE) + != 0) + linkonce = TRUE; + + /* The GNU toolchain uses an extension for ELF: a section + beginning with the magic string .gnu.linkonce is a linkonce + section. */ + if (strncmp (segment_name (symsec), ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0) + linkonce = TRUE; + } + + /* This must duplicate the test in adjust_reloc_syms. */ + return (symsec != &bfd_und_section + && symsec != &bfd_abs_section + && ! bfd_is_com_section (symsec) + && !linkonce +#ifdef OBJ_ELF + /* A global or weak symbol is treated as external. */ + && (OUTPUT_FLAVOR != bfd_target_elf_flavour + || (! S_IS_WEAK (sym) + && (! S_IS_EXTERNAL (sym) + || mips_pic == EMBEDDED_PIC))) +#endif + ); +} + + /* Given a mips16 variant frag FRAGP, return non-zero if it needs an extended opcode. SEC is the section the frag is in. */ @@ -12950,8 +13054,7 @@ md_estimate_size_before_relax (fragp, segtype) fragS *fragp; asection *segtype; { - int change = 0; - bfd_boolean linkonce = FALSE; + int change; if (RELAX_BRANCH_P (fragp->fr_subtype)) { @@ -12967,60 +13070,9 @@ md_estimate_size_before_relax (fragp, segtype) return (RELAX_MIPS16_EXTENDED (fragp->fr_subtype) ? 4 : 2); if (mips_pic == NO_PIC) - { - change = nopic_need_relax (fragp->fr_symbol, 0); - } + change = nopic_need_relax (fragp->fr_symbol, 0); else if (mips_pic == SVR4_PIC) - { - symbolS *sym; - asection *symsec; - - sym = fragp->fr_symbol; - - /* Handle the case of a symbol equated to another symbol. */ - while (symbol_equated_reloc_p (sym)) - { - symbolS *n; - - /* It's possible to get a loop here in a badly written - program. */ - n = symbol_get_value_expression (sym)->X_add_symbol; - if (n == sym) - break; - sym = n; - } - - symsec = S_GET_SEGMENT (sym); - - /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */ - if (symsec != segtype && ! S_IS_LOCAL (sym)) - { - if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE) - != 0) - linkonce = TRUE; - - /* The GNU toolchain uses an extension for ELF: a section - beginning with the magic string .gnu.linkonce is a linkonce - section. */ - if (strncmp (segment_name (symsec), ".gnu.linkonce", - sizeof ".gnu.linkonce" - 1) == 0) - linkonce = TRUE; - } - - /* This must duplicate the test in adjust_reloc_syms. */ - change = (symsec != &bfd_und_section - && symsec != &bfd_abs_section - && ! bfd_is_com_section (symsec) - && !linkonce -#ifdef OBJ_ELF - /* A global or weak symbol is treated as external. */ - && (OUTPUT_FLAVOR != bfd_target_elf_flavour - || (! S_IS_WEAK (sym) - && (! S_IS_EXTERNAL (sym) - || mips_pic == EMBEDDED_PIC))) -#endif - ); - } + change = pic_need_relax (fragp->fr_symbol, segtype); else abort (); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 0bbc35a..c9be2ed 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2003-02-07 Richard Sandiford + * gas/mips/rel12.[sd], gas/mips/rel13.[sd]: New tests. + * gas/mips/mips.exp: Run them. + +2003-02-07 Richard Sandiford + * gas/mips/expr1.[sd]: New test. * gas/mips/mips.exp: Run it. diff --git a/gas/testsuite/gas/mips/elf-rel12.d b/gas/testsuite/gas/mips/elf-rel12.d new file mode 100644 index 0000000..c57a83c --- /dev/null +++ b/gas/testsuite/gas/mips/elf-rel12.d @@ -0,0 +1,11 @@ +#as: -march=mips1 -mabi=32 +#readelf: --relocs +#name: MIPS ELF reloc 12 + +Relocation section '\.rel\.text' at offset .* contains 4 entries: + *Offset * Info * Type * Sym\.Value * Sym\. Name +0+0004 * 0+..05 * R_MIPS_HI16 * 0+0000 * l1 +0+0008 * 0+..06 * R_MIPS_LO16 * 0+0000 * l1 +0+0000 * 0+..05 * R_MIPS_HI16 * 0+0004 * l2 +0+000c * 0+..06 * R_MIPS_LO16 * 0+0004 * l2 +#pass diff --git a/gas/testsuite/gas/mips/elf-rel12.s b/gas/testsuite/gas/mips/elf-rel12.s new file mode 100644 index 0000000..a3c4021 --- /dev/null +++ b/gas/testsuite/gas/mips/elf-rel12.s @@ -0,0 +1,14 @@ + .ent foo +foo: + lui $4,%hi(l2) + la $3,l1 + addiu $4,$4,%lo(l2) + + .space 64 + .end foo + + .globl l1 + .globl l2 + .data +l1: .word 1 +l2: .word 2 diff --git a/gas/testsuite/gas/mips/elf-rel13.d b/gas/testsuite/gas/mips/elf-rel13.d new file mode 100644 index 0000000..0c3289d --- /dev/null +++ b/gas/testsuite/gas/mips/elf-rel13.d @@ -0,0 +1,17 @@ +#as: -march=mips2 -mabi=32 -KPIC +#readelf: --relocs +#name: MIPS ELF reloc 13 + +Relocation section '\.rel\.text' at offset .* contains 9 entries: + *Offset * Info * Type * Sym\.Value * Sym\. Name +0+0000 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.data +0+0014 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.data +0+0010 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.data +0+0018 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.data +# The next two lines could be in either order. +0+000c * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.rodata +0+0008 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.rodata +0+001c * 0+..06 * R_MIPS_LO16 * 0+0000 * \.rodata +0+0004 * 0+..09 * R_MIPS_GOT16 * 0+0000 * \.bss +0+0020 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.bss +#pass diff --git a/gas/testsuite/gas/mips/elf-rel13.s b/gas/testsuite/gas/mips/elf-rel13.s new file mode 100644 index 0000000..761fcbb --- /dev/null +++ b/gas/testsuite/gas/mips/elf-rel13.s @@ -0,0 +1,22 @@ + .ent foo +foo: + lw $4,%got(l1)($gp) + lw $4,%got(l2)($gp) + lw $4,%got(l3)($gp) + lw $4,%got(l3)($gp) + lw $4,%got(l1+0x400)($gp) + addiu $4,$4,%lo(l1) + addiu $4,$4,%lo(l1+0x400) + addiu $4,$4,%lo(l3) + addiu $4,$4,%lo(l2) + .space 64 + .end foo + + .data +l1: .word 1 + + .lcomm l2, 4 + + .rdata + .word 1 +l3: .word 2 diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp index 090e0b5..9d950a4 100644 --- a/gas/testsuite/gas/mips/mips.exp +++ b/gas/testsuite/gas/mips/mips.exp @@ -608,6 +608,8 @@ if { [istarget mips*-*-*] } then { run_dump_test "elf-rel10" run_dump_test "elf-rel11" } + run_dump_test "elf-rel12" + run_dump_test "elf-rel13" run_dump_test "${tmips}${el}empic" run_dump_test "empic2" run_dump_test "empic3_e" -- cgit v1.1