(reloc_needs_lo_p): Only return true if HAVE_IN_PLACE_ADDENDS.
(mips_frob_file): Rework so that only a single pass through the
relocs is needed. Allow %lo()s to have higher offsets than their
corresponding %hi()s or %got()s.
testsuite/
* gas/mips/elf{,el}-rel.d: Adjust so that the earliest %hi() matches
the earliest %lo().
* gas/mips/elf-rel11.d: Don't expect the relocs to be reordered.
* gas/mips/elf-rel20.[sd]: New test.
* gas/mips/mips.exp: Run it.
+2004-07-03 Richard Sandiford <rsandifo@redhat.com>
+
+ * config/tc-mips.c (HAVE_IN_PLACE_ADDENDS): New macro.
+ (reloc_needs_lo_p): Only return true if HAVE_IN_PLACE_ADDENDS.
+ (mips_frob_file): Rework so that only a single pass through the
+ relocs is needed. Allow %lo()s to have higher offsets than their
+ corresponding %hi()s or %got()s.
+
2004-07-02 Nick Clifton <nickc@redhat.com>
* config/tc-arm.c (md_apply_fix3:BFD_RELOC_ARM_IMMEDIATE): Do not
#define HAVE_64BIT_OBJECTS (mips_abi == N64_ABI)
+/* True if relocations are stored in-place. */
+#define HAVE_IN_PLACE_ADDENDS (!HAVE_NEWABI)
+
/* We can only have 64bit addresses if the object file format supports it. */
#define HAVE_32BIT_ADDRESSES \
(HAVE_32BIT_GPRS \
static inline bfd_boolean
reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_HI16_S
- || reloc == BFD_RELOC_MIPS_GOT16);
+ return (HAVE_IN_PLACE_ADDENDS
+ && (reloc == BFD_RELOC_HI16_S
+ || reloc == BFD_RELOC_MIPS_GOT16));
}
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
#endif
}
-/* Sort any unmatched HI16_S relocs so that they immediately precede
- the corresponding LO reloc. This is called before md_apply_fix3 and
- tc_gen_reloc. Unmatched HI16_S relocs can only be generated by
- explicit use of the %hi modifier. */
+/* Sort any unmatched HI16 and GOT16 relocs so that they immediately precede
+ the corresponding LO16 reloc. This is called before md_apply_fix3 and
+ tc_gen_reloc. Unmatched relocs can only be generated by use of explicit
+ relocation operators.
+
+ For our purposes, a %lo() expression matches a %got() or %hi()
+ expression if:
+
+ (a) it refers to the same symbol; and
+ (b) the offset applied in the %lo() expression is no lower than
+ the offset applied in the %got() or %hi().
+
+ (b) allows us to cope with code like:
+
+ lui $4,%hi(foo)
+ lh $4,%lo(foo+2)($4)
+
+ ...which is legal on RELA targets, and has a well-defined behaviour
+ if the user knows that adding 2 to "foo" will not induce a carry to
+ the high 16 bits.
+
+ When several %lo()s match a particular %got() or %hi(), we use the
+ following rules to distinguish them:
+
+ (1) %lo()s with smaller offsets are a better match than %lo()s with
+ higher offsets.
+
+ (2) %lo()s with no matching %got() or %hi() are better than those
+ that already have a matching %got() or %hi().
+
+ (3) later %lo()s are better than earlier %lo()s.
+
+ These rules are applied in order.
+
+ (1) means, among other things, that %lo()s with identical offsets are
+ chosen if they exist.
+
+ (2) means that we won't associate several high-part relocations with
+ the same low-part relocation unless there's no alternative. Having
+ several high parts for the same low part is a GNU extension; this rule
+ allows careful users to avoid it.
+
+ (3) is purely cosmetic. mips_hi_fixup_list is is in reverse order,
+ with the last high-part relocation being at the front of the list.
+ It therefore makes sense to choose the last matching low-part
+ relocation, all other things being equal. It's also easier
+ to code that way. */
void
mips_frob_file (void)
for (l = mips_hi_fixup_list; l != NULL; l = l->next)
{
segment_info_type *seginfo;
- int pass;
+ bfd_boolean matched_lo_p;
+ fixS **hi_pos, **lo_pos, **pos;
assert (reloc_needs_lo_p (l->fixp->fx_r_type));
if (fixup_has_matching_lo_p (l->fixp))
continue;
- /* Look through the fixups for this segment for a matching %lo.
- When we find one, move the %hi just in front of it. We do
- this in two passes. In the first pass, we try to find a
- unique %lo. In the second pass, we permit multiple %hi
- relocs for a single %lo (this is a GNU extension). */
seginfo = seg_info (l->seg);
- for (pass = 0; pass < 2; pass++)
- {
- fixS *f, *prev;
- prev = NULL;
- for (f = seginfo->fix_root; f != NULL; f = f->fx_next)
+ /* Set HI_POS to the position of this relocation in the chain.
+ Set LO_POS to the position of the chosen low-part relocation.
+ MATCHED_LO_P is true on entry to the loop if *POS is a low-part
+ relocation that matches an immediately-preceding high-part
+ relocation. */
+ hi_pos = NULL;
+ lo_pos = NULL;
+ matched_lo_p = FALSE;
+ for (pos = &seginfo->fix_root; *pos != NULL; pos = &(*pos)->fx_next)
+ {
+ if (*pos == l->fixp)
+ hi_pos = pos;
+
+ if ((*pos)->fx_r_type == BFD_RELOC_LO16
+ && (*pos)->fx_addsy == l->fixp->fx_addsy
+ && (*pos)->fx_offset >= l->fixp->fx_offset
+ && (lo_pos == NULL
+ || (*pos)->fx_offset < (*lo_pos)->fx_offset
+ || (!matched_lo_p
+ && (*pos)->fx_offset == (*lo_pos)->fx_offset)))
+ lo_pos = pos;
+
+ matched_lo_p = (reloc_needs_lo_p ((*pos)->fx_r_type)
+ && fixup_has_matching_lo_p (*pos));
+ }
+
+ /* If we found a match, remove the high-part relocation from its
+ current position and insert it before the low-part relocation.
+ Make the offsets match so that fixup_has_matching_lo_p()
+ will return true.
+
+ We don't warn about unmatched high-part relocations since some
+ versions of gcc have been known to emit dead "lui ...%hi(...)"
+ instructions. */
+ if (lo_pos != NULL)
+ {
+ l->fixp->fx_offset = (*lo_pos)->fx_offset;
+ if (l->fixp->fx_next != *lo_pos)
{
- /* Check whether this is a %lo fixup which matches l->fixp. */
- if (f->fx_r_type == BFD_RELOC_LO16
- && f->fx_addsy == l->fixp->fx_addsy
- && f->fx_offset == l->fixp->fx_offset
- && (pass == 1
- || prev == NULL
- || !reloc_needs_lo_p (prev->fx_r_type)
- || !fixup_has_matching_lo_p (prev)))
- {
- fixS **pf;
-
- /* Move l->fixp before f. */
- for (pf = &seginfo->fix_root;
- *pf != l->fixp;
- pf = &(*pf)->fx_next)
- assert (*pf != NULL);
-
- *pf = l->fixp->fx_next;
-
- l->fixp->fx_next = f;
- if (prev == NULL)
- seginfo->fix_root = l->fixp;
- else
- prev->fx_next = l->fixp;
-
- break;
- }
-
- prev = f;
+ *hi_pos = l->fixp->fx_next;
+ l->fixp->fx_next = *lo_pos;
+ *lo_pos = l->fixp;
}
-
- if (f != NULL)
- break;
-
-#if 0 /* GCC code motion plus incomplete dead code elimination
- can leave a %hi without a %lo. */
- if (pass == 1)
- as_warn_where (l->fixp->fx_file, l->fixp->fx_line,
- _("Unmatched %%hi reloc"));
-#endif
}
}
}
+2004-07-03 Richard Sandiford <rsandifo@redhat.com>
+
+ * config/tc-mips.c (HAVE_IN_PLACE_ADDENDS): New macro.
+ (reloc_needs_lo_p): Only return true if HAVE_IN_PLACE_ADDENDS.
+ (mips_frob_file): Rework so that only a single pass through the
+ relocs is needed. Allow %lo()s to have higher offsets than their
+ corresponding %hi()s or %got()s.
+
+testsuite/
+ * gas/mips/elf{,el}-rel.d: Adjust so that the earliest %hi() matches
+ the earliest %lo().
+ * gas/mips/elf-rel11.d: Don't expect the relocs to be reordered.
+ * gas/mips/elf-rel20.[sd]: New test.
+ * gas/mips/mips.exp: Run it.
+
2004-07-03 Maciej W. Rozycki <macro@linux-mips.org>
* gas/mips/elf-rel9.[sd]: Fix typo in %lo() expression.
0+000002c R_MIPS_LO16 \.text
0+0000030 R_MIPS_HI16 \.text
0+0000048 R_MIPS_LO16 \.text
-0+0000064 R_MIPS_HI16 \.text
+0+0000034 R_MIPS_HI16 \.text
0+000004c R_MIPS_LO16 \.text
-0+0000068 R_MIPS_HI16 \.text
+0+0000038 R_MIPS_HI16 \.text
0+0000050 R_MIPS_LO16 \.text
-0+000006c R_MIPS_HI16 \.text
+0+000003c R_MIPS_HI16 \.text
0+0000054 R_MIPS_LO16 \.text
-0+0000074 R_MIPS_HI16 \.text
+0+0000044 R_MIPS_HI16 \.text
0+0000058 R_MIPS_LO16 \.text
-0+0000070 R_MIPS_HI16 \.text
+0+0000040 R_MIPS_HI16 \.text
0+000005c R_MIPS_LO16 \.text
0+0000060 R_MIPS_HI16 \.text
0+0000078 R_MIPS_LO16 \.text
-0+0000034 R_MIPS_HI16 \.text
+0+0000064 R_MIPS_HI16 \.text
0+000007c R_MIPS_LO16 \.text
-0+0000038 R_MIPS_HI16 \.text
+0+0000068 R_MIPS_HI16 \.text
0+0000080 R_MIPS_LO16 \.text
-0+000003c R_MIPS_HI16 \.text
+0+000006c R_MIPS_HI16 \.text
0+0000084 R_MIPS_LO16 \.text
-0+0000044 R_MIPS_HI16 \.text
+0+0000074 R_MIPS_HI16 \.text
0+0000088 R_MIPS_LO16 \.text
-0+0000040 R_MIPS_HI16 \.text
+0+0000070 R_MIPS_HI16 \.text
0+000008c R_MIPS_LO16 \.text
0+0000 * 0+..0000001d * R_MIPS_HIGHEST * 0+0000 * bar \+ 0
* Type2: R_MIPS_NONE *
* Type3: R_MIPS_NONE *
-0+0008 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * bar \+ 0
+0+0004 * 0+..00000005 * R_MIPS_HI16 * 0+0000 * bar \+ 0
* Type2: R_MIPS_NONE *
* Type3: R_MIPS_NONE *
-0+0004 * 0+..00000005 * R_MIPS_HI16 * 0+0000 * bar \+ 0
+0+0008 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * bar \+ 0
* Type2: R_MIPS_NONE *
* Type3: R_MIPS_NONE *
0+000c * 0+..00000006 * R_MIPS_LO16 * 0+0000 * bar \+ 0
0+0018 * 0+..0000001d * R_MIPS_HIGHEST * 0+0000 * bar \+ 12345678
* Type2: R_MIPS_NONE *
* Type3: R_MIPS_NONE *
-0+0020 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * bar \+ 12345678
+0+001c * 0+..00000005 * R_MIPS_HI16 * 0+0000 * bar \+ 12345678
* Type2: R_MIPS_NONE *
* Type3: R_MIPS_NONE *
-0+001c * 0+..00000005 * R_MIPS_HI16 * 0+0000 * bar \+ 12345678
+0+0020 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * bar \+ 12345678
* Type2: R_MIPS_NONE *
* Type3: R_MIPS_NONE *
0+0024 * 0+..00000006 * R_MIPS_LO16 * 0+0000 * bar \+ 12345678
--- /dev/null
+#as: -march=mips2 -mabi=32 -KPIC
+#readelf: --relocs
+#name: MIPS ELF reloc 20
+
+Relocation section '\.rel\.text' at offset .* contains 8 entries:
+ *Offset * Info * Type * Sym\.Value * Sym\. Name
+0+0000 * 0+..05 * R_MIPS_HI16 * 0+0000 * foo
+0+0010 * 0+..06 * R_MIPS_LO16 * 0+0000 * foo
+0+0004 * 0+..05 * R_MIPS_HI16 * 0+0000 * foo
+0+0014 * 0+..06 * R_MIPS_LO16 * 0+0000 * foo
+0+000c * 0+..05 * R_MIPS_HI16 * 0+0000 * \.bss
+0+0018 * 0+..06 * R_MIPS_LO16 * 0+0000 * \.bss
+0+0008 * 0+..05 * R_MIPS_HI16 * 0+0000 * \.bss
+0+001c * 0+..06 * R_MIPS_LO16 * 0+0000 * \.bss
+#pass
--- /dev/null
+ lui $4,%hi(foo)
+ lui $5,%hi(foo + 0x80000)
+ lui $7,%hi(bar + 0x80000)
+ lui $6,%hi(bar)
+ addiu $4,$4,%lo(foo + 2)
+ addiu $5,$5,%lo(foo + 0x80004)
+ addiu $6,$6,%lo(bar + 2)
+ addiu $7,$7,%lo(bar + 0x80004)
+ .section .bss
+bar:
+ .space 0x80010
0+000002c R_MIPS_LO16 \.text
0+0000030 R_MIPS_HI16 \.text
0+0000048 R_MIPS_LO16 \.text
-0+0000064 R_MIPS_HI16 \.text
+0+0000034 R_MIPS_HI16 \.text
0+000004c R_MIPS_LO16 \.text
-0+0000068 R_MIPS_HI16 \.text
+0+0000038 R_MIPS_HI16 \.text
0+0000050 R_MIPS_LO16 \.text
-0+000006c R_MIPS_HI16 \.text
+0+000003c R_MIPS_HI16 \.text
0+0000054 R_MIPS_LO16 \.text
-0+0000074 R_MIPS_HI16 \.text
+0+0000044 R_MIPS_HI16 \.text
0+0000058 R_MIPS_LO16 \.text
-0+0000070 R_MIPS_HI16 \.text
+0+0000040 R_MIPS_HI16 \.text
0+000005c R_MIPS_LO16 \.text
0+0000060 R_MIPS_HI16 \.text
0+0000078 R_MIPS_LO16 \.text
-0+0000034 R_MIPS_HI16 \.text
+0+0000064 R_MIPS_HI16 \.text
0+000007c R_MIPS_LO16 \.text
-0+0000038 R_MIPS_HI16 \.text
+0+0000068 R_MIPS_HI16 \.text
0+0000080 R_MIPS_LO16 \.text
-0+000003c R_MIPS_HI16 \.text
+0+000006c R_MIPS_HI16 \.text
0+0000084 R_MIPS_LO16 \.text
-0+0000044 R_MIPS_HI16 \.text
+0+0000074 R_MIPS_HI16 \.text
0+0000088 R_MIPS_LO16 \.text
-0+0000040 R_MIPS_HI16 \.text
+0+0000070 R_MIPS_HI16 \.text
0+000008c R_MIPS_LO16 \.text
run_dump_test "elf-rel18"
}
run_dump_test "elf-rel19"
+ run_dump_test "elf-rel20"
if { !$no_mips16 } {
run_dump_test "${tmips}mips${el}16-e"