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