diff src/unexelfsgi.c @ 50:ee648375d8d6 r19-16b91

Import from CVS: tag r19-16b91
author cvs
date Mon, 13 Aug 2007 08:56:41 +0200
parents 376386a54a3c
children 8b0bdfdf0cf0
line wrap: on
line diff
--- a/src/unexelfsgi.c	Mon Aug 13 08:56:06 2007 +0200
+++ b/src/unexelfsgi.c	Mon Aug 13 08:56:41 2007 +0200
@@ -479,7 +479,12 @@
 	     new_bss_addr - roundup(old_bss_addr,0x1000)
 
      */
-
+  /* Still more mods... Olivier Galibert 19971705
+     - support for .sbss section (automagically changed to data without
+       name change)
+     - support for 64bits ABI (will need a bunch of fixes in the rest
+       of the code before it works
+     */
 
 #include <sys/types.h>
 #include <stdio.h>
@@ -492,6 +497,28 @@
 #include <elf.h>
 #include <sym.h> /* for HDRR declaration */
 #include <sys/mman.h>
+#include <config.h>
+#include "sysdep.h"
+
+/* in 64bits mode, use 64bits elf */
+#ifdef _ABI64
+typedef Elf64_Shdr l_Elf_Shdr;
+typedef Elf64_Phdr l_Elf_Phdr;
+typedef Elf64_Ehdr l_Elf_Ehdr;
+typedef Elf64_Addr l_Elf_Addr;
+typedef Elf64_Word l_Elf_Word;
+typedef Elf64_Off  l_Elf_Off;
+typedef Elf64_Sym  l_Elf_Sym;
+#else
+typedef Elf32_Shdr l_Elf_Shdr;
+typedef Elf32_Phdr l_Elf_Phdr;
+typedef Elf32_Ehdr l_Elf_Ehdr;
+typedef Elf32_Addr l_Elf_Addr;
+typedef Elf32_Word l_Elf_Word;
+typedef Elf32_Off  l_Elf_Off;
+typedef Elf32_Sym  l_Elf_Sym;
+#endif
+
 
 #ifndef emacs
 #define fatal(a, b, c) fprintf(stderr, a, b, c), exit(1)
@@ -504,13 +531,13 @@
  */
 
 #define OLD_SECTION_H(n) \
