-/* 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,
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., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/*
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
-a.out file before starting to write the text segment.a
+a.out file before starting to write the text segment.
* EXEC_MAGIC
#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 */
-
+#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
+#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 */
+};
+#endif /* not MSDOS */
+#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
+#else /* not COFF_ENCAPSULATE */
#include <a.out.h>
-#endif
+#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 */
#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 */
static long text_scnptr;
static long data_scnptr;
+static long coff_offset;
+
#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))
#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
#ifdef emacs
+#include "lisp.h"
+
static
report_error (file, fd)
char *file;
{
if (fd)
close (fd);
- error ("Failure operating on %s\n", file);
+ report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
}
#endif /* emacs */
static int copy_sym ();
static void mark_x ();
-/* ****************************************************************
- * unexec
- *
- * driving logic.
- */
-unexec (new_name, a_name, data_start, bss_start, entry_address)
- char *new_name, *a_name;
- unsigned data_start, bss_start, entry_address;
-{
- int new, a_out = -1;
-
- if (a_name && (a_out = open (a_name, 0)) < 0)
- {
- PERROR (a_name);
- }
- if ((new = creat (new_name, 0666)) < 0)
- {
- PERROR (new_name);
- }
-
- if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
- || copy_text_and_data (new, a_out) < 0
- || copy_sym (new, a_out, a_name, new_name) < 0
-#ifdef COFF
-#ifndef COFF_BSD_SYMBOLS
- || adjust_lnnoptrs (new, a_out, new_name) < 0
-#endif
-#endif
- )
- {
- close (new);
- /* unlink (new_name); /* Failed, unlink new a.out */
- return -1;
- }
-
- close (new);
- if (a_out >= 0)
- close (a_out);
- mark_x (new_name);
- return 0;
-}
-
/* ****************************************************************
* make_hdr
*
}
#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);
block_copy_start += sizeof (f_ohdr);
}
/* Loop through section headers, copying them in */
+ 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))
{
* 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--)
{
*/
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
}
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 */
+#endif
#ifdef A_TEXT_OFFSET
hdr.a_text -= A_TEXT_OFFSET (ohdr);
#endif
#endif /* not COFF */
}
\f
+write_segment (new, ptr, end)
+ int new;
+ register char *ptr, *end;
+{
+ register int i, nwrite, ret;
+ char buf[80];
+#ifndef USE_CRT_DLL
+ extern int errno;
+#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));
+
+ for (i = 0; ptr < end;)
+ {
+ /* 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);
+ /* If write gets a page fault, it means we reached
+ 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
+#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,
+ "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
+ ptr, new, nwrite, ret, errno);
+ PERROR (buf);
+ }
+#endif
+ i += nwrite;
+ ptr += nwrite;
+ }
+}
/* ****************************************************************
* copy_text_and_data
*
#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
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
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;
return 0;
}
-
-write_segment (new, ptr, end)
- int new;
- register char *ptr, *end;
-{
- register int i, nwrite, ret;
- char buf[80];
- extern int errno;
- char zeros[128];
-
- bzero (zeros, sizeof zeros);
-
- for (i = 0; ptr < end;)
- {
- /* distance to next multiple of 128. */
- nwrite = (((int) ptr + 128) & -128) - (int) ptr;
- /* But not beyond specified end. */
- if (nwrite > end - ptr) nwrite = end - ptr;
- ret = write (new, ptr, nwrite);
- /* If write gets a page fault, it means we reached
- 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);
- else if (nwrite != ret)
- {
- sprintf (buf,
- "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
- ptr, new, nwrite, ret, errno);
- PERROR (buf);
- }
- i += nwrite;
- ptr += nwrite;
- }
-}
\f
/* ****************************************************************
* copy_sym
#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)
{
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;
}
}
}
+#ifndef MSDOS
close (new);
+#endif
+ return 0;
}
#endif /* COFF_BSD_SYMBOLS */
#endif /* COFF */
-#endif /* not CANNOT_UNEXEC */
+/* ****************************************************************
+ * unexec
+ *
+ * driving logic.
+ */
+unexec (new_name, a_name, data_start, bss_start, entry_address)
+ char *new_name, *a_name;
+ unsigned data_start, bss_start, entry_address;
+{
+ int new, a_out = -1;
+
+ if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
+ {
+ PERROR (a_name);
+ }
+ if ((new = creat (new_name, 0666)) < 0)
+ {
+ PERROR (new_name);
+ }
+
+ if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
+ || copy_text_and_data (new, a_out) < 0
+ || copy_sym (new, a_out, a_name, new_name) < 0
+#ifdef COFF
+#ifndef COFF_BSD_SYMBOLS
+ || adjust_lnnoptrs (new, a_out, new_name) < 0
+#endif
+#endif
+ )
+ {
+ close (new);
+ /* unlink (new_name); /* Failed, unlink new a.out */
+ return -1;
+ }
+
+ close (new);
+ if (a_out >= 0)
+ close (a_out);
+ mark_x (new_name);
+ return 0;
+}
#endif /* not CANNOT_DUMP */
+
+/* arch-tag: 62409b69-e27a-4a7c-9413-0210d6b54e7f
+ (do not change this comment) */