$NetBSD: patch-az,v 1.4 1999/06/12 22:39:27 cgd Exp $

--- src/unexelf.c.orig	Sun Aug  9 22:33:12 1998
+++ src/unexelf.c	Thu Jun  3 23:31:50 1999
@@ -501,9 +501,16 @@
 #  include <sys/exec_ecoff.h>
 #  define HDRR		struct ecoff_symhdr
 #  define pHDRR		HDRR *
-# endif
+# endif /* __alpha__*/
+
+# ifdef __mips__
+#  define SHT_MIPS_DEBUG	DT_MIPS_FLAGS
+#  define HDRR		struct Elf_Shdr
+# endif /* __mips__ */
+
 #endif /* __NetBSD__ */
 
+
 #ifdef __OpenBSD__
 # include <sys/exec_elf.h>
 #endif
@@ -527,6 +534,14 @@
 extern void fatal (char *, ...);
 #endif
 
+#if defined ( __sony_news) && defined (_SYSTYPE_SYSV)
+# define HAVE_MIPS_SBSS
+#endif
+
+#if (defined (__mips__) || defined (__powerpc__)) && (defined(__NetBSD__) || defined(__OpenBSD__))
+# define HAVE_MIPS_SBSS
+#endif
+
 #ifndef ELF_BSS_SECTION_NAME
 #define ELF_BSS_SECTION_NAME ".bss"
 #endif
@@ -585,6 +600,47 @@
   return x - rem + y;
 }
 
+#if defined(__alpha__) || (defined ( __sony_news) && defined (_SYSTYPE_SYSV))
+/* We are using  ECOFF symbols embedded in ELF. */
+
+void
+relocate_ecoff_symhdr(symhdr, diff)
+    HDRR *symhdr;
+    ElfW(Word) diff;
+{
+  symhdr->cbLineOffset += diff;
+  symhdr->cbDnOffset   += diff;
+  symhdr->cbPdOffset   += diff;
+  symhdr->cbSymOffset  += diff;
+  symhdr->cbOptOffset  += diff;
+  symhdr->cbAuxOffset  += diff;
+  symhdr->cbSsOffset   += diff;
+  symhdr->cbSsExtOffset += diff;
+  symhdr->cbFdOffset   += diff;
+  symhdr->cbRfdOffset  += diff;
+  symhdr->cbExtOffset  += diff;
+}
+#endif /* __alpha__ or __sony_news and systype_sysv */
+
+#ifdef notyet
+void
+relocate_elf_proghdr(p, diff)
+    HDRR *symhdr;
+    ElfW(Word) diff;
+{
+	phdr->sh_name  += diff;
+	phdr->sh_type  += diff;
+	phdr->sh_flags += diff;
+	phdr->sh_addr  += diff;
+	phdr->sh_offset += diff;
+	phdr->sh_size  += diff;
+	phdr->sh_link  += diff;
+	phdr->sh_info  += diff;
+	phdr->sh_addralign += diff;
+	phdr->sh_entsize += diff;
+};
+#endif /* notyet */
+
 /* ****************************************************************
  * unexec
  *
@@ -620,9 +676,10 @@
   ElfW(Addr) new_data2_addr;
 
   int n, nn, old_bss_index, old_data_index, new_data2_index;
-#if defined ( __sony_news) && defined (_SYSTYPE_SYSV)
+#ifdef HAVE_MIPS_SBSS
   int old_sbss_index, old_mdebug_index;
-#endif /* __sony_news && _SYSTYPE_SYSV */
+  int bss_phdr_index;
+#endif /* HAVE_MIPS_SBSS */
   struct stat stat_buf;
 
   /* Open the old file & map it into the address space. */
@@ -672,7 +729,7 @@
   if (old_bss_index == old_file_h->e_shnum)
     fatal ("Can't find .bss in %s.\n", old_name, 0);
 
