-/* Copyright (C) 1985 Free Software Foundation, Inc.
+/* Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
This file is part of GNU Emacs.
and this notice must be preserved on all copies. */
-/*
+/*
* unexec.c - Convert a running program into an a.out file.
- *
+ *
* Author: Spencer W. Thomas
* Computer Science Dept.
* University of Utah
* Takes a snapshot of the program and makes an a.out format file in the
* file named by the string argument new_name.
* If a_name is non-NULL, the symbol table will be taken from the given file.
- *
- * The boundaries within the a.out file may be adjusted with the data_start
+ * On some machines, an existing a_name file is required.
+ *
+ * The boundaries within the a.out file may be adjusted with the data_start
* and bss_start arguments. Either or both may be given as 0 for defaults.
- *
+ *
* Data_start gives the boundary between the text segment and the data
* segment of the program. The text segment can contain shared, read-only
* program code and literal data, while the data segment is always unshared
- * and unprotected. Data_start gives the lowest unprotected address. Since
- * the granularity of write-protection is on 1k page boundaries on the VAX, a
- * given data_start value which is not on a page boundary is rounded down to
- * the beginning of the page it is on. The default when 0 is given leaves the
- * number of protected pages the same as it was before.
- *
+ * and unprotected. Data_start gives the lowest unprotected address.
+ * The value you specify may be rounded down to a suitable boundary
+ * as required by the machine you are using.
+ *
+ * Specifying zero for data_start means the boundary between text and data
+ * should not be the same as when the program was loaded.
+ * If NO_REMAP is defined, the argument data_start is ignored and the
+ * segment boundaries are never changed.
+ *
* Bss_start indicates how much of the data segment is to be saved in the
* a.out file and restored when the program is executed. It gives the lowest
* unsaved address, and is rounded up to a page boundary. The default when 0
*
*/
-#ifdef emacs
-#include "config.h"
-#define has_error
-#endif
+/* There are several compilation parameters affecting unexec:
+
+* COFF
+
+Define this if your system uses COFF for executables.
+Otherwise we assume you use Berkeley format.
+
+* NO_REMAP
+
+Define this if you do not want to try to save Emacs's pure data areas
+as part of the text segment.
+
+Saving them as text is good because it allows users to share more.
+
+However, on machines that locate the text area far from the data area,
+the boundary cannot feasibly be moved. Such machines require
+NO_REMAP.
+
+Also, remapping can cause trouble with the built-in startup routine
+/lib/crt0.o, which defines `environ' as an initialized variable.
+Dumping `environ' as pure does not work! So, to use remapping,
+you must write a startup routine for your machine in Emacs's crt0.c.
+If NO_REMAP is defined, Emacs uses the system's crt0.o.
+
+* SECTION_ALIGNMENT
+
+Some machines that use COFF executables require that each section
+start on a certain boundary *in the COFF file*. Such machines should
+define SECTION_ALIGNMENT to a mask of the low-order bits that must be
+zero on such a boundary. This mask is used to control padding between
+segments in the COFF file.
+
+If SECTION_ALIGNMENT is not defined, the segments are written
+consecutively with no attempt at alignment. This is right for
+unmodified system V.
+
+* SEGMENT_MASK
+
+Some machines require that the beginnings and ends of segments
+*in core* be on certain boundaries. For most machines, a page
+boundary is sufficient. That is the default. When a larger
+boundary is needed, define SEGMENT_MASK to a mask of
+the bits that must be zero on such a boundary.
+
+* A_TEXT_OFFSET(HDR)
+
+Some machines count the a.out header as part of the size of the text
+segment (a_text); they may actually load the header into core as the
+first data in the text segment. Some have additional padding between
+the header and the real text of the program that is counted in a_text.
+
+For these machines, define A_TEXT_OFFSET(HDR) to examine the header
+structure HDR and return the number of bytes to add to `a_text'
+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
+a.out file before starting to write the text segment.a
+
+* EXEC_MAGIC
+
+For machines using COFF, this macro, if defined, is a value stored
+into the magic number field of the output file.
+
+* ADJUST_EXEC_HEADER
+
+This macro can be used to generate statements to adjust or
+initialize nonstandard fields in the file header
+
+* ADDR_CORRECT(ADDR)
+
+Macro to correct an int which is the bit pattern of a pointer to a byte
+into an int which is the number of a byte.
-#ifndef has_error
+This macro has a default definition which is usually right.
+This default definition is a no-op on most machines (where a
+pointer looks like an int) but not on all machines.
+
+*/
+
+#ifndef mips /* mips machine requires completely separate code. */
+
+#ifndef emacs
#define PERROR(arg) perror (arg); return -1
#else
+#include "config.h"
#define PERROR(file) report_error (file, new)
#endif
#ifndef CANNOT_DUMP /* all rest of file! */
-#include <sys/param.h>
+#include <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/types.h>
#endif
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
-
+
extern char *start_of_text (); /* Start of text */
extern char *start_of_data (); /* Start of initialized data */
-
+
#ifdef COFF
+#ifndef USG
+#ifndef STRIDE
+#ifndef UMAX
+/* I have a suspicion that these are turned off on all systems
+ and can be deleted. Try it in version 19. */
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
+#include <syms.h>
+#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 int text_scnptr;
+static long text_scnptr;
+static long data_scnptr;
#else /* not COFF */
extern char *sbrk ();
-#include <a.out.h>
#define SYMS_START ((long) N_SYMOFF (ohdr))
#ifdef HPUX
-#ifdef hp9000s200
+#ifdef HP9000S200_ID
#define MY_ID HP9000S200_ID
#else
#include <model.h>
#define MY_ID MYSYS
-#endif /* not hp9000s200 */
+#endif /* no HP9000S200_ID */
static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};
static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};
#define N_TXTOFF(x) TEXT_OFFSET(x)
#endif /* not USG */
#endif /* not HPUX */
+static int unexec_text_start;
+static int unexec_data_start;
+
#endif /* not COFF */
static int pagemask;
-#if defined (BSD4_1) || defined (USG)
-#ifdef EXEC_PAGESIZE
-#define getpagesize() EXEC_PAGESIZE
-#else
-#ifdef NBPG
-#define getpagesize() NBPG * CLSIZE
-#ifndef CLSIZE
-#define CLSIZE 1
-#endif /* no CLSIZE */
-#else /* no NBPG */
-#define getpagesize() NBPC
-#endif /* no NBPG */
-#endif /* no EXEC_PAGESIZE */
-#endif /* BSD4_1 or USG */
-
/* Correct an int which is the bit pattern of a pointer to a byte
into an int which is the number of a byte.
This is a no-op on ordinary machines, but not on all. */
#ifndef ADDR_CORRECT /* Let m-*.h files override this definition */
-#define ADDR_CORRECT(x) (((char *)(x)) - ((char *) 0))
+#define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
#endif
-#ifdef has_error
+#ifdef emacs
static
report_error (file, fd)
close (fd);
error ("Failure operating on %s", file);
}
-#endif /* has_error */
+#endif /* emacs */
#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
int a1, a2;
{
close (fd);
-#ifdef has_error
+#ifdef emacs
error (msg, a1, a2);
#else
fprintf (stderr, msg, a1, a2);
{
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) < 0
|| copy_sym (new, a_out, a_name, new_name) < 0
#ifdef COFF
- || adjust_lnnoptrs (new) < 0
+ || adjust_lnnoptrs (new, a_out, new_name) < 0
#endif
)
{
char *a_name;
char *new_name;
{
+ int tem;
#ifdef COFF
auto struct scnhdr f_thdr; /* Text section header */
auto struct scnhdr f_dhdr; /* Data section header */
auto struct scnhdr f_bhdr; /* Bss section header */
auto struct scnhdr scntemp; /* Temporary section header */
register int scns;
- register long bias; /* Bias to add for growth */
+#endif /* COFF */
+ unsigned int bss_end;
+
+ pagemask = getpagesize () - 1;
+
+ /* Adjust text/data boundary. */
+#ifdef NO_REMAP
+ data_start = (int) start_of_data ();
+#else /* not NO_REMAP */
+ if (!data_start)
+ data_start = (int) start_of_data ();
+#endif /* not NO_REMAP */
+ data_start = ADDR_CORRECT (data_start);
+
+#ifdef SEGMENT_MASK
+ data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */
+#else
+ data_start = data_start & ~pagemask; /* (Down) to page boundary. */
+#endif
+
+ bss_end = (ADDR_CORRECT (sbrk (0)) + pagemask) & ~pagemask;
+ /* Adjust data/bss boundary. */
+ if (bss_start != 0)
+ {
+ bss_start = (ADDR_CORRECT (bss_start) + pagemask) & ~pagemask; /* (Up) to page bdry. */
+ if (bss_start > bss_end)
+ {
+ ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
+ bss_start);
+ }
+ }
+ else
+ bss_start = bss_end;
+
+ if (data_start > bss_start) /* Can't have negative data size. */
+ {
+ ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
+ data_start, bss_start);
+ }
+
+#ifdef COFF
/* Salvage as much info from the existing file as possible */
if (a_out >= 0)
{
PERROR (a_name);
}
block_copy_start += sizeof (f_ohdr);
- }
+ }
/* Loop through section headers, copying them in */
for (scns = f_hdr.f_nscns; scns > 0; scns--) {
if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
{
PERROR (a_name);
}
- block_copy_start += sizeof (scntemp);
if (scntemp.s_scnptr > 0L)
{
- block_copy_start += scntemp.s_size;
+ if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
+ block_copy_start = scntemp.s_scnptr + scntemp.s_size;
}
if (strcmp (scntemp.s_name, ".text") == 0)
{
{
f_bhdr = scntemp;
}
- }
+ }
}
else
{
ERROR0 ("can't build a COFF file from scratch yet");
}
- pagemask = getpagesize () - 1;
-
- if (!data_start)
- data_start = (int) start_of_data ();
- data_start = ADDR_CORRECT (data_start);
- data_start = data_start & ~pagemask; /* down to a page boundary */
+ /* 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);
#ifdef EXEC_MAGIC
f_ohdr.magic = EXEC_MAGIC;
#endif
+#ifndef NO_REMAP
f_ohdr.text_start = (long) start_of_text ();
f_ohdr.tsize = data_start - f_ohdr.text_start;
f_ohdr.data_start = data_start;
- f_ohdr.dsize = (long) sbrk (0) - f_ohdr.data_start;
- f_ohdr.bsize = 0;
+#endif /* NO_REMAP */
+ f_ohdr.dsize = bss_start - f_ohdr.data_start;
+ f_ohdr.bsize = bss_end - bss_start;
f_thdr.s_size = f_ohdr.tsize;
f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
- f_thdr.s_scnptr = (f_thdr.s_scnptr + pagemask) & ~pagemask; /* round up */
+ lnnoptr = f_thdr.s_lnnoptr;
+#ifdef SECTION_ALIGNMENT
+ /* Some systems require special alignment
+ of the sections in the file itself. */
+ f_thdr.s_scnptr
+ = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
+#endif /* SECTION_ALIGNMENT */
text_scnptr = f_thdr.s_scnptr;
f_dhdr.s_paddr = f_ohdr.data_start;
f_dhdr.s_vaddr = f_ohdr.data_start;
f_dhdr.s_size = f_ohdr.dsize;
f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
- f_dhdr.s_scnptr &= ~pagemask; /* round down to page boundary */
+#ifdef SECTION_ALIGNMENT
+ /* Some systems require special alignment
+ of the sections in the file itself. */
+ f_dhdr.s_scnptr
+ = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
+#endif /* SECTION_ALIGNMENT */
+ data_scnptr = f_dhdr.s_scnptr;
f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
f_bhdr.s_size = f_ohdr.bsize;
f_hdr.f_symptr += bias;
}
- if (f_thdr.s_lnnoptr > 0L)
+ if (f_thdr.s_lnnoptr > 0L)
{
f_thdr.s_lnnoptr += bias;
}
+#ifdef ADJUST_EXEC_HEADER
+ ADJUST_EXEC_HEADER
+#endif /* ADJUST_EXEC_HEADER */
+
if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
{
PERROR (new_name);
PERROR (new_name);
}
return (0);
-
+
#else /* if not COFF */
/* Get symbol table info from header of a.out file if given one. */
{
ERROR1 ("invalid magic number in %s", a_name);
}
-#ifdef celerity
- hdr.a_scovrfl = ohdr.a_scovrfl;
-#endif
-#ifdef HPUX
- hdr.a_lesyms = ohdr.a_lesyms;
- hdr.a_sltsize = ohdr.a_sltsize;
- hdr.a_dnttsize = ohdr.a_dnttsize;
- hdr.a_vtsize = ohdr.a_vtsize;
-#else /* not HPUX */
- hdr.a_syms = ohdr.a_syms;
-#endif /* not HPUX */
+ hdr = ohdr;
}
else
{
-#ifdef celerity
- hdr.a_scovrfl = 0;
-#endif
-#ifdef HPUX
- hdr.a_lesyms = 0;
- hdr.a_sltsize = 0;
- hdr.a_dnttsize = 0;
- hdr.a_vtsize = 0;
-#else /* not HPUX */
- hdr.a_syms = 0; /* No a.out, so no symbol info. */
-#endif /* not HPUX */
+ bzero (hdr, sizeof hdr);
}
- /* Construct header from user structure. */
-#ifdef HPUX
- /* (((MAGIC) ohdr.a_magic) == ((MAGIC) OLDMAGIC)) This does not work */
- hdr.a_magic = ((ohdr.a_magic.file_type == OLDMAGIC.file_type) ?
- NEWMAGIC : ohdr.a_magic);
-#else /* not HPUX */
-/* hdr.a_magic = NEWMAGIC; */
- hdr.a_magic = ohdr.a_magic;
-#endif /* not HPUX */
-#ifdef sun3
- hdr.a_machtype = ohdr.a_machtype;
-#endif /* sun3 */
- hdr.a_trsize = 0;
- hdr.a_drsize = 0;
- hdr.a_entry = entry_address;
+ unexec_text_start = (long) start_of_text ();
+ unexec_data_start = data_start;
- pagemask = getpagesize () - 1;
+ /* Machine-dependent fixup for header, or maybe for unexec_text_start */
+#ifdef ADJUST_EXEC_HEADER
+ ADJUST_EXEC_HEADER;
+#endif /* ADJUST_EXEC_HEADER */
- /* Adjust data/bss boundary. */
- if (bss_start != 0)
- {
- bss_start = (ADDR_CORRECT (bss_start) + pagemask) & ~pagemask; /* (Up) to page bdry. */
- if (bss_start > ADDR_CORRECT (sbrk (0)))
- {
- ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
- bss_start);
- }
- }
- else
- {
- bss_start = ADDR_CORRECT (sbrk (0));
- bss_start = (bss_start + pagemask) & ~pagemask;
- }
+ hdr.a_trsize = 0;
+ hdr.a_drsize = 0;
+ if (entry_address != 0)
+ hdr.a_entry = entry_address;
- /* Adjust text/data boundary. */
- if (!data_start)
- data_start = (int) start_of_data ();
+ hdr.a_bss = bss_end - bss_start;
+ hdr.a_data = bss_start - data_start;
+#ifdef NO_REMAP
+ hdr.a_text = ohdr.a_text;
+#else /* not NO_REMAP */
+ hdr.a_text = data_start - unexec_text_start;
+#endif /* not NO_REMAP */
- data_start = ADDR_CORRECT (data_start);
-#ifdef sun
- data_start = data_start & ~(SEGSIZ - 1); /* (Down) to segment boundary. */
-#else
- data_start = data_start & ~pagemask; /* (Down) to page boundary. */
+#ifdef A_TEXT_OFFSET
+ hdr.a_text += A_TEXT_OFFSET (ohdr);
#endif
- if (data_start > bss_start) /* Can't have negative data size. */
- {
- ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
- data_start, bss_start);
- }
-
- hdr.a_bss = ADDR_CORRECT (sbrk (0)) - bss_start;
- if (hdr.a_bss < 0)
- hdr.a_bss = 0;
- hdr.a_data = bss_start - data_start;
-#if defined(sequent)
- hdr.a_text = data_start - (long) start_of_text () + sizeof(hdr) + N_ADDRADJ(ohdr);
-#else
- hdr.a_text = data_start - (long) start_of_text ();
-#endif /* not sequent */
-
if (write (new, &hdr, sizeof hdr) != sizeof hdr)
{
PERROR (new_name);
}
+
+#ifdef A_TEXT_OFFSET
+ hdr.a_text -= A_TEXT_OFFSET (ohdr);
+#endif
+
return 0;
#endif /* not COFF */
copy_text_and_data (new)
int new;
{
- register int nwrite, ret;
register char *end;
- int i;
register char *ptr;
- char buf[80];
- extern int errno;
-
+
#ifdef COFF
lseek (new, (long) text_scnptr, 0);
ptr = (char *) f_ohdr.text_start;
- end = ptr + f_ohdr.tsize + f_ohdr.dsize;
- while (ptr < end)
- {
- nwrite = 128;
- if (nwrite > end - ptr) nwrite = end - ptr;
- ret = write (new, ptr, nwrite);
- 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);
- }
- ptr += nwrite;
- }
- return (0);
+ end = ptr + f_ohdr.tsize;
+ write_segment (new, ptr, end);
+
+ lseek (new, (long) data_scnptr, 0);
+ ptr = (char *) f_ohdr.data_start;
+ end = ptr + f_ohdr.dsize;
+ write_segment (new, ptr, end);
#else /* if not COFF */
-#if defined(sun3) || defined(sequent)
- lseek (new, (long) (N_TXTOFF (hdr) + sizeof (hdr)), 0);
+/* 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.
+ 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
+ the extra A_TEXT_OFFSET bytes, only the actual bytes of code. */
+
+#ifdef A_TEXT_SEEK
+ lseek (new, (long) A_TEXT_SEEK (hdr), 0);
+#else
+#ifdef A_TEXT_OFFSET
+ /* Note that on the Sequent machine A_TEXT_OFFSET != sizeof (hdr)
+ and sizeof (hdr) is the correct amount to add here. */
+ /* In version 19, eliminate this case and use A_TEXT_SEEK whenever
+ N_TXTOFF is not right. */
+ lseek (new, (long) N_TXTOFF (hdr) + sizeof (hdr), 0);
#else
lseek (new, (long) N_TXTOFF (hdr), 0);
-#endif
+#endif /* no A_TEXT_OFFSET */
+#endif /* no A_TEXT_SEEK */
+
+ ptr = (char *) unexec_text_start;
+ end = ptr + hdr.a_text;
+ write_segment (new, ptr, end);
+
+ ptr = (char *) unexec_data_start;
+ end = ptr + hdr.a_data;
+/* This lseek is certainly incorrect when A_TEXT_OFFSET
+ and I believe it is a no-op otherwise.
+ Let's see if its absence ever fails. */
+/* lseek (new, (long) N_TXTOFF (hdr) + hdr.a_text, 0); */
+ write_segment (new, ptr, end);
+
+#endif /* not COFF */
+
+ 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);
- ptr = start_of_text ();
- end = ptr + hdr.a_text + hdr.a_data;
-#if defined(sequent)
- end -= (sizeof(hdr) + N_ADDRADJ(hdr));
-#endif
for (i = 0; ptr < end;)
{
- nwrite = 128;
+ /* 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)
- {
- /* BZS - again, see above about N_TXTOFF on a SUN */
-#if defined(sun3) || defined(sequent)
- lseek (new, (long) (N_TXTOFF (hdr) + i + nwrite + sizeof (hdr)), 0);
-#else
- lseek (new, (long) (N_TXTOFF (hdr) + i + nwrite), 0);
-#endif
- }
+ write (new, zeros, nwrite);
else if (nwrite != ret)
{
sprintf (buf,
i += nwrite;
ptr += nwrite;
}
-
- return 0;
-#endif /* not COFF */
}
\f
/* ****************************************************************
return 0;
#endif /* COFF */
-#ifdef sun3
- /* BZS - I might be covering a sin with this */
- lseek (new, N_SYMOFF (hdr), 0);
-#else
- lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */
-#endif
+#ifdef COFF
+ if (lnnoptr) /* if there is line number info */
+ lseek (a_out, lnnoptr, 0); /* start copying from there */
+ else
+#endif /* COFF */
+ lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */
+
while ((n = read (a_out, page, sizeof page)) > 0)
{
if (write (new, page, n) != n)
#ifdef COFF
-adjust_lnnoptrs (new)
- int new;
+/* This function is probably very slow. Instead of reopening the new
+ file for input and output it should copy from the old to the new
+ using the two descriptors already open (WRITEDESC and READDESC).
+ Instead of reading one small structure at a time it should use
+ a reasonable size buffer. But I don't have time to work on such
+ things, so I am installing it as submitted to me. -- RMS. */
+
+adjust_lnnoptrs (writedesc, readdesc, new_name)
+ int writedesc;
+ int readdesc;
+ char *new_name;
{
- return 0;
+ register int nsyms;
+ register int new;
+#ifdef amdahl_uts
+ SYMENT symentry;
+ AUXENT auxentry;
+#else
+ struct syment symentry;
+ struct auxent auxentry;
+#endif
+
+ if (!lnnoptr || !f_hdr.f_symptr)
+ return 0;
+
+ if ((new = open (new_name, 2)) < 0)
+ {
+ PERROR (new_name);
+ return -1;
+ }
+
+ lseek (new, f_hdr.f_symptr, 0);
+ for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
+ {
+ read (new, &symentry, SYMESZ);
+ if (symentry.n_numaux)
+ {
+ 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);
+ }
+ }
+ }
+ close (new);
}
#endif /* COFF */
#endif /* not CANNOT_DUMP */
+\f
+#else /* mips */
+
+/* Unexec for mips machines.
+ Note that I regard it as the responsibility of people at Mips
+ to tell me about any changes that need to be made in this code.
+ I won't take responsibility to think about it even if a change
+ I make elsewhere causes it to break. -- RMS. */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <varargs.h>
+#include <filehdr.h>
+#include <aouthdr.h>
+#include <scnhdr.h>
+#include <sym.h>
+
+#include "m-mips.h"
+
+#define private static
+\f
+extern int errno;
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define EEOF -1
+
+private void
+fatal(s, va_alist)
+ va_dcl
+{
+ va_list ap;
+ if (errno == EEOF) {
+ fputs("unexec: unexpected end of file, ", stderr);
+ }
+ else if (errno < sys_nerr) {
+ fprintf(stderr, "unexec: %s, ", sys_errlist[errno]);
+ }
+ else {
+ fprintf(stderr, "unexec: error code %d, ", errno);
+ }
+ va_start(ap);
+ _doprnt(s, ap, stderr);
+ fputs(".\n", stderr);
+ exit(1);
+}
+
+#define READ(_fd, _buffer, _size, _error_message, _error_arg) \
+ errno = EEOF; \
+ if (read(_fd, _buffer, _size) != _size) \
+ fatal(_error_message, _error_arg);
+
+#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
+ if (write(_fd, _buffer, _size) != _size) \
+ fatal(_error_message, _error_arg);
+
+#define SEEK(_fd, _position, _error_message, _error_arg) \
+ errno = EEOF; \
+ if (lseek(_fd, _position, L_SET) != _position) \
+ fatal(_error_message, _error_arg);
+\f
+struct headers {
+ struct filehdr fhdr;
+ struct aouthdr aout;
+ struct scnhdr text_section;
+ struct scnhdr rdata_section;
+ struct scnhdr data_section;
+ struct scnhdr sdata_section;
+ struct scnhdr sbss_section;
+ struct scnhdr bss_section;
+};
+
+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, old;
+ int pagesize, brk;
+ int newsyms, symrel;
+ int nread;
+ struct headers hdr;
+#define BUFSIZE 8192
+ char buffer[BUFSIZE];
+
+ old = open (a_name, O_RDONLY, 0);
+ if (old < 0) fatal("openning %s", a_name);
+
+ new = creat (new_name, 0666);
+ if (new < 0) fatal("creating %s", new_name);
+
+ hdr = *((struct headers *)TEXT_START);
+ if (hdr.fhdr.f_magic != MIPSELMAGIC
+ && hdr.fhdr.f_magic != MIPSEBMAGIC) {
+ fprintf(stderr, "unexec: input file magic number is %x, not %x or %x.\n",
+ hdr.fhdr.f_magic, MIPSELMAGIC, MIPSEBMAGIC);
+ exit(1);
+ }
+ if (hdr.fhdr.f_opthdr != sizeof(hdr.aout)) {
+ fprintf(stderr, "unexec: input a.out header is %d bytes, not %d.\n",
+ hdr.fhdr.f_opthdr, sizeof(hdr.aout));
+ exit(1);
+ }
+#if 0
+ if (hdr.aout.magic != ZMAGIC
+ && hdr.aout.magic != NMAGIC
+ && hdr.aout.magic != OMAGIC) {
+ fprintf(stderr, "unexec: input file a.out magic number is %o, not %o, %o, or %o.\n",
+ hdr.aout.magic, ZMAGIC, NMAGIC, OMAGIC);
+ exit(1);
+ }
+#else
+ if (hdr.aout.magic != ZMAGIC) {
+ fprintf(stderr, "unexec: input file a.out magic number is %o, not %o.\n",
+ hdr.aout.magic, ZMAGIC);
+ exit(1);
+ }
+#endif
+ if (hdr.fhdr.f_nscns != 6) {
+ fprintf(stderr, "unexec: %d sections instead of 6.\n", hdr.fhdr.f_nscns);
+ }
+#define CHECK_SCNHDR(field, name, flags) \
+ if (strcmp(hdr.field.s_name, name) != 0) { \
+ fprintf(stderr, "unexec: %s section where %s expected.\n", \
+ hdr.field.s_name, name); \
+ exit(1); \
+ } \
+ else if (hdr.field.s_flags != flags) { \
+ fprintf(stderr, "unexec: %x flags where %x expected in %s section.\n", \
+ hdr.field.s_flags, flags, name); \
+ }
+ CHECK_SCNHDR(text_section, _TEXT, STYP_TEXT);
+ CHECK_SCNHDR(rdata_section, _RDATA, STYP_RDATA);
+ CHECK_SCNHDR(data_section, _DATA, STYP_DATA);
+ CHECK_SCNHDR(sdata_section, _SDATA, STYP_SDATA);
+ CHECK_SCNHDR(sbss_section, _SBSS, STYP_SBSS);
+ CHECK_SCNHDR(bss_section, _BSS, STYP_BSS);
+
+ pagesize = getpagesize();
+ brk = (sbrk(0) + pagesize - 1) & (-pagesize);
+ hdr.aout.dsize = brk - DATA_START;
+ hdr.aout.bsize = 0;
+ if (entry_address == 0) {
+ extern __start();
+ hdr.aout.entry = (unsigned)__start;
+ }
+ else {
+ hdr.aout.entry = entry_address;
+ }
+ hdr.aout.bss_start = hdr.aout.data_start + hdr.aout.dsize;
+ hdr.rdata_section.s_size = data_start - DATA_START;
+ hdr.data_section.s_vaddr = data_start;
+ hdr.data_section.s_paddr = data_start;
+ hdr.data_section.s_size = brk - DATA_START;
+ hdr.data_section.s_scnptr = hdr.rdata_section.s_scnptr
+ + hdr.rdata_section.s_size;
+ hdr.sdata_section.s_vaddr = hdr.data_section.s_vaddr
+ + hdr.data_section.s_size;
+ hdr.sdata_section.s_paddr = hdr.sdata_section.s_paddr;
+ hdr.sdata_section.s_size = 0;
+ hdr.sdata_section.s_scnptr = hdr.data_section.s_scnptr
+ + hdr.data_section.s_size;
+ hdr.sbss_section.s_vaddr = hdr.sdata_section.s_vaddr
+ + hdr.sdata_section.s_size;
+ hdr.sbss_section.s_paddr = hdr.sbss_section.s_vaddr;
+ hdr.sbss_section.s_size = 0;
+ hdr.sbss_section.s_scnptr = hdr.sdata_section.s_scnptr
+ + hdr.sdata_section.s_size;
+ hdr.bss_section.s_vaddr = hdr.sbss_section.s_vaddr
+ + hdr.sbss_section.s_size;
+ hdr.bss_section.s_paddr = hdr.bss_section.s_vaddr;
+ hdr.bss_section.s_size = 0;
+ hdr.bss_section.s_scnptr = hdr.sbss_section.s_scnptr
+ + hdr.sbss_section.s_size;
+
+ WRITE(new, TEXT_START, hdr.aout.tsize,
+ "writing text section to %s", new_name);
+ WRITE(new, DATA_START, hdr.aout.dsize,
+ "writing text section to %s", new_name);
+
+ SEEK(old, hdr.fhdr.f_symptr, "seeking to start of symbols in %s", a_name);
+ errno = EEOF;
+ nread = read(old, buffer, BUFSIZE);
+ if (nread < sizeof(HDRR)) fatal("reading symbols from %s", a_name);
+#define symhdr ((pHDRR)buffer)
+ newsyms = hdr.aout.tsize + hdr.aout.dsize;
+ symrel = newsyms - hdr.fhdr.f_symptr;
+ hdr.fhdr.f_symptr = newsyms;
+ symhdr->cbLineOffset += symrel;
+ symhdr->cbDnOffset += symrel;
+ symhdr->cbPdOffset += symrel;
+ symhdr->cbSymOffset += symrel;
+ symhdr->cbOptOffset += symrel;
+ symhdr->cbAuxOffset += symrel;
+ symhdr->cbSsOffset += symrel;
+ symhdr->cbSsExtOffset += symrel;
+ symhdr->cbFdOffset += symrel;
+ symhdr->cbRfdOffset += symrel;
+ symhdr->cbExtOffset += symrel;
+#undef symhdr
+ do {
+ if (write(new, buffer, nread) != nread)
+ fatal("writing symbols to %s", new_name);
+ nread = read(old, buffer, BUFSIZE);
+ if (nread < 0) fatal("reading symbols from %s", a_name);
+#undef BUFSIZE
+ } while (nread != 0);
+
+ SEEK(new, 0, "seeking to start of header in %s", new_name);
+ WRITE(new, &hdr, sizeof(hdr),
+ "writing header of %s", new_name);
+
+ close(old);
+ close(new);
+ mark_x(new_name);
+}
+
+/*
+ * mark_x
+ *
+ * After succesfully building the new a.out, mark it executable
+ */
+static
+mark_x (name)
+ char *name;
+{
+ struct stat sbuf;
+ int um = umask (777);
+ umask (um);
+ if (stat(name, &sbuf) < 0)
+ fatal("getting protection on %s", name);
+ sbuf.st_mode |= 0111 & ~um;
+ if (chmod(name, sbuf.st_mode) < 0)
+ fatal("setting protection on %s", name);
+}
+
+#endif /* mips */