Jan Synacek e76854
From 75dc7e12d73ad8c1bf9583515e41913980883dbe Mon Sep 17 00:00:00 2001
Jan Synacek e76854
From: Alan Modra <amodra@gmail.com>
Jan Synacek e76854
Date: Sun, 8 Nov 2015 09:29:00 -0800
Jan Synacek e76854
Subject: ELF unexec: Drive from PT_LOAD header rather than sections
Jan Synacek e76854
Jan Synacek e76854
Emacs should build on ppc64el.  A problem with the bss has been fixed.
Jan Synacek e76854
Jan Synacek e76854
This upstream patch has been added [7/10]:
Jan Synacek e76854
Jan Synacek e76854
  ELF unexec: Drive from PT_LOAD header rather than sections
Jan Synacek e76854
Jan Synacek e76854
  This rewrites bss handling in the ELF unexec code.  Finding bss
Jan Synacek e76854
  sections by name results in complicated code that
Jan Synacek e76854
  - does not account for all names of possible bss sections,
Jan Synacek e76854
  - assumes specific ordering of bss sections,
Jan Synacek e76854
  - can wrongly choose a SHT_NOBITS section not in the bss segment,
Jan Synacek e76854
  - incorrectly calculates bss size (no accounting for alignment gaps),
Jan Synacek e76854
  - assumes .data and .bss are in the same segment.
Jan Synacek e76854
Jan Synacek e76854
  All of these problems and more are solved by finding the bss segment
Jan Synacek e76854
  in PT_LOAD headers, ie. the address range included in p_memsz but not
Jan Synacek e76854
  p_filesz of the last PT_LOAD header, then matching SHT_NOBITS sections
Jan Synacek e76854
  in that address range.
Jan Synacek e76854
Jan Synacek e76854
  * unexelf.c: Delete old ppc comment.
Jan Synacek e76854
  (OLD_PROGRAM_H): Define.
Jan Synacek e76854
  (round_up): Delete.
Jan Synacek e76854
  (unexec): Don't search for bss style sections by name.  Instead,
Jan Synacek e76854
  use the last PT_LOAD header address range covered by p_memsz
Jan Synacek e76854
  but not p_filesz and match any SHT_NOBITS section in that
Jan Synacek e76854
  address range.  Simplify initialisation of section header vars.
Jan Synacek e76854
  Don't assume that section headers are above bss segment.  Move
Jan Synacek e76854
  copying of bss area out of section loop.  Align .data2 section
Jan Synacek e76854
  to 1, since it now covers the entire bss area.  For SHT_NOBITS
Jan Synacek e76854
  sections in the bss segment, leave sh_addr and sh_addralign
Jan Synacek e76854
  unchanged, but correct sh_offset.  Clear memory corresponding
Jan Synacek e76854
  to SHT_NOBITS .plt section.  Delete comment and hacks for
Jan Synacek e76854
  sections partly overlapping bss range now that the full range
Jan Synacek e76854
  is properly calculated.  Delete now dead .sbss code.
