This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix linking of .gpdword on MIPS


I did my first MIPS GNU/Linux testing for a long time (actually a "build
world" in order to test a dl-machine.h patch) and I found that n64 was
basically unusable; every switch statement segfaulted.  It turned out
to be fallout from:

2006-11-02  Daniel Jacobowitz  <dan@codesourcery.com>

	* libbfd-in.h (_bfd_clear_contents): New prototype.
	* reloc.c (_bfd_clear_contents): New.
	* libbfd.h: Regenerated.

	* elf32-arm.c (elf32_arm_final_link_relocate): Use
	_bfd_clear_contents.
	* elf32-d10v.c (elf32_d10v_relocate_section): Likewise.
	* elf32-hppa.c (elf32_hppa_relocate_section): Likewise.
	* elf32-i386.c (elf_i386_relocate_section): Likewise.
	* elf32-ppc.c (ppc_elf_relocate_section): Likewise.
	* elf32-s390.c (elf_s390_relocate_section): Likewise.
	* elf32-sh.c (sh_elf_relocate_section): Likewise.
	* elf32-xtensa.c (elf_xtensa_relocate_section): Likewise.
	* elf64-ppc.c (ppc64_elf_relocate_section): Likewise.
	* elf64-s390.c (elf_s390_relocate_section): Likewise.
	* elf64-x86-64.c (elf64_x86_64_relocate_section): Likewise.
	* elfxx-sparc.c (_bfd_sparc_elf_relocate_section): Likewise.

	* elfxx-ia64.c (elfNN_ia64_relocate_section): Set value to
	zero for discarded symbols.
	* elfxx-mips.c (mips_elf_calculate_relocation): Likewise.

The patch ignores the addend on a relocation against symbol 0,
on the basis that:

	/* r_symndx will be zero only for relocs against symbols
	   from removed linkonce sections, or sections discarded by
	   a linker script.  */

But that isn't true on MIPS; r_symndx is also zero the second
and subsequent entries in a composite relocation, when the addend
is carried over from the result of the previous relocations.

Are we really confident that this is the only exception, and that true
relocations against symbol zero will not reach here?  If so, I think
the patch below is the correct fix.  If not, it seems dangerous to
explicitly ignore what I understand to be correct semantics,
and treat S + A as zero simply because S is zero.

Patch tested on mips64-linux-gnu (binutils).  I'll do another build
world with it to make sure that the problem is fixed.

There are no linker tests for gpword and gpdword at present, so the
patch adds one of each.  The n32 version doesn't need a composite
relocation and works fine already.

Richard


bfd/
	* elfxx-mips.c (mips_elf_calculate_relocation): Replace
	save_addend with two new arguments, first_in_sequence and
	last_in_sequence.  Only treat zero symbols specially if
	first_in_sequence.  Replace use of !save_addend with
	last_in_sequence.
	(_bfd_mips_elf_relocate_section): Update caller accordingly.
	Replace use_save_addend_p with first_in_sequence and
	last_in_sequence.

ld/testsuite/
	* ld-mips-elf/gpword-n32.d, ld-mips-elf/gpword-n32.ld,
	* ld-mips-elf/gpword-n32.s, ld-mips-elf/gpdword-n64.d,
	* ld-mips-elf/gpdword-n64.ld, ld-mips-elf/gpdword-n64.s: New tests.
	* ld-mips-elf/mips-elf.exp: Run them.

Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.195
diff -u -p -r1.195 elfxx-mips.c
--- bfd/elfxx-mips.c	20 Feb 2007 12:35:19 -0000	1.195
+++ bfd/elfxx-mips.c	26 Feb 2007 22:23:25 -0000
@@ -3862,6 +3862,12 @@ is_gott_symbol (struct bfd_link_info *in
    REQUIRE_JALXP indicates whether or not the opcode used with this
    relocation must be JALX.
 
+   MIPS relocations are generally composite, with one of more
+   relocations being combined to produce a single field adjustment.
+   FIRST_IN_SEQUENCE is true if this relocation is the first or only
+   reloc in the composite sequence; likewise LAST_IN_SEQUENCE for the
+   last or only reloc.
+
    This function returns bfd_reloc_continue if the caller need take no
    further action regarding this relocation, bfd_reloc_notsupported if
    something goes dramatically wrong, bfd_reloc_overflow if an
@@ -3876,7 +3882,8 @@ mips_elf_calculate_relocation (bfd *abfd
 			       Elf_Internal_Sym *local_syms,
 			       asection **local_sections, bfd_vma *valuep,
 			       const char **namep, bfd_boolean *require_jalxp,
-			       bfd_boolean save_addend)
+			       bfd_boolean first_in_sequence,
+			       bfd_boolean last_in_sequence)
 {
   /* The eventual value we will return.  */
   bfd_vma value;
@@ -4323,7 +4330,7 @@ mips_elf_calculate_relocation (bfd *abfd
 						   input_section))
 	    return bfd_reloc_undefined;
 	}