-     (*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
+     (*(l_Elf_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))
 #define NEW_SECTION_H(n) \
-     (*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
+     (*(l_Elf_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))
 #define OLD_PROGRAM_H(n) \
-     (*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
+     (*(l_Elf_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))
 #define NEW_PROGRAM_H(n) \
-     (*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
+     (*(l_Elf_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))
 
 #define PATCH_INDEX(n) \
   do { \
@@ -542,8 +569,8 @@
      char *name;
      char *section_names;
      char *file_name;
-     Elf32_Ehdr *old_file_h;
-     Elf32_Shdr *old_section_h;
+     l_Elf_Ehdr *old_file_h;
+     l_Elf_Shdr *old_section_h;
      int noerror;
 {
   int idx;
@@ -581,9 +608,9 @@
 void
 unexec (new_name, old_name, data_start, bss_start, entry_address)
      char *new_name, *old_name;
-     unsigned data_start, bss_start, entry_address;
+     uintptr_t data_start, bss_start, entry_address;
 {
-  extern unsigned int bss_end;
+  extern uintptr_t bss_end;
   int new_file, old_file, new_file_size;
 
   /* Pointers to the base of the image of the two files.  */
@@ -591,21 +618,22 @@
 
   /* Pointers to the file, program and section headers for the old and new
      files.  */
-  Elf32_Ehdr *old_file_h, *new_file_h;
-  Elf32_Phdr *old_program_h, *new_program_h;
-  Elf32_Shdr *old_section_h, *new_section_h;
+  l_Elf_Ehdr *old_file_h, *new_file_h;
+  l_Elf_Phdr *old_program_h, *new_program_h;
+  l_Elf_Shdr *old_section_h, *new_section_h;
 
   /* Point to the section name table in the old file.  */
   char *old_section_names;
 
-  Elf32_Addr old_bss_addr, new_bss_addr;
-  Elf32_Word old_bss_size, new_data2_size;
-  Elf32_Off  new_data2_offset;
-  Elf32_Addr new_data2_addr;
-  Elf32_Addr new_offsets_shift;
+  l_Elf_Addr old_bss_addr, new_bss_addr;
+  l_Elf_Addr old_base_addr;
+  l_Elf_Word old_bss_size, new_data2_size;
+  l_Elf_Off  new_data2_offset, new_base_offset;
+  l_Elf_Addr new_data2_addr;
+  l_Elf_Addr new_offsets_shift;
 
   int n, nn, old_bss_index, old_data_index, new_data2_index;
-  int old_mdebug_index;
+  int old_mdebug_index, old_sbss_index;
   struct stat stat_buf;
 
   /* Open the old file & map it into the address space.  */
@@ -630,9 +658,9 @@
 
   /* Get pointers to headers & section names.  */
 
-  old_file_h = (Elf32_Ehdr *) old_base;
-  old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
-  old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
+  old_file_h = (l_Elf_Ehdr *) old_base;
+  old_program_h = (l_Elf_Phdr *) ((byte *) old_base + old_file_h->e_phoff);
+  old_section_h = (l_Elf_Shdr *) ((byte *) old_base + old_file_h->e_shoff);
   old_section_names
     = (char *) old_base + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
 
@@ -641,6 +669,11 @@
   old_mdebug_index = find_section (".mdebug", old_section_names,
 				   old_name, old_file_h, old_section_h, 1);
 
+  /* Find the .sbss section, if any.  */
+
+  old_sbss_index = find_section (".sbss", old_section_names,
+				 old_name, old_file_h, old_section_h, 1);
+
   /* Find the old .bss section. */
 
   old_bss_index = find_section (".bss", old_section_names,
@@ -654,9 +687,10 @@
 
   old_bss_addr	    = OLD_SECTION_H (old_bss_index).sh_addr;
   old_bss_size	    = OLD_SECTION_H (old_bss_index).sh_size;
+  old_base_addr     = old_sbss_index == -1 ? old_bss_addr : OLD_SECTION_H (old_sbss_index).sh_addr;
 #if defined(emacs) || !defined(DEBUG)
-  bss_end	    = (unsigned int) sbrk (0);
-  new_bss_addr	    = (Elf32_Addr) bss_end;
+  bss_end	    = (uintptr_t) sbrk (0);
+  new_bss_addr	    = (l_Elf_Addr) bss_end;
 #else
   new_bss_addr	    = old_bss_addr + old_bss_size + 0x1234;
 #endif
@@ -664,13 +698,16 @@
   new_data2_size    = new_bss_addr - old_bss_addr;
   new_data2_offset  = OLD_SECTION_H (old_data_index).sh_offset +
     (new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
+  new_base_offset  = OLD_SECTION_H (old_data_index).sh_offset +
+    (old_base_addr - OLD_SECTION_H (old_data_index).sh_addr);
   new_offsets_shift = new_bss_addr -
-    ((old_bss_addr & ~0xfff) + ((old_bss_addr & 0xfff) ? 0x1000 : 0));
+    ((old_base_addr & ~0xfff) + ((old_base_addr & 0xfff) ? 0x1000 : 0));
 
 #ifdef DEBUG
   fprintf (stderr, "old_bss_index %d\n", old_bss_index);
   fprintf (stderr, "old_bss_addr %x\n", old_bss_addr);
   fprintf (stderr, "old_bss_size %x\n", old_bss_size);
+  fprintf (stderr, "old_base_addr %x\n", old_base_addr);
   fprintf (stderr, "new_bss_addr %x\n", new_bss_addr);
   fprintf (stderr, "new_data2_addr %x\n", new_data2_addr);
   fprintf (stderr, "new_data2_size %x\n", new_data2_size);
@@ -702,10 +739,10 @@
   if (new_base == (caddr_t) -1)
     fatal ("Can't mmap (%s): errno %d\n", new_name, errno);
 
-  new_file_h = (Elf32_Ehdr *) new_base;
-  new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
+  new_file_h = (l_Elf_Ehdr *) new_base;
+  new_program_h = (l_Elf_Phdr *) ((byte *) new_base + old_file_h->e_phoff);
   new_section_h
-    = (Elf32_Shdr *) ((byte *) new_base + old_file_h->e_shoff
+    = (l_Elf_Shdr *) ((byte *) new_base + old_file_h->e_shoff
 		      + new_offsets_shift);
 
   /* Make our new file, program and section headers as copies of the
@@ -747,7 +784,7 @@
 
       /* Supposedly this condition is okay for the SGI.  */
 #if 0
-      if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > old_bss_addr)
+      if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > old_base_addr)
 	fatal ("Program segment above .bss in %s\n", old_name, 0);
 #endif
 
@@ -755,11 +792,12 @@
 	  && (round_up ((NEW_PROGRAM_H (n)).p_vaddr
 			+ (NEW_PROGRAM_H (n)).p_filesz,
 			alignment)
-	      == round_up (old_bss_addr, alignment)))
+	      == round_up (old_base_addr, alignment)))
 	break;
     }
   if (n < 0)
-    fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
+    fatal ("Couldn't find segment next to %s in %s\n",
+	   old_sbss_index == -1 ? ".sbss" : ".bss", old_name, 0);
 
   NEW_PROGRAM_H (n).p_filesz += new_offsets_shift;
   NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
@@ -843,7 +881,7 @@
       /* Any section that was original placed AFTER the bss
 	 section must now be adjusted by NEW_OFFSETS_SHIFT.  */
 
-      if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset)
+      if (NEW_SECTION_H (nn).sh_offset >= new_base_offset)
 	NEW_SECTION_H (nn).sh_offset += new_offsets_shift;
       
       /* If any section hdr refers to the section after the new .data
@@ -857,17 +895,26 @@
 	  && NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
 	PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
       
+      /* Fix the type and alignment for the .sbss section */
+      if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sbss"))
+	{
+	  NEW_SECTION_H (nn).sh_type = SHT_PROGBITS;
+	  NEW_SECTION_H (nn).sh_offset = round_up (NEW_SECTION_H (nn).sh_offset,
+						   NEW_SECTION_H (nn).sh_addralign);
+	}
+
       /* 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)
 	continue;
       
-      /* Write out the sections. .data and .data1 (and data2, called
+      /* Write out the sections. .data, .data1 and .sbss (and data2, called
 	 ".data" in the strings table) get copied from the current process
 	 instead of the old file.  */
       if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data")
 	  || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data1")
-	  || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".got"))
+	  || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".got")
+	  || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sbss"))
 	src = (caddr_t) OLD_SECTION_H (n).sh_addr;
       else
 	src = old_base + OLD_SECTION_H (n).sh_offset;
@@ -932,9 +979,9 @@
       if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
 	  || NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
 	{
-	  Elf32_Shdr *spt = &NEW_SECTION_H (nn);
+	  l_Elf_Shdr *spt = &NEW_SECTION_H (nn);
 	  unsigned int num = spt->sh_size / spt->sh_entsize;
-	  Elf32_Sym * sym = (Elf32_Sym *) (NEW_SECTION_H (nn).sh_offset
+	  l_Elf_Sym * sym = (l_Elf_Sym *) (NEW_SECTION_H (nn).sh_offset
 					   + new_base);
 	  for (; num--; sym++)
 	    {