-#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
+#ifdef HAVE_MIPS_SBSS
   for (old_sbss_index = 1; old_sbss_index < (int) old_file_h->e_shnum;
        old_sbss_index++)
     {
@@ -713,10 +770,10 @@
     }
     if (old_mdebug_index == old_file_h->e_shnum)
 	old_mdebug_index = 0;
-#else /* not (__sony_news && _SYSTYPE_SYSV) */	    
+#else /* not HAVE_MIPS_SBSS */
   old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
   old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
-#endif /* not (__sony_news && _SYSTYPE_SYSV) */	    
+#endif /* not HAVE_MIPS_SBSS */
 #if defined (emacs) || !defined (DEBUG)
   new_bss_addr = (ElfW(Addr)) sbrk (0);
 #else
@@ -724,9 +781,9 @@
 #endif
   new_data2_addr = old_bss_addr;
   new_data2_size = new_bss_addr - old_bss_addr;
-#if !defined (__sony_news) || !defined (_SYSTYPE_SYSV)
+#ifndef HAVE_MIPS_SBSS
   new_data2_offset = OLD_SECTION_H (old_bss_index).sh_offset;
-#endif /*  not (__sony_news && _SYSTYPE_SYSV) */
+#endif /*  not HAVE_MIPS_SBSS */
 
 #ifdef DEBUG
   fprintf (stderr, "old_bss_index %d\n", old_bss_index);
@@ -811,14 +868,14 @@
       if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
 	alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
 
-#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
+#ifdef HAVE_MIPS_SBSS
       if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz
 	  > round_up (old_bss_addr, alignment))
 	fatal ("Program segment above .bss in %s\n", old_name, 0);
-#else /* not (__sony_news && _SYSTYPE_SYSV) */
+#else /* not HAVE_MIPS_SBSS */
       if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > old_bss_addr)
 	fatal ("Program segment above .bss in %s\n", old_name, 0);
