X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/eb8c3be94e12644f506b8857e49ffef88046bb0b..8e6208c5d2c91d70f2338d1c3d788e194c6c9d52:/src/unexec.c diff --git a/src/unexec.c b/src/unexec.c index c07bc1a4be..6b6136bead 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, @@ -137,7 +137,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 +164,44 @@ 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_ENCAPSULATE int need_coff_header = 1; #include /* The location might be a poor assumption */ #else +#ifdef MSDOS +#include +#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 */ +}; + + +#else /* not MSDOS */ #include +#endif /* not MSDOS */ #endif -/* 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 +211,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 */ @@ -207,11 +241,22 @@ static long data_scnptr; #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)) @@ -277,6 +322,8 @@ static int pagemask; #ifdef emacs +#include "lisp.h" + static report_error (file, fd) char *file; @@ -284,7 +331,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 +370,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); } @@ -440,6 +487,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, 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)) { @@ -607,7 +655,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--) { @@ -675,7 +725,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 +790,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 @@ -836,7 +895,7 @@ copy_text_and_data (new, a_out) /* 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 +907,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; @@ -872,14 +1014,18 @@ write_segment (new, ptr, end) register int i, nwrite, ret; char buf[80]; extern int errno; - char zeros[128]; + /* 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 +1033,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 +1055,7 @@ write_segment (new, ptr, end) ptr, new, nwrite, ret, errno); PERROR (buf); } +#endif i += nwrite; ptr += nwrite; } @@ -1010,7 +1170,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 +1196,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 */