This is the mail archive of the binutils@sources.redhat.com 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 a linker segfault for PPC sdata


This is a slightly weird patch...

One of our customers has an environment which supports both small data
access and shared libraries on PowerPC.  Non-PIC code generates sdata
relocations, PIC code doesn't.  If it so happens that a variable is defined
in a shared library, referenced in a non-PIC object, and of the appropriate
size, then there will be SDA21 relocations against it.  This crashes ld; we
check the output section for the variable unconditionally.

This is the obvious solution: generate a copy relocation into .sbss.  There
was already some code to do this, but it hasn't worked lately (I didn't do
the archeology).

OK?  Tested on cross binutils to powerpc-linux; without the bfd patch, the
ld test causes a linker segfault.

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-05-17  Daniel Jacobowitz  <dan@codesourcery.com>

	* bfd/elf32-ppc.c (struct ppc_elf_link_hash_entry): Add new field
	has_sda_refs.
	(ppc_elf_copy_indirect_symbol): Copy has_sda_refs.
	(ppc_elf_check_relocs): Set has_sda_refs.
	(ppc_elf_adjust_dynamic_symbol): Check has_sda_refs before eliminating
	copy relocations.  Use has_sda_refs to place variables in .sbss.
	(ppc_elf_finish_dynamic_symbol): Use has_sda_refs to place variables in
	.sbss.

2005-05-17  Daniel Jacobowitz  <dan@codesourcery.com>

	* ld-powerpc/sdalib.s, ld-powerpc/sdadyn.s, ld-powerpc/sdadyn.d: New
	files.
	* ld-powerpc/powerpc.exp: Run the new test.

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.159
diff -u -p -r1.159 elf32-ppc.c
--- bfd/elf32-ppc.c	17 May 2005 13:55:02 -0000	1.159
+++ bfd/elf32-ppc.c	17 May 2005 21:17:30 -0000
@@ -2241,6 +2241,10 @@ struct ppc_elf_link_hash_entry
 #define TLS_TLS		16	/* Any TLS reloc.  */
 #define TLS_TPRELGD	32	/* TPREL reloc resulting from GD->IE. */
   char tls_mask;
+
+  /* Nonzero if we have seen a small data relocation referring to this
+     symbol.  */
+  unsigned char has_sda_refs;
 };
 
 #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
@@ -2486,6 +2490,7 @@ ppc_elf_copy_indirect_symbol (const stru
     }
 
   edir->tls_mask |= eind->tls_mask;
+  edir->has_sda_refs |= eind->has_sda_refs;
 
   if (ELIMINATE_COPY_RELOCS
       && ind->root.type != bfd_link_hash_indirect
@@ -2899,6 +2904,12 @@ ppc_elf_check_relocs (bfd *abfd,
 	      bad_shared_reloc (abfd, r_type);
 	      return FALSE;
 	    }
+	  if (h != NULL)
+	    {
+	      ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
+	      /* We may need a copy reloc.  */
+	      h->non_got_ref = TRUE;
+	    }
 	  break;
 
 	case R_PPC_PLT32:
@@ -3781,7 +3792,11 @@ ppc_elf_adjust_dynamic_symbol (struct bf
   if (!h->non_got_ref)
     return TRUE;
 
-  if (ELIMINATE_COPY_RELOCS)
+   /* If we didn't find any dynamic relocs in read-only sections, then we'll
+      be keeping the dynamic relocs and avoiding the copy reloc.  We can't
+      do this if there are any small data relocations.  */
+  if (ELIMINATE_COPY_RELOCS
+      && !ppc_elf_hash_entry (h)->has_sda_refs)
     {
       struct ppc_elf_dyn_relocs *p;
       for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
@@ -3791,8 +3806,6 @@ ppc_elf_adjust_dynamic_symbol (struct bf
 	    break;
 	}
 
-      /* If we didn't find any dynamic relocs in read-only sections, then
-	 we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
       if (p == NULL)
 	{
 	  h->non_got_ref = 0;
@@ -3810,11 +3823,10 @@ ppc_elf_adjust_dynamic_symbol (struct bf
      both the dynamic object and the regular object will refer to the
      same memory location for the variable.
 
-     Of course, if the symbol is sufficiently small, we must instead
-     allocate it in .sbss.  FIXME: It would be better to do this if and
-     only if there were actually SDAREL relocs for that symbol.  */
+     Of course, if the symbol is referenced using SDAREL relocs, we
+     must instead allocate it in .sbss.  */
 
-  if (h->size <= elf_gp_size (htab->elf.dynobj))
+  if (ppc_elf_hash_entry (h)->has_sda_refs)
     s = htab->dynsbss;
   else
     s = htab->dynbss;
@@ -3828,7 +3840,7 @@ ppc_elf_adjust_dynamic_symbol (struct bf
     {
       asection *srel;
 
-      if (h->size <= elf_gp_size (htab->elf.dynobj))
+      if (ppc_elf_hash_entry (h)->has_sda_refs)
 	srel = htab->relsbss;
       else
 	srel = htab->relbss;
@@ -6265,7 +6277,7 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 
       BFD_ASSERT (h->dynindx != -1);
 
-      if (h->size <= elf_gp_size (htab->elf.dynobj))
+      if (ppc_elf_hash_entry (h)->has_sda_refs)
 	s = htab->relsbss;
       else
 	s = htab->relbss;
Index: ld/testsuite/ld-powerpc/powerpc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/powerpc.exp,v
retrieving revision 1.9
diff -u -p -r1.9 powerpc.exp
--- ld/testsuite/ld-powerpc/powerpc.exp	12 May 2005 07:32:07 -0000	1.9
+++ ld/testsuite/ld-powerpc/powerpc.exp	17 May 2005 21:17:30 -0000
@@ -69,6 +69,10 @@ set ppcelftests {
      {{readelf -WSsrl tlsso32.r} {objdump -dr tlsso32.d}
       {objdump -sj.got tlsso32.g} {objdump -sj.tdata tlsso32.t}}
       "tls32.so"}
+    {"Shared library with global symbol" "-shared -melf32ppc" "" {sdalib.s}
+     {} "sdalib.so"}
+    {"Dynamic application with SDA" "-melf32ppc tmpdir/sdalib.so" "" {sdadyn.s}
+     {{objdump -R sdadyn.d}} "sdadyn"}
 }
 
 set ppc64elftests {
Index: ld/testsuite/ld-powerpc/sdadyn.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/sdadyn.d
diff -N ld/testsuite/ld-powerpc/sdadyn.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/sdadyn.d	17 May 2005 21:17:30 -0000
@@ -0,0 +1,8 @@
+
+.*: +file format elf32-powerpc
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+#...
+.* R_PPC_COPY        lib_var
+#pass
Index: ld/testsuite/ld-powerpc/sdadyn.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/sdadyn.s
diff -N ld/testsuite/ld-powerpc/sdadyn.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/sdadyn.s	17 May 2005 21:17:30 -0000
@@ -0,0 +1,3 @@
+	.globl _start
+_start:
+	lwz	3,lib_var@sda21(0)
Index: ld/testsuite/ld-powerpc/sdalib.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/sdalib.s
diff -N ld/testsuite/ld-powerpc/sdalib.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/sdalib.s	17 May 2005 21:17:30 -0000
@@ -0,0 +1,4 @@
+	.globl lib_var
+	.type lib_var, @object
+lib_var:
+	.word	1


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