(Font Lock): Correct invalid @xref.
[bpt/emacs.git] / src / unexec.c
index 2de8b20..dadea56 100644 (file)
@@ -14,7 +14,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /*
@@ -133,7 +134,7 @@ before writing it (above and beyond the number of bytes of actual
 program text).  HDR's standard fields are already correct, except that
 this adjustment to the `a_text' field has not yet been made;
 thus, the amount of offset can depend on the data in the file.
-  
+
 * A_TEXT_SEEK(HDR)
 
 If defined, this macro specifies the number of bytes to seek into the
@@ -170,14 +171,14 @@ pointer looks like an int) but not on all machines.
 
 #ifndef CANNOT_DUMP  /* all rest of file!  */
 
-#ifndef CANNOT_UNEXEC /* most of rest of file */
-
-#ifdef COFF_ENCAPSULATE
-int need_coff_header = 1;
-#include <coff-encap/a.out.encap.h> /* The location might be a poor assumption */
-#else
-#ifdef MSDOS
+#if defined(COFF) && defined(HAVE_COFF_H)
 #include <coff.h>
+#ifdef MSDOS
+#if __DJGPP__ > 1
+#include <fcntl.h>  /* for O_RDONLY, O_RDWR */
+#include <crt0.h>   /* for _crt0_startup_flags and its bits */
+static int save_djgpp_startup_flags;
+#endif /* __DJGPP__ > 1 */
 #define filehdr external_filehdr
 #define scnhdr external_scnhdr
 #define syment external_syment
@@ -195,16 +196,18 @@ struct aouthdr
   unsigned long                text_start;/* base of text used for this file */
   unsigned long                data_start;/* base of data used for this file */
 };
-
-
-#else /* not MSDOS */
-#include <a.out.h>
 #endif /* not MSDOS */
-#endif
+#else  /* not COFF */
+#ifdef COFF_ENCAPSULATE
+int need_coff_header = 1;
+#include <coff-encap/a.out.encap.h> /* The location might be a poor assumption */
+#else  /* not COFF_ENCAPSULATE */
+#include <a.out.h>
+#endif /* not COFF_ENCAPSULATE */
+#endif /* not COFF */
 
-/* Define getpagesize () if the system does not.
-   Note that this may depend on symbols defined in a.out.h
- */
+/* Define getpagesize if the system does not.
+   Note that this may depend on symbols defined in a.out.h.  */
 #include "getpagesize.h"
 
 #ifndef makedev                        /* Try to detect types.h already loaded */
@@ -242,6 +245,8 @@ long lnnoptr;                       /* Pointer to line-number info within file */
 static long text_scnptr;
 static long data_scnptr;
 
+static long coff_offset;
+
 #else /* not COFF */
 
 #ifdef HPUX
@@ -283,7 +288,7 @@ static EXEC_HDR_TYPE hdr, ohdr;
 
 #else /* not HPUX */
 
-#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX)
+#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (GNU_LINUX)
 static struct bhdr hdr, ohdr;
 #define a_magic fmagic
 #define a_text tsize
@@ -394,7 +399,7 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
     {
       close (new);
       /* unlink (new_name);            /* Failed, unlink new a.out */
-      return -1;       
+      return -1;
     }
 
   close (new);
@@ -473,9 +478,32 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
     }
 
 #ifdef COFF
+  coff_offset = 0L;            /* stays zero, except in DJGPP */
+
   /* Salvage as much info from the existing file as possible */
   if (a_out >= 0)
     {
+#ifdef MSDOS
+#if __DJGPP__ > 1
+      /* Support the coff-go32-exe format with a prepended stub, since
+        this is what GCC 2.8.0 and later generates by default in DJGPP.  */
+      unsigned short mz_header[3];
+
+      if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
+       {
+         PERROR (a_name);
+       }
+      if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a) /* "MZ" or "ZM" */
+       {
+         coff_offset = (long)mz_header[2] * 512L;
+         if (mz_header[1])
+           coff_offset += (long)mz_header[1] - 512L;
+         lseek (a_out, coff_offset, 0);
+       }
+      else
+       lseek (a_out, 0L, 0);
+#endif /* __DJGPP__ > 1 */
+#endif /* MSDOS */
       if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
        {
          PERROR (a_name);
@@ -490,7 +518,7 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
          block_copy_start += sizeof (f_ohdr);
        }
       /* Loop through section headers, copying them in */
