changeset 14782:8988aa71854e

Handle both AIX 3.2 and 4.1 bind output. (make_hdr): Handle data_start being non-zero for 4.1. Padding sections are omitted in 4.1, but padding bytes can still be present. Calculate bias directly from first real section following bss. (copy_text_and_data): Correct data section starting point for 4.1. (adjust_lnnoptrs): Adjust line number pointers correctly for both 3.2 and 4.1, based on published IBM documentation. (unrelocate_symbols): Compute and subtract relocation offsets for text and data sections. Handle data_start being non-zero for 4.1. Skip unnecessary writes.
author Richard M. Stallman <rms@gnu.org>
date Thu, 07 Mar 1996 20:17:45 +0000
parents b4879ed5b5c3
children e7b489e4f25d
files src/unexaix.c
diffstat 1 files changed, 96 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/unexaix.c	Thu Mar 07 18:15:59 1996 +0000
+++ b/src/unexaix.c	Thu Mar 07 20:17:45 1996 +0000
@@ -33,6 +33,14 @@
  * Date:	Tue Mar  2 1982
  * Modified heavily since then.
  *
+ * Updated for AIX 4.1.3 by Bill_Mann @ PraxisInt.com, Feb 1996
+ *   As of AIX 4.1, text, data, and bss are pre-relocated by the binder in
+ *   such a way that the file can be mapped with code in one segment and
+ *   data/bss in another segment, without reading or copying the file, by
+ *   the AIX exec loader.  Padding sections are omitted, nevertheless
+ *   small amounts of 'padding' still occurs between sections in the file.
+ *   As modified, this code handles both 3.2 and 4.1 conventions.
+ *
  * Synopsis:
  *	unexec (new_name, a_name, data_start, bss_start, entry_address)
  *	char *new_name, *a_name;
@@ -203,21 +211,20 @@
 #endif /* not UMAX */
 #endif /* Not STRIDE */
 #endif /* not USG */
-static long block_copy_start;		/* Old executable start point */
 static struct filehdr f_hdr;		/* File header */
 static struct aouthdr f_ohdr;		/* Optional file header (a.out) */
 long bias;			/* Bias to add for growth */
 long lnnoptr;			/* Pointer to line-number info within file */
-#define SYMS_START block_copy_start
 
 static long text_scnptr;
 static long data_scnptr;
 #ifdef XCOFF
+#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1))
 static long load_scnptr;
 static long orig_load_scnptr;
 static long orig_data_scnptr;
 #endif
-static long data_st;
+static ulong data_st;                   /* start of data area written out */
 
 #ifndef MAX_SECTIONS
 #define MAX_SECTIONS	10
@@ -381,7 +388,6 @@
 
 #ifdef COFF
   /* Salvage as much info from the existing file as possible */
-  block_copy_start = 0;
   f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL;
   f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL;
   if (a_out >= 0)
@@ -390,14 +396,12 @@
 	{
 	  PERROR (a_name);
 	}
