X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/3b7ad313e0d7b351c55cf999474b61cdc18ecad1..e07436e1c6334ccf39e383698f43a90b2895456d:/src/unexalpha.c diff --git a/src/unexalpha.c b/src/unexalpha.c index 2bbffde05a..9ffeee973b 100644 --- a/src/unexalpha.c +++ b/src/unexalpha.c @@ -1,6 +1,6 @@ /* 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. @@ -27,13 +27,64 @@ Boston, MA 02111-1307, USA. */ #include #include #include +#include +#ifdef HAVE_STRING_H +#include +#endif +#if !defined (__NetBSD__) && !defined (__OpenBSD__) #include #include #include #include - -static void fatal_unexec (); -static void mark_x (); +#ifndef __linux__ +# include +# include +#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 + +/* 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; \ @@ -49,14 +100,18 @@ static void mark_x (); 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 +#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; @@ -71,6 +126,8 @@ static struct scnhdr *sdata_section; static struct scnhdr *sbss_section; static struct scnhdr *bss_section; +static struct scnhdr old_data_scnhdr; + static unsigned long Brk; struct headers { @@ -87,6 +144,7 @@ struct headers { #define DEFAULT_ENTRY_ADDRESS __start #endif +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; @@ -140,7 +198,7 @@ unexec (new_name, a_name, 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) @@ -157,7 +215,7 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) #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", \ @@ -167,6 +225,15 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) 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 */ @@ -176,10 +243,10 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) #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); @@ -200,6 +267,8 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) 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) @@ -266,6 +335,8 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) #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; @@ -292,6 +363,21 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) 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 @@ -324,15 +410,9 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) 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 @@ -347,70 +427,86 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) } -#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)", 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__ */ +} + /* * mark_x