Subject: bug#20614: Segmentation fault when building on Power8 Little Endian

From: Andreas Schwab <[email-masked]>
Date: Sat, 10 Oct 2015 17:44:24 +0200

Please try this patch instead:

diff --git a/src/unexelf.c b/src/unexelf.c
index 483da6e..2e8b4c7 100644
--- a/src/unexelf.c
+++ b/src/unexelf.c
@@ -616,6 +616,32 @@ find_section (const char *name, const char *section_names, const char *file_name
   return -1;
 }
 
+/* Find the index of the first bss (NOBITS) section, count the number
+   of bss sections that follow and compute the overall size of these
+   sections.  */
+static int
+find_bss_sections (const char *file_name,
+		   ElfW(Ehdr) *old_file_h, ElfW(Shdr) *old_section_h,
+		   ElfW (Word) *size, int *num)
+{
+  ptrdiff_t idx;
+
+  for (idx = 1; idx < old_file_h->e_shnum; idx++)
+    if (OLD_SECTION_H (idx).sh_type == SHT_NOBITS)
+      {
+	ptrdiff_t idx2 = idx;
+
+	while (OLD_SECTION_H (idx2 + 1).sh_type == SHT_NOBITS)
+	  idx2++;
+	*size = (OLD_SECTION_H (idx2).sh_addr + OLD_SECTION_H (idx2).sh_size
+		 - OLD_SECTION_H (idx).sh_addr);
+	*num = idx2 + 1 - idx;
+	return idx;
+      }
+  fatal ("Can't find bss section in %s", file_name);
+  return -1;
+}
+
 /* ****************************************************************
  * unexec
  *
@@ -652,13 +678,14 @@ unexec (const char *new_name, const char *old_name)
 
   ElfW (Addr) old_bss_addr, new_bss_addr;
   ElfW (Word) old_bss_size, new_data2_size;
+  int n_bss_sections;
   ElfW (Off)  new_data2_offset;
   ElfW (Addr) new_data2_addr;
   ElfW (Off)  old_bss_offset;
   ElfW (Word) new_data2_incr;
 
   ptrdiff_t n, nn;
-  ptrdiff_t old_bss_index, old_sbss_index, old_plt_index;
+  ptrdiff_t old_bss_index;
   ptrdiff_t old_data_index, new_data2_index;
 #if defined _SYSTYPE_SYSV || defined __sgi
   ptrdiff_t old_mdebug_index;
@@ -716,50 +743,12 @@ unexec (const char *new_name, const char *old_name)
   /* Find the old .bss section.  Figure out parameters of the new
      data2 and bss sections.  */
 
-  old_bss_index = find_section (".bss", old_section_names,
-				old_name, old_file_h, old_section_h, 0);
-
-  old_sbss_index = find_section (".sbss", old_section_names,
-				 old_name, old_file_h, old_section_h, 1);
-  if (old_sbss_index != -1)
-    if (OLD_SECTION_H (old_sbss_index).sh_type != SHT_NOBITS)
-      old_sbss_index = -1;
-
-  /* PowerPC64 has .plt in the BSS section.  */
-  old_plt_index = find_section (".plt", old_section_names,
-				old_name, old_file_h, old_section_h, 1);
-  if (old_plt_index != -1)
-    if (OLD_SECTION_H (old_plt_index).sh_type != SHT_NOBITS)
-      old_plt_index = -1;
+  old_bss_index = find_bss_sections (old_name, old_file_h, old_section_h,
+				     &old_bss_size, &n_bss_sections);
 
