Comment fixes.
[bpt/emacs.git] / src / unexec.c
index 5417f76..6b6136b 100644 (file)
@@ -1,10 +1,10 @@
-/* Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1985,86,87,88,92,93,94 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -137,7 +137,7 @@ 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
-a.out file before starting to write the text segment.a
+a.out file before starting to write the text segment.
 
 * EXEC_MAGIC
 
@@ -164,24 +164,44 @@ pointer looks like an int) but not on all machines.
 #define PERROR(arg) perror (arg); return -1
 #else
 #define IN_UNEXEC
-#include "config.h"
+#include <config.h>
 #define PERROR(file) report_error (file, new)
 #endif
 
 #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
+#include <coff.h>
+#define filehdr external_filehdr
+#define scnhdr external_scnhdr
+#define syment external_syment
+#define auxent external_auxent
+#define n_numaux e_numaux
+#define n_type e_type
+struct aouthdr
+{
+  unsigned short       magic;  /* type of file                         */
+  unsigned short       vstamp; /* version stamp                        */
+  unsigned long                tsize;  /* text size in bytes, padded to FW bdry*/
+  unsigned long                dsize;  /* initialized data "  "                */
+  unsigned long                bsize;  /* uninitialized data "   "             */
+  unsigned long                entry;  /* entry pt.                            */
+  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
 
-/* 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 */
@@ -191,6 +211,20 @@ int need_coff_header = 1;
 #include <sys/stat.h>
 #include <errno.h>
 
+#include <sys/file.h>  /* Must be after sys/types.h for USG and BSD4_1*/
+
+#ifdef USG5
+#include <fcntl.h>
+#endif
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+
+
 extern char *start_of_text ();         /* Start of text */
 extern char *start_of_data ();         /* Start of initialized data */
 
@@ -207,7 +241,22 @@ static long data_scnptr;
 
 #else /* not COFF */
 
+#ifdef HPUX
+extern void *sbrk ();
+#else
+#if 0
+/* Some systems with __STDC__ compilers still declare this `char *' in some
+   header file, and our declaration conflicts.  The return value is always
+   cast, so it should be harmless to leave it undefined.  Hopefully
+   machines with different size pointers and ints declare sbrk in a header
+   file.  */
+#ifdef __STDC__
+extern void *sbrk ();
+#else
 extern char *sbrk ();
+#endif /* __STDC__ */
+#endif
+#endif /* HPUX */
 
 #define SYMS_START ((long) N_SYMOFF (ohdr))
 
@@ -231,7 +280,7 @@ static EXEC_HDR_TYPE hdr, ohdr;
 
 #else /* not HPUX */
 
-#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE)
+#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX)
 static struct bhdr hdr, ohdr;
 #define a_magic fmagic
 #define a_text tsize
@@ -273,6 +322,8 @@ static int pagemask;
 
 #ifdef emacs
 
+#include "lisp.h"
+
 static
 report_error (file, fd)
      char *file;
@@ -280,7 +331,7 @@ report_error (file, fd)
 {
   if (fd)
     close (fd);
-  error ("Failure operating on %s\n", file);
+  report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
 }
 #endif /* emacs */
 
@@ -319,7 +370,7 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 {
   int new, a_out = -1;
 
-  if (a_name && (a_out = open (a_name, 0)) < 0)
+  if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
     {
       PERROR (a_name);
     }
@@ -436,6 +487,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);
       for (scns = f_hdr.f_nscns; scns > 0; scns--) {
        if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
          {
@@ -475,7 +527,7 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
    * space.
    */
 
-  bias = bss_end - (f_ohdr.data_start + f_dhdr.s_size);
+  bias = bss_start - (f_ohdr.data_start + f_dhdr.s_size);
 
 #endif
 
@@ -599,11 +651,13 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
    * .lib), adjust the address of where the section data is in the
    * file, and write out the header.
    *
-   * If any section preceeds .text or .data in the file, this code
+   * If any section precedes .text or .data in the file, this code
    * will not adjust the file pointer for that section correctly.
    */
 
-  lseek (a_out, sizeof (f_hdr) + sizeof (f_ohdr), 0);
+  /* This used to use sizeof (f_ohdr) instead of .f_opthdr.
+     .f_opthdr is said to be right when there is no optional header.  */
+  lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0);
 
   for (scns = f_hdr.f_nscns; scns > 0; scns--)
     {
@@ -671,7 +725,11 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
        */
       ERROR0 ("can't build a COFF file from scratch yet");
 #else
-      bzero (hdr, sizeof hdr);
+#ifdef MSDOS   /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
+      bzero ((void *)&hdr, sizeof hdr);
+#else
+      bzero (&hdr, sizeof hdr);
+#endif
 #endif
     }
 
