X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/3a22ee3595841a85186c367d0cfdc09553ad22f8..a3b10252a6f892598638bec3c3ecb5537411c188:/src/unexec.c diff --git a/src/unexec.c b/src/unexec.c index 3cb2941be0..fb00c27e54 100644 --- a/src/unexec.c +++ b/src/unexec.c @@ -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 @@ -170,15 +171,14 @@ pointer looks like an int) but not on all machines. #ifndef CANNOT_DUMP /* all rest of file! */ -#ifndef CANNOT_UNEXEC /* most of rest of file */ - -#ifdef COFF_ENCAPSULATE -int need_coff_header = 1; -#include /* The location might be a poor assumption */ -#else +#ifdef COFF +#include #ifdef MSDOS -#include <../go32/gotypes.h> -#include <../go32/ed/coff.h> +#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 @@ -187,25 +187,27 @@ int need_coff_header = 1; #define n_type e_type struct aouthdr { - word16 magic; /* type of file */ - word16 vstamp; /* version stamp */ - word32 tsize; /* text size in bytes, padded to FW bdry*/ - word32 dsize; /* initialized data " " */ - word32 bsize; /* uninitialized data " " */ - word32 entry; /* entry pt. */ - word32 text_start; /* base of text used for this file */ - word32 data_start; /* base of data used for this file */ + 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 */ }; - - -#else /* not MSDOS */ -#include #endif /* not MSDOS */ -#endif +#else /* not COFF */ +#ifdef COFF_ENCAPSULATE +int need_coff_header = 1; +#include /* The location might be a poor assumption */ +#else /* not COFF_ENCAPSULATE */ +#include +#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 */ @@ -215,6 +217,20 @@ struct aouthdr #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 */ @@ -229,6 +245,8 @@ 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 @@ -312,6 +330,8 @@ static int pagemask; #ifdef emacs +#include "lisp.h" + static report_error (file, fd) char *file; @@ -319,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 */ @@ -358,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); } @@ -458,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); @@ -475,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)) { @@ -642,7 +686,9 @@ make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) * 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--) { @@ -775,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 @@ -855,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 @@ -869,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 @@ -887,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; @@ -910,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); @@ -931,7 +1094,16 @@ write_segment (new, ptr, end) && errno == EFAULT #endif ) - write (new, zeros, nwrite); + { + /* 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, @@ -939,6 +1111,7 @@ write_segment (new, ptr, end) ptr, new, nwrite, ret, errno); PERROR (buf); } +#endif i += nwrite; ptr += nwrite; } @@ -967,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) { @@ -1056,7 +1231,7 @@ adjust_lnnoptrs (writedesc, readdesc, new_name) #ifdef MSDOS if ((new = writedesc) < 0) #else - if ((new = open (new_name, 2)) < 0) + if ((new = open (new_name, O_RDWR)) < 0) #endif { PERROR (new_name); @@ -1089,6 +1264,4 @@ adjust_lnnoptrs (writedesc, readdesc, new_name) #endif /* COFF */ -#endif /* not CANNOT_UNEXEC */ - #endif /* not CANNOT_DUMP */