summaryrefslogtreecommitdiff
path: root/src/unexalpha.c
diff options
context:
space:
mode:
authorRichard M. Stallman <rms@gnu.org>1994-09-17 00:59:56 +0000
committerRichard M. Stallman <rms@gnu.org>1994-09-17 00:59:56 +0000
commitb061d5f1ee381550f844843d02cae9afbe2199b4 (patch)
tree90ecb8f8753cdb4b6512d97d63f950b89dc62858 /src/unexalpha.c
parentce99fd6592360172ad88189e2e187344f17f23af (diff)
downloademacs-b061d5f1ee381550f844843d02cae9afbe2199b4.tar.gz
emacs-b061d5f1ee381550f844843d02cae9afbe2199b4.tar.bz2
emacs-b061d5f1ee381550f844843d02cae9afbe2199b4.zip
Initial revision
Diffstat (limited to 'src/unexalpha.c')
-rw-r--r--src/unexalpha.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/unexalpha.c b/src/unexalpha.c
new file mode 100644
index 00000000000..6260288d0bc
--- /dev/null
+++ b/src/unexalpha.c
@@ -0,0 +1,440 @@
+/* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
+
+ Copyright (C) 1994 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 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+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. */
+
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <varargs.h>
+#include <filehdr.h>
+#include <aouthdr.h>
+#include <scnhdr.h>
+#include <syms.h>
+
+static void fatal_unexec ();
+static void mark_x ();
+
+#define READ(_fd, _buffer, _size, _error_message, _error_arg) \
+ errno = EEOF; \
+ if (read (_fd, _buffer, _size) != _size) \
+ fatal_unexec (_error_message, _error_arg);
+
+#define WRITE(_fd, _buffer, _size, _error_message, _error_arg) \
+ if (write (_fd, _buffer, _size) != _size) \
+ fatal_unexec (_error_message, _error_arg);
+
+#define SEEK(_fd, _position, _error_message, _error_arg) \
+ errno = EEOF; \
+ if (lseek (_fd, _position, L_SET) != _position) \
+ fatal_unexec (_error_message, _error_arg);
+
+extern int errno;
+extern char *strerror ();
+
+void *sbrk();
+
+#define EEOF -1
+
+static struct scnhdr *text_section;
+static struct scnhdr *init_section;
+static struct scnhdr *finit_section;
+static struct scnhdr *rdata_section;
+static struct scnhdr *data_section;
+static struct scnhdr *pdata_section;
+static struct scnhdr *xdata_section;
+static struct scnhdr *got_section;
+static struct scnhdr *lit8_section;
+static struct scnhdr *lit4_section;
+static struct scnhdr *sdata_section;
+static struct scnhdr *sbss_section;
+static struct scnhdr *bss_section;
+
+static unsigned int Brk;
+
+struct headers {
+ struct filehdr fhdr;
+ struct aouthdr aout;
+ struct scnhdr section[_MIPS_NSCNS_MAX];
+};
+
+
+
+/* Define name of label for entry point for the dumped executable. */
+
+#ifndef DEFAULT_ENTRY_ADDRESS
+#define DEFAULT_ENTRY_ADDRESS __start
+#endif
+
+unexec (new_name, a_name, data_start, bss_start, entry_address)
+ char *new_name, *a_name;
+ unsigned long data_start, bss_start, entry_address;
+{
+ int new, old;
+ char * oldptr;
+ struct headers ohdr, nhdr;
+ struct stat stat;
+ long pagesize, brk;
+ long newsyms, symrel;
+ int nread;
+ int i;
+ long vaddr, scnptr;
+#define BUFSIZE 8192
+ char buffer[BUFSIZE];
+
+ if ((old = open (a_name, O_RDONLY)) < 0)
+ fatal_unexec ("opening %s", a_name);
+
+ new = creat (new_name, 0666);
+ if (new < 0) fatal_unexec ("creating %s", new_name);
+
+ if ((fstat (old, &stat) == -1))
+ fatal_unexec ("fstat %s", a_name);
+
+ oldptr = (char *)mmap (0, stat.st_size, PROT_READ, MAP_FILE|MAP_SHARED, old, 0);
+
+ if (oldptr == (char *)-1)
+ fatal_unexec ("mmap %s", a_name);
+
+ close (old);
+
+ /* This is a copy of the a.out header of the original executable */
+
+ ohdr = (*(struct headers *)oldptr);
+
+ /* This is where we build the new header from the in-memory copy */
+
+ nhdr = *((struct headers *)TEXT_START);
+
+ /* First do some consistency checks */
+
+ if (nhdr.fhdr.f_magic != ALPHAMAGIC
+ && nhdr.fhdr.f_magic != ALPHAUMAGIC)
+ {
+ fprintf (stderr, "unexec: input file magic number is %x, not %x or %x.\n",
+ nhdr.fhdr.f_magic, ALPHAMAGIC, ALPHAUMAGIC);
+ exit (1);
+ }
+
+ if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
+ {
+ fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
+ nhdr.fhdr.f_opthdr, sizeof (nhdr.aout));
+ exit (1);
+ }
+ if (nhdr.aout.magic != ZMAGIC)
+ {
+ fprintf (stderr, "unexec: input file a.out magic number is %o, not %o.\n",
+ nhdr.aout.magic, ZMAGIC);
+ exit (1);
+ }
+
+
+ /* Now check the existence of certain header section and grab
+ their addresses. */
+
+#define CHECK_SCNHDR(ptr, name, flags) \
+ ptr = NULL; \
+ for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++) \
+ if (strcmp (nhdr.section[i].s_name, name) == 0) \
+ { \
+ if (nhdr.section[i].s_flags != flags) \
+ fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
+ nhdr.section[i].s_flags, flags, name); \
+ ptr = nhdr.section + i; \
+ } \
+
+ CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
+ CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
+#ifdef _FINI
+ CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
+#endif /* _FINI */
+ CHECK_SCNHDR (rdata_section, _RDATA, STYP_RDATA);
+#ifdef _PDATA
+ CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
+#endif _PDATA
+#ifdef _GOT
+ CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
+#endif _GOT
+ CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
+#ifdef _XDATA
+ CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
+#endif /* _XDATA */
+#ifdef _LIT8
+ CHECK_SCNHDR (lit8_section, _LIT8, STYP_LIT8);
+ CHECK_SCNHDR (lit4_section, _LIT4, STYP_LIT4);
+#endif /* _LIT8 */
+ CHECK_SCNHDR (sdata_section, _SDATA, STYP_SDATA);
+ CHECK_SCNHDR (sbss_section, _SBSS, STYP_SBSS);
+ CHECK_SCNHDR (bss_section, _BSS, STYP_BSS);
+#if 0 /* Apparently this error check goes off on irix 3.3,
+ but it doesn't indicate a real problem. */
+ if (i != nhdr.fhdr.f_nscns)
+ fprintf (stderr, "unexec: %d sections found instead of %d.\n",
+ i, nhdr.fhdr.f_nscns);
+#endif
+
+
+ pagesize = getpagesize ();
+ brk = (((long) (sbrk (0))) + pagesize - 1) & (-pagesize);
+
+ /* Remember the current break */
+
+ Brk = brk;
+
+ nhdr.aout.dsize = brk - DATA_START;
+ nhdr.aout.bsize = 0;
+ if (entry_address == 0)
+ {
+ extern DEFAULT_ENTRY_ADDRESS ();
+ nhdr.aout.entry = (unsigned long)DEFAULT_ENTRY_ADDRESS;
+ }
+ else
+ nhdr.aout.entry = entry_address;
+
+ nhdr.aout.bss_start = nhdr.aout.data_start + nhdr.aout.dsize;
+ rdata_section->s_size = data_start - DATA_START;
+
+ /* Adjust start and virtual addresses of rdata_section, too. */
+ rdata_section->s_vaddr = DATA_START;
+ rdata_section->s_paddr = DATA_START;
+ rdata_section->s_scnptr = text_section->s_scnptr + nhdr.aout.tsize;
+
+ data_section->s_vaddr = data_start;
+ data_section->s_paddr = data_start;
+ data_section->s_size = brk - data_start;
+ data_section->s_scnptr = rdata_section->s_scnptr + rdata_section->s_size;
+ vaddr = data_section->s_vaddr + data_section->s_size;
+ scnptr = data_section->s_scnptr + data_section->s_size;
+ if (lit8_section != NULL)
+ {
+ lit8_section->s_vaddr = vaddr;
+ lit8_section->s_paddr = vaddr;
+ lit8_section->s_size = 0;
+ lit8_section->s_scnptr = scnptr;
+ }
+ if (lit4_section != NULL)
+ {
+ lit4_section->s_vaddr = vaddr;
+ lit4_section->s_paddr = vaddr;
+ lit4_section->s_size = 0;
+ lit4_section->s_scnptr = scnptr;
+ }
+ if (sdata_section != NULL)
+ {
+ sdata_section->s_vaddr = vaddr;
+ sdata_section->s_paddr = vaddr;
+ sdata_section->s_size = 0;
+ sdata_section->s_scnptr = scnptr;
+ }
+#ifdef _XDATA
+ if (xdata_section != NULL)
+ {
+ xdata_section->s_vaddr = vaddr;
+ xdata_section->s_paddr = vaddr;
+ xdata_section->s_size = 0;
+ xdata_section->s_scnptr = scnptr;
+ }
+#endif
+#ifdef _GOT
+ if (got_section != NULL)
+ {
+ got_section->s_vaddr = vaddr;
+ got_section->s_paddr = vaddr;
+ got_section->s_size = 0;
+ got_section->s_scnptr = scnptr;
+ }
+#endif /*_GOT */
+ if (sbss_section != NULL)
+ {
+ sbss_section->s_vaddr = vaddr;
+ sbss_section->s_paddr = vaddr;
+ sbss_section->s_size = 0;
+ sbss_section->s_scnptr = scnptr;
+ }
+ if (bss_section != NULL)
+ {
+ bss_section->s_vaddr = vaddr;
+ bss_section->s_paddr = vaddr;
+ bss_section->s_size = 0;
+ bss_section->s_scnptr = scnptr;
+ }
+
+ WRITE (new, (char *)TEXT_START, nhdr.aout.tsize,
+ "writing text section to %s", new_name);
+ WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
+ "writing data section to %s", new_name);
+
+
+ /*
+ * Construct new symbol table header
+ */
+
+ bcopy (oldptr + nhdr.fhdr.f_symptr, buffer, cbHDRR);
+
+#define symhdr ((pHDRR)buffer)
+ newsyms = nhdr.aout.tsize + nhdr.aout.dsize;
+ symrel = newsyms - nhdr.fhdr.f_symptr;
+ nhdr.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;
+
+ WRITE (new, buffer, cbHDRR, "writing symbol table header of %s", new_name);
+
+ /*
+ * Copy the symbol table and line numbers
+ */
+ WRITE (new, oldptr + ohdr.fhdr.f_symptr + cbHDRR,
+ stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
+ "writing symbol table of %s", new_name);
+
+#if 0
+
+/* Not needed for now */
+
+ update_dynamic_symbols (oldptr, new, newsyms,
+ ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->issExtMax,
+ ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbExtOffset,
+ ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbSsExtOffset);
+
+#endif
+
+#undef symhdr
+
+ SEEK (new, 0, "seeking to start of header in %s", new_name);
+ WRITE (new, &nhdr, sizeof (nhdr),
+ "writing header of %s", new_name);
+
+ close (old);
+ close (new);
+ mark_x (new_name);
+}
+
+
+#if 0
+
+/* Not needed for now */
+
+/* The following function updates the values of some symbols
+ that are used by the dynamic loader:
+
+ _edata
+ _end
+
+*/
+
+
+update_dynamic_symbols (old, new, newsyms, nsyms, symoff, stroff)
+char *old; /* Pointer to old executable */
+int new; /* File descriptor for new executable */
+long newsyms; /* Offset of Symbol table in new executable */
+int nsyms; /* Number of symbol table entries */
+long symoff; /* Offset of External Symbols in old file */
+long stroff; /* Offset of string table in old file */
+{
+ long i;
+ int found = 0;
+ EXTR n_end, n_edata;
+
+ /* We go through the symbol table entries until we have found the two
+ symbols. */
+
+ /* cbEXTR is the size of an external symbol table entry */
+
+ for (i = 0; i < nsyms && found < 2; i += cbEXTR)
+ {
+ register pEXTR x = (pEXTR) (old + symoff + i);
+ char *s;
+
+ s = old + stroff + x->asym.iss; /* name of the symbol */
+
+ if (!strcmp(s,"_edata"))
+ {
+ found++;
+ bcopy (x, &n_edata, cbEXTR);
+ n_edata.asym.value = Brk;
+ SEEK (new, newsyms + cbHDRR + i,
+ "seeking to symbol _edata in %s", new_name);
+ WRITE (new, n_edata, cbEXTR,
+ "writing symbol table entry for _edata into %s", new_name);
+ }
+ else if (!strcmp(s,"_end"))
+ {
+ found++;
+ bcopy (x, &n_end, cbEXTR);
+ n_end.asym.value = Brk;
+ SEEK (new, newsyms + cbHDRR + i,
+ "seeking to symbol _end in %s", new_name);
+ WRITE (new, n_end, cbEXTR,
+ "writing symbol table entry for _end into %s", new_name);
+ }
+ }
+
+}
+
+#endif
+
+
+/*
+ * mark_x
+ *
+ * After successfully building the new a.out, mark it executable
+ */
+
+static void
+mark_x (name)
+ char *name;
+{
+ struct stat sbuf;
+ int um = umask (777);
+ umask (um);
+ if (stat (name, &sbuf) < 0)
+ fatal_unexec ("getting protection on %s", name);
+ sbuf.st_mode |= 0111 & ~um;
+ if (chmod (name, sbuf.st_mode) < 0)
+ fatal_unexec ("setting protection on %s", name);
+}
+
+static void
+fatal_unexec (s, va_alist)
+ va_dcl
+{
+ va_list ap;
+ if (errno == EEOF)
+ fputs ("unexec: unexpected end of file, ", stderr);
+ else
+ fprintf (stderr, "unexec: %s, ", strerror (errno));
+ va_start (ap);
+ _doprnt (s, ap, stderr);
+ fputs (".\n", stderr);
+ exit (1);
+}
+