@@ -732,6 +790,11 @@ 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 Linux when using QMAGIC.  */
+  /* This adjustment was done above only #ifndef NO_REMAP,
+     so only undo it now #ifndef NO_REMAP.  */
+  /* #ifndef NO_REMAP  */
+#endif
 #ifdef A_TEXT_OFFSET
   hdr.a_text -= A_TEXT_OFFSET (ohdr);
 #endif
@@ -804,7 +867,7 @@ copy_text_and_data (new, a_out)
            {
              n = size > sizeof (page) ? sizeof (page) : size;
              if (read (a_out, page, n) != n || write (new, page, n) != n)
-               PERROR ("xemacs");
+               PERROR ("emacs");
            }
          lseek (a_out, old_a_out_ptr, 0);
        }
@@ -832,7 +895,7 @@ copy_text_and_data (new, a_out)
 
 /* 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
@@ -844,9 +907,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;
@@ -868,14 +1014,18 @@ write_segment (new, ptr, end)
   register int i, nwrite, ret;
   char buf[80];
   extern int errno;
-  char zeros[128];
+  /* 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);
@@ -883,8 +1033,21 @@ write_segment (new, ptr, end)
         a gap between the old text segment and the old data segment.
         This gap has probably been remapped into part of the text segment.
         So write zeros for it.  */
-      if (ret == -1 && errno == EFAULT)
-       write (new, zeros, nwrite);
+      if (ret == -1
+#ifdef EFAULT
+         && errno == EFAULT
+#endif
+         )
+       {
+         /* 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,
@@ -892,6 +1055,7 @@ write_segment (new, ptr, end)
                   ptr, new, nwrite, ret, errno);
          PERROR (buf);
        }
+#endif
       i += nwrite;
       ptr += nwrite;
     }
@@ -942,7 +1106,7 @@ copy_sym (new, a_out, a_name, new_name)
 /* ****************************************************************
  * mark_x
  *
- * After succesfully building the new a.out, mark it executable
+ * After successfully building the new a.out, mark it executable
  */
 static void
 mark_x (name)
@@ -1006,7 +1170,11 @@ adjust_lnnoptrs (writedesc, readdesc, new_name)
   if (!lnnoptr || !f_hdr.f_symptr)
     return 0;
 
-  if ((new = open (new_name, 2)) < 0)
+#ifdef MSDOS
+  if ((new = writedesc) < 0)
+#else
+  if ((new = open (new_name, O_RDWR)) < 0)
+#endif
     {
       PERROR (new_name);
       return -1;
@@ -1020,20 +1188,22 @@ adjust_lnnoptrs (writedesc, readdesc, new_name)
        {
          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 (ISFCN (symentry.n_type) || symentry.n_type == 0x2400)
+           {
+             auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
+             lseek (new, -AUXESZ, 1);
+             write (new, &auxentry, AUXESZ);
+           }
        }
     }
+#ifndef MSDOS
   close (new);
+#endif
+  return 0;
 }
 
 #endif /* COFF_BSD_SYMBOLS */
 
 #endif /* COFF */
 
-#endif /* not CANNOT_UNEXEC */
-
 #endif /* not CANNOT_DUMP */