[patch] MIPS: Follow the ABI rules for ordering HI16_S/LO16 relocs
Maciej W. Rozycki
macro@linux-mips.org
Mon Jun 28 16:22:00 GMT 2004
Hello,
This is a follow-on patch to the "mips-merge-lo16" one, that is required
for gas to handle the case when multiple LO16 relocations are associated
with a preceding HI16_S (or GOT16) one.
This is one of the fortunate areas the MIPS ABI supplement is clear
about. On page 4-18 of the spec, there is the following statement:
"R_MIPS_LO16 entries without an R_MIPS_HI16 entry immediately preceding
are orphaned and the previously defined R_MIPS_HI16 is used for computing
the addend." The implication is for a correct calculation of the addend
for a LO16 relocation, the corresponding HI16 relocation has to precede it
with no other HI16 relocations inbetween.
Here's a patch that extends reordering of HI16_S/GOT16 and LO16
relocations. After pairing all HI16_S/GOT16 relocations with a
corresponding LO16 one, all sections are scanned for any orphaned LO16
relocations and if ones are found, they are grouped following the closest
matching HI16_S/GOT16 one. If no matching HI16_S/GOT16 is found a warning
is issued as a broken binary results.
The included test case illustrates operation -- orphaned LO16 relocations
are actually quite a common case with current gcc if explicit relocs are
used. Building the Linux kernel with the "mips-merge-lo16" patch applied
to binutils yields several linker warnings about an "access beyond end of
merged section", which is a sign of using a wrong HI16_S relocation for
calculating the addend of a LO16 one.
gas/:
2004-06-28 Maciej W. Rozycki <macro@linux-mips.org>
* config/tc-mips.c (mips_frob_file): Rename to...
(adjust_hi_relocs): ... this.
(adjust_lo_relocs): New function to attach orphaned LO16 relocs to
their corresponding HI16_S/GOT16 ones.
(mips_frob_file): New function wrapping adjust_hi_relocs() and
adjust_lo_relocs().
gas/testsuite/:
2004-06-28 Maciej W. Rozycki <macro@linux-mips.org>
* gas/mips/elf-rel20.d: New test for reordering of orphaned LO16
relocs.
* gas/mips/elf-rel20.l: Stderr output for the new test.
* gas/mips/elf-rel20.s: Source for the new test.
* gas/mips/mips.exp: Run the new test.
This has been tested for the mipsel-linux-gnu target with a lot of new
regressions being results of genuine gas bugs. I'll address each of them
in following mails.
OK to apply?
Maciej
binutils-2.15.91-20040625-mips-hilo-reloc-sort.patch
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/gas/config/tc-mips.c binutils-2.15.91-20040625/gas/config/tc-mips.c
--- binutils-2.15.91-20040625.macro/gas/config/tc-mips.c 2004-06-15 03:25:28.000000000 +0000
+++ binutils-2.15.91-20040625/gas/config/tc-mips.c 2004-06-27 18:24:07.000000000 +0000
@@ -872,6 +872,8 @@ static void mips16_immed
static size_t my_getSmallExpression
(expressionS *, bfd_reloc_code_real_type *, char *);
static void my_getExpression (expressionS *, char *);
+static void adjust_hi_relocs (void);
+static void adjust_lo_relocs (bfd *, asection *, void *);
static void s_align (int);
static void s_change_sec (int);
static void s_change_section (int);
@@ -10670,14 +10672,23 @@ mips_frob_file_before_adjust (void)
#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. */
+/* Reorder HI16_S and LO16 relocs to match ABI rules. This is called
+ before md_apply_fix3 and tc_gen_reloc. */
void
mips_frob_file (void)
{
+ adjust_hi_relocs ();
+ bfd_map_over_sections (stdoutput, adjust_lo_relocs, NULL);
+}
+
+/* Sort any unmatched HI16_S relocs so that they immediately precede
+ the corresponding LO reloc. Unmatched HI16_S relocs can only be
+ generated by explicit use of the %hi modifier. */
+
+static void
+adjust_hi_relocs (void)
+{
struct mips_hi_fixup *l;
for (l = mips_hi_fixup_list; l != NULL; l = l->next)
@@ -10754,6 +10765,85 @@ mips_frob_file (void)
}
}
+/* Find any orphaned LO16 relocs and reorder them so that they follow
+ their corresponding HI16_S relocs with no other intervening HI16_S relocs.
+ Unmatched LO16 relocs can only be generated by explicit use of the %lo
+ modifier. */
+
+static void
+adjust_lo_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *seg,
+ void *ptr ATTRIBUTE_UNUSED)
+{
+ segment_info_type *seginfo = seg_info (seg);
+ fixS *f, *pf = NULL;
+
+ for (f = seginfo->fix_root; f != NULL; pf = f, f = f->fx_next)
+ if (f->fx_r_type == BFD_RELOC_LO16)
+ {
+ fixS *g, *prec_hi = seginfo->fix_root, *match_hi = NULL;
+
+ /* Find the last preceding HI16_S reloc and the last preceding
+ matching HI16_S reloc. */
+ for (g = seginfo->fix_root; g != f; g = g->fx_next)
+ {
+ if (g->fx_r_type == BFD_RELOC_HI16_S
+ || (g->fx_r_type == BFD_RELOC_MIPS_GOT16
+ && pic_need_relax (g->fx_addsy, seg)))
+ prec_hi = g;
+ /* Permit matches against GOT16 relocs even if against global
+ symbols to handle variant frags. */
+ if ((g->fx_r_type == BFD_RELOC_HI16_S
+ || g->fx_r_type == BFD_RELOC_MIPS_GOT16)
+ && g->fx_addsy == f->fx_addsy && g->fx_offset == f->fx_offset)
+ {
+ prec_hi = g;
+ match_hi = g;
+ }
+ }
+
+ /* If they're the same, there's nothing to do. */
+ if (prec_hi == match_hi)
+ continue;
+
+ /* If there's no preceding matching HI16_S reloc, then try
+ to match with any succeeding one. */
+ if (!match_hi)
+ for (g = f; g != NULL; g = g->fx_next)
+ if ((g->fx_r_type == BFD_RELOC_HI16_S
+ || g->fx_r_type == BFD_RELOC_MIPS_GOT16)
+ && g->fx_addsy == f->fx_addsy && g->fx_offset == f->fx_offset)
+ match_hi = g;
+
+ /* If there's still, then it's a true orphan. The source is
+ broken; can't do much about it. */
+ if (!match_hi)
+ {
+ as_warn_where (f->fx_file, f->fx_line,
+ _("orphaned %%lo relocation"));
+ continue;
+ }
+
+ /* Order orphaned siblings by the increasing section offset. */
+ for (g = match_hi->fx_next; g != NULL; g = g->fx_next)
+ {
+ if (g->fx_r_type != BFD_RELOC_LO16
+ || g->fx_addsy != f->fx_addsy || g->fx_offset != f->fx_offset
+ || g->fx_where > f->fx_where)
+ break;
+ match_hi = g;
+ }
+
+ /* Finally place the orphan where appropriate. */
+ g = f->fx_next;
+ f->fx_next = match_hi->fx_next;
+ match_hi->fx_next = f;
+ if (pf == NULL)
+ seginfo->fix_root = g;
+ else
+ pf->fx_next = g;
+ }
+}
+
/* We may have combined relocations without symbols in the N32/N64 ABI.
We have to prevent gas from dropping them. */
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/elf-rel20.d binutils-2.15.91-20040625/gas/testsuite/gas/mips/elf-rel20.d
--- binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/elf-rel20.d 1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040625/gas/testsuite/gas/mips/elf-rel20.d 2004-06-27 16:50:49.000000000 +0000
@@ -0,0 +1,17 @@
+#readelf: --relocs
+#name: MIPS ELF reloc 20
+#as: -march=mips1 -mabi=32
+#source: elf-rel20.s
+#stderr: elf-rel20.l
+
+# Test reordering of orphaned lo16 relocs.
+
+Relocation section '\.rel\.text' at offset .* contains 7 entries:
+ *Offset * Info * Type * Sym\.Value * Sym\. Name
+0+000004 * 0+000205 * R_MIPS_HI16 * 0+000000 * \.data
+0+000000 * 0+000206 * R_MIPS_LO16 * 0+000000 * \.data
+0+000008 * 0+000206 * R_MIPS_LO16 * 0+000000 * \.data
+0+000014 * 0+000206 * R_MIPS_LO16 * 0+000000 * \.data
+0+00000c * 0+000a05 * R_MIPS_HI16 * 0+000000 * ext
+0+000010 * 0+000a06 * R_MIPS_LO16 * 0+000000 * ext
+0+000018 * 0+000206 * R_MIPS_LO16 * 0+000000 * \.data
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/elf-rel20.l binutils-2.15.91-20040625/gas/testsuite/gas/mips/elf-rel20.l
--- binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/elf-rel20.l 1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040625/gas/testsuite/gas/mips/elf-rel20.l 2004-06-27 16:45:44.000000000 +0000
@@ -0,0 +1,2 @@
+.*: Assembler messages:
+.*:19: Warning: orphaned %lo relocation
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/elf-rel20.s binutils-2.15.91-20040625/gas/testsuite/gas/mips/elf-rel20.s
--- binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/elf-rel20.s 1970-01-01 00:00:00.000000000 +0000
+++ binutils-2.15.91-20040625/gas/testsuite/gas/mips/elf-rel20.s 2004-06-27 16:33:39.000000000 +0000
@@ -0,0 +1,21 @@
+# Source file used to test reordering of orphaned lo16 relocs.
+
+ .data
+nil:
+ .asciiz "nil"
+foo:
+ .asciiz "foo"
+bar:
+ .asciiz "bar"
+
+ .text
+fun:
+ addiu $2, $0, %lo(foo)
+ lui $4, %hi(foo)
+ addiu $5, $4, %lo(foo)
+ lui $8, %hi(ext)
+ addiu $8, $8, %lo(ext)
+ addiu $4, $4, %lo(foo)
+ addiu $3, $0, %lo(bar)
+
+ .space 16
diff -up --recursive --new-file binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/mips.exp binutils-2.15.91-20040625/gas/testsuite/gas/mips/mips.exp
--- binutils-2.15.91-20040625.macro/gas/testsuite/gas/mips/mips.exp 2004-05-12 03:25:38.000000000 +0000
+++ binutils-2.15.91-20040625/gas/testsuite/gas/mips/mips.exp 2004-06-27 16:43:14.000000000 +0000
@@ -660,6 +660,7 @@ if { [istarget mips*-*-*] } then {
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"
More information about the Binutils
mailing list