-  if (old_sbss_index == -1 && old_plt_index == -1)
-    {
-      old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
-      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
-      old_bss_offset = OLD_SECTION_H (old_bss_index).sh_offset;
-      new_data2_index = old_bss_index;
-    }
-  else if (old_plt_index != -1
-	   && (old_sbss_index == -1
-	       || (OLD_SECTION_H (old_sbss_index).sh_addr
-		   > OLD_SECTION_H (old_plt_index).sh_addr)))
-    {
-      old_bss_addr = OLD_SECTION_H (old_plt_index).sh_addr;
-      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
-	+ OLD_SECTION_H (old_plt_index).sh_size;
-      if (old_sbss_index != -1)
-	old_bss_size += OLD_SECTION_H (old_sbss_index).sh_size;
-      old_bss_offset = OLD_SECTION_H (old_plt_index).sh_offset;
-      new_data2_index = old_plt_index;
-    }
-  else
-    {
-      old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
-      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
-	+ OLD_SECTION_H (old_sbss_index).sh_size;
-      old_bss_offset = OLD_SECTION_H (old_sbss_index).sh_offset;
-      new_data2_index = old_sbss_index;
-    }
+  old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
+  old_bss_offset = OLD_SECTION_H (old_bss_index).sh_offset;
+  new_data2_index = old_bss_index;
 
   /* Find the old .data section.  Figure out parameters of
      the new data2 and bss sections.  */
@@ -851,20 +840,11 @@ unexec (const char *new_name, const char *old_name)
     {
       /* Compute maximum of all requirements for alignment of section.  */
       ElfW (Word) alignment = (NEW_PROGRAM_H (n)).p_align;
-      if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
+      if (OLD_SECTION_H (old_bss_index).sh_addralign > alignment)
 	alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
 
-#ifdef __sgi
-	  /* According to [email-masked] (Karsten Kuenne)
-	     and [email-masked] (Alexandre Oliva), on IRIX 5.2, we
-	     always get "Program segment above .bss" when dumping
-	     when the executable doesn't have an sbss section.  */
-      if (old_sbss_index != -1)
-#endif /* __sgi */
       if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz
-	  > (old_sbss_index == -1
-	     ? old_bss_addr
-	     : round_up (old_bss_addr, alignment)))
+	  > round_up (old_bss_addr, alignment))
 	  fatal ("Program segment above .bss in %s", old_name);
 
       if (NEW_PROGRAM_H (n).p_type == PT_LOAD
@@ -932,12 +912,10 @@ unexec (const char *new_name, const char *old_name)
       memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n),
 	      old_file_h->e_shentsize);
 
-      if (n == old_bss_index
-	  /* The new bss and sbss section's size is zero, and its file offset
-	     and virtual address should be off by NEW_DATA2_SIZE.  */
-	  || n == old_sbss_index || n == old_plt_index
-	  )
+      if (n >= old_bss_index && n < old_bss_index + n_bss_sections)
 	{
+	  /* The new bss section's size is zero, and its file offset
+	     and virtual address should be off by NEW_DATA2_SIZE.  */
 	  /* NN should be `old_s?bss_index + 1' at this point. */
 	  NEW_SECTION_H (nn).sh_offset = new_data2_offset + new_data2_size;
 	  NEW_SECTION_H (nn).sh_addr = new_data2_addr + new_data2_size;
@@ -998,15 +976,6 @@ temacs:
 	  && NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
 	PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
 
-      if (old_sbss_index != -1)
-	if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".sbss"))
-	  {
-	    NEW_SECTION_H (nn).sh_offset =
-	      round_up (NEW_SECTION_H (nn).sh_offset,
-			NEW_SECTION_H (nn).sh_addralign);
-	    NEW_SECTION_H (nn).sh_type = SHT_PROGBITS;
-	  }
-
       /* Now, start to copy the content of sections.  */
       if (NEW_SECTION_H (nn).sh_type == SHT_NULL
 	  || NEW_SECTION_H (nn).sh_type == SHT_NOBITS)
@@ -1226,7 +1195,7 @@ temacs:
 	      nn = symp->st_shndx;
 	      if (nn > old_bss_index)
 		nn--;
-	      if (nn == old_bss_index)
+	      if (nn >= old_bss_index && nn < old_bss_index + n_bss_sections)
 		memset (new, 0, symp->st_size);
 	      else
 		{
-- 
2.6.1

Andreas.

-- 
Andreas Schwab, SUSE Labs, [email-masked]
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."