changeset 69560:dab2f548eda2

[BROKEN_NOCOMBRELOC]: Include assert.h. (unexec) [BROKEN_NOCOMBRELOC]: Handle platforms whose nocombreloc option is broken (e.g., MIPS/NetBSD).
author Eli Zaretskii <eliz@gnu.org>
date Sat, 18 Mar 2006 14:51:54 +0000
parents 130314bad206
children 496d2fcbae73
files src/unexelf.c
diffstat 1 files changed, 82 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/unexelf.c	Sat Mar 18 14:47:20 2006 +0000
+++ b/src/unexelf.c	Sat Mar 18 14:51:54 2006 +0000
@@ -433,6 +433,9 @@
 #if __sgi
 #include <syms.h> /* for HDRR declaration */
 #endif /* __sgi */
+#ifdef BROKEN_NOCOMBRELOC
+#include <assert.h>
+#endif
 
 #ifndef MAP_ANON
 #ifdef MAP_ANONYMOUS
@@ -687,6 +690,9 @@
   int old_mdebug_index;
   struct stat stat_buf;
   int old_file_size;
+#ifdef BROKEN_NOCOMBRELOC
+  int unreloc_sections[10], n_unreloc_sections;
+#endif
 
   /* Open the old file, allocate a buffer of the right size, and read
      in the file contents.  */
@@ -1218,6 +1224,7 @@
 
   /* This loop seeks out relocation sections for the data section, so
      that it can undo relocations performed by the runtime linker.  */
+#ifndef BROKEN_NOCOMBRELOC
   for (n = new_file_h->e_shnum - 1; n; n--)
     {
       ElfW(Shdr) section = NEW_SECTION_H (n);
@@ -1272,6 +1279,81 @@
 	  break;
 	}
     }
+#else /* BROKEN_NOCOMBRELOC */
+  for (n = 1, n_unreloc_sections = 0; n < new_file_h->e_shnum; n++)
+    if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data")
+	|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata")
+	|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit4")
+	|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit8")
+#ifdef IRIX6_5			/* see above */
+	|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".got")
+#endif
+	|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata1")
+	|| !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data1"))
+      {
+	assert (n_unreloc_sections
+		< (sizeof (unreloc_sections) / sizeof (unreloc_sections[0])));
+	unreloc_sections[n_unreloc_sections++] = n;
+#ifdef DEBUG
+	fprintf (stderr, "section %d: %s\n", n,
+		 old_section_names + NEW_SECTION_H (n).sh_name);
+#endif
+      }
+
+  for (n = new_file_h->e_shnum - 1; n; n--)
+    {
+      ElfW(Shdr) section = NEW_SECTION_H (n);
+      caddr_t reloc, end;
+      ElfW(Addr) addr, offset;
+      int target;
+
+      switch (section.sh_type)
+	{
+	default:
+	  break;
+	case SHT_REL:
+	case SHT_RELA:
+	  /* This code handles two different size structs, but there should
+	     be no harm in that provided that r_offset is always the first
+	     member.  */
+	  for (reloc = old_base + section.sh_offset,
+		 end = reloc + section.sh_size;
+	       reloc < end;
+	       reloc += section.sh_entsize)
+	    {
+	      addr = ((ElfW(Rel) *) reloc)->r_offset;
+#ifdef __alpha__
+	      /* The Alpha ELF binutils currently have a bug that
+		 sometimes results in relocs that contain all
+		 zeroes.  Work around this for now...  */
+	      if (addr == 0)
+		continue;
+#endif
+	      for (nn = 0; nn < n_unreloc_sections; nn++)
+		{
+		  target = unreloc_sections[nn];
+		  if (NEW_SECTION_H (target).sh_addr <= addr
+		      && addr < (NEW_SECTION_H (target).sh_addr +
+				 NEW_SECTION_H (target).sh_size))
+		    {
+		      offset = (NEW_SECTION_H (target).sh_addr -
+				NEW_SECTION_H (target).sh_offset);
+		      memcpy (new_base + addr - offset,
+			      old_base + addr - offset,
+			      sizeof (ElfW(Addr)));
+#ifdef DEBUG
+		      fprintf (stderr, "unrelocate: [%08lx] <= %08lx\n",
+			       (long) addr,
+			       (long) *((long *) (new_base + addr - offset)));
+#endif
+		      break;
+		    }
+		}
+	    }
+	  break;
+	}
+    }
+#endif	/* BROKEN_NOCOMBRELOC */
 
   /* Write out new_file, and free the buffers.  */