/* Unexec for DEC alpha. schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
- Copyright (C) 1994 Free Software Foundation, Inc.
+ Copyright (C) 1994, 2000 Free Software Foundation, Inc.
This file is part of GNU Emacs.
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, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
\f
#include <config.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdio.h>
-#include <varargs.h>
+#include <errno.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#if !defined (__NetBSD__) && !defined (__OpenBSD__)
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <syms.h>
-
-static void fatal_unexec ();
-static void mark_x ();
+#ifndef __linux__
+# include <reloc.h>
+# include <elf_abi.h>
+#endif
+#else /* __NetBSD__ or __OpenBSD__ */
+/*
+ * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
+ * there's no desire to support ECOFF as the executable format in the
+ * long term.
+ */
+#include <sys/exec_ecoff.h>
+
+/* Structures, constants, etc., that NetBSD defines strangely. */
+#define filehdr ecoff_filehdr
+#define aouthdr ecoff_aouthdr
+#define scnhdr ecoff_scnhdr
+#define HDRR struct ecoff_symhdr
+#define pHDRR HDRR *
+#define cbHDRR sizeof(HDRR)
+#ifdef __OpenBSD__
+#define ALPHAMAGIC ECOFF_MAGIC_NATIVE_ALPHA
+#else
+#define ALPHAMAGIC ECOFF_MAGIC_NETBSD_ALPHA
+#endif
+#define ZMAGIC ECOFF_ZMAGIC
+
+/* Misc. constants that NetBSD doesn't define at all. */
+#define ALPHAUMAGIC 0617
+#define _MIPS_NSCNS_MAX 35
+#define STYP_TEXT 0x00000020
+#define STYP_DATA 0x00000040
+#define STYP_BSS 0x00000080
+#define STYP_RDATA 0x00000100
+#define STYP_SDATA 0x00000200
+#define STYP_SBSS 0x00000400
+#define STYP_INIT 0x80000000
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _INIT ".init"
+#define _RDATA ".rdata"
+#define _SDATA ".sdata"
+#define _SBSS ".sbss"
+#endif /* __NetBSD__ || __OpenBSD__ */
+
+static void fatal_unexec __P ((char *, char *));
+static void mark_x __P ((char *));
+
+static void update_dynamic_symbols __P ((char *, char *, int, struct aouthdr));
#define READ(_fd, _buffer, _size, _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();
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+void *sbrk ();
+#endif
#define EEOF -1
static struct scnhdr *text_section;
+static struct scnhdr *rel_dyn_section;
+static struct scnhdr *dynstr_section;
+static struct scnhdr *dynsym_section;
static struct scnhdr *init_section;
static struct scnhdr *finit_section;
static struct scnhdr *rdata_section;
static struct scnhdr *sbss_section;
static struct scnhdr *bss_section;
+static struct scnhdr old_data_scnhdr;
+
static unsigned long Brk;
struct headers {
#define DEFAULT_ENTRY_ADDRESS __start
#endif
\f
+void
unexec (new_name, a_name, data_start, bss_start, entry_address)
char *new_name, *a_name;
unsigned long data_start, bss_start, entry_address;
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));
+ nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout));
exit (1);
}
if (nhdr.aout.magic != ZMAGIC)
#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 (strncmp (nhdr.section[i].s_name, name, 8) == 0) \
{ \
if (nhdr.section[i].s_flags != flags) \
fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
CHECK_SCNHDR (text_section, _TEXT, STYP_TEXT);
CHECK_SCNHDR (init_section, _INIT, STYP_INIT);
+#ifdef _REL_DYN
+ CHECK_SCNHDR (rel_dyn_section, _REL_DYN, STYP_REL_DYN);
+#endif /* _REL_DYN */
+#ifdef _DYNSYM
+ CHECK_SCNHDR (dynsym_section, _DYNSYM, STYP_DYNSYM);
+#endif /* _REL_DYN */
+#ifdef _DYNSTR
+ CHECK_SCNHDR (dynstr_section, _DYNSTR, STYP_DYNSTR);
+#endif /* _REL_DYN */
#ifdef _FINI
CHECK_SCNHDR (finit_section, _FINI, STYP_FINI);
#endif /* _FINI */
#endif
#ifdef _PDATA
CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
-#endif _PDATA
+#endif /* _PDATA */
#ifdef _GOT
CHECK_SCNHDR (got_section, _GOT, STYP_GOT);
-#endif _GOT
+#endif /* _GOT */
CHECK_SCNHDR (data_section, _DATA, STYP_DATA);
#ifdef _XDATA
CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
Brk = brk;
+ bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
+
nhdr.aout.dsize = brk - DATA_START;
nhdr.aout.bsize = 0;
if (entry_address == 0)
#ifdef _GOT
if (got_section != NULL)
{
+ bcopy (got_section, buffer, sizeof (struct scnhdr));
+
got_section->s_vaddr = vaddr;
got_section->s_paddr = vaddr;
got_section->s_size = 0;
WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
"writing data section to %s", new_name);
+#ifdef _GOT
+#define old_got_section ((struct scnhdr *)buffer)
+
+ if (got_section != NULL)
+ {
+ SEEK (new, old_got_section->s_scnptr,
+ "seeking to start of got_section in %s", new_name);
+ WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
+ "writing new got_section of %s", new_name);
+ SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
+ "seeking to end of data section of %s", new_name);
+ }
+
+#undef old_got_section
+#endif
/*
* Construct new symbol table header
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_name, new, newsyms,
- ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->issExtMax,
- ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbExtOffset,
- ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbSsExtOffset);
-
+#ifdef _REL_DYN
+ if (rel_dyn_section)
+ update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
#endif
#undef symhdr
}
-#if 0
+static void
+update_dynamic_symbols (old, new_name, new, aout)
+ char *old; /* Pointer to old executable */
+ char *new_name; /* Name of new executable */
+ int new; /* File descriptor for new executable */
+ struct aouthdr aout; /* a.out info from the file header */
+{
+#if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
-/* Not needed for now */
+ typedef struct dynrel_info {
+ char * addr;
+ unsigned type:8;
+ unsigned index:24;
+ unsigned info:8;
+ unsigned pad:8;
+ } dr_info;
-/* The following function updates the values of some symbols
- that are used by the dynamic loader:
+ int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
+ int i;
+ dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
+ Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
- _edata
- _end
+ for (i = 0; i < nsyms; i++) {
+ register Elf32_Sym x;
-*/
+ if (rd_base[i].index == 0)
+ continue;
+ x = ds_base[rd_base[i].index];
-update_dynamic_symbols (old, new_name, new, newsyms, nsyms, symoff, stroff)
- char *old; /* Pointer to old executable */
- char *new_name; /* Name of new 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;
+#if 0
+ fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
+ old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
+#endif
- /* We go through the symbol table entries until we have found the two
- symbols. */
- /* cbEXTR is the size of an external symbol table entry */
+ if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
+ && (x.st_shndx == 0)
+ /* && (x.st_value == NULL) */
+ ) {
+ /* OK, this is probably a reference to an object in a shared
+ library, so copy the old value. This is done in several steps:
+ 1. reladdr is the address of the location in question relative to
+ the start of the data section,
+ 2. oldref is the addr is the mapped in temacs executable,
+ 3. newref is the address of the location in question in the
+ undumped executable,
+ 4. len is the size of the object reference in bytes --
+ currently only 4 (long) and 8 (quad) are supported.
+ */
+ register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr;
+ char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
+ unsigned long newref = aout.tsize + reladdr;
+ int len;
- 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);
- }
- }
+#if 0
+ fprintf (stderr, "...relocated\n");
+#endif
-}
+ if (rd_base[i].type == R_REFLONG)
+ len = 4;
+ else if (rd_base[i].type == R_REFQUAD)
+ len = 8;
+ else
+ fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i);
+
+ SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
+ WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
+ }
+#if 0
+ else
+ fprintf (stderr, "...not relocated\n");
#endif
+ }
+
+#endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
+}
+
\f
/*
* mark_x
fputs (".\n", stderr);
exit (1);
}
+
+/* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
+ (do not change this comment) */