[PATCH] MIPS/BFD: Handle linker garbage collection with n64 relocs
Maciej W. Rozycki
macro@linux-mips.org
Tue Apr 10 10:23:00 GMT 2012
Hello,
Here's another problem that I stumbled upon while testing a modified
mips64-linux-gnu configuration that defaults to n64 (that probably applies
to a pristine mips64-openbsd configuration too). We fail processing
linker garbage collection of unused input sections with compound
relocations. We only ever remove the first relocation in each triplet
that is subject to GC and as a result an attempt to produce a broken
binary is made and fails miserably. This appears as follows in the ld
test suite:
Executing on host: sh -c {.../obj/ld/ld-new -o tmpdir/gcrel -L.../ld/testsuite/ld-gc -r --gc-sections -e main --defsym __stack_chk_fail=0 tmpdir/gc.o 2>&1} /dev/null ld.tmp (timeout = 300)
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2732
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2731
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2732
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2737
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2731
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2732
[...]
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2732
FAIL: Check --gc-section/-r/-e
and likewise:
Executing on host: sh -c {.../obj/ld/ld-new -o tmpdir/gcrel -L.../ld/testsuite/ld-gc -r --gc-sections -u used_func --defsym __stack_chk_fail=0 tmpdir/gc.o 2>&1} /dev/null ld.tmp (timeout = 300)
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2732
[...]
.../obj/ld/ld-new: BFD (GNU Binutils) 2.22.52.20120409 assertion fail ../../bfd/elf64-mips.c:2732
FAIL: Check --gc-section/-r/-u
The cause of this is we don't treat individual relocations in a triplet
specially and as a result any empty subsequent relocations never qualify
for removal as they do not refer to any section.
The fix below removes the problem and causes no regressions with said
modified mips64-linux-gnu configuration nor a pristine mips-linux-gnu one.
The RELOC_AGAINST_DISCARDED_SECTION macro has a bit weird semantics, it's
not really intended to behave like a function call, and I think there's
little point in making it do (e.g. adding argument protection throughout),
if at all possible. Therefore some unusual syntactic sugar had to be
added around the macro reference, so that its expansion can be executed
three times consecutively over a relocation triplet. This is explained in
the comment included with the change itself. The new code also avoids a
duplicate call to MIPS_ELF_RTYPE_TO_HOWTO, hence a bit unusual form of the
loop introduced.
OK to apply?
2012-04-10 Maciej W. Rozycki <macro@linux-mips.org>
bfd/
* elfxx-mips.c (mips_reloc_against_discarded_section): New
function.
(_bfd_mips_elf_relocate_section): Call it, in place of
RELOC_AGAINST_DISCARDED_SECTION.
Maciej
binutils-2.21-mips64-reloc-discard.patch
Index: binutils/bfd/elfxx-mips.c
===================================================================
--- binutils.orig/bfd/elfxx-mips.c
+++ binutils/bfd/elfxx-mips.c
@@ -9324,6 +9324,52 @@ mips_elf_adjust_addend (bfd *output_bfd,
}
}
+/* Handle relocations against symbols from removed linkonce sections,
+ or sections discarded by a linker script. We need this wrapper around
+ RELOC_AGAINST_DISCARDED_SECTION to handle triplets of compound relocs
+ on 64-bit ELF targets. In this case for any relocation handled, which
+ always be the first in a triplet, the remaining two have to be processed
+ likewise, even if they are R_MIPS_NONE. It is the symbol index referred
+ by the first reloc that applies to all the three and the remaining two
+ never refer to an object symbol.
+
+ Note that RELOC_AGAINST_DISCARDED_SECTION is a macro that uses "continue"
+ and therefore requires to be pasted in a loop. It also defines a block
+ and does not protect any of its arguments, hence the extra brackets. */
+
+static void
+mips_reloc_against_discarded_section (bfd *output_bfd,
+ struct bfd_link_info *info,
+ bfd *input_bfd, asection *input_section,
+ Elf_Internal_Rela **rel,
+ const Elf_Internal_Rela **relend,
+ bfd_boolean rel_reloc,
+ reloc_howto_type *howto,
+ bfd_byte *contents)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+ const int final_rel = bed->s->int_rels_per_ext_rel - 1;
+ int i = 0;
+
+ while (1)
+ {
+ do
+ {
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ (*rel), (*relend), howto, contents);
+ }
+ while (0);
+ if (i == final_rel)
+ break;
+
+ i++;
+ (*rel)++;
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd,
+ ELF_R_TYPE (output_bfd, (*rel)->r_info),
+ !rel_reloc);
+ }
+}
+
/* Relocate a MIPS ELF section. */
bfd_boolean
@@ -9390,8 +9436,12 @@ _bfd_mips_elf_relocate_section (bfd *out
}
if (sec != NULL && elf_discarded_section (sec))
- RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, relend, howto, contents);
+ {
+ mips_reloc_against_discarded_section (output_bfd, info, input_bfd,
+ input_section, &rel, &relend,
+ rel_reloc, howto, contents);
+ continue;
+ }
if (r_type == R_MIPS_64 && ! NEWABI_P (input_bfd))
{
More information about the Binutils
mailing list