-      lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0);
+      lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
       for (scns = f_hdr.f_nscns; scns > 0; scns--) {
        if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
          {
@@ -793,12 +821,13 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
       PERROR (new_name);
     }
 
+#if 0 /* This #ifndef caused a bug on GNU/Linux when using QMAGIC.  */
   /* This adjustment was done above only #ifndef NO_REMAP,
      so only undo it now #ifndef NO_REMAP.  */
-#ifndef NO_REMAP
+  /* #ifndef NO_REMAP  */
+#endif
 #ifdef A_TEXT_OFFSET
   hdr.a_text -= A_TEXT_OFFSET (ohdr);
-#endif
 #endif
 
   return 0;
@@ -877,6 +906,19 @@ copy_text_and_data (new, a_out)
 
 #else /* COFF, but not USG_SHARED_LIBRARIES */
 
+#ifdef MSDOS
+#if __DJGPP__ >= 2
+  /* Dump the original table of exception handlers, not the one
+     where our exception hooks are registered.  */
+  __djgpp_exception_toggle ();
+
+  /* Switch off startup flags that might have been set at runtime
+     and which might change the way that dumped Emacs works.  */
+  save_djgpp_startup_flags = _crt0_startup_flags;
+  _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
+#endif
+#endif
+
   lseek (new, (long) text_scnptr, 0);
   ptr = (char *) f_ohdr.text_start;
 #ifdef HEADER_INCL_IN_TEXT
@@ -891,13 +933,23 @@ copy_text_and_data (new, a_out)
   end = ptr + f_ohdr.dsize;
   write_segment (new, ptr, end);
 
+#ifdef MSDOS
+#if __DJGPP__ >= 2
+  /* Restore our exception hooks.  */
+  __djgpp_exception_toggle ();
+
+  /* Restore the startup flags.  */
+  _crt0_startup_flags = save_djgpp_startup_flags;
+#endif
+#endif
+
 #endif /* USG_SHARED_LIBRARIES */
 
 #else /* if not COFF */
 
 /* Some machines count the header as part of the text segment.
    That is to say, the header appears in core
-   just before the address that start_of_text () returns.
+   just before the address that start_of_text returns.
    For them, N_TXTOFF is the place where the header goes.
    We must adjust the seek to the place after the header.
    Note that at this point hdr.a_text does *not* count
@@ -909,9 +961,92 @@ copy_text_and_data (new, a_out)
   lseek (new, (long) N_TXTOFF (hdr), 0);
 #endif /* no A_TEXT_SEEK */
 
+#ifdef RISCiX
+
+  /* Acorn's RISC-iX has a wacky way of initialising the position of the heap.
+   * There is a little table in crt0.o that is filled at link time with
+   * the min and current brk positions, among other things.  When start
+   * runs, it copies the table to where these parameters live during
+   * execution.  This data is in text space, so it cannot be modified here
+   * before saving the executable, so the data is written manually.  In
+   * addition, the table does not have a label, and the nearest accessible
+   * label (mcount) is not prefixed with a '_', thus making it inaccessible
+   * from within C programs.  To overcome this, emacs's executable is passed
+   * through the command 'nm %s | fgrep mcount' into a pipe, and the
+   * resultant output is then used to find the address of 'mcount'.  As far as
+   * is possible to determine, in RISC-iX releases prior to 1.2, the negative
+   * offset of the table from mcount is 0x2c, whereas from 1.2 onwards it is
+   * 0x30.  bss_end has been rounded up to page boundary.  This solution is
+   * based on suggestions made by Kevin Welton and Steve Hunt of Acorn, and
+   * avoids the need for a custom version of crt0.o for emacs which has its
+   * table in data space.
+   */
+
+  {
+    char command[1024];
+    char errbuf[1024];
+    char address_text[32];
+    int  proforma[4];
+    FILE *pfile;
+    char *temp_ptr;
+    char c;
+    int mcount_address, mcount_offset, count;
+    extern char *_execname;
+
+
+    /* The use of _execname is incompatible with RISCiX 1.1 */
+    sprintf (command, "nm %s | fgrep mcount", _execname);
+
+    if ( (pfile = popen(command, "r")) == NULL)
+    {
+      sprintf (errbuf, "Could not open pipe");
+      PERROR (errbuf);
+    }
+
+    count=0;
+    while ( ((c=getc(pfile)) != EOF) && (c != ' ') && (count < 31))
+      address_text[count++]=c;
+    address_text[count]=0;
+
+    if ((count == 0) || pclose(pfile) != NULL)
+    {
+      sprintf (errbuf, "Failed to execute the command '%s'\n", command);
+      PERROR (errbuf);
+    }
+
+    sscanf(address_text, "%x", &mcount_address);
+    ptr = (char *) unexec_text_start;
+    mcount_offset = (char *)mcount_address - ptr;
+
+#ifdef RISCiX_1_1
+#define EDATA_OFFSET 0x2c
+#else
+#define EDATA_OFFSET 0x30
+#endif
+
+    end = ptr + mcount_offset - EDATA_OFFSET;
+
+    write_segment (new, ptr, end);
+
+    proforma[0] = bss_end;     /* becomes _edata */
+    proforma[1] = bss_end;     /* becomes _end */
+    proforma[2] = bss_end;     /* becomes _minbrk */
+    proforma[3] = bss_end;     /* becomes _curbrk */
+
+    write (new, proforma, 16);
+
+    temp_ptr = ptr;
+    ptr = end + 16;
+    end = temp_ptr + hdr.a_text;
+
+    write_segment (new, ptr, end);
+  }
+
+#else /* !RISCiX */
   ptr = (char *) unexec_text_start;
   end = ptr + hdr.a_text;
   write_segment (new, ptr, end);
+#endif /* RISCiX */
 
   ptr = (char *) unexec_data_start;
   end = ptr + hdr.a_data;
@@ -932,15 +1067,21 @@ write_segment (new, ptr, end)
 {
   register int i, nwrite, ret;
   char buf[80];
+#ifndef USE_CRT_DLL
   extern int errno;
-  char zeros[128];
+#endif
+  /* This is the normal amount to write at once.
+     It is the size of block that NFS uses.  */
+  int writesize = 1 << 13;
+  int pagesize = getpagesize ();
+  char zeros[1 << 13];
 
-  bzero (zeros, sizeof zeros);
+  bzero (zeros, sizeof (zeros));
 
   for (i = 0; ptr < end;)
     {
-      /* distance to next multiple of 128.  */
-      nwrite = (((int) ptr + 128) & -128) - (int) ptr;
+      /* Distance to next multiple of writesize.  */
+      nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
       /* But not beyond specified end.  */
       if (nwrite > end - ptr) nwrite = end - ptr;
       ret = write (new, ptr, nwrite);
@@ -953,7 +1094,16 @@ write_segment (new, ptr, end)
          && errno == EFAULT
 #endif
          )
-       write (new, zeros, nwrite);
+       {
+         /* Write only a page of zeros at once,
+            so that we we don't overshoot the start
+            of the valid memory in the old data segment.  */
+         if (nwrite > pagesize)
+           nwrite = pagesize;
+         write (new, zeros, nwrite);
+       }
+#if 0 /* Now that we have can ask `write' to write more than a page,
+        it is legit for write do less than the whole amount specified.  */
       else if (nwrite != ret)
        {
          sprintf (buf,
@@ -961,6 +1111,7 @@ write_segment (new, ptr, end)
                   ptr, new, nwrite, ret, errno);
          PERROR (buf);
        }
+#endif
       i += nwrite;
       ptr += nwrite;
     }
@@ -989,10 +1140,12 @@ copy_sym (new, a_out, a_name, new_name)
 
 #ifdef COFF
   if (lnnoptr)                 /* if there is line number info */
-    lseek (a_out, lnnoptr, 0); /* start copying from there */
+    lseek (a_out, coff_offset + lnnoptr, 0);   /* start copying from there */
   else
-#endif /* COFF */
-    lseek (a_out, SYMS_START, 0);      /* Position a.out to symtab. */
+    lseek (a_out, coff_offset + SYMS_START, 0);        /* Position a.out to symtab. */
+#else  /* not COFF */
+  lseek (a_out, SYMS_START, 0);        /* Position a.out to symtab. */
+#endif /* not COFF */
 
   while ((n = read (a_out, page, sizeof page)) > 0)
     {
@@ -1111,6 +1264,7 @@ adjust_lnnoptrs (writedesc, readdesc, new_name)
 
 #endif /* COFF */
 
-#endif /* not CANNOT_UNEXEC */
-
 #endif /* not CANNOT_DUMP */
+
+/* arch-tag: 62409b69-e27a-4a7c-9413-0210d6b54e7f
+   (do not change this comment) */