public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* PowerPC64 toc edit segfault
@ 2011-02-08  3:02 Alan Modra
  2011-02-09  8:20 ` Alan Modra
  0 siblings, 1 reply; 3+ messages in thread
From: Alan Modra @ 2011-02-08  3:02 UTC (permalink / raw)
  To: binutils

This fixes an oversight in the PowerPC64 linker TOC editing code, that
can lead to a segfault.  An input object file may have a non-empty
.toc section but no references to the .toc entries.  Odd, but possible.
Most likely with user assembly, but might also occur due to compiler
bugs.

Applied mainline and branch.

	* elf64-ppc.c (ppc64_elf_edit_toc): Don't segfault on NULL
	local_syms when looking for local symbols in .toc.

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.340
diff -u -p -r1.340 elf64-ppc.c
--- bfd/elf64-ppc.c	31 Jan 2011 22:38:26 -0000	1.340
+++ bfd/elf64-ppc.c	8 Feb 2011 01:33:46 -0000
@@ -8372,34 +8372,35 @@ ppc64_elf_edit_toc (struct bfd_link_info
 
 	  /* We shouldn't have local or global symbols defined in the TOC,
 	     but handle them anyway.  */
-	  for (sym = local_syms;
-	       sym < local_syms + symtab_hdr->sh_info;
-	       ++sym)
-	    if (sym->st_value != 0
-		&& bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
-	      {
-		unsigned long i;
+	  if (local_syms != NULL)
+	    for (sym = local_syms;
+		 sym < local_syms + symtab_hdr->sh_info;
+		 ++sym)
+	      if (sym->st_value != 0
+		  && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
+		{
+		  unsigned long i;
 
-		if (sym->st_value > toc->rawsize)
-		  i = toc->rawsize >> 3;
-		else
-		  i = sym->st_value >> 3;
+		  if (sym->st_value > toc->rawsize)
+		    i = toc->rawsize >> 3;
+		  else
+		    i = sym->st_value >> 3;
 
-		if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
-		  {
-		    if (local_toc_syms)
-		      (*_bfd_error_handler)
-			(_("%s defined on removed toc entry"),
-			 bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
-		    do
-		      ++i;
-		    while ((skip[i] & (ref_from_discarded | can_optimize)));
-		    sym->st_value = (bfd_vma) i << 3;
-		  }
+		  if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
+		    {
+		      if (local_toc_syms)
+			(*_bfd_error_handler)
+			  (_("%s defined on removed toc entry"),
+			   bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+		      do
+			++i;
+		      while ((skip[i] & (ref_from_discarded | can_optimize)));
+		      sym->st_value = (bfd_vma) i << 3;
+		    }
 
-		sym->st_value -= skip[i];
-		symtab_hdr->contents = (unsigned char *) local_syms;
-	      }
+		  sym->st_value -= skip[i];
+		  symtab_hdr->contents = (unsigned char *) local_syms;
+		}
 
 	  /* Adjust any global syms defined in this toc input section.  */
 	  if (toc_inf.global_toc_syms)

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: PowerPC64 toc edit segfault
  2011-02-08  3:02 PowerPC64 toc edit segfault Alan Modra
@ 2011-02-09  8:20 ` Alan Modra
  2011-02-15  4:00   ` Alan Modra
  0 siblings, 1 reply; 3+ messages in thread
From: Alan Modra @ 2011-02-09  8:20 UTC (permalink / raw)
  To: binutils

This fixes two segfaults in ppc64_elf_edit_toc, found when simply
running the binutils testsuite using an -mcmodel=medium ppc64
compiler.  Embarrassing.  My binutils testsuite runs weren't using a
new bleeding edge compiler as I thought, but the old 4.4.1 system
compiler.

Also fixes a number of ld tests that fail/xpass with a new ppc64 gcc.
I'm disabling the non-PIC visibility tests entirely for
powerpc*-linux.  See the comment for why.

Applied mainline and 2.21 branch.

bfd/
	* elf64-ppc.c (ppc64_elf_edit_toc): Don't free toc relocs until
	we are done.  When optimising large toc, check that a global
	symbol on a toc reloc is defined in a kept section.
ld/testsuite/
	* ld-elfvsb/elfvsb.exp: Don't run any non-PIC tests on powerpc*-linux.
	* ld-gc/gc.exp: Ensure powerpc64 test continues to fail.
	* ld-srec/srec.exp: Don't edit toc on powerpc64.

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.341
diff -u -p -r1.341 elf64-ppc.c
--- bfd/elf64-ppc.c	8 Feb 2011 02:54:42 -0000	1.341
+++ bfd/elf64-ppc.c	9 Feb 2011 06:52:20 -0000
@@ -7907,7 +7908,7 @@ ppc64_elf_edit_toc (struct bfd_link_info
       asection *toc, *sec;
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
-      Elf_Internal_Rela *relstart, *rel;
+      Elf_Internal_Rela *relstart, *rel, *toc_relocs;
       unsigned long *skip, *drop;
       unsigned char *used;
       unsigned char *keep, last, some_unused;
@@ -7922,6 +7923,7 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	  || elf_discarded_section (toc))
 	continue;
 
+      toc_relocs = NULL;
       local_syms = NULL;
       symtab_hdr = &elf_symtab_hdr (ibfd);
 
@@ -8017,12 +8019,12 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	  && toc->reloc_count != 0)
 	{
 	  /* Read toc relocs.  */
-	  relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
-						info->keep_memory);
-	  if (relstart == NULL)
+	  toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+						  info->keep_memory);
+	  if (toc_relocs == NULL)
 	    goto error_ret;
 
-	  for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+	  for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
 	    {
 	      enum elf_ppc64_reloc_type r_type;
 	      unsigned long r_symndx;
@@ -8040,6 +8042,10 @@ ppc64_elf_edit_toc (struct bfd_link_info
 			      r_symndx, ibfd))
 		goto error_ret;
 
+	      if (sym_sec == NULL
+		  || elf_discarded_section (sym_sec))
+		continue;
+
 	      if (!SYMBOL_CALLS_LOCAL (info, h))
 		continue;
 
@@ -8078,11 +8084,8 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		}
 
 	      skip[rel->r_offset >> 3]
-		|= can_optimize | ((rel - relstart) << 2);
+		|= can_optimize | ((rel - toc_relocs) << 2);
 	    }
-
-	  if (elf_section_data (toc)->relocs != relstart)
-	    free (relstart);
 	}
 
       if (skip == NULL)
@@ -8099,6 +8102,9 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	      && relstart != NULL
 	      && elf_section_data (sec)->relocs != relstart)
 	    free (relstart);
+	  if (toc_relocs != NULL
+	      && elf_section_data (toc)->relocs != toc_relocs)
+	    free (toc_relocs);
 	  if (skip != NULL)
 	    free (skip);
 	  return FALSE;
@@ -8338,7 +8344,7 @@ ppc64_elf_edit_toc (struct bfd_link_info
 		  else if ((skip[val >> 3] & can_optimize) != 0)
 		    {
 		      Elf_Internal_Rela *tocrel
-			= elf_section_data (toc)->relocs + (skip[val >> 3] >> 2);
+			= toc_relocs + (skip[val >> 3] >> 2);
 		      unsigned long tsym = ELF64_R_SYM (tocrel->r_info);
 
 		      switch (r_type)
@@ -8418,15 +8424,9 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	      Elf_Internal_Rela *wrel;
 	      bfd_size_type sz;
 
-	      /* Read toc relocs.  */
-	      relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
-						    TRUE);
-	      if (relstart == NULL)
-		goto error_ret;
-
 	      /* Remove unused toc relocs, and adjust those we keep.  */
-	      wrel = relstart;
-	      for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+	      wrel = toc_relocs;
+	      for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
 		if ((skip[rel->r_offset >> 3]
 		     & (ref_from_discarded | can_optimize)) == 0)
 		  {
@@ -8439,12 +8439,15 @@ ppc64_elf_edit_toc (struct bfd_link_info
 					    &local_syms, NULL, NULL))
 		  goto error_ret;
 
-	      toc->reloc_count = wrel - relstart;
+	      elf_section_data (toc)->relocs = toc_relocs;
+	      toc->reloc_count = wrel - toc_relocs;
 	      rel_hdr = _bfd_elf_single_rel_hdr (toc);
 	      sz = rel_hdr->sh_entsize;
 	      rel_hdr->sh_size = toc->reloc_count * sz;
 	    }
 	}
+      else if (elf_section_data (toc)->relocs != toc_relocs)
+	free (toc_relocs);
 
       if (local_syms != NULL
 	  && symtab_hdr->contents != (unsigned char *) local_syms)
Index: ld/testsuite/ld-elfvsb/elfvsb.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-elfvsb/elfvsb.exp,v
retrieving revision 1.34
diff -u -p -r1.34 elfvsb.exp
--- ld/testsuite/ld-elfvsb/elfvsb.exp	8 Nov 2010 06:43:37 -0000	1.34
+++ ld/testsuite/ld-elfvsb/elfvsb.exp	9 Feb 2011 07:54:30 -0000
@@ -249,6 +249,14 @@ proc visibility_run {visibility} {
 	set VSBCFLAG ""
     }}}}}}}}}
 
+    if { [istarget powerpc*-*-linux*] } {
+	# Testing non-PIC libraries is a waste of effort on any target.
+	# If you don't pass -fpic or -fPIC to gcc, gcc will assume quite
+	# reasonably that you are not compiling for a shared library.
+	# It can then make optimisations that result in shared library
+	# functions and variables not being overridable.  Newer versions
+	# of gcc are more likely to do this.
+    } else {
     # Compile the main program.
     if ![ld_compile "$CC -g $CFLAGS $SHCFLAG $VSBCFLAG" $srcdir/$subdir/main.c $tmpdir/mainnp.o] {
 	unresolved "visibility ($visibility) (non PIC)"
@@ -369,8 +377,11 @@ proc visibility_run {visibility} {
 		visibility_test $visibility vp "visibility ($visibility)" mainnp.o sh1p.o sh2p.o elfvsb
 	    } }
 	}
-    }
+    }}
 
+    if { [istarget powerpc*-*-linux*] } {
+	# Don't bother.
+    } else {
     # Now do the same tests again, but this time compile main.c PIC.
     if ![ld_compile "$CC -g $CFLAGS $SHCFLAG $VSBCFLAG -DSHARED $picflag" $srcdir/$subdir/main.c $tmpdir/mainp.o] {
 	unresolved "visibility ($visibility) (PIC main, non PIC so)"
@@ -433,7 +444,7 @@ proc visibility_run {visibility} {
 	} else {
 	    unresolved "visibility ($visibility) (PIC main)"
 	}
-    }
+    }}
 }
 
 if [istarget mips*-*-*] {
Index: ld/testsuite/ld-gc/gc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-gc/gc.exp,v
retrieving revision 1.10
diff -u -p -r1.10 gc.exp
--- ld/testsuite/ld-gc/gc.exp	8 Nov 2010 06:43:37 -0000	1.10
+++ ld/testsuite/ld-gc/gc.exp	9 Feb 2011 07:54:30 -0000
@@ -27,6 +27,11 @@ if ![check_gc_sections_available] {
 set cflags "-ffunction-sections -fdata-sections"
 set objfile "tmpdir/gc.o"
 
+if [istarget powerpc64*-*-*] {
+    # otherwise with -mcmodel=medium gcc we get XPASSes.
+    set cflags "$cflags -mminimal-toc"
+}
+
 if { [is_remote host] || [which $CC] != 0 } {
     ld_compile "$CC -c $CFLAGS $cflags" $srcdir/$subdir/gc.c $objfile
 }
Index: ld/testsuite/ld-srec/srec.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-srec/srec.exp,v
retrieving revision 1.33
diff -u -p -r1.33 srec.exp
--- ld/testsuite/ld-srec/srec.exp	1 Oct 2009 23:29:28 -0000	1.33
+++ ld/testsuite/ld-srec/srec.exp	9 Feb 2011 07:54:31 -0000
@@ -271,6 +271,10 @@ proc run_srec_test { test objs } {
 	set flags "$flags -no-relax"
     }
 
+    if [istarget powerpc64*-*-*] {
+	set flags "$flags --no-toc-optimize"
+    }
+
     if { ![ld_simple_link $ld tmpdir/sr1 "$flags $objs"] \
 	 || ![ld_simple_link $ld tmpdir/sr2.sr "$flags --oformat srec $objs"] } {
 	fail $test

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: PowerPC64 toc edit segfault
  2011-02-09  8:20 ` Alan Modra