Jan Synacek e76854
  (Bug#20614)
Jan Synacek e76854
Jan Synacek e76854
Origin: upstream, commit: 0d6442265e5b709af5eebedf8f0d6b82974f4c31
Jan Synacek e76854
Bug: http://debbugs.gnu.org/20614
Jan Synacek e76854
Bug-Debian: http://bugs.debian.org/808347
Jan Synacek e76854
Added-by: Rob Browning <rlb@defaultvalue.org>
Jan Synacek e76854
---
Jan Synacek e76854
 src/unexelf.c |  292 +++++++++++++++-------------------------------------------
Jan Synacek e76854
 1 file changed, 78 insertions(+), 214 deletions(-)
Jan Synacek e76854
Jan Synacek e76854
Index: emacs-24.5/src/unexelf.c
Jan Synacek e76854
===================================================================
Jan Synacek e76854
--- emacs-24.5.orig/src/unexelf.c
Jan Synacek e76854
+++ emacs-24.5/src/unexelf.c
Jan Synacek e76854
@@ -535,29 +535,6 @@ verify ((! TYPE_SIGNED (ElfW (Half))
Jan Synacek e76854
 /* Get the address of a particular section or program header entry,
Jan Synacek e76854
  * accounting for the size of the entries.
Jan Synacek e76854
  */
Jan Synacek e76854
-/*
Jan Synacek e76854
-   On PPC Reference Platform running Solaris 2.5.1
Jan Synacek e76854
-   the plt section is also of type NOBI like the bss section.
Jan Synacek e76854
-   (not really stored) and therefore sections after the bss
Jan Synacek e76854
-   section start at the plt offset. The plt section is always
Jan Synacek e76854
-   the one just before the bss section.
Jan Synacek e76854
-   Thus, we modify the test from
Jan Synacek e76854
-      if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset)
Jan Synacek e76854
-   to
Jan Synacek e76854
-      if (NEW_SECTION_H (nn).sh_offset >=
Jan Synacek e76854
-               OLD_SECTION_H (old_bss_index-1).sh_offset)
Jan Synacek e76854
-   This is just a hack. We should put the new data section
Jan Synacek e76854
-   before the .plt section.
Jan Synacek e76854
-   And we should not have this routine at all but use
Jan Synacek e76854
-   the libelf library to read the old file and create the new
Jan Synacek e76854
-   file.
Jan Synacek e76854
-   The changed code is minimal and depends on prep set in m/prep.h
Jan Synacek e76854
-   Erik Deumens
Jan Synacek e76854
-   Quantum Theory Project
Jan Synacek e76854
-   University of Florida
Jan Synacek e76854
-   deumens@qtp.ufl.edu
Jan Synacek e76854
-   Apr 23, 1996
Jan Synacek e76854
-   */
Jan Synacek e76854
 
Jan Synacek e76854
 static void *
Jan Synacek e76854
 entry_address (void *section_h, ptrdiff_t idx, ptrdiff_t entsize)
Jan Synacek e76854
@@ -570,23 +547,14 @@ entry_address (void *section_h, ptrdiff_
Jan Synacek e76854
   (*(ElfW (Shdr) *) entry_address (old_section_h, n, old_file_h->e_shentsize))
Jan Synacek e76854
 #define NEW_SECTION_H(n) \
Jan Synacek e76854
   (*(ElfW (Shdr) *) entry_address (new_section_h, n, new_file_h->e_shentsize))
Jan Synacek e76854
+#define OLD_PROGRAM_H(n) \
Jan Synacek e76854
+  (*(ElfW (Phdr) *) entry_address (old_program_h, n, old_file_h->e_phentsize))
Jan Synacek e76854
 #define NEW_PROGRAM_H(n) \
Jan Synacek e76854
   (*(ElfW (Phdr) *) entry_address (new_program_h, n, new_file_h->e_phentsize))
Jan Synacek e76854
 
Jan Synacek e76854
 #define PATCH_INDEX(n) ((n) += old_bss_index <= (n))
Jan Synacek e76854
 typedef unsigned char byte;
Jan Synacek e76854
 
Jan Synacek e76854
-/* Round X up to a multiple of Y.  */
Jan Synacek e76854
-
Jan Synacek e76854
-static ElfW (Addr)
Jan Synacek e76854
-round_up (ElfW (Addr) x, ElfW (Addr) y)
Jan Synacek e76854
-{
Jan Synacek e76854
-  ElfW (Addr) rem = x % y;
Jan Synacek e76854
-  if (rem == 0)
Jan Synacek e76854
-    return x;
Jan Synacek e76854
-  return x - rem + y;
Jan Synacek e76854
-}
Jan Synacek e76854
-
Jan Synacek e76854
 /* Return the index of the section named NAME.
Jan Synacek e76854
    SECTION_NAMES, FILE_NAME and FILE_H give information
Jan Synacek e76854
    about the file we are looking in.
Jan Synacek e76854
@@ -650,16 +618,15 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   /* Point to the section name table in the old file.  */
Jan Synacek e76854
   char *old_section_names;
Jan Synacek e76854
 
Jan Synacek e76854
+  ElfW (Phdr) *old_bss_seg, *new_bss_seg;
Jan Synacek e76854
   ElfW (Addr) old_bss_addr, new_bss_addr;
Jan Synacek e76854
   ElfW (Word) old_bss_size, new_data2_size;
Jan Synacek e76854
   ElfW (Off)  new_data2_offset;
Jan Synacek e76854
   ElfW (Addr) new_data2_addr;
Jan Synacek e76854
   ElfW (Off)  old_bss_offset;
Jan Synacek e76854
-  ElfW (Word) new_data2_incr;
Jan Synacek e76854
 
Jan Synacek e76854
   ptrdiff_t n, nn;
Jan Synacek e76854
-  ptrdiff_t old_bss_index, old_sbss_index, old_plt_index;
Jan Synacek e76854
-  ptrdiff_t old_data_index, new_data2_index;
Jan Synacek e76854
+  ptrdiff_t old_bss_index, old_data_index;
Jan Synacek e76854
   struct stat stat_buf;
Jan Synacek e76854
   off_t old_file_size;
Jan Synacek e76854
   int mask;
Jan Synacek e76854
@@ -704,54 +671,40 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   old_section_names = (char *) old_base
Jan Synacek e76854
     + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
Jan Synacek e76854
 
Jan Synacek e76854
-  /* Find the old .bss section.  Figure out parameters of the new
Jan Synacek e76854
-     data2 and bss sections.  */
Jan Synacek e76854
-
Jan Synacek e76854
-  old_bss_index = find_section (".bss", old_section_names,
Jan Synacek e76854
-				old_name, old_file_h, old_section_h, 0);
Jan Synacek e76854
-
Jan Synacek e76854
-  old_sbss_index = find_section (".sbss", old_section_names,
Jan Synacek e76854
-				 old_name, old_file_h, old_section_h, 1);
Jan Synacek e76854
-  if (old_sbss_index != -1)
Jan Synacek e76854
-    if (OLD_SECTION_H (old_sbss_index).sh_type != SHT_NOBITS)
Jan Synacek e76854
-      old_sbss_index = -1;
Jan Synacek e76854
-
Jan Synacek e76854
-  /* PowerPC64 has .plt in the BSS section.  */
Jan Synacek e76854
-  old_plt_index = find_section (".plt", old_section_names,
Jan Synacek e76854
-				old_name, old_file_h, old_section_h, 1);
Jan Synacek e76854
-  if (old_plt_index != -1)
Jan Synacek e76854
-    if (OLD_SECTION_H (old_plt_index).sh_type != SHT_NOBITS)
Jan Synacek e76854
-      old_plt_index = -1;
Jan Synacek e76854
-
Jan Synacek e76854
-  if (old_sbss_index == -1 && old_plt_index == -1)
Jan Synacek e76854
-    {
Jan Synacek e76854
-      old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
Jan Synacek e76854
-      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
Jan Synacek e76854
-      old_bss_offset = OLD_SECTION_H (old_bss_index).sh_offset;
Jan Synacek e76854
-      new_data2_index = old_bss_index;
Jan Synacek e76854
-    }
Jan Synacek e76854
-  else if (old_plt_index != -1
Jan Synacek e76854
-	   && (old_sbss_index == -1
Jan Synacek e76854
-	       || (OLD_SECTION_H (old_sbss_index).sh_addr
Jan Synacek e76854
-		   > OLD_SECTION_H (old_plt_index).sh_addr)))
Jan Synacek e76854
+  /* Find the PT_LOAD header covering the highest address.  This
Jan Synacek e76854
+     segment will be where bss sections are located, past p_filesz.  */
Jan Synacek e76854
+  old_bss_seg = 0;
Jan Synacek e76854
+  for (n = old_file_h->e_phnum; --n >= 0; )
Jan Synacek e76854
     {
Jan Synacek e76854
-      old_bss_addr = OLD_SECTION_H (old_plt_index).sh_addr;
Jan Synacek e76854
-      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
Jan Synacek e76854
-	+ OLD_SECTION_H (old_plt_index).sh_size;
Jan Synacek e76854
-      if (old_sbss_index != -1)
Jan Synacek e76854
-	old_bss_size += OLD_SECTION_H (old_sbss_index).sh_size;
Jan Synacek e76854
-      old_bss_offset = OLD_SECTION_H (old_plt_index).sh_offset;
Jan Synacek e76854
-      new_data2_index = old_plt_index;
Jan Synacek e76854
+      ElfW (Phdr) *seg = &OLD_PROGRAM_H (n);
Jan Synacek e76854
+      if (seg->p_type == PT_LOAD
Jan Synacek e76854
+	  && (old_bss_seg == 0
Jan Synacek e76854
+	      || seg->p_vaddr > old_bss_seg->p_vaddr))
Jan Synacek e76854
+	old_bss_seg = seg;
Jan Synacek e76854
     }
Jan Synacek e76854
-  else
Jan Synacek e76854
+
Jan Synacek e76854
+  /* Note that old_bss_addr may be lower than the first bss section
Jan Synacek e76854
+     address, since the section may need aligning.  */
Jan Synacek e76854
+  old_bss_addr = old_bss_seg->p_vaddr + old_bss_seg->p_filesz;
Jan Synacek e76854
+  old_bss_offset = old_bss_seg->p_offset + old_bss_seg->p_filesz;
Jan Synacek e76854
+  old_bss_size = old_bss_seg->p_memsz - old_bss_seg->p_filesz;
Jan Synacek e76854
+
Jan Synacek e76854
+  /* Find the first bss style section in the bss segment range.  */
Jan Synacek e76854
+  old_bss_index = -1;
Jan Synacek e76854
+  for (n = old_file_h->e_shnum; --n > 0; )
Jan Synacek e76854
     {
Jan Synacek e76854
-      old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
Jan Synacek e76854
-      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
Jan Synacek e76854
-	+ OLD_SECTION_H (old_sbss_index).sh_size;
Jan Synacek e76854
-      old_bss_offset = OLD_SECTION_H (old_sbss_index).sh_offset;
Jan Synacek e76854
-      new_data2_index = old_sbss_index;
Jan Synacek e76854
+      ElfW (Shdr) *shdr = &OLD_SECTION_H (n);
Jan Synacek e76854
+      if (shdr->sh_type == SHT_NOBITS
Jan Synacek e76854
+	  && shdr->sh_addr >= old_bss_addr
Jan Synacek e76854
+	  && shdr->sh_addr + shdr->sh_size <= old_bss_addr + old_bss_size
Jan Synacek e76854
+	  && (old_bss_index == -1
Jan Synacek e76854
+	      || OLD_SECTION_H (old_bss_index).sh_addr > shdr->sh_addr))
Jan Synacek e76854
+	old_bss_index = n;
Jan Synacek e76854
     }
Jan Synacek e76854
 
Jan Synacek e76854
+  if (old_bss_index == -1)
Jan Synacek e76854
+    fatal ("no bss section found");
Jan Synacek e76854
+
Jan Synacek e76854
   /* Find the old .data section.  Figure out parameters of
Jan Synacek e76854
      the new data2 and bss sections.  */
Jan Synacek e76854
 
Jan Synacek e76854
@@ -762,13 +715,7 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   new_bss_addr = (ElfW (Addr)) new_break;
Jan Synacek e76854
   new_data2_addr = old_bss_addr;
Jan Synacek e76854
   new_data2_size = new_bss_addr - old_bss_addr;
Jan Synacek e76854
-  new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset
Jan Synacek e76854
-    + (new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
Jan Synacek e76854
-  /* This is the amount by which the sections following the bss sections
Jan Synacek e76854
-     must be shifted in the image.  It can differ from new_data2_size if
Jan Synacek e76854
-     the end of the old .data section (and thus the offset of the .bss
Jan Synacek e76854
-     section) was unaligned.  */
Jan Synacek e76854
-  new_data2_incr = new_data2_size + (new_data2_offset - old_bss_offset);
Jan Synacek e76854
+  new_data2_offset = old_bss_offset;
Jan Synacek e76854
 
Jan Synacek e76854
 #ifdef UNEXELF_DEBUG
Jan Synacek e76854
   fprintf (stderr, "old_bss_index %td\n", old_bss_index);
Jan Synacek e76854
@@ -779,7 +726,6 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   DEBUG_LOG (new_data2_addr);
Jan Synacek e76854
   DEBUG_LOG (new_data2_size);
Jan Synacek e76854
   DEBUG_LOG (new_data2_offset);
Jan Synacek e76854
-  DEBUG_LOG (new_data2_incr);
Jan Synacek e76854
 #endif
Jan Synacek e76854
 
Jan Synacek e76854
   if (new_bss_addr < old_bss_addr + old_bss_size)
Jan Synacek e76854
@@ -793,7 +739,7 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   if (new_file < 0)
Jan Synacek e76854
     fatal ("Can't creat (%s): %s", new_name, strerror (errno));
Jan Synacek e76854
 
Jan Synacek e76854
-  new_file_size = old_file_size + old_file_h->e_shentsize + new_data2_incr;
Jan Synacek e76854
+  new_file_size = old_file_size + old_file_h->e_shentsize + new_data2_size;
Jan Synacek e76854
 
Jan Synacek e76854
   if (ftruncate (new_file, new_file_size))
Jan Synacek e76854
     fatal ("Can't ftruncate (%s): %s", new_name, strerror (errno));
Jan Synacek e76854
@@ -812,15 +758,15 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   /* Fix up file header.  We'll add one section.  Section header is
Jan Synacek e76854
      further away now.  */
Jan Synacek e76854
 
Jan Synacek e76854
-  new_file_h->e_shoff += new_data2_incr;
Jan Synacek e76854
+  if (new_file_h->e_shoff >= old_bss_offset)
Jan Synacek e76854
+    new_file_h->e_shoff += new_data2_size;
Jan Synacek e76854
   new_file_h->e_shnum += 1;
Jan Synacek e76854
 
Jan Synacek e76854
   /* Modify the e_shstrndx if necessary. */
Jan Synacek e76854
   PATCH_INDEX (new_file_h->e_shstrndx);
Jan Synacek e76854
 
Jan Synacek e76854
-  new_program_h = (ElfW (Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
Jan Synacek e76854
-  new_section_h = (ElfW (Shdr) *)
Jan Synacek e76854
-    ((byte *) new_base + old_file_h->e_shoff + new_data2_incr);
Jan Synacek e76854
+  new_program_h = (ElfW (Phdr) *) ((byte *) new_base + new_file_h->e_phoff);
Jan Synacek e76854
+  new_section_h = (ElfW (Shdr) *) ((byte *) new_base + new_file_h->e_shoff);
Jan Synacek e76854
 
Jan Synacek e76854
   memcpy (new_program_h, old_program_h,
Jan Synacek e76854
 	  old_file_h->e_phnum * old_file_h->e_phentsize);
Jan Synacek e76854
@@ -832,65 +778,21 @@ unexec (const char *new_name, const char
Jan Synacek e76854
   fprintf (stderr, "New section count %td\n", (ptrdiff_t) new_file_h->e_shnum);
Jan Synacek e76854
 #endif
Jan Synacek e76854
 
Jan Synacek e76854
-  /* Fix up a new program header.  Extend the writable data segment so
Jan Synacek e76854
-     that the bss area is covered too. Find that segment by looking
Jan Synacek e76854
-     for a segment that ends just before the .bss area.  Make sure
Jan Synacek e76854
-     that no segments are above the new .data2.  Put a loop at the end
Jan Synacek e76854
-     to adjust the offset and address of any segment that is above
Jan Synacek e76854
-     data2, just in case we decide to allow this later.  */
Jan Synacek e76854
+  /* Fix up program header.  Extend the writable data segment so
Jan Synacek e76854
+     that the bss area is covered too.  */
Jan Synacek e76854
 
Jan Synacek e76854
-  for (n = new_file_h->e_phnum; --n >= 0; )
Jan Synacek e76854
-    {
Jan Synacek e76854
-      /* Compute maximum of all requirements for alignment of section.  */
Jan Synacek e76854
-      ElfW (Word) alignment = (NEW_PROGRAM_H (n)).p_align;
Jan Synacek e76854
-      if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
Jan Synacek e76854
-	alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
Jan Synacek e76854
-
Jan Synacek e76854
-#ifdef __sgi
Jan Synacek e76854
-	  /* According to r02kar@x4u2.desy.de (Karsten Kuenne)
Jan Synacek e76854
-	     and oliva@gnu.org (Alexandre Oliva), on IRIX 5.2, we
Jan Synacek e76854
-	     always get "Program segment above .bss" when dumping
Jan Synacek e76854
-	     when the executable doesn't have an sbss section.  */
Jan Synacek e76854
-      if (old_sbss_index != -1)
Jan Synacek e76854
-#endif /* __sgi */
Jan Synacek e76854
-      if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz
Jan Synacek e76854
-	  > (old_sbss_index == -1
Jan Synacek e76854
-	     ? old_bss_addr
Jan Synacek e76854
-	     : round_up (old_bss_addr, alignment)))
Jan Synacek e76854
-	  fatal ("Program segment above .bss in %s", old_name);
Jan Synacek e76854
-
Jan Synacek e76854
-      if (NEW_PROGRAM_H (n).p_type == PT_LOAD
Jan Synacek e76854
-	  && (round_up ((NEW_PROGRAM_H (n)).p_vaddr
Jan Synacek e76854
-			+ (NEW_PROGRAM_H (n)).p_filesz,
Jan Synacek e76854
-			alignment)
Jan Synacek e76854
-	      == round_up (old_bss_addr, alignment)))
Jan Synacek e76854
-	break;
Jan Synacek e76854
-    }
Jan Synacek e76854
-  if (n < 0)
Jan Synacek e76854
-    fatal ("Couldn't find segment next to .bss in %s", old_name);
Jan Synacek e76854
-
Jan Synacek e76854
-  /* Make sure that the size includes any padding before the old .bss
Jan Synacek e76854
-     section.  */
Jan Synacek e76854
-  NEW_PROGRAM_H (n).p_filesz = new_bss_addr - NEW_PROGRAM_H (n).p_vaddr;
Jan Synacek e76854
-  NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
Jan Synacek e76854
-
Jan Synacek e76854
-#if 0 /* Maybe allow section after data2 - does this ever happen? */
Jan Synacek e76854
-  for (n = new_file_h->e_phnum; --n >= 0; )
Jan Synacek e76854
-    {
Jan Synacek e76854
-      if (NEW_PROGRAM_H (n).p_vaddr
Jan Synacek e76854
-	  && NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr)
Jan Synacek e76854
-	NEW_PROGRAM_H (n).p_vaddr += new_data2_size - old_bss_size;
Jan Synacek e76854
+  new_bss_seg = new_program_h + (old_bss_seg - old_program_h);
Jan Synacek e76854
+  new_bss_seg->p_filesz = new_bss_addr - new_bss_seg->p_vaddr;
Jan Synacek e76854
+  new_bss_seg->p_memsz = new_bss_seg->p_filesz;
Jan Synacek e76854
 
Jan Synacek e76854
-      if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset)
Jan Synacek e76854
-	NEW_PROGRAM_H (n).p_offset += new_data2_incr;
Jan Synacek e76854
-    }
Jan Synacek e76854
-#endif
Jan Synacek e76854
+  /* Copy over what we have in memory now for the bss area. */
Jan Synacek e76854
+  memcpy (new_base + new_data2_offset, (caddr_t) old_bss_addr, new_data2_size);
Jan Synacek e76854
 
Jan Synacek e76854
   /* Fix up section headers based on new .data2 section.  Any section
Jan Synacek e76854
      whose offset or virtual address is after the new .data2 section
Jan Synacek e76854
-     gets its value adjusted.  .bss size becomes zero and new address
Jan Synacek e76854
-     is set.  data2 section header gets added by copying the existing
Jan Synacek e76854
-     .data header and modifying the offset, address and size.  */
Jan Synacek e76854
+     gets its value adjusted.  .bss size becomes zero.  data2 section
Jan Synacek e76854
+     header gets added by copying the existing .data header and
Jan Synacek e76854
+     modifying the offset, address and size.  */
Jan Synacek e76854
 
Jan Synacek e76854
   /* Walk through all section headers, insert the new data2 section right
Jan Synacek e76854
      before the new bss section. */
Jan Synacek e76854
@@ -901,9 +803,7 @@ unexec (const char *new_name, const char
Jan Synacek e76854
       ElfW (Shdr) *new_shdr = &NEW_SECTION_H (nn);
Jan Synacek e76854
 
Jan Synacek e76854
       /* If it is (s)bss section, insert the new data2 section before it.  */
Jan Synacek e76854
-      /* new_data2_index is the index of either old_sbss or old_bss, that was
Jan Synacek e76854
-	 chosen as a section for new_data2.   */
Jan Synacek e76854
-      if (n == new_data2_index)
Jan Synacek e76854
+      if (n == old_bss_index)
Jan Synacek e76854
 	{
Jan Synacek e76854
 	  /* Steal the data section header for this data2 section. */
Jan Synacek e76854
 	  memcpy (new_shdr, &OLD_SECTION_H (old_data_index),
Jan Synacek e76854
@@ -912,68 +812,43 @@ unexec (const char *new_name, const char
Jan Synacek e76854
 	  new_shdr->sh_addr = new_data2_addr;
Jan Synacek e76854
 	  new_shdr->sh_offset = new_data2_offset;
Jan Synacek e76854
 	  new_shdr->sh_size = new_data2_size;
Jan Synacek e76854
-	  /* Use the bss section's alignment. This will assure that the
Jan Synacek e76854
-	     new data2 section always be placed in the same spot as the old
Jan Synacek e76854
-	     bss section by any other application. */
Jan Synacek e76854
-	  new_shdr->sh_addralign = old_shdr->sh_addralign;
Jan Synacek e76854
-
Jan Synacek e76854
-	  /* Now copy over what we have in the memory now. */
Jan Synacek e76854
-	  memcpy (new_shdr->sh_offset + new_base,
Jan Synacek e76854
-		  (caddr_t) old_shdr->sh_addr,
Jan Synacek e76854
-		  new_data2_size);
Jan Synacek e76854
+	  new_shdr->sh_addralign = 1;
Jan Synacek e76854
 	  nn++;
Jan Synacek e76854
 	  new_shdr++;
Jan Synacek e76854
 	}
Jan Synacek e76854
 
Jan Synacek e76854
       memcpy (new_shdr, old_shdr, old_file_h->e_shentsize);
Jan Synacek e76854
 
Jan Synacek e76854
-      if (n == old_bss_index
Jan Synacek e76854
-	  /* The new bss and sbss section's size is zero, and its file offset
Jan Synacek e76854
-	     and virtual address should be off by NEW_DATA2_SIZE.  */
Jan Synacek e76854
-	  || n == old_sbss_index || n == old_plt_index
Jan Synacek e76854
-	  )
Jan Synacek e76854
+      if (new_shdr->sh_type == SHT_NOBITS
Jan Synacek e76854
+	  && new_shdr->sh_addr >= old_bss_addr
Jan Synacek e76854
+	  && (new_shdr->sh_addr + new_shdr->sh_size
Jan Synacek e76854
+	      <= old_bss_addr + old_bss_size))
Jan Synacek e76854
 	{
Jan Synacek e76854
-	  /* NN should be `old_s?bss_index + 1' at this point. */
Jan Synacek e76854
-	  new_shdr->sh_offset = new_data2_offset + new_data2_size;
Jan Synacek e76854
-	  new_shdr->sh_addr = new_data2_addr + new_data2_size;
Jan Synacek e76854
-	  /* Let the new bss section address alignment be the same as the
Jan Synacek e76854
-	     section address alignment followed the old bss section, so
Jan Synacek e76854
-	     this section will be placed in exactly the same place. */
Jan Synacek e76854
-	  new_shdr->sh_addralign = OLD_SECTION_H (nn).sh_addralign;
Jan Synacek e76854
+	  /* SHT_NOBITS sections do not need a valid sh_offset, so it
Jan Synacek e76854
+	     might be incorrect.  Write the correct value.  */
Jan Synacek e76854
+	  new_shdr->sh_offset = (new_shdr->sh_addr - new_bss_seg->p_vaddr
Jan Synacek e76854
+				 + new_bss_seg->p_offset);
Jan Synacek e76854
+
Jan Synacek e76854
+	  /* If this is was a SHT_NOBITS .plt section, then it is
Jan Synacek e76854
+	     probably a PowerPC PLT.  If it is PowerPC64 ELFv1 then
Jan Synacek e76854
+	     glibc ld.so doesn't initialize the toc pointer word.  A
Jan Synacek e76854
+	     non-zero toc pointer word can defeat Power7 thread safety
Jan Synacek e76854
+	     during lazy update of a PLT entry.  This only matters if
Jan Synacek e76854
+	     emacs becomes multi-threaded.  */
Jan Synacek e76854
+	  if (strcmp (old_section_names + new_shdr->sh_name, ".plt") == 0)
Jan Synacek e76854
+	    memset (new_shdr->sh_offset + new_base, 0, new_shdr->sh_size);
Jan Synacek e76854
+
Jan Synacek e76854
+	  /* Set the new bss and sbss section's size to zero, because
Jan Synacek e76854
+	     we've already covered this address range by .data2.  */
Jan Synacek e76854
 	  new_shdr->sh_size = 0;
Jan Synacek e76854
 	}
Jan Synacek e76854
       else
Jan Synacek e76854
 	{
Jan Synacek e76854
 	  /* Any section that was originally placed after the .bss
Jan Synacek e76854
-	     section should now be off by NEW_DATA2_INCR.  If a
Jan Synacek e76854
-	     section overlaps the .bss section, consider it to be
Jan Synacek e76854
-	     placed after the .bss section.  Overlap can occur if the
Jan Synacek e76854
-	     section just before .bss has less-strict alignment; this
Jan Synacek e76854
-	     was observed between .symtab and .bss on Solaris 2.5.1
Jan Synacek e76854
-	     (sparc) with GCC snapshot 960602.
Jan Synacek e76854
-
Jan Synacek e76854
-> dump -h temacs
Jan Synacek e76854
-
Jan Synacek e76854
-temacs:
Jan Synacek e76854
-
Jan Synacek e76854
-	   **** SECTION HEADER TABLE ****
Jan Synacek e76854
-[No]	Type	Flags	Addr         Offset       Size        	Name
Jan Synacek e76854
-	Link	Info	Adralgn      Entsize
Jan Synacek e76854
-
Jan Synacek e76854
-[22]	1	3	0x335150     0x315150     0x4          	.data.rel.local
Jan Synacek e76854
-	0	0	0x4          0
Jan Synacek e76854
-
Jan Synacek e76854
-[23]	8	3	0x335158     0x315158     0x42720      	.bss
Jan Synacek e76854
-	0	0	0x8          0
Jan Synacek e76854
-
Jan Synacek e76854
-[24]	2	0	0            0x315154     0x1c9d0      	.symtab
Jan Synacek e76854
-	25	1709	0x4          0x10
Jan Synacek e76854
-	  */
Jan Synacek e76854
-
Jan Synacek e76854
-	  if (new_shdr->sh_offset >= old_bss_offset
Jan Synacek e76854
-	      || (new_shdr->sh_offset + new_shdr->sh_size
Jan Synacek e76854
-		  > new_data2_offset))
Jan Synacek e76854
-	    new_shdr->sh_offset += new_data2_incr;
Jan Synacek e76854
+	     section should now be off by NEW_DATA2_SIZE.  */
Jan Synacek e76854
+
Jan Synacek e76854
+	  if (new_shdr->sh_offset >= old_bss_offset)
Jan Synacek e76854
+	    new_shdr->sh_offset += new_data2_size;
Jan Synacek e76854
 
Jan Synacek e76854
 	  /* Any section that was originally placed after the section
Jan Synacek e76854
 	     header table should now be off by the size of one section
Jan Synacek e76854
@@ -993,23 +868,13 @@ temacs:
Jan Synacek e76854
 	  && new_shdr->sh_type != SHT_DYNSYM)
Jan Synacek e76854
 	PATCH_INDEX (new_shdr->sh_info);
Jan Synacek e76854
 
Jan Synacek e76854
-      if (old_sbss_index != -1)
Jan Synacek e76854
-	if (!strcmp (old_section_names + new_shdr->sh_name, ".sbss"))
Jan Synacek e76854
-	  {
Jan Synacek e76854
-	    new_shdr->sh_offset =
Jan Synacek e76854
-	      round_up (new_shdr->sh_offset,
Jan Synacek e76854
-			new_shdr->sh_addralign);
Jan Synacek e76854
-	    new_shdr->sh_type = SHT_PROGBITS;
Jan Synacek e76854
-	  }
Jan Synacek e76854
-
Jan Synacek e76854
       /* Now, start to copy the content of sections.  */
Jan Synacek e76854
       if (new_shdr->sh_type == SHT_NULL
Jan Synacek e76854
 	  || new_shdr->sh_type == SHT_NOBITS)
Jan Synacek e76854
 	continue;
Jan Synacek e76854
 
Jan Synacek e76854
-      /* Write out the sections. .data and .data1 (and data2, called
Jan Synacek e76854
-	 ".data" in the strings table) get copied from the current process
Jan Synacek e76854
-	 instead of the old file.  */
Jan Synacek e76854
+      /* Some sections are copied from the current process instead of
Jan Synacek e76854
+	 the old file.  */
Jan Synacek e76854
       if (!strcmp (old_section_names + new_shdr->sh_name, ".data")
Jan Synacek e76854
 	  || !strcmp (old_section_names + new_shdr->sh_name, ".sdata")
Jan Synacek e76854
 	  || !strcmp (old_section_names + new_shdr->sh_name, ".lit4")
Jan Synacek e76854
@@ -1038,8 +903,7 @@ temacs:
Jan Synacek e76854
 	  || !strcmp (old_section_names + new_shdr->sh_name, ".got")
Jan Synacek e76854
 #endif
Jan Synacek e76854
 	  || !strcmp (old_section_names + new_shdr->sh_name, ".sdata1")
Jan Synacek e76854
-	  || !strcmp (old_section_names + new_shdr->sh_name, ".data1")
Jan Synacek e76854
-	  || !strcmp (old_section_names + new_shdr->sh_name, ".sbss"))
Jan Synacek e76854
+	  || !strcmp (old_section_names + new_shdr->sh_name, ".data1"))
Jan Synacek e76854
 	src = (caddr_t) old_shdr->sh_addr;
Jan Synacek e76854
       else
Jan Synacek e76854
 	src = old_base + old_shdr->sh_offset;