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]

Alpha executables segfault when linked with -z,now


Apparently I managed to tickle a glibc bug with my
elf_backend_dtrel_excludes_plt change.  See the comment below.  This
patch avoids it.

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 3f3adc0..3e90624 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,9 @@
+2017-02-20  Alan Modra  <amodra@gmail.com>
+
+	PR 21181
+	* elflink.c (bfd_elf_final_link): Make DT_REL/DT_RELA zero
+	if DT_RELSZ/DT_RELASZ is zero.
+
 2017-02-17  Nick Clifton  <nickc@redhat.com>
 
 	* compress.c (bfd_get_full_section_contents): Remember to reduce
diff --git a/bfd/elflink.c b/bfd/elflink.c
index dfebb11..455b2c3 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -12109,6 +12109,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	  Elf_Internal_Dyn dyn;
 	  const char *name;
 	  unsigned int type;
+	  bfd_size_type sh_size;
+	  bfd_vma sh_addr;
 
 	  bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
 
@@ -12242,8 +12244,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 		type = SHT_REL;
 	      else
 		type = SHT_RELA;
-	      dyn.d_un.d_val = 0;
-	      dyn.d_un.d_ptr = 0;
+	      sh_size = 0;
+	      sh_addr = 0;
 	      for (i = 1; i < elf_numsections (abfd); i++)
 		{
 		  Elf_Internal_Shdr *hdr;
@@ -12252,28 +12254,42 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 		  if (hdr->sh_type == type
 		      && (hdr->sh_flags & SHF_ALLOC) != 0)
 		    {
-		      if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
-			dyn.d_un.d_val += hdr->sh_size;
-		      else
-			{
-			  if (dyn.d_un.d_ptr == 0
-			      || hdr->sh_addr < dyn.d_un.d_ptr)
-			    dyn.d_un.d_ptr = hdr->sh_addr;
-			}
+		      sh_size += hdr->sh_size;
+		      if (sh_addr == 0
+			  || sh_addr > hdr->sh_addr)
+			sh_addr = hdr->sh_addr;
 		    }
 		}
+
 	      if (bed->dtrel_excludes_plt && htab->srelplt != NULL)
 		{
 		  /* Don't count procedure linkage table relocs in the
 		     overall reloc count.  */
-		  if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
-		    dyn.d_un.d_val -= htab->srelplt->size;
+		  sh_size -= htab->srelplt->size;
+		  if (sh_size == 0)
+		    /* If the size is zero, make the address zero too.
+		       This is to avoid a glibc bug.  If the backend
+		       emits DT_RELA/DT_RELASZ even when DT_RELASZ is
+		       zero, then we'll put DT_RELA at the end of
+		       DT_JMPREL.  glibc will interpret the end of
+		       DT_RELA matching the end of DT_JMPREL as the
+		       case where DT_RELA includes DT_JMPREL, and for
+		       LD_BIND_NOW will decide that processing DT_RELA
+		       will process the PLT relocs too.  Net result:
+		       No PLT relocs applied.  */
+		    sh_addr = 0;
+
 		  /* If .rela.plt is the first .rela section, exclude
 		     it from DT_RELA.  */
-		  else if (dyn.d_un.d_ptr == (htab->srelplt->output_section->vma
-					      + htab->srelplt->output_offset))
-		    dyn.d_un.d_ptr += htab->srelplt->size;
+		  else if (sh_addr == (htab->srelplt->output_section->vma
+				       + htab->srelplt->output_offset))
+		    sh_addr += htab->srelplt->size;
 		}
+
+	      if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ)
+		dyn.d_un.d_val = sh_size;
+	      else
+		dyn.d_un.d_ptr = sh_addr;
 	      break;
 	    }
 	  bed->s->swap_dyn_out (dynobj, &dyn, dyncon);

-- 
Alan Modra
Australia Development Lab, IBM


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