@ 2011-02-15  4:00   ` Alan Modra
  0 siblings, 0 replies; 3+ messages in thread
From: Alan Modra @ 2011-02-15  4:00 UTC (permalink / raw)
  To: binutils

On Wed, Feb 09, 2011 at 06:50:28PM +1030, Alan Modra wrote:
> This fixes two segfaults in ppc64_elf_edit_toc, found when simply

> @@ -8418,15 +8424,9 @@ ppc64_elf_edit_toc (struct bfd_link_info
>  	      Elf_Internal_Rela *wrel;
>  	      bfd_size_type sz;
>  
> -	      /* Read toc relocs.  */
> -	      relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
> -						    TRUE);
> -	      if (relstart == NULL)
> -		goto error_ret;
> -
>  	      /* Remove unused toc relocs, and adjust those we keep.  */
> -	      wrel = relstart;
> -	      for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
> +	      wrel = toc_relocs;
> +	      for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
>  		if ((skip[rel->r_offset >> 3]
>  		     & (ref_from_discarded | can_optimize)) == 0)
>  		  {

Blah.  Removing the above "Read toc relocs" caused a segfault when
linking -mcmodel=small code.

	* elf64-ppc.c (ppc64_elf_edit_toc): Reinstate second read of
	toc relocs.  Fuss over free(NULL).

Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.342
diff -u -p -r1.342 elf64-ppc.c
--- bfd/elf64-ppc.c	9 Feb 2011 08:16:00 -0000	1.342
+++ bfd/elf64-ppc.c	15 Feb 2011 03:54:10 -0000
@@ -8424,6 +8424,12 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	      bfd_size_type sz;
 
 	      /* Remove unused toc relocs, and adjust those we keep.  */
+	      if (toc_relocs == NULL)
+		toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+							info->keep_memory);
+	      if (toc_relocs == NULL)
+		goto error_ret;
+
 	      wrel = toc_relocs;
 	      for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
 		if ((skip[rel->r_offset >> 3]
@@ -8445,7 +8451,8 @@ ppc64_elf_edit_toc (struct bfd_link_info
 	      rel_hdr->sh_size = toc->reloc_count * sz;
 	    }
 	}
-      else if (elf_section_data (toc)->relocs != toc_relocs)
+      else if (toc_relocs != NULL
+	       && elf_section_data (toc)->relocs != toc_relocs)
 	free (toc_relocs);
 
       if (local_syms != NULL

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2011-02-15  4:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-08  3:02 PowerPC64 toc edit segfault Alan Modra
2011-02-09  8:20 ` Alan Modra
2011-02-15  4:00   ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).