[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