-#endif /* not (__sony_news && _SYSTYPE_SYSV) */
+#endif /* not HAVE_MIPS_SBSS */
 
       if (NEW_PROGRAM_H (n).p_type == PT_LOAD
 	  && (round_up ((NEW_PROGRAM_H (n)).p_vaddr
@@ -830,11 +887,16 @@
   if (n < 0)
     fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0);
 
+#ifdef HAVE_MIPS_SBSS
+  bss_phdr_index = n;
+#endif
+
   /* Make sure that the size includes any padding before the old .bss
      section.  */
   NEW_PROGRAM_H (n).p_filesz = new_bss_addr - NEW_PROGRAM_H (n).p_vaddr;
   NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz;
 
+
 #if 0 /* Maybe allow section after data2 - does this ever happen? */
   for (n = new_file_h->e_phnum - 1; n >= 0; n--)
     {
@@ -867,15 +929,15 @@
     {
       caddr_t src;
       int temp_index;
-#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
+#ifdef HAVE_MIPS_SBSS
       /* If it is (s)bss section, insert the new data2 section before it.  */
       /* new_data2_index is the index of either old_sbss or old_bss, that was
 	 chosen as a section for new_data2.   */
       temp_index = new_data2_index;
-#else /* not (__sony_news && _SYSTYPE_SYSV) */
+#else /* not HAVE_MIPS_SBSS */
       /* If it is bss section, insert the new data2 section before it.  */
       temp_index = old_bss_index;
-#endif /* not (__sony_news && _SYSTYPE_SYSV) */
+#endif /* not HAVE_MIPS_SBSS */
       if (n == temp_index)
 	{
 	  /* Steal the data section header for this data2 section. */
@@ -901,11 +963,11 @@
 	      old_file_h->e_shentsize);
       
       if (n == old_bss_index
-#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
+#ifdef HAVE_MIPS_SBSS
 	  /* 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
-#endif /* __sony_news and _SYSTYPE_SYSV */
+#endif /* HAVE_MIPS_SBSS */
 	  )
 	{
 	  /* NN should be `old_bss_index + 1' at this point. */
@@ -916,6 +978,28 @@
 	     this section will be placed in exactly the same place. */
 	  NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign;
 	  NEW_SECTION_H (nn).sh_size = 0;
+
+#ifdef HAVE_MIPS_SBSS
+	  /* On ELF mips,  the new data section replaces both .sbss and .bss
+	     (we have, after all, written to them.).  Adding new_data2_size
+	     to the sh_addr and sh_offset of sbss puts sbss at the end of
+	     the new data section. setting the size to zero makes it empty.
+	     But then, adding the new_data2_size to the bss address puts
+	     its start  beyond the end of the original bss. If the sbss size
+	     was bigger than a page,  the bss ends up not covered by the
+	     program header.  This breaks strip. Since both sbss and bss
+	     are zero-sized,  just use the same address and file offset for
+	     both, guaranteeing other tools will assign them to the same
+	     program section (asssuming no sections are loaded at higher
+	     offsets.)  */
+	  if (n == old_bss_index) {
+	    	 int new_sbss_bss_padding = NEW_SECTION_H(nn).sh_addr -
+		    NEW_SECTION_H(nn - 1).sh_addr;
+		printf("sbss to bss offset =0x%x\n", new_sbss_bss_padding);
+		NEW_SECTION_H(nn).sh_addr =NEW_SECTION_H(nn - 1).sh_addr;
+		NEW_SECTION_H(nn).sh_offset =NEW_SECTION_H(nn - 1).sh_offset;
+	  }
+#endif  /* HAVE_MIPS_SBSS */
 	}
       else
 	{
@@ -970,14 +1054,14 @@
 	  || !strcmp ((old_section_names + NEW_SECTION_H(n).sh_name),
 		      ".sdata")
 #endif
-#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
+#ifdef HAVE_MIPS_SBSS
 	  || !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")
-#endif /* __sony_news && _SYSTYPE_SYSV */
+#endif /* HAVE_MIPS_SBSS */
 	  || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
 		      ".data1"))
 	src = (caddr_t) OLD_SECTION_H (n).sh_addr;
@@ -993,18 +1077,7 @@
 	  == 0)
 	{
 	  pHDRR symhdr = (pHDRR) (NEW_SECTION_H (nn).sh_offset + new_base);
-
-	  symhdr->cbLineOffset += new_data2_size;
-	  symhdr->cbDnOffset += new_data2_size;
-	  symhdr->cbPdOffset += new_data2_size;
-	  symhdr->cbSymOffset += new_data2_size;
-	  symhdr->cbOptOffset += new_data2_size;
-	  symhdr->cbAuxOffset += new_data2_size;
-	  symhdr->cbSsOffset += new_data2_size;
-	  symhdr->cbSsExtOffset += new_data2_size;
-	  symhdr->cbFdOffset += new_data2_size;
-	  symhdr->cbRfdOffset += new_data2_size;
-	  symhdr->cbExtOffset += new_data2_size;
+	  relocate_ecoff_symhdr(symhdr, new_data2_size);
 	}
 #endif /* __alpha__ */
 
@@ -1017,20 +1090,11 @@
 
 	  if (diff)
 	    {
-	      phdr->cbLineOffset += diff;
-	      phdr->cbDnOffset   += diff;
-	      phdr->cbPdOffset   += diff;
-	      phdr->cbSymOffset  += diff;
-	      phdr->cbOptOffset  += diff;
-	      phdr->cbAuxOffset  += diff;
-	      phdr->cbSsOffset   += diff;
-	      phdr->cbSsExtOffset += diff;
-	      phdr->cbFdOffset   += diff;
-	      phdr->cbRfdOffset  += diff;
-	      phdr->cbExtOffset  += diff;
+	      relocate_ecoff_symhdr(phdr, diff);
 	    }
 	}
-#endif /* __sony_news && _SYSTYPE_SYSV */
+#endif /* __sony_news and systype_sysv */
+
       /* If it is the symbol table, its st_shndx field needs to be patched.  */
       if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB
 	  || NEW_SECTION_H (nn).sh_type == SHT_DYNSYM)
