X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/1ba3de0010efb5fe36e28231c898892c7eba6ce5..a3b10252a6f892598638bec3c3ecb5537411c188:/src/unexec.c diff --git a/src/unexec.c b/src/unexec.c index bd6985a349..fb00c27e54 100644 --- a/src/unexec.c +++ b/src/unexec.c @@ -1,10 +1,10 @@ -/* 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, @@ -14,7 +14,8 @@ 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. */ +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* @@ -137,7 +138,7 @@ 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 @@ -164,24 +165,49 @@ pointer looks like an int) but not on all machines. #define PERROR(arg) perror (arg); return -1 #else #define IN_UNEXEC -#include "config.h" +#include #define PERROR(file) report_error (file, new) #endif #ifndef CANNOT_DUMP /* all rest of file! */ -#ifndef CANNOT_UNEXEC /* most of rest of file */ - +#ifdef COFF +#include +#ifdef MSDOS +#if __DJGPP__ > 1 +#include /* for O_RDONLY, O_RDWR */ +#include /* 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 /* The location might be a poor assumption */ -#else +#else /* not COFF_ENCAPSULATE */ #include -#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 */ @@ -191,6 +217,20 @@ int need_coff_header = 1; #include #include +#include /* Must be after sys/types.h for USG and BSD4_1*/ + +#ifdef USG5 +#include +#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 */ @@ -205,13 +245,26 @@ long lnnoptr; /* Pointer to line-number info within file */ 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)) @@ -235,7 +288,7 @@ static EXEC_HDR_TYPE hdr, ohdr; #else /* not HPUX */ -#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) +#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX) static struct bhdr hdr, ohdr; #define a_magic fmagic #define a_text tsize @@ -277,6 +330,8 @@ static int pagemask; #ifdef emacs +#include "lisp.h" + static report_error (file, fd) char *file; @@ -284,7 +339,7 @@ report_error (file, fd) { if (fd) close (fd); - error ("Failure operating on %s\n", file); + report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil)); } #endif /* emacs */ @@ -323,7 +378,7 @@ unexec (new_name, a_name, data_start, bss_start, entry_address) { int new, a_out = -1; - if (a_name && (a_out = open (a_name, 0)) < 0) + if (a_name && (a_out = open (a_name, O_RDONLY)) < 0) { PERROR (a_name); } @@ -423,9 +478,32 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) } #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); @@ -440,6 +518,7 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_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)) { @@ -603,11 +682,13 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) * .lib), adjust the address of where the section data is in the * file, and write out the header. * - * If any section preceeds .text or .data in the file, this code + * If any section precedes .text or .data in the file, this code * 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--) { @@ -675,7 +756,11 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) */ 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 } @@ -736,6 +821,11 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) PERROR (new_name); } +#if 0 /* This #ifndef caused a bug on 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 @@ -808,7 +898,7 @@ copy_text_and_data (new, a_out) { n = size > sizeof (page) ? sizeof (page) : size; if (read (a_out, page, n) != n || write (new, page, n) != n) - PERROR ("xemacs"); + PERROR ("emacs"); } lseek (a_out, old_a_out_ptr, 0); } @@ -816,6 +906,19 @@ copy_text_and_data (new, a_out) #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 @@ -830,13 +933,23 @@ copy_text_and_data (new, a_out) 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 @@ -848,9 +961,92 @@ copy_text_and_data (new, a_out) 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; @@ -871,15 +1067,21 @@ write_segment (new, ptr, end) { register int i, nwrite, ret; char buf[80]; +#ifndef USE_CRT_DLL extern int errno; - char zeros[128]; +#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); + bzero (zeros, sizeof (zeros)); for (i = 0; ptr < end;) { - /* distance to next multiple of 128. */ - nwrite = (((int) ptr + 128) & -128) - (int) ptr; + /* 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); @@ -887,8 +1089,21 @@ write_segment (new, ptr, end) 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); + 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, @@ -896,6 +1111,7 @@ write_segment (new, ptr, end) ptr, new, nwrite, ret, errno); PERROR (buf); } +#endif i += nwrite; ptr += nwrite; } @@ -924,10 +1140,12 @@ copy_sym (new, a_out, a_name, new_name) #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) { @@ -946,7 +1164,7 @@ copy_sym (new, a_out, a_name, new_name) /* **************************************************************** * mark_x * - * After succesfully building the new a.out, mark it executable + * After successfully building the new a.out, mark it executable */ static void mark_x (name) @@ -1010,7 +1228,11 @@ adjust_lnnoptrs (writedesc, readdesc, new_name) 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; @@ -1032,13 +1254,14 @@ adjust_lnnoptrs (writedesc, readdesc, new_name) } } } +#ifndef MSDOS close (new); +#endif + return 0; } #endif /* COFF_BSD_SYMBOLS */ #endif /* COFF */ -#endif /* not CANNOT_UNEXEC */ - #endif /* not CANNOT_DUMP */