-      block_copy_start += sizeof (f_hdr);
       if (f_hdr.f_opthdr > 0)
 	{
 	  if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
 	    {
 	      PERROR (a_name);
 	    }
-	  block_copy_start += sizeof (f_ohdr);
 	}
       if (f_hdr.f_nscns > MAX_SECTIONS)
 	{
@@ -410,11 +414,6 @@
 	  {
 	    PERROR (a_name);
 	  }
-	if (s->s_scnptr > 0L)
-	  {
-            if (block_copy_start < s->s_scnptr + s->s_size)
-	      block_copy_start = s->s_scnptr + s->s_size;
-	  }
 
 #define CHECK_SCNHDR(ptr, name, flags) \
   if (strcmp(s->s_name, name) == 0) { \
@@ -459,7 +458,11 @@
 
   /* Now we alter the contents of all the f_*hdr variables
      to correspond to what we want to dump.  */
-  f_hdr.f_flags |= (F_RELFLG | F_EXEC);		/* Why? */
+
+  /* Indicate that the reloc information is no longer valid for ld (bind);
+     we only update it enough to fake out the exec-time loader.  */
+  f_hdr.f_flags |= (F_RELFLG | F_EXEC);
+
 #ifdef EXEC_MAGIC
   f_ohdr.magic = EXEC_MAGIC;
 #endif
@@ -467,73 +470,77 @@
   f_ohdr.tsize = data_start - f_ohdr.text_start;
   f_ohdr.text_start = (long) start_of_text ();
 #endif
-  f_ohdr.dsize = bss_start - ((unsigned) &_data);
+  data_st = f_ohdr.data_start ? f_ohdr.data_start : (ulong) &_data;
+  f_ohdr.dsize = bss_start - data_st;
   f_ohdr.bsize = bss_end - bss_start;
 
   f_dhdr->s_size = f_ohdr.dsize;
   f_bhdr->s_size = f_ohdr.bsize;
-  f_bhdr->s_paddr = f_ohdr.dsize;
-  f_bhdr->s_vaddr = f_ohdr.dsize;
+  f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize;
+  f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
 
   /* fix scnptr's */
   {
-    long ptr;
+    ulong ptr = section[0].s_scnptr;
 
-    for (scns = 0; scns < f_hdr.f_nscns; scns++) {
-      struct scnhdr *s = &section[scns];
-      if (scns == 0)
-	ptr = s->s_scnptr;
-
-      if (s->s_scnptr != 0)
-	{
-	  s->s_scnptr = ptr;
-	}
+    bias = -1;
+    for (scns = 0; scns < f_hdr.f_nscns; scns++)
+      {
+	struct scnhdr *s = &section[scns];
 
-      if ((s->s_flags & 0xffff) == STYP_PAD)
-	{
-	  /*
-	   * the text_start should probably be o_algntext but that doesn't
-	   * seem to change
-	   */
-	  if (f_ohdr.text_start != 0) /* && scns != 0 */
-	    {
-	      s->s_size = 512 - (s->s_scnptr % 512);
-	      if (s->s_size == 512)
-		s->s_size = 0;
-	    }
-	}
+	if (s->s_flags & STYP_PAD)        /* .pad sections omitted in AIX 4.1 */
+	  {
+	    /*
+	     * the text_start should probably be o_algntext but that doesn't
+	     * seem to change
+	     */
+	    if (f_ohdr.text_start != 0) /* && scns != 0 */
+	      {
+		s->s_size = 512 - (ptr % 512);
+		if (s->s_size == 512)
+		  s->s_size = 0;
+	      }
+	    s->s_scnptr = ptr;
+	  }
+	else if (s->s_flags & STYP_DATA)
+	  s->s_scnptr = ptr;
+	else if (!(s->s_flags & (STYP_TEXT | STYP_BSS)))
+	  {
+	    if (bias == -1)                /* if first section after bss */
+	      bias = ptr - s->s_scnptr;
 
-      ptr = ptr + s->s_size;
-    }
-
-    bias = ptr - block_copy_start;
+	    s->s_scnptr += bias;
+	    ptr = s->s_scnptr;
+	  }
+  
+	ptr = ptr + s->s_size;
+      }
   }
 
   /* fix other pointers */
-  for (scns = 0; scns < f_hdr.f_nscns; scns++) {
-    struct scnhdr *s = &section[scns];
+  for (scns = 0; scns < f_hdr.f_nscns; scns++)
+    {
+      struct scnhdr *s = &section[scns];
 
-    if (s->s_relptr != 0)
-      {
-	s->s_relptr += bias;
-      }
-    if (s->s_lnnoptr != 0)
-      {
-	if (lnnoptr == 0) lnnoptr = s->s_lnnoptr;
-	s->s_lnnoptr += bias;
-      }
-  }
+      if (s->s_relptr != 0)
+	{
+	  s->s_relptr += bias;
+	}
+      if (s->s_lnnoptr != 0)
+	{
+	  if (lnnoptr == 0) lnnoptr = s->s_lnnoptr;
+	  s->s_lnnoptr += bias;
+	}
+    }
 
   if (f_hdr.f_symptr > 0L)
     {
       f_hdr.f_symptr += bias;
     }
 
-  data_st = data_start;
   text_scnptr = f_thdr->s_scnptr;
   data_scnptr = f_dhdr->s_scnptr;
   load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;
-  block_copy_start = orig_load_scnptr;
 
 #ifdef ADJUST_EXEC_HEADER
   ADJUST_EXEC_HEADER
@@ -583,7 +590,7 @@
   write_segment (new, ptr, end);
 
   lseek (new, (long) data_scnptr, 0);
-  ptr = (char *) &_data;
+  ptr = (char *) data_st;
   end = ptr + f_ohdr.dsize;
   write_segment (new, ptr, end);
 
@@ -644,13 +651,13 @@
   if (a_out < 0)
     return 0;
 
-  if (SYMS_START == 0L)
+  if (orig_load_scnptr == 0L)
     return 0;
 
-  if (lnnoptr && lnnoptr < SYMS_START)	/* if there is line number info */
-    lseek (a_out, lnnoptr, 0);		/* start copying from there */
+  if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info  */
+    lseek (a_out, lnnoptr, 0);  /* start copying from there */
   else
-    lseek (a_out, SYMS_START, 0);	/* Position a.out to symtab. */
+    lseek (a_out, orig_load_scnptr, 0); /* Position a.out to symtab. */
 
   while ((n = read (a_out, page, sizeof page)) > 0)
     {
@@ -703,6 +710,8 @@
  *	the auxiliary entries that need adjustment, this routine will
  *	be fixed.  As it is now, all such entries are wrong and sdb
  *	will complain.   Fred Fish, UniSoft Systems Inc.
+ *
+ *      I believe this is now fixed correctly.  Bill Mann
  */
 
 #ifdef COFF
@@ -743,15 +752,17 @@
   for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
     {
       read (new, &symentry, SYMESZ);
-      for (naux = 0; naux < symentry.n_numaux; naux++)
+      for (naux = symentry.n_numaux; naux-- != 0; )
 	{
 	  read (new, &auxentry, AUXESZ);
 	  nsyms++;
-	  if (ISFCN (symentry.n_type)) {
-	    auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
-	    lseek (new, -AUXESZ, 1);
-	    write (new, &auxentry, AUXESZ);
-	  }
+	  if (naux != 0              /* skip csect auxentry (last entry) */
+              && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT))
+            {
+              auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
+              lseek (new, -AUXESZ, 1);
+              write (new, &auxentry, AUXESZ);
+            }
 	}
     }
   close (new);
@@ -774,8 +785,8 @@
   register LDREL *ldrel;
   LDHDR ldhdr;
   LDREL ldrel_buf [20];
-  ulong t_start = (ulong) &_text;
-  ulong d_start = (ulong) &_data;
+  ulong t_reloc = (ulong) &_text - f_ohdr.text_start;
+  ulong d_reloc = (ulong) &_data - ALIGN(f_ohdr.data_start, 2);
   int * p;
   int dirty;
 
@@ -837,49 +848,37 @@
 	{
 	  int orig_int;
 
-#ifdef AIX4_1
-	  lseek (a_out, orig_data_scnptr + (ldrel->l_vaddr - d_start), 0);
-#else
-	  lseek (a_out, orig_data_scnptr + ldrel->l_vaddr, 0);
-#endif
+	  lseek (a_out,
+                 orig_data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0);
 
 	  if (read (a_out, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int))
 	    {
 	      PERROR (a_name);
 	    }
 
+          p = (int *) (ldrel->l_vaddr + d_reloc);
+
 	  switch (ldrel->l_symndx) {
 	  case SYMNDX_TEXT:
-#ifdef AIX4_1
-	    p = (int *) (ldrel->l_vaddr);
-	    orig_int = * p;
-#else
-	    p = (int *) (d_start + ldrel->l_vaddr);
-	    orig_int = * p - (t_start - f_ohdr.text_start);
-#endif
+	    orig_int = * p - t_reloc;
 	    break;
 
 	  case SYMNDX_DATA:
 	  case SYMNDX_BSS:
-#ifdef AIX4_1
-	    p = (int *) (ldrel->l_vaddr);
-	    orig_int = * p;
-#else
-	    p = (int *) (d_start + ldrel->l_vaddr);
-	    orig_int = * p - (d_start - f_ohdr.data_start);
-#endif
+	    orig_int = * p - d_reloc;
 	    break;
 	  }
 
-#ifdef AIX4_1
-	  lseek (new, data_scnptr + (ldrel->l_vaddr - d_start), 0);
-#else
-	  lseek (new, data_scnptr + ldrel->l_vaddr, 0);
-#endif
-	  if (write (new, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int))
-	    {
-	      PERROR (new_name);
-	    }
+          if (orig_int != * p)
+            {
+              lseek (new,
+                     data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0);
+              if (write (new, (void *) &orig_int, sizeof (orig_int))
+                  != sizeof (orig_int))
+                {
+                  PERROR (new_name);
+                }
+            }
 	}
     }
 }