-      else if (r_symndx == 0)
+      else if (first_in_sequence && r_symndx == 0)
 	/* r_symndx will be zero only for relocs against symbols
 	   from removed linkonce sections, or sections discarded by
 	   a linker script.  */
@@ -4499,7 +4506,7 @@ mips_elf_calculate_relocation (bfd *abfd
 
     case R_MIPS_GPREL32:
       value = (addend + symbol + gp0 - gp);
-      if (!save_addend)
+      if (last_in_sequence)
 	value &= howto->dst_mask;
       break;
 
@@ -7743,7 +7750,8 @@ _bfd_mips_elf_relocate_section (bfd *out
   Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *relend;
   bfd_vma addend = 0;
-  bfd_boolean use_saved_addend_p = FALSE;
+  bfd_boolean first_in_sequence = TRUE;
+  bfd_boolean last_in_sequence;
   const struct elf_backend_data *bed;
 
   bed = get_elf_backend_data (output_bfd);
@@ -7784,7 +7792,7 @@ _bfd_mips_elf_relocate_section (bfd *out
 					     (input_bfd, input_section,
 					      rel - relocs)));
 
-      if (!use_saved_addend_p)
+      if (first_in_sequence)
 	{
 	  Elf_Internal_Shdr *rel_hdr;
 
@@ -7966,9 +7974,9 @@ _bfd_mips_elf_relocate_section (bfd *out
       if (rel + 1 < relend
 	  && rel->r_offset == rel[1].r_offset
 	  && ELF_R_TYPE (input_bfd, rel[1].r_info) != R_MIPS_NONE)
-	use_saved_addend_p = TRUE;
+	last_in_sequence = FALSE;
       else
-	use_saved_addend_p = FALSE;
+	last_in_sequence = TRUE;
 
       /* Figure out what value we are supposed to relocate.  */
       switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
@@ -7976,7 +7984,8 @@ _bfd_mips_elf_relocate_section (bfd *out
 					     addend, howto, local_syms,
 					     local_sections, &value,
 					     &name, &require_jalx,
-					     use_saved_addend_p))
+					     first_in_sequence,
+					     last_in_sequence))
 	{
 	case bfd_reloc_continue:
 	  /* There's nothing to do.  */
@@ -7996,11 +8005,9 @@ _bfd_mips_elf_relocate_section (bfd *out
 	  return FALSE;
 
 	case bfd_reloc_overflow:
-	  if (use_saved_addend_p)
-	    /* Ignore overflow until we reach the last relocation for
-	       a given location.  */
-	    ;
-	  else
+	  /* Ignore overflow until we reach the last relocation for
+	     a given location.  */
+	  if (last_in_sequence)
 	    {
 	      BFD_ASSERT (name != NULL);
 	      if (! ((*info->callbacks->reloc_overflow)
@@ -8019,8 +8026,10 @@ _bfd_mips_elf_relocate_section (bfd *out
 	}
 
       /* If we've got another relocation for the address, keep going
-	 until we reach the last one.  */
-      if (use_saved_addend_p)
+	 until we reach the last one.  Set FIRST_IN_SEQUENE as
+	 appropriate for the next relocation.  */
+      first_in_sequence = last_in_sequence;
+      if (!first_in_sequence)
 	{
 	  addend = value;
 	  continue;
Index: ld/testsuite/ld-mips-elf/gpword-n32.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpword-n32.d
diff -N ld/testsuite/ld-mips-elf/gpword-n32.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpword-n32.d	26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,11 @@
+#name: MIPS .gpword (n32)
+#source: gpword-n32.s
+#as: -n32 -KPIC -EB
+#ld: -melf32btsmipn32 -Tgpword-n32.ld
+#objdump: -sj.rodata
+
+.*file format .*
+
+Contents of section \.rodata:
+ 55560000 bcdd8010 .*
+
Index: ld/testsuite/ld-mips-elf/gpword-n32.ld
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpword-n32.ld
diff -N ld/testsuite/ld-mips-elf/gpword-n32.ld
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpword-n32.ld	26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,14 @@
+SECTIONS
+{
+  . = 0x12340000;
+  .stuff : { *(.stuff) }
+
+  . = 0x55550000;
+  .text : { *(.text) }
+
+  . = ALIGN (0x10000);
+  _gp = . + 0x7ff0;
+  .rodata : { *(.rodata) }
+
+  /DISCARD/ : { *(.reginfo) }
+}
Index: ld/testsuite/ld-mips-elf/gpword-n32.s
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpword-n32.s
diff -N ld/testsuite/ld-mips-elf/gpword-n32.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpword-n32.s	26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,10 @@
+	.globl	_start
+_start:
+	jr	$31
+
+	.section .stuff
+A:
+	nop
+
+	.section .rodata
+	.gpword A
Index: ld/testsuite/ld-mips-elf/gpdword-n64.d
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpdword-n64.d
diff -N ld/testsuite/ld-mips-elf/gpdword-n64.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpdword-n64.d	26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,10 @@
+#name: MIPS .gpdword (n64)
+#source: gpdword-n64.s
+#as: -64 -KPIC -EB
+#ld: -melf64btsmip -Tgpdword-n64.ld
+#objdump: -sj.rodata
+
+.*file format .*
+
+Contents of section \.rodata:
+ 240010000 fffffffe cffe8010 .*
Index: ld/testsuite/ld-mips-elf/gpdword-n64.ld
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpdword-n64.ld
diff -N ld/testsuite/ld-mips-elf/gpdword-n64.ld
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpdword-n64.ld	26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,14 @@
+SECTIONS
+{
+  . = 0x110000000;
+  .stuff : { *(.stuff) }
+
+  . = 0x240000000;
+  .text : { *(.text) }
+
+  . = ALIGN (0x10000);
+  _gp = . + 0x7ff0;
+  .rodata : { *(.rodata) }
+
+  /DISCARD/ : { *(.reginfo) }
+}
Index: ld/testsuite/ld-mips-elf/gpdword-n64.s
===================================================================
RCS file: ld/testsuite/ld-mips-elf/gpdword-n64.s
diff -N ld/testsuite/ld-mips-elf/gpdword-n64.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-mips-elf/gpdword-n64.s	26 Feb 2007 22:23:25 -0000
@@ -0,0 +1,10 @@
+	.globl	_start
+_start:
+	jr	$31
+
+	.section .stuff
+A:
+	nop
+
+	.section .rodata
+	.gpdword A
Index: ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mips-elf/mips-elf.exp,v
retrieving revision 1.41
diff -u -p -r1.41 mips-elf.exp
--- ld/testsuite/ld-mips-elf/mips-elf.exp	2 Nov 2006 15:20:31 -0000	1.41
+++ ld/testsuite/ld-mips-elf/mips-elf.exp	26 Feb 2007 22:23:25 -0000
@@ -87,6 +87,8 @@ if { $linux_gnu } {
     run_dump_test "rel32-o32"
     run_dump_test "rel32-n32"
     run_dump_test "rel64"
+    run_dump_test "gpword-n32"
+    run_dump_test "gpdword-n64"
 }
 
 if { $embedded_elf } {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]