Mercurial > hg > xemacs-beta
diff src/unexaix.c @ 286:57709be46d1b r21-0b41
Import from CVS: tag r21-0b41
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:35:03 +0200 |
parents | c42ec1d1cded |
children | 4b85ae5eabfb |
line wrap: on
line diff
--- a/src/unexaix.c Mon Aug 13 10:34:15 2007 +0200 +++ b/src/unexaix.c Mon Aug 13 10:35:03 2007 +0200 @@ -1,4 +1,5 @@ -/* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. +/* Dump an executable image. + Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. This file is part of XEmacs. @@ -17,26 +18,14 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* Synched up with: FSF 19.31. */ +/* Synched up with: FSF 20.2. */ -/* Modified by Andrew.Vignaux@comp.vuw.ac.nz to get it to work :-) */ - -/* - * unexec.c - Convert a running program into an a.out file. +/* Originally based on the COFF unexec.c by Spencer W. Thomas. * - * Author: Spencer W. Thomas - * Computer Science Dept. - * University of Utah - * Date: Tue Mar 2 1982 - * Modified heavily since then. - * - * Updated for AIX 4.1.3 by Bill_Mann @ PraxisInt.com, Feb 1996 - * As of AIX 4.1, text, data, and bss are pre-relocated by the binder in - * such a way that the file can be mapped with code in one segment and - * data/bss in another segment, without reading or copying the file, by - * the AIX exec loader. Padding sections are omitted, nevertheless - * small amounts of 'padding' still occurs between sections in the file. - * As modified, this code handles both 3.2 and 4.1 conventions. + * Subsequently hacked on by + * Bill Mann <Bill_Man@praxisint.com> + * Andrew Vignaux <Andrew.Vignaux@comp.vuw.ac.nz> + * Mike Sperber <sperber@informatik.uni-tuebingen.de> * * Synopsis: * unexec (new_name, a_name, data_start, bss_start, entry_address) @@ -48,123 +37,17 @@ * If a_name is non-NULL, the symbol table will be taken from the given file. * On some machines, an existing a_name file is required. * - * The boundaries within the a.out file may be adjusted with the data_start - * and bss_start arguments. Either or both may be given as 0 for defaults. + * data_start and entry_address are ignored. * - * Data_start gives the boundary between the text segment and the data - * segment of the program. The text segment can contain shared, read-only - * program code and literal data, while the data segment is always unshared - * and unprotected. Data_start gives the lowest unprotected address. - * The value you specify may be rounded down to a suitable boundary - * as required by the machine you are using. - * - * Specifying zero for data_start means the boundary between text and data - * should not be the same as when the program was loaded. - * If NO_REMAP is defined, the argument data_start is ignored and the - * segment boundaries are never changed. - * - * Bss_start indicates how much of the data segment is to be saved in the + * bss_start indicates how much of the data segment is to be saved in the * a.out file and restored when the program is executed. It gives the lowest * unsaved address, and is rounded up to a page boundary. The default when 0 * is given assumes that the entire data segment is to be stored, including * the previous data and bss as well as any additional storage allocated with - * break (2). - * - * The new file is set up to start at entry_address. - * - * If you make improvements I'd like to get them too. - * harpo!utah-cs!thomas, thomas@Utah-20 + * sbrk(2). * */ -/* There are several compilation parameters affecting unexec: - -* COFF - -Define this if your system uses COFF for executables. -Otherwise we assume you use Berkeley format. - -* NO_REMAP - -Define this if you do not want to try to save Emacs's pure data areas -as part of the text segment. - -Saving them as text is good because it allows users to share more. - -However, on machines that locate the text area far from the data area, -the boundary cannot feasibly be moved. Such machines require -NO_REMAP. - -Also, remapping can cause trouble with the built-in startup routine -/lib/crt0.o, which defines `environ' as an initialized variable. -Dumping `environ' as pure does not work! So, to use remapping, -you must write a startup routine for your machine in Emacs's crt0.c. -If NO_REMAP is defined, Emacs uses the system's crt0.o. - -* SECTION_ALIGNMENT - -Some machines that use COFF executables require that each section -start on a certain boundary *in the COFF file*. Such machines should -define SECTION_ALIGNMENT to a mask of the low-order bits that must be -zero on such a boundary. This mask is used to control padding between -segments in the COFF file. - -If SECTION_ALIGNMENT is not defined, the segments are written -consecutively with no attempt at alignment. This is right for -unmodified system V. - -* SEGMENT_MASK - -Some machines require that the beginnings and ends of segments -*in core* be on certain boundaries. For most machines, a page -boundary is sufficient. That is the default. When a larger -boundary is needed, define SEGMENT_MASK to a mask of -the bits that must be zero on such a boundary. - -* A_TEXT_OFFSET(HDR) - -Some machines count the a.out header as part of the size of the text -segment (a_text); they may actually load the header into core as the -first data in the text segment. Some have additional padding between -the header and the real text of the program that is counted in a_text. - -For these machines, define A_TEXT_OFFSET(HDR) to examine the header -structure HDR and return the number of bytes to add to `a_text' -before writing it (above and beyond the number of bytes of actual -program text). HDR's standard fields are already correct, except that -this adjustment to the `a_text' field has not yet been made; -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 - -* EXEC_MAGIC - -For machines using COFF, this macro, if defined, is a value stored -into the magic number field of the output file. - -* ADJUST_EXEC_HEADER - -This macro can be used to generate statements to adjust or -initialize nonstandard fields in the file header - -* ADDR_CORRECT(ADDR) - -Macro to correct an int which is the bit pattern of a pointer to a byte -into an int which is the number of a byte. - -This macro has a default definition which is usually right. -This default definition is a no-op on most machines (where a -pointer looks like an int) but not on all machines. - -*/ - -#define XCOFF -#define COFF -#define NO_REMAP - #ifndef emacs #define PERROR(arg) perror (arg); return -1 #else @@ -178,58 +61,42 @@ */ #include "getpagesize.h" -#ifndef makedev /* Try to detect types.h already loaded */ #include <sys/types.h> -#endif #include <stdio.h> #include <sys/stat.h> #include <errno.h> +#include <unistd.h> +#include <fcntl.h> extern char *start_of_text (void); /* Start of text */ extern char *start_of_data (void); /* Start of initialized data */ extern int _data; -extern int _edata; extern int _text; -extern int _etext; -extern int _end; -#ifdef COFF -#ifndef USG -#ifndef STRIDE -#ifndef UMAX -#ifndef sun386 -/* I have a suspicion that these are turned off on all systems - and can be deleted. Try it in version 19. */ + #include <filehdr.h> #include <aouthdr.h> #include <scnhdr.h> #include <syms.h> -#endif /* not sun386 */ -#endif /* not UMAX */ -#endif /* Not STRIDE */ -#endif /* not USG */ + static struct filehdr f_hdr; /* File header */ static struct aouthdr f_ohdr; /* Optional file header (a.out) */ -long bias; /* Bias to add for growth */ -long lnnoptr; /* Pointer to line-number info within file */ +static long bias; /* Bias to add for growth */ +static long lnnoptr; /* Pointer to line-number info within file */ static long text_scnptr; static long data_scnptr; -#ifdef XCOFF #define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1)) static long load_scnptr; static long orig_load_scnptr; static long orig_data_scnptr; -static unrelocate_symbols (int, int, char *, char *); -#endif -static ulong data_st; /* start of data area written out */ +static int unrelocate_symbols (int, int, char *, char *); #ifndef MAX_SECTIONS #define MAX_SECTIONS 10 #endif -static adjust_lnnoptrs (int, int, char *); -#endif /* COFF */ +static int adjust_lnnoptrs (int, int, char *); static int pagemask; @@ -244,7 +111,7 @@ #ifdef emacs #include "lisp.h" -static +static void report_error (char *file, int fd) { if (fd) @@ -257,7 +124,7 @@ #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1 #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1 -static +static void report_error_1 (int fd, char *msg, int a1, int a2) { close (fd); @@ -273,7 +140,7 @@ static void mark_x (char *); static int copy_text_and_data (int); static int copy_sym (int, int, char *, char *); -static write_segment (int, char *, char *); +static void write_segment (int, char *, char *); /* **************************************************************** * unexec @@ -281,11 +148,11 @@ * driving logic. */ int unexec (char *new_name, char *a_name, - uintptr_t data_start, - uintptr_t bss_start, - uintptr_t entry_address) + uintptr_t data_start, + uintptr_t bss_start, + uintptr_t entry_address) { - int new, a_out = -1; + int new = -1, a_out = -1; if (a_name && (a_out = open (a_name, 0)) < 0) { @@ -295,19 +162,16 @@ { PERROR (new_name); } - if (make_hdr (new,a_out,data_start,bss_start,entry_address,a_name,new_name) < 0 + if (make_hdr (new, a_out, + data_start, bss_start, + entry_address, + a_name, new_name) < 0 || copy_text_and_data (new) < 0 || copy_sym (new, a_out, a_name, new_name) < 0 -#ifdef COFF || adjust_lnnoptrs (new, a_out, new_name) < 0 -#endif -#ifdef XCOFF - || unrelocate_symbols (new, a_out, a_name, new_name) < 0 -#endif - ) + || unrelocate_symbols (new, a_out, a_name, new_name) < 0) { close (new); - /* unlink (new_name); */ /* Failed, unlink new a.out */ return -1; } @@ -325,7 +189,10 @@ * Modify the text and data sizes. */ static int -make_hdr (int new, int a_out, unsigned data_start, unsigned bss_start, unsigned entry_address, char *a_name, char *new_name) +make_hdr (int new, int a_out, + unsigned data_start, unsigned bss_start, + unsigned entry_address, + char *a_name, char *new_name) { int scns; unsigned int bss_end; @@ -343,17 +210,10 @@ pagemask = getpagesize () - 1; /* Adjust text/data boundary. */ -#ifdef NO_REMAP data_start = (long) start_of_data (); -#endif /* NO_REMAP */ data_start = ADDR_CORRECT (data_start); -#ifdef SEGMENT_MASK - data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */ -#else data_start = data_start & ~pagemask; /* (Down) to page boundary. */ -#endif - bss_end = ADDR_CORRECT (sbrk (0)) + pagemask; bss_end &= ~ pagemask; @@ -378,7 +238,6 @@ data_start, bss_start); } -#ifdef COFF /* Salvage as much info from the existing file as possible */ f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL; f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL; @@ -455,15 +314,7 @@ we only update it enough to fake out the exec-time loader. */ f_hdr.f_flags |= (F_RELFLG | F_EXEC); -#ifdef EXEC_MAGIC - f_ohdr.magic = EXEC_MAGIC; -#endif -#ifndef NO_REMAP - f_ohdr.tsize = data_start - f_ohdr.text_start; - f_ohdr.text_start = (long) start_of_text (); -#endif - data_st = f_ohdr.data_start ? f_ohdr.data_start : (ulong) &_data; - f_ohdr.dsize = bss_start - data_st; + f_ohdr.dsize = bss_start - f_ohdr.data_start; f_ohdr.bsize = bss_end - bss_start; f_dhdr->s_size = f_ohdr.dsize; @@ -475,7 +326,6 @@ { ulong ptr = section[0].s_scnptr; - bias = -1; for (scns = 0; scns < f_hdr.f_nscns; scns++) { struct scnhdr *s = §ion[scns]; @@ -494,17 +344,12 @@ } s->s_scnptr = ptr; } - else if (s->s_flags & STYP_DATA) - s->s_scnptr = ptr; - else if (!(s->s_flags & (STYP_TEXT | STYP_BSS))) + else { - if (bias == -1) /* if first section after bss */ bias = ptr - s->s_scnptr; + s->s_scnptr = ptr; + } - s->s_scnptr += bias; - ptr = s->s_scnptr; - } - ptr = ptr + s->s_size; } } @@ -534,10 +379,6 @@ data_scnptr = f_dhdr->s_scnptr; load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; -#ifdef ADJUST_EXEC_HEADER - ADJUST_EXEC_HEADER -#endif /* ADJUST_EXEC_HEADER */ - if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) { PERROR (new_name); @@ -560,8 +401,6 @@ } return (0); - -#endif /* COFF */ } /* **************************************************************** @@ -575,13 +414,13 @@ char *end; char *ptr; - lseek (new, (long) text_scnptr, 0); + lseek (new, (long) text_scnptr, SEEK_SET); ptr = start_of_text () + text_scnptr; end = ptr + f_ohdr.tsize; write_segment (new, ptr, end); - lseek (new, (long) data_scnptr, 0); - ptr = (char *) data_st; + lseek (new, (long) data_scnptr, SEEK_SET); + ptr = (char *) f_ohdr.data_start; end = ptr + f_ohdr.dsize; write_segment (new, ptr, end); @@ -589,6 +428,7 @@ } #define UnexBlockSz (1<<12) /* read/write block size */ +static void write_segment (int new, char *ptr, char *end) { int i, nwrite, ret; @@ -642,9 +482,9 @@ return 0; if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info */ - lseek (a_out, lnnoptr, 0); /* start copying from there */ + lseek (a_out, lnnoptr, SEEK_SET); /* start copying from there */ else - lseek (a_out, orig_load_scnptr, 0); /* Position a.out to symtab. */ + lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */ while ((n = read (a_out, page, sizeof page)) > 0) { @@ -683,44 +523,14 @@ PERROR (name); } -/* - * If the COFF file contains a symbol table and a line number section, - * then any auxiliary entries that have values for x_lnnoptr must - * be adjusted by the amount that the line number section has moved - * in the file (bias computed in make_hdr). The #@$%&* designers of - * the auxiliary entry structures used the absolute file offsets for - * the line number entry rather than an offset from the start of the - * line number section! - * - * When I figure out how to scan through the symbol table and pick out - * the auxiliary entries that need adjustment, this routine will - * be fixed. As it is now, all such entries are wrong and sdb - * will complain. Fred Fish, UniSoft Systems Inc. - * - * I believe this is now fixed correctly. Bill Mann - */ - -#ifdef COFF - -/* This function is probably very slow. Instead of reopening the new - file for input and output it should copy from the old to the new - using the two descriptors already open (WRITEDESC and READDESC). - Instead of reading one small structure at a time it should use - a reasonable size buffer. But I don't have time to work on such - things, so I am installing it as submitted to me. -- RMS. */ - +static int adjust_lnnoptrs (int writedesc, int readdesc, char *new_name) { int nsyms; int naux; int new; -#ifdef amdahl_uts - SYMENT symentry; - AUXENT auxentry; -#else struct syment symentry; union auxent auxentry; -#endif if (!lnnoptr || !f_hdr.f_symptr) return 0; @@ -731,14 +541,14 @@ return -1; } - lseek (new, f_hdr.f_symptr, 0); + lseek (new, f_hdr.f_symptr, SEEK_SET); for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) { read (new, &symentry, SYMESZ); if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL) { symentry.n_value += bias; - lseek (new, -SYMESZ, 1); + lseek (new, -SYMESZ, SEEK_CUR); write (new, &symentry, SYMESZ); } @@ -750,37 +560,36 @@ && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT)) { auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; - lseek (new, -AUXESZ, 1); + lseek (new, -AUXESZ, SEEK_CUR); write (new, &auxentry, AUXESZ); } } } close (new); + + return 0; } -#endif /* COFF */ - -#ifdef XCOFF - -/* It is probably a false economy to optimise this routine (it used to - read one LDREL and do do two lseeks per iteration) but the wrath of - RMS (see above :-) would be too much to bear */ - +static int unrelocate_symbols (int new, int a_out, char *a_name, char *new_name) { int i; - int l; - LDREL *ldrel; LDHDR ldhdr; - LDREL ldrel_buf [20]; + LDREL ldrel; ulong t_reloc = (ulong) &_text - f_ohdr.text_start; +#ifndef ALIGN_DATA_RELOC + ulong d_reloc = (ulong) &_data - f_ohdr.data_start; +#else + /* This worked (and was needed) before AIX 4.2. + I have no idea why. -- Mike */ ulong d_reloc = (ulong) &_data - ALIGN(f_ohdr.data_start, 2); +#endif int * p; if (load_scnptr == 0) return 0; - lseek (a_out, orig_load_scnptr, 0); + lseek (a_out, orig_load_scnptr, SEEK_SET); if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr)) { PERROR (new_name); @@ -789,46 +598,40 @@ #define SYMNDX_TEXT 0 #define SYMNDX_DATA 1 #define SYMNDX_BSS 2 - l = 0; - for (i = 0; i < ldhdr.l_nreloc; i++, l--, ldrel++) - { - if (l == 0) { - lseek (a_out, - orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, - 0); - l = ldhdr.l_nreloc - i; - if (l > sizeof (ldrel_buf) / LDRELSZ) - l = sizeof (ldrel_buf) / LDRELSZ; + for (i = 0; i < ldhdr.l_nreloc; i++) + { + lseek (a_out, + orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, + SEEK_SET); - if (read (a_out, ldrel_buf, l * LDRELSZ) != l * LDRELSZ) - { - PERROR (a_name); - } - ldrel = ldrel_buf; - } + if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ) + { + PERROR (a_name); + } /* move the BSS loader symbols to the DATA segment */ - if (ldrel->l_symndx == SYMNDX_BSS) + if (ldrel.l_symndx == SYMNDX_BSS) { - ldrel->l_symndx = SYMNDX_DATA; + ldrel.l_symndx = SYMNDX_DATA; lseek (new, load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, - 0); + SEEK_SET); - if (write (new, ldrel, LDRELSZ) != LDRELSZ) + if (write (new, &ldrel, LDRELSZ) != LDRELSZ) { PERROR (new_name); } } - if (ldrel->l_rsecnm == f_ohdr.o_sndata) + if (ldrel.l_rsecnm == f_ohdr.o_sndata) { int orig_int; lseek (a_out, - orig_data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0); + orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start), + SEEK_SET); if (read (a_out, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int)) @@ -836,9 +639,9 @@ PERROR (a_name); } - p = (int *) (ldrel->l_vaddr + d_reloc); + p = (int *) (ldrel.l_vaddr + d_reloc); - switch (ldrel->l_symndx) { + switch (ldrel.l_symndx) { case SYMNDX_TEXT: orig_int = * p - t_reloc; break; @@ -852,7 +655,8 @@ if (orig_int != * p) { lseek (new, - data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0); + data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start), + SEEK_SET); if (write (new, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int)) { @@ -861,5 +665,5 @@ } } } + return 0; } -#endif /* XCOFF */