160251Shibler /* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
260251Shibler 
360251Shibler     This program is free software; you can redistribute it and/or modify
460251Shibler     it under the terms of the GNU General Public License as published by
560251Shibler     the Free Software Foundation; either version 1, or (at your option)
660251Shibler     any later version.
760251Shibler 
860251Shibler     This program is distributed in the hope that it will be useful,
960251Shibler     but WITHOUT ANY WARRANTY; without even the implied warranty of
1060251Shibler     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1160251Shibler     GNU General Public License for more details.
1260251Shibler 
1360251Shibler     You should have received a copy of the GNU General Public License
1460251Shibler     along with this program; if not, write to the Free Software
1560251Shibler     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1660251Shibler 
1760251Shibler In other words, you are welcome to use, share and improve this program.
1860251Shibler You are forbidden to forbid anyone else to use, share and improve
1960251Shibler what you give them.   Help stamp out software-hoarding!  */
2060251Shibler 
2160251Shibler 
2260251Shibler /*
2360251Shibler  * unexec.c - Convert a running program into an a.out file.
2460251Shibler  *
2560251Shibler  * Author:	Spencer W. Thomas
2660251Shibler  * 		Computer Science Dept.
2760251Shibler  * 		University of Utah
2860251Shibler  * Date:	Tue Mar  2 1982
2960251Shibler  * Modified heavily since then.
3060251Shibler  *
3160251Shibler  * Synopsis:
3260251Shibler  *	unexec (new_name, a_name, data_start, bss_start, entry_address)
3360251Shibler  *	char *new_name, *a_name;
3460251Shibler  *	unsigned data_start, bss_start, entry_address;
3560251Shibler  *
3660251Shibler  * Takes a snapshot of the program and makes an a.out format file in the
3760251Shibler  * file named by the string argument new_name.
3860251Shibler  * If a_name is non-NULL, the symbol table will be taken from the given file.
3960251Shibler  * On some machines, an existing a_name file is required.
4060251Shibler  *
4160251Shibler  * The boundaries within the a.out file may be adjusted with the data_start
4260251Shibler  * and bss_start arguments.  Either or both may be given as 0 for defaults.
4360251Shibler  *
4460251Shibler  * Data_start gives the boundary between the text segment and the data
4560251Shibler  * segment of the program.  The text segment can contain shared, read-only
4660251Shibler  * program code and literal data, while the data segment is always unshared
4760251Shibler  * and unprotected.  Data_start gives the lowest unprotected address.
4860251Shibler  * The value you specify may be rounded down to a suitable boundary
4960251Shibler  * as required by the machine you are using.
5060251Shibler  *
5160251Shibler  * Specifying zero for data_start means the boundary between text and data
5260251Shibler  * should not be the same as when the program was loaded.
5360251Shibler  * If NO_REMAP is defined, the argument data_start is ignored and the
5460251Shibler  * segment boundaries are never changed.
5560251Shibler  *
5660251Shibler  * Bss_start indicates how much of the data segment is to be saved in the
5760251Shibler  * a.out file and restored when the program is executed.  It gives the lowest
5860251Shibler  * unsaved address, and is rounded up to a page boundary.  The default when 0
5960251Shibler  * is given assumes that the entire data segment is to be stored, including
6060251Shibler  * the previous data and bss as well as any additional storage allocated with
6160251Shibler  * break (2).
6260251Shibler  *
6360251Shibler  * The new file is set up to start at entry_address.
6460251Shibler  *
6560251Shibler  * If you make improvements I'd like to get them too.
6660251Shibler  * harpo!utah-cs!thomas, thomas@Utah-20
6760251Shibler  *
6860251Shibler  */
6960251Shibler 
7060251Shibler /* Modified to support SysVr3 shared libraries by James Van Artsdalen
7160251Shibler  * of Dell Computer Corporation.  james@bigtex.cactus.org.
7260251Shibler  */
7360251Shibler 
7460251Shibler /* There are several compilation parameters affecting unexec:
7560251Shibler 
7660251Shibler * COFF
7760251Shibler 
7860251Shibler Define this if your system uses COFF for executables.
7960251Shibler Otherwise we assume you use Berkeley format.
8060251Shibler 
8160251Shibler * NO_REMAP
8260251Shibler 
8360251Shibler Define this if you do not want to try to save Emacs's pure data areas
8460251Shibler as part of the text segment.
8560251Shibler 
8660251Shibler Saving them as text is good because it allows users to share more.
8760251Shibler 
8860251Shibler However, on machines that locate the text area far from the data area,
8960251Shibler the boundary cannot feasibly be moved.  Such machines require
9060251Shibler NO_REMAP.
9160251Shibler 
9260251Shibler Also, remapping can cause trouble with the built-in startup routine
9360251Shibler /lib/crt0.o, which defines `environ' as an initialized variable.
9460251Shibler Dumping `environ' as pure does not work!  So, to use remapping,
9560251Shibler you must write a startup routine for your machine in Emacs's crt0.c.
9660251Shibler If NO_REMAP is defined, Emacs uses the system's crt0.o.
9760251Shibler 
9860251Shibler * SECTION_ALIGNMENT
9960251Shibler 
10060251Shibler Some machines that use COFF executables require that each section
10160251Shibler start on a certain boundary *in the COFF file*.  Such machines should
10260251Shibler define SECTION_ALIGNMENT to a mask of the low-order bits that must be
10360251Shibler zero on such a boundary.  This mask is used to control padding between
10460251Shibler segments in the COFF file.
10560251Shibler 
10660251Shibler If SECTION_ALIGNMENT is not defined, the segments are written
10760251Shibler consecutively with no attempt at alignment.  This is right for
10860251Shibler unmodified system V.
10960251Shibler 
11060251Shibler * SEGMENT_MASK
11160251Shibler 
11260251Shibler Some machines require that the beginnings and ends of segments
11360251Shibler *in core* be on certain boundaries.  For most machines, a page
11460251Shibler boundary is sufficient.  That is the default.  When a larger
11560251Shibler boundary is needed, define SEGMENT_MASK to a mask of
11660251Shibler the bits that must be zero on such a boundary.
11760251Shibler 
11860251Shibler * A_TEXT_OFFSET(HDR)
11960251Shibler 
12060251Shibler Some machines count the a.out header as part of the size of the text
12160251Shibler segment (a_text); they may actually load the header into core as the
12260251Shibler first data in the text segment.  Some have additional padding between
12360251Shibler the header and the real text of the program that is counted in a_text.
12460251Shibler 
12560251Shibler For these machines, define A_TEXT_OFFSET(HDR) to examine the header
12660251Shibler structure HDR and return the number of bytes to add to `a_text'
12760251Shibler before writing it (above and beyond the number of bytes of actual
12860251Shibler program text).  HDR's standard fields are already correct, except that
12960251Shibler this adjustment to the `a_text' field has not yet been made;
13060251Shibler thus, the amount of offset can depend on the data in the file.
13160251Shibler 
13260251Shibler * A_TEXT_SEEK(HDR)
13360251Shibler 
13460251Shibler If defined, this macro specifies the number of bytes to seek into the
13560251Shibler a.out file before starting to write the text segment.a
13660251Shibler 
13760251Shibler * EXEC_MAGIC
13860251Shibler 
13960251Shibler For machines using COFF, this macro, if defined, is a value stored
14060251Shibler into the magic number field of the output file.
14160251Shibler 
14260251Shibler * ADJUST_EXEC_HEADER
14360251Shibler 
14460251Shibler This macro can be used to generate statements to adjust or
14560251Shibler initialize nonstandard fields in the file header
14660251Shibler 
14760251Shibler * ADDR_CORRECT(ADDR)
14860251Shibler 
14960251Shibler Macro to correct an int which is the bit pattern of a pointer to a byte
15060251Shibler into an int which is the number of a byte.
15160251Shibler 
15260251Shibler This macro has a default definition which is usually right.
15360251Shibler This default definition is a no-op on most machines (where a
15460251Shibler pointer looks like an int) but not on all machines.
15560251Shibler 
15660251Shibler */
15760251Shibler 
15860251Shibler #ifndef emacs
15960251Shibler #define PERROR(arg) perror (arg); return -1
16060251Shibler #else
16160251Shibler #include "config.h"
16260251Shibler #define PERROR(file) report_error (file, new)
16360251Shibler #endif
16460251Shibler 
16560251Shibler #ifndef CANNOT_DUMP  /* all rest of file!  */
16660251Shibler 
16760251Shibler #ifndef CANNOT_UNEXEC /* most of rest of file */
16860251Shibler 
16960251Shibler #include <a.out.h>
17060251Shibler /* Define getpagesize () if the system does not.
17160251Shibler    Note that this may depend on symbols defined in a.out.h
17260251Shibler  */
17360251Shibler #include "getpagesize.h"
17460251Shibler 
17560251Shibler #ifndef makedev			/* Try to detect types.h already loaded */
17660251Shibler #include <sys/types.h>
17760251Shibler #endif
17860251Shibler #include <stdio.h>
17960251Shibler #include <sys/stat.h>
18060251Shibler #include <errno.h>
18160251Shibler 
18260251Shibler extern char *start_of_text ();		/* Start of text */
18360251Shibler extern char *start_of_data ();		/* Start of initialized data */
18460251Shibler 
18560251Shibler #ifdef COFF
18660251Shibler #ifndef USG
18760251Shibler #ifndef STRIDE
18860251Shibler #ifndef UMAX
18960251Shibler #ifndef sun386
19060251Shibler /* I have a suspicion that these are turned off on all systems
19160251Shibler    and can be deleted.  Try it in version 19.  */
19260251Shibler #include <filehdr.h>
19360251Shibler #include <aouthdr.h>
19460251Shibler #include <scnhdr.h>
19560251Shibler #include <syms.h>
19660251Shibler #endif /* not sun386 */
19760251Shibler #endif /* not UMAX */
19860251Shibler #endif /* Not STRIDE */
19960251Shibler #endif /* not USG */
20060251Shibler static long block_copy_start;		/* Old executable start point */
20160251Shibler static struct filehdr f_hdr;		/* File header */
20260251Shibler static struct aouthdr f_ohdr;		/* Optional file header (a.out) */
20360251Shibler long bias;			/* Bias to add for growth */
20460251Shibler long lnnoptr;			/* Pointer to line-number info within file */
20560251Shibler #define SYMS_START block_copy_start
20660251Shibler 
20760251Shibler static long text_scnptr;
20860251Shibler static long data_scnptr;
20960251Shibler 
21060251Shibler #else /* not COFF */
21160251Shibler 
21260251Shibler extern char *sbrk ();
21360251Shibler 
21460251Shibler #define SYMS_START ((long) N_SYMOFF (ohdr))
21560251Shibler 
21660251Shibler /* Some machines override the structure name for an a.out header.  */
21760251Shibler #ifndef EXEC_HDR_TYPE
21860251Shibler #define EXEC_HDR_TYPE struct exec
21960251Shibler #endif
22060251Shibler 
22160251Shibler #ifdef HPUX
22260251Shibler #ifdef HP9000S200_ID
22360251Shibler #define MY_ID HP9000S200_ID
22460251Shibler #else
22560251Shibler #include <model.h>
22660251Shibler #define MY_ID MYSYS
22760251Shibler #endif /* no HP9000S200_ID */
22860251Shibler static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};
22960251Shibler static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};
23060251Shibler #define N_TXTOFF(x) TEXT_OFFSET(x)
23160251Shibler #define N_SYMOFF(x) LESYM_OFFSET(x)
23260251Shibler static EXEC_HDR_TYPE hdr, ohdr;
23360251Shibler 
23460251Shibler #else /* not HPUX */
23560251Shibler 
23660251Shibler #if defined (USG) && !defined (IBMRTAIX) && !defined (IRIS)
23760251Shibler static struct bhdr hdr, ohdr;
23860251Shibler #define a_magic fmagic
23960251Shibler #define a_text tsize
24060251Shibler #define a_data dsize
24160251Shibler #define a_bss bsize
24260251Shibler #define a_syms ssize
24360251Shibler #define a_trsize rtsize
24460251Shibler #define a_drsize rdsize
24560251Shibler #define a_entry entry
24660251Shibler #define	N_BADMAG(x) \
24760251Shibler     (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\
24860251Shibler      ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC)
24960251Shibler #define NEWMAGIC FMAGIC
25060251Shibler #else /* IRIS or IBMRTAIX or not USG */
25160251Shibler static EXEC_HDR_TYPE hdr, ohdr;
25260251Shibler #define NEWMAGIC ZMAGIC
25360251Shibler #endif /* IRIS or IBMRTAIX not USG */
25460251Shibler #endif /* not HPUX */
25560251Shibler 
25660251Shibler static int unexec_text_start;
25760251Shibler static int unexec_data_start;
25860251Shibler 
25960251Shibler #endif /* not COFF */
26060251Shibler 
26160251Shibler static int pagemask;
26260251Shibler 
26360251Shibler /* Correct an int which is the bit pattern of a pointer to a byte
26460251Shibler    into an int which is the number of a byte.
26560251Shibler    This is a no-op on ordinary machines, but not on all.  */
26660251Shibler 
26760251Shibler #ifndef ADDR_CORRECT   /* Let m-*.h files override this definition */
26860251Shibler #define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
26960251Shibler #endif
27060251Shibler 
27160251Shibler #ifdef emacs
27260251Shibler 
27360251Shibler static
report_error(file,fd)27460251Shibler report_error (file, fd)
27560251Shibler      char *file;
27660251Shibler      int fd;
27760251Shibler {
27860251Shibler   if (fd)
27960251Shibler     close (fd);
28060251Shibler   error ("Failure operating on %s", file);
28160251Shibler }
28260251Shibler #endif /* emacs */
28360251Shibler 
28460251Shibler #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
28560251Shibler #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
28660251Shibler #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
28760251Shibler 
28860251Shibler static
report_error_1(fd,msg,a1,a2)28960251Shibler report_error_1 (fd, msg, a1, a2)
29060251Shibler      int fd;
29160251Shibler      char *msg;
29260251Shibler      int a1, a2;
29360251Shibler {
29460251Shibler   close (fd);
29560251Shibler #ifdef emacs
29660251Shibler   error (msg, a1, a2);
29760251Shibler #else
29860251Shibler   fprintf (stderr, msg, a1, a2);
29960251Shibler   fprintf (stderr, "\n");
30060251Shibler #endif
30160251Shibler }
30260251Shibler 
30360251Shibler /* ****************************************************************
30460251Shibler  * unexec
30560251Shibler  *
30660251Shibler  * driving logic.
30760251Shibler  */
unexec(new_name,a_name,data_start,bss_start,entry_address)30860251Shibler unexec (new_name, a_name, data_start, bss_start, entry_address)
30960251Shibler      char *new_name, *a_name;
31060251Shibler      unsigned data_start, bss_start, entry_address;
31160251Shibler {
31260251Shibler   int new, a_out = -1;
31360251Shibler 
31460251Shibler   if (a_name && (a_out = open (a_name, 0)) < 0)
31560251Shibler     {
31660251Shibler       PERROR (a_name);
31760251Shibler     }
31860251Shibler   if ((new = creat (new_name, 0666)) < 0)
31960251Shibler     {
32060251Shibler       PERROR (new_name);
32160251Shibler     }
32260251Shibler 
32360251Shibler   if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
32460251Shibler       || copy_text_and_data (new, a_out) < 0
32560251Shibler       || copy_sym (new, a_out, a_name, new_name) < 0
32660251Shibler #ifdef COFF
32760251Shibler       || adjust_lnnoptrs (new, a_out, new_name) < 0
32860251Shibler #endif
32960251Shibler       )
33060251Shibler     {
33160251Shibler       close (new);
33260251Shibler       /* unlink (new_name);	    	/* Failed, unlink new a.out */
33360251Shibler       return -1;
33460251Shibler     }
33560251Shibler 
33660251Shibler   close (new);
33760251Shibler   if (a_out >= 0)
33860251Shibler     close (a_out);
33960251Shibler   mark_x (new_name);
34060251Shibler   return 0;
34160251Shibler }
34260251Shibler 
34360251Shibler /* ****************************************************************
34460251Shibler  * make_hdr
34560251Shibler  *
34660251Shibler  * Make the header in the new a.out from the header in core.
34760251Shibler  * Modify the text and data sizes.
34860251Shibler  */
34960251Shibler static int
make_hdr(new,a_out,data_start,bss_start,entry_address,a_name,new_name)35060251Shibler make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
35160251Shibler      int new, a_out;
35260251Shibler      unsigned data_start, bss_start, entry_address;
35360251Shibler      char *a_name;
35460251Shibler      char *new_name;
35560251Shibler {
35660251Shibler   int tem;
35760251Shibler #ifdef COFF
35860251Shibler   auto struct scnhdr f_thdr;		/* Text section header */
35960251Shibler   auto struct scnhdr f_dhdr;		/* Data section header */
36060251Shibler   auto struct scnhdr f_bhdr;		/* Bss section header */
36160251Shibler   auto struct scnhdr scntemp;		/* Temporary section header */
36260251Shibler   register int scns;
36360251Shibler #endif /* COFF */
36460251Shibler #ifdef USG_SHARED_LIBRARIES
36560251Shibler   extern unsigned int bss_end;
36660251Shibler #else
36760251Shibler   unsigned int bss_end;
36860251Shibler #endif
36960251Shibler 
37060251Shibler   pagemask = getpagesize () - 1;
37160251Shibler 
37260251Shibler   /* Adjust text/data boundary. */
37360251Shibler #ifdef NO_REMAP
37460251Shibler   data_start = (int) start_of_data ();
37560251Shibler #else /* not NO_REMAP */
37660251Shibler   if (!data_start)
37760251Shibler     data_start = (int) start_of_data ();
37860251Shibler #endif /* not NO_REMAP */
37960251Shibler   data_start = ADDR_CORRECT (data_start);
38060251Shibler 
38160251Shibler #ifdef SEGMENT_MASK
38260251Shibler   data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */
38360251Shibler #else
38460251Shibler   data_start = data_start & ~pagemask; /* (Down) to page boundary. */
38560251Shibler #endif
38660251Shibler 
38760251Shibler   bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
38860251Shibler   bss_end &= ~ pagemask;
38960251Shibler 
39060251Shibler   /* Adjust data/bss boundary. */
39160251Shibler   if (bss_start != 0)
39260251Shibler     {
39360251Shibler       bss_start = (ADDR_CORRECT (bss_start) + pagemask);
39460251Shibler       /* (Up) to page bdry. */
39560251Shibler       bss_start &= ~ pagemask;
39660251Shibler       if (bss_start > bss_end)
39760251Shibler 	{
39860251Shibler 	  ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
39960251Shibler 		  bss_start);
40060251Shibler 	}
40160251Shibler     }
40260251Shibler   else
40360251Shibler     bss_start = bss_end;
40460251Shibler 
40560251Shibler   if (data_start > bss_start)	/* Can't have negative data size. */
40660251Shibler     {
40760251Shibler       ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
40860251Shibler 	      data_start, bss_start);
40960251Shibler     }
41060251Shibler 
41160251Shibler #ifdef COFF
41260251Shibler   /* Salvage as much info from the existing file as possible */
41360251Shibler   if (a_out >= 0)
41460251Shibler     {
41560251Shibler       if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
41660251Shibler 	{
41760251Shibler 	  PERROR (a_name);
41860251Shibler 	}
41960251Shibler       block_copy_start += sizeof (f_hdr);
42060251Shibler       if (f_hdr.f_opthdr > 0)
42160251Shibler 	{
42260251Shibler 	  if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
42360251Shibler 	    {
42460251Shibler 	      PERROR (a_name);
42560251Shibler 	    }
42660251Shibler 	  block_copy_start += sizeof (f_ohdr);
42760251Shibler 	}
42860251Shibler       /* Loop through section headers, copying them in */
42960251Shibler       for (scns = f_hdr.f_nscns; scns > 0; scns--) {
43060251Shibler 	if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
43160251Shibler 	  {
43260251Shibler 	    PERROR (a_name);
43360251Shibler 	  }
43460251Shibler 	if (scntemp.s_scnptr > 0L)
43560251Shibler 	  {
43660251Shibler             if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
43760251Shibler 	      block_copy_start = scntemp.s_scnptr + scntemp.s_size;
43860251Shibler 	  }
43960251Shibler 	if (strcmp (scntemp.s_name, ".text") == 0)
44060251Shibler 	  {
44160251Shibler 	    f_thdr = scntemp;
44260251Shibler 	  }
44360251Shibler 	else if (strcmp (scntemp.s_name, ".data") == 0)
44460251Shibler 	  {
44560251Shibler 	    f_dhdr = scntemp;
44660251Shibler 	  }
44760251Shibler 	else if (strcmp (scntemp.s_name, ".bss") == 0)
44860251Shibler 	  {
44960251Shibler 	    f_bhdr = scntemp;
45060251Shibler 	  }
45160251Shibler       }
45260251Shibler     }
45360251Shibler   else
45460251Shibler     {
45560251Shibler       ERROR0 ("can't build a COFF file from scratch yet");
45660251Shibler     }
45760251Shibler 
45860251Shibler   /* Now we alter the contents of all the f_*hdr variables
45960251Shibler      to correspond to what we want to dump.  */
46060251Shibler 
46160251Shibler #ifdef USG_SHARED_LIBRARIES
46260251Shibler 
46360251Shibler   /* The amount of data we're adding to the file is distance from the
46460251Shibler    * end of the original .data space to the current end of the .data
46560251Shibler    * space.
46660251Shibler    */
46760251Shibler 
46860251Shibler   bias = bss_end - (f_ohdr.data_start + f_dhdr.s_size);
46960251Shibler 
47060251Shibler #endif
47160251Shibler 
47260251Shibler   f_hdr.f_flags |= (F_RELFLG | F_EXEC);
47360251Shibler #ifdef EXEC_MAGIC
47460251Shibler   f_ohdr.magic = EXEC_MAGIC;
47560251Shibler #endif
47660251Shibler #ifndef NO_REMAP
47760251Shibler   f_ohdr.text_start = (long) start_of_text ();
47860251Shibler   f_ohdr.tsize = data_start - f_ohdr.text_start;
47960251Shibler   f_ohdr.data_start = data_start;
48060251Shibler #endif /* NO_REMAP */
48160251Shibler   f_ohdr.dsize = bss_start - f_ohdr.data_start;
48260251Shibler   f_ohdr.bsize = bss_end - bss_start;
48360251Shibler   f_thdr.s_size = f_ohdr.tsize;
48460251Shibler   f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
48560251Shibler   f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
48660251Shibler   lnnoptr = f_thdr.s_lnnoptr;
48760251Shibler #ifdef SECTION_ALIGNMENT
48860251Shibler   /* Some systems require special alignment
48960251Shibler      of the sections in the file itself.  */
49060251Shibler   f_thdr.s_scnptr
49160251Shibler     = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
49260251Shibler #endif /* SECTION_ALIGNMENT */
49360251Shibler   text_scnptr = f_thdr.s_scnptr;
49460251Shibler   f_dhdr.s_paddr = f_ohdr.data_start;
49560251Shibler   f_dhdr.s_vaddr = f_ohdr.data_start;
49660251Shibler   f_dhdr.s_size = f_ohdr.dsize;
49760251Shibler   f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
49860251Shibler #ifdef SECTION_ALIGNMENT
49960251Shibler   /* Some systems require special alignment
50060251Shibler      of the sections in the file itself.  */
50160251Shibler   f_dhdr.s_scnptr
50260251Shibler     = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
50360251Shibler #endif /* SECTION_ALIGNMENT */
50460251Shibler #ifdef DATA_SECTION_ALIGNMENT
50560251Shibler   /* Some systems require special alignment
50660251Shibler      of the data section only.  */
50760251Shibler   f_dhdr.s_scnptr
50860251Shibler     = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT;
50960251Shibler #endif /* DATA_SECTION_ALIGNMENT */
51060251Shibler   data_scnptr = f_dhdr.s_scnptr;
51160251Shibler   f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
51260251Shibler   f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
51360251Shibler   f_bhdr.s_size = f_ohdr.bsize;
51460251Shibler   f_bhdr.s_scnptr = 0L;
51560251Shibler #ifndef USG_SHARED_LIBRARIES
51660251Shibler   bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
51760251Shibler #endif
51860251Shibler 
51960251Shibler   if (f_hdr.f_symptr > 0L)
52060251Shibler     {
52160251Shibler       f_hdr.f_symptr += bias;
52260251Shibler     }
52360251Shibler 
52460251Shibler   if (f_thdr.s_lnnoptr > 0L)
52560251Shibler     {
52660251Shibler       f_thdr.s_lnnoptr += bias;
52760251Shibler     }
52860251Shibler 
52960251Shibler #ifdef ADJUST_EXEC_HEADER
53060251Shibler   ADJUST_EXEC_HEADER
53160251Shibler #endif /* ADJUST_EXEC_HEADER */
53260251Shibler 
53360251Shibler   if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
53460251Shibler     {
53560251Shibler       PERROR (new_name);
53660251Shibler     }
53760251Shibler 
53860251Shibler   if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
53960251Shibler     {
54060251Shibler       PERROR (new_name);
54160251Shibler     }
54260251Shibler 
54360251Shibler #ifndef USG_SHARED_LIBRARIES
54460251Shibler 
54560251Shibler   if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
54660251Shibler     {
54760251Shibler       PERROR (new_name);
54860251Shibler     }
54960251Shibler 
55060251Shibler   if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
55160251Shibler     {
55260251Shibler       PERROR (new_name);
55360251Shibler     }
55460251Shibler 
55560251Shibler   if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
55660251Shibler     {
55760251Shibler       PERROR (new_name);
55860251Shibler     }
55960251Shibler 
56060251Shibler #else /* USG_SHARED_LIBRARIES */
56160251Shibler 
56260251Shibler   /* The purpose of this code is to write out the new file's section
56360251Shibler    * header table.
56460251Shibler    *
56560251Shibler    * Scan through the original file's sections.  If the encountered
56660251Shibler    * section is one we know (.text, .data or .bss), write out the
56760251Shibler    * correct header.  If it is a section we do not know (such as
56860251Shibler    * .lib), adjust the address of where the section data is in the
56960251Shibler    * file, and write out the header.
57060251Shibler    *
57160251Shibler    * If any section preceeds .text or .data in the file, this code
57260251Shibler    * will not adjust the file pointer for that section correctly.
57360251Shibler    */
57460251Shibler 
575*60297Shibler   lseek (a_out, (off_t) sizeof (f_hdr) + sizeof (f_ohdr), 0);
57660251Shibler 
57760251Shibler   for (scns = f_hdr.f_nscns; scns > 0; scns--)
57860251Shibler     {
57960251Shibler       if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
58060251Shibler 	PERROR (a_name);
58160251Shibler 
58260251Shibler       if (!strcmp (scntemp.s_name, f_thdr.s_name))	/* .text */
58360251Shibler 	{
58460251Shibler 	  if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
58560251Shibler 	    PERROR (new_name);
58660251Shibler 	}
58760251Shibler       else if (!strcmp (scntemp.s_name, f_dhdr.s_name))	/* .data */
58860251Shibler 	{
58960251Shibler 	  if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
59060251Shibler 	    PERROR (new_name);
59160251Shibler 	}
59260251Shibler       else if (!strcmp (scntemp.s_name, f_bhdr.s_name))	/* .bss */
59360251Shibler 	{
59460251Shibler 	  if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
59560251Shibler 	    PERROR (new_name);
59660251Shibler 	}
59760251Shibler       else
59860251Shibler 	{
59960251Shibler 	  if (scntemp.s_scnptr)
60060251Shibler 	    scntemp.s_scnptr += bias;
60160251Shibler 	  if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
60260251Shibler 	    PERROR (new_name);
60360251Shibler 	}
60460251Shibler     }
60560251Shibler #endif /* USG_SHARED_LIBRARIES */
60660251Shibler 
60760251Shibler   return (0);
60860251Shibler 
60960251Shibler #else /* if not COFF */
61060251Shibler 
61160251Shibler   /* Get symbol table info from header of a.out file if given one. */
61260251Shibler   if (a_out >= 0)
61360251Shibler     {
61460251Shibler       if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr)
61560251Shibler 	{
61660251Shibler 	  PERROR (a_name);
61760251Shibler 	}
61860251Shibler 
61960251Shibler       if (N_BADMAG (ohdr))
62060251Shibler 	{
62160251Shibler 	  ERROR1 ("invalid magic number in %s", a_name);
62260251Shibler 	}
62360251Shibler       hdr = ohdr;
62460251Shibler     }
62560251Shibler   else
62660251Shibler     {
62760251Shibler       bzero (hdr, sizeof hdr);
62860251Shibler     }
62960251Shibler 
63060251Shibler   unexec_text_start = (long) start_of_text ();
63160251Shibler   unexec_data_start = data_start;
63260251Shibler 
63360251Shibler   /* Machine-dependent fixup for header, or maybe for unexec_text_start */
63460251Shibler #ifdef ADJUST_EXEC_HEADER
63560251Shibler   ADJUST_EXEC_HEADER;
63660251Shibler #endif /* ADJUST_EXEC_HEADER */
63760251Shibler 
63860251Shibler   hdr.a_trsize = 0;
63960251Shibler   hdr.a_drsize = 0;
64060251Shibler   if (entry_address != 0)
64160251Shibler     hdr.a_entry = entry_address;
64260251Shibler 
64360251Shibler   hdr.a_bss = bss_end - bss_start;
64460251Shibler   hdr.a_data = bss_start - data_start;
64560251Shibler #ifdef NO_REMAP
64660251Shibler   hdr.a_text = ohdr.a_text;
64760251Shibler #else /* not NO_REMAP */
64860251Shibler   hdr.a_text = data_start - unexec_text_start;
64960251Shibler 
65060251Shibler #ifdef A_TEXT_OFFSET
65160251Shibler   hdr.a_text += A_TEXT_OFFSET (ohdr);
65260251Shibler #endif
65360251Shibler 
65460251Shibler #endif /* not NO_REMAP */
65560251Shibler 
65660251Shibler   if (write (new, &hdr, sizeof hdr) != sizeof hdr)
65760251Shibler     {
65860251Shibler       PERROR (new_name);
65960251Shibler     }
66060251Shibler 
66160251Shibler #ifdef A_TEXT_OFFSET
66260251Shibler   hdr.a_text -= A_TEXT_OFFSET (ohdr);
66360251Shibler #endif
66460251Shibler 
66560251Shibler   return 0;
66660251Shibler 
66760251Shibler #endif /* not COFF */
66860251Shibler }
66960251Shibler 
67060251Shibler /* ****************************************************************
67160251Shibler  * copy_text_and_data
67260251Shibler  *
67360251Shibler  * Copy the text and data segments from memory to the new a.out
67460251Shibler  */
67560251Shibler static int
copy_text_and_data(new,a_out)67660251Shibler copy_text_and_data (new, a_out)
67760251Shibler      int new, a_out;
67860251Shibler {
67960251Shibler   register char *end;
68060251Shibler   register char *ptr;
68160251Shibler 
68260251Shibler #ifdef COFF
68360251Shibler 
68460251Shibler #ifdef USG_SHARED_LIBRARIES
68560251Shibler 
68660251Shibler   int scns;
68760251Shibler   struct scnhdr scntemp;		/* Temporary section header */
68860251Shibler 
68960251Shibler   /* The purpose of this code is to write out the new file's section
69060251Shibler    * contents.
69160251Shibler    *
69260251Shibler    * Step through the section table.  If we know the section (.text,
69360251Shibler    * .data) do the appropriate thing.  Otherwise, if the section has
69460251Shibler    * no allocated space in the file (.bss), do nothing.  Otherwise,
69560251Shibler    * the section has space allocated in the file, and is not a section
69660251Shibler    * we know.  So just copy it.
69760251Shibler    */
69860251Shibler 
699*60297Shibler   lseek (a_out, (off_t) sizeof (struct filehdr) + sizeof (struct aouthdr), 0);
70060251Shibler 
70160251Shibler   for (scns = f_hdr.f_nscns; scns > 0; scns--)
70260251Shibler     {
70360251Shibler       if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
70460251Shibler 	PERROR ("temacs");
70560251Shibler 
70660251Shibler       if (!strcmp (scntemp.s_name, ".text"))
70760251Shibler 	{
708*60297Shibler 	  lseek (new, (off_t) text_scnptr, 0);
70960251Shibler 	  ptr = (char *) f_ohdr.text_start;
71060251Shibler 	  end = ptr + f_ohdr.tsize;
71160251Shibler 	  write_segment (new, ptr, end);
71260251Shibler 	}
71360251Shibler       else if (!strcmp (scntemp.s_name, ".data"))
71460251Shibler 	{
715*60297Shibler 	  lseek (new, (off_t) data_scnptr, 0);
71660251Shibler 	  ptr = (char *) f_ohdr.data_start;
71760251Shibler 	  end = ptr + f_ohdr.dsize;
71860251Shibler 	  write_segment (new, ptr, end);
71960251Shibler 	}
72060251Shibler       else if (!scntemp.s_scnptr)
72160251Shibler 	; /* do nothing - no data for this section */
72260251Shibler       else
72360251Shibler 	{
72460251Shibler 	  char page[BUFSIZ];
72560251Shibler 	  int size, n;
726*60297Shibler 	  long old_a_out_ptr = lseek (a_out, (off_t) 0, 1);
72760251Shibler 
728*60297Shibler 	  lseek (a_out, (off_t) scntemp.s_scnptr, 0);
72960251Shibler 	  for (size = scntemp.s_size; size > 0; size -= sizeof (page))
73060251Shibler 	    {
73160251Shibler 	      n = size > sizeof (page) ? sizeof (page) : size;
73260251Shibler 	      if (read (a_out, page, n) != n || write (new, page, n) != n)
73360251Shibler 		PERROR ("xemacs");
73460251Shibler 	    }
735*60297Shibler 	  lseek (a_out, (off_t) old_a_out_ptr, 0);
73660251Shibler 	}
73760251Shibler     }
73860251Shibler 
73960251Shibler #else /* COFF, but not USG_SHARED_LIBRARIES */
74060251Shibler 
741*60297Shibler   lseek (new, (off_t) text_scnptr, 0);
74260251Shibler   ptr = (char *) f_ohdr.text_start;
74360251Shibler   end = ptr + f_ohdr.tsize;
74460251Shibler   write_segment (new, ptr, end);
74560251Shibler 
746*60297Shibler   lseek (new, (off_t) data_scnptr, 0);
74760251Shibler   ptr = (char *) f_ohdr.data_start;
74860251Shibler   end = ptr + f_ohdr.dsize;
74960251Shibler   write_segment (new, ptr, end);
75060251Shibler 
75160251Shibler #endif /* USG_SHARED_LIBRARIES */
75260251Shibler 
75360251Shibler #else /* if not COFF */
75460251Shibler 
75560251Shibler /* Some machines count the header as part of the text segment.
75660251Shibler    That is to say, the header appears in core
75760251Shibler    just before the address that start_of_text () returns.
75860251Shibler    For them, N_TXTOFF is the place where the header goes.
75960251Shibler    We must adjust the seek to the place after the header.
76060251Shibler    Note that at this point hdr.a_text does *not* count
76160251Shibler    the extra A_TEXT_OFFSET bytes, only the actual bytes of code.  */
76260251Shibler 
76360251Shibler #ifdef A_TEXT_SEEK
764*60297Shibler   lseek (new, (off_t) A_TEXT_SEEK (hdr), 0);
76560251Shibler #else
76660251Shibler #ifdef A_TEXT_OFFSET
76760251Shibler   /* Note that on the Sequent machine A_TEXT_OFFSET != sizeof (hdr)
76860251Shibler      and sizeof (hdr) is the correct amount to add here.  */
76960251Shibler   /* In version 19, eliminate this case and use A_TEXT_SEEK whenever
77060251Shibler      N_TXTOFF is not right.  */
771*60297Shibler   lseek (new, (off_t) N_TXTOFF (hdr) + sizeof (hdr), 0);
77260251Shibler #else
773*60297Shibler   lseek (new, (off_t) N_TXTOFF (hdr), 0);
77460251Shibler #endif /* no A_TEXT_OFFSET */
77560251Shibler #endif /* no A_TEXT_SEEK */
77660251Shibler 
77760251Shibler   ptr = (char *) unexec_text_start;
77860251Shibler   end = ptr + hdr.a_text;
77960251Shibler   write_segment (new, ptr, end);
78060251Shibler 
78160251Shibler   ptr = (char *) unexec_data_start;
78260251Shibler   end = ptr + hdr.a_data;
78360251Shibler /*  This lseek is certainly incorrect when A_TEXT_OFFSET
78460251Shibler     and I believe it is a no-op otherwise.
78560251Shibler     Let's see if its absence ever fails.  */
786*60297Shibler /*  lseek (new, (off_t) N_TXTOFF (hdr) + hdr.a_text, 0); */
78760251Shibler   write_segment (new, ptr, end);
78860251Shibler 
78960251Shibler #endif /* not COFF */
79060251Shibler 
79160251Shibler   return 0;
79260251Shibler }
79360251Shibler 
write_segment(new,ptr,end)79460251Shibler write_segment (new, ptr, end)
79560251Shibler      int new;
79660251Shibler      register char *ptr, *end;
79760251Shibler {
79860251Shibler   register int i, nwrite, ret;
79960251Shibler   char buf[80];
80060251Shibler   extern int errno;
80160251Shibler   char zeros[128];
80260251Shibler 
80360251Shibler   bzero (zeros, sizeof zeros);
80460251Shibler 
80560251Shibler   for (i = 0; ptr < end;)
80660251Shibler     {
80760251Shibler       /* distance to next multiple of 128.  */
80860251Shibler       nwrite = (((int) ptr + 128) & -128) - (int) ptr;
80960251Shibler       /* But not beyond specified end.  */
81060251Shibler       if (nwrite > end - ptr) nwrite = end - ptr;
81160251Shibler       ret = write (new, ptr, nwrite);
81260251Shibler       /* If write gets a page fault, it means we reached
81360251Shibler 	 a gap between the old text segment and the old data segment.
81460251Shibler 	 This gap has probably been remapped into part of the text segment.
81560251Shibler 	 So write zeros for it.  */
81660251Shibler       if (ret == -1 && errno == EFAULT)
81760251Shibler 	write (new, zeros, nwrite);
81860251Shibler       else if (nwrite != ret)
81960251Shibler 	{
82060251Shibler 	  sprintf (buf,
82160251Shibler 		   "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
82260251Shibler 		   ptr, new, nwrite, ret, errno);
82360251Shibler 	  PERROR (buf);
82460251Shibler 	}
82560251Shibler       i += nwrite;
82660251Shibler       ptr += nwrite;
82760251Shibler     }
82860251Shibler }
82960251Shibler 
83060251Shibler /* ****************************************************************
83160251Shibler  * copy_sym
83260251Shibler  *
83360251Shibler  * Copy the relocation information and symbol table from the a.out to the new
83460251Shibler  */
83560251Shibler static int
copy_sym(new,a_out,a_name,new_name)83660251Shibler copy_sym (new, a_out, a_name, new_name)
83760251Shibler      int new, a_out;
83860251Shibler      char *a_name, *new_name;
83960251Shibler {
84060251Shibler   char page[1024];
84160251Shibler   int n;
84260251Shibler 
84360251Shibler   if (a_out < 0)
84460251Shibler     return 0;
84560251Shibler 
84660251Shibler #ifdef COFF
84760251Shibler   if (SYMS_START == 0L)
84860251Shibler     return 0;
84960251Shibler #endif  /* COFF */
85060251Shibler 
85160251Shibler #ifdef COFF
85260251Shibler   if (lnnoptr)			/* if there is line number info */
853*60297Shibler     lseek (a_out, (off_t) lnnoptr, 0);	/* start copying from there */
85460251Shibler   else
85560251Shibler #endif /* COFF */
856*60297Shibler     lseek (a_out, (off_t) SYMS_START, 0);	/* Position a.out to symtab. */
85760251Shibler 
85860251Shibler   while ((n = read (a_out, page, sizeof page)) > 0)
85960251Shibler     {
86060251Shibler       if (write (new, page, n) != n)
86160251Shibler 	{
86260251Shibler 	  PERROR (new_name);
86360251Shibler 	}
86460251Shibler     }
86560251Shibler   if (n < 0)
86660251Shibler     {
86760251Shibler       PERROR (a_name);
86860251Shibler     }
86960251Shibler   return 0;
87060251Shibler }
87160251Shibler 
87260251Shibler /* ****************************************************************
87360251Shibler  * mark_x
87460251Shibler  *
87560251Shibler  * After succesfully building the new a.out, mark it executable
87660251Shibler  */
87760251Shibler static
mark_x(name)87860251Shibler mark_x (name)
87960251Shibler      char *name;
88060251Shibler {
88160251Shibler   struct stat sbuf;
88260251Shibler   int um;
88360251Shibler   int new = 0;  /* for PERROR */
88460251Shibler 
88560251Shibler   um = umask (777);
88660251Shibler   umask (um);
88760251Shibler   if (stat (name, &sbuf) == -1)
88860251Shibler     {
88960251Shibler       PERROR (name);
89060251Shibler     }
89160251Shibler   sbuf.st_mode |= 0111 & ~um;
89260251Shibler   if (chmod (name, sbuf.st_mode) == -1)
89360251Shibler     PERROR (name);
89460251Shibler }
89560251Shibler 
89660251Shibler /*
89760251Shibler  *	If the COFF file contains a symbol table and a line number section,
89860251Shibler  *	then any auxiliary entries that have values for x_lnnoptr must
89960251Shibler  *	be adjusted by the amount that the line number section has moved
90060251Shibler  *	in the file (bias computed in make_hdr).  The #@$%&* designers of
90160251Shibler  *	the auxiliary entry structures used the absolute file offsets for
90260251Shibler  *	the line number entry rather than an offset from the start of the
90360251Shibler  *	line number section!
90460251Shibler  *
90560251Shibler  *	When I figure out how to scan through the symbol table and pick out
90660251Shibler  *	the auxiliary entries that need adjustment, this routine will
90760251Shibler  *	be fixed.  As it is now, all such entries are wrong and sdb
90860251Shibler  *	will complain.   Fred Fish, UniSoft Systems Inc.
90960251Shibler  */
91060251Shibler 
91160251Shibler #ifdef COFF
91260251Shibler 
91360251Shibler /* This function is probably very slow.  Instead of reopening the new
91460251Shibler    file for input and output it should copy from the old to the new
91560251Shibler    using the two descriptors already open (WRITEDESC and READDESC).
91660251Shibler    Instead of reading one small structure at a time it should use
91760251Shibler    a reasonable size buffer.  But I don't have time to work on such
91860251Shibler    things, so I am installing it as submitted to me.  -- RMS.  */
91960251Shibler 
adjust_lnnoptrs(writedesc,readdesc,new_name)92060251Shibler adjust_lnnoptrs (writedesc, readdesc, new_name)
92160251Shibler      int writedesc;
92260251Shibler      int readdesc;
92360251Shibler      char *new_name;
92460251Shibler {
92560251Shibler   register int nsyms;
92660251Shibler   register int new;
92760251Shibler #ifdef amdahl_uts
92860251Shibler   SYMENT symentry;
92960251Shibler   AUXENT auxentry;
93060251Shibler #else
93160251Shibler   struct syment symentry;
93260251Shibler   union auxent auxentry;
93360251Shibler #endif
93460251Shibler 
93560251Shibler   if (!lnnoptr || !f_hdr.f_symptr)
93660251Shibler     return 0;
93760251Shibler 
93860251Shibler   if ((new = open (new_name, 2)) < 0)
93960251Shibler     {
94060251Shibler       PERROR (new_name);
94160251Shibler       return -1;
94260251Shibler     }
94360251Shibler 
944*60297Shibler   lseek (new, (off_t) f_hdr.f_symptr, 0);
94560251Shibler   for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
94660251Shibler     {
94760251Shibler       read (new, &symentry, SYMESZ);
94860251Shibler       if (symentry.n_numaux)
94960251Shibler 	{
95060251Shibler 	  read (new, &auxentry, AUXESZ);
95160251Shibler 	  nsyms++;
95260251Shibler 	  if (ISFCN (symentry.n_type)) {
95360251Shibler 	    auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
954*60297Shibler 	    lseek (new, (off_t) -AUXESZ, 1);
95560251Shibler 	    write (new, &auxentry, AUXESZ);
95660251Shibler 	  }
95760251Shibler 	}
95860251Shibler     }
95960251Shibler   close (new);
96060251Shibler }
96160251Shibler 
96260251Shibler #endif /* COFF */
96360251Shibler 
96460251Shibler #endif /* not CANNOT_UNEXEC */
96560251Shibler 
96660251Shibler #endif /* not CANNOT_DUMP */
967