1*60251Shibler /* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
2*60251Shibler 
3*60251Shibler     This program is free software; you can redistribute it and/or modify
4*60251Shibler     it under the terms of the GNU General Public License as published by
5*60251Shibler     the Free Software Foundation; either version 1, or (at your option)
6*60251Shibler     any later version.
7*60251Shibler 
8*60251Shibler     This program is distributed in the hope that it will be useful,
9*60251Shibler     but WITHOUT ANY WARRANTY; without even the implied warranty of
10*60251Shibler     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*60251Shibler     GNU General Public License for more details.
12*60251Shibler 
13*60251Shibler     You should have received a copy of the GNU General Public License
14*60251Shibler     along with this program; if not, write to the Free Software
15*60251Shibler     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16*60251Shibler 
17*60251Shibler In other words, you are welcome to use, share and improve this program.
18*60251Shibler You are forbidden to forbid anyone else to use, share and improve
19*60251Shibler what you give them.   Help stamp out software-hoarding!  */
20*60251Shibler 
21*60251Shibler 
22*60251Shibler /*
23*60251Shibler  * unexec.c - Convert a running program into an a.out file.
24*60251Shibler  *
25*60251Shibler  * Author:	Spencer W. Thomas
26*60251Shibler  * 		Computer Science Dept.
27*60251Shibler  * 		University of Utah
28*60251Shibler  * Date:	Tue Mar  2 1982
29*60251Shibler  * Modified heavily since then.
30*60251Shibler  *
31*60251Shibler  * Synopsis:
32*60251Shibler  *	unexec (new_name, a_name, data_start, bss_start, entry_address)
33*60251Shibler  *	char *new_name, *a_name;
34*60251Shibler  *	unsigned data_start, bss_start, entry_address;
35*60251Shibler  *
36*60251Shibler  * Takes a snapshot of the program and makes an a.out format file in the
37*60251Shibler  * file named by the string argument new_name.
38*60251Shibler  * If a_name is non-NULL, the symbol table will be taken from the given file.
39*60251Shibler  * On some machines, an existing a_name file is required.
40*60251Shibler  *
41*60251Shibler  * The boundaries within the a.out file may be adjusted with the data_start
42*60251Shibler  * and bss_start arguments.  Either or both may be given as 0 for defaults.
43*60251Shibler  *
44*60251Shibler  * Data_start gives the boundary between the text segment and the data
45*60251Shibler  * segment of the program.  The text segment can contain shared, read-only
46*60251Shibler  * program code and literal data, while the data segment is always unshared
47*60251Shibler  * and unprotected.  Data_start gives the lowest unprotected address.
48*60251Shibler  * The value you specify may be rounded down to a suitable boundary
49*60251Shibler  * as required by the machine you are using.
50*60251Shibler  *
51*60251Shibler  * Specifying zero for data_start means the boundary between text and data
52*60251Shibler  * should not be the same as when the program was loaded.
53*60251Shibler  * If NO_REMAP is defined, the argument data_start is ignored and the
54*60251Shibler  * segment boundaries are never changed.
55*60251Shibler  *
56*60251Shibler  * Bss_start indicates how much of the data segment is to be saved in the
57*60251Shibler  * a.out file and restored when the program is executed.  It gives the lowest
58*60251Shibler  * unsaved address, and is rounded up to a page boundary.  The default when 0
59*60251Shibler  * is given assumes that the entire data segment is to be stored, including
60*60251Shibler  * the previous data and bss as well as any additional storage allocated with
61*60251Shibler  * break (2).
62*60251Shibler  *
63*60251Shibler  * The new file is set up to start at entry_address.
64*60251Shibler  *
65*60251Shibler  * If you make improvements I'd like to get them too.
66*60251Shibler  * harpo!utah-cs!thomas, thomas@Utah-20
67*60251Shibler  *
68*60251Shibler  */
69*60251Shibler 
70*60251Shibler /* Modified to support SysVr3 shared libraries by James Van Artsdalen
71*60251Shibler  * of Dell Computer Corporation.  james@bigtex.cactus.org.
72*60251Shibler  */
73*60251Shibler 
74*60251Shibler /* There are several compilation parameters affecting unexec:
75*60251Shibler 
76*60251Shibler * COFF
77*60251Shibler 
78*60251Shibler Define this if your system uses COFF for executables.
79*60251Shibler Otherwise we assume you use Berkeley format.
80*60251Shibler 
81*60251Shibler * NO_REMAP
82*60251Shibler 
83*60251Shibler Define this if you do not want to try to save Emacs's pure data areas
84*60251Shibler as part of the text segment.
85*60251Shibler 
86*60251Shibler Saving them as text is good because it allows users to share more.
87*60251Shibler 
88*60251Shibler However, on machines that locate the text area far from the data area,
89*60251Shibler the boundary cannot feasibly be moved.  Such machines require
90*60251Shibler NO_REMAP.
91*60251Shibler 
92*60251Shibler Also, remapping can cause trouble with the built-in startup routine
93*60251Shibler /lib/crt0.o, which defines `environ' as an initialized variable.
94*60251Shibler Dumping `environ' as pure does not work!  So, to use remapping,
95*60251Shibler you must write a startup routine for your machine in Emacs's crt0.c.
96*60251Shibler If NO_REMAP is defined, Emacs uses the system's crt0.o.
97*60251Shibler 
98*60251Shibler * SECTION_ALIGNMENT
99*60251Shibler 
100*60251Shibler Some machines that use COFF executables require that each section
101*60251Shibler start on a certain boundary *in the COFF file*.  Such machines should
102*60251Shibler define SECTION_ALIGNMENT to a mask of the low-order bits that must be
103*60251Shibler zero on such a boundary.  This mask is used to control padding between
104*60251Shibler segments in the COFF file.
105*60251Shibler 
106*60251Shibler If SECTION_ALIGNMENT is not defined, the segments are written
107*60251Shibler consecutively with no attempt at alignment.  This is right for
108*60251Shibler unmodified system V.
109*60251Shibler 
110*60251Shibler * SEGMENT_MASK
111*60251Shibler 
112*60251Shibler Some machines require that the beginnings and ends of segments
113*60251Shibler *in core* be on certain boundaries.  For most machines, a page
114*60251Shibler boundary is sufficient.  That is the default.  When a larger
115*60251Shibler boundary is needed, define SEGMENT_MASK to a mask of
116*60251Shibler the bits that must be zero on such a boundary.
117*60251Shibler 
118*60251Shibler * A_TEXT_OFFSET(HDR)
119*60251Shibler 
120*60251Shibler Some machines count the a.out header as part of the size of the text
121*60251Shibler segment (a_text); they may actually load the header into core as the
122*60251Shibler first data in the text segment.  Some have additional padding between
123*60251Shibler the header and the real text of the program that is counted in a_text.
124*60251Shibler 
125*60251Shibler For these machines, define A_TEXT_OFFSET(HDR) to examine the header
126*60251Shibler structure HDR and return the number of bytes to add to `a_text'
127*60251Shibler before writing it (above and beyond the number of bytes of actual
128*60251Shibler program text).  HDR's standard fields are already correct, except that
129*60251Shibler this adjustment to the `a_text' field has not yet been made;
130*60251Shibler thus, the amount of offset can depend on the data in the file.
131*60251Shibler 
132*60251Shibler * A_TEXT_SEEK(HDR)
133*60251Shibler 
134*60251Shibler If defined, this macro specifies the number of bytes to seek into the
135*60251Shibler a.out file before starting to write the text segment.a
136*60251Shibler 
137*60251Shibler * EXEC_MAGIC
138*60251Shibler 
139*60251Shibler For machines using COFF, this macro, if defined, is a value stored
140*60251Shibler into the magic number field of the output file.
141*60251Shibler 
142*60251Shibler * ADJUST_EXEC_HEADER
143*60251Shibler 
144*60251Shibler This macro can be used to generate statements to adjust or
145*60251Shibler initialize nonstandard fields in the file header
146*60251Shibler 
147*60251Shibler * ADDR_CORRECT(ADDR)
148*60251Shibler 
149*60251Shibler Macro to correct an int which is the bit pattern of a pointer to a byte
150*60251Shibler into an int which is the number of a byte.
151*60251Shibler 
152*60251Shibler This macro has a default definition which is usually right.
153*60251Shibler This default definition is a no-op on most machines (where a
154*60251Shibler pointer looks like an int) but not on all machines.
155*60251Shibler 
156*60251Shibler */
157*60251Shibler 
158*60251Shibler #ifndef emacs
159*60251Shibler #define PERROR(arg) perror (arg); return -1
160*60251Shibler #else
161*60251Shibler #include "config.h"
162*60251Shibler #define PERROR(file) report_error (file, new)
163*60251Shibler #endif
164*60251Shibler 
165*60251Shibler #ifndef CANNOT_DUMP  /* all rest of file!  */
166*60251Shibler 
167*60251Shibler #ifndef CANNOT_UNEXEC /* most of rest of file */
168*60251Shibler 
169*60251Shibler #include <a.out.h>
170*60251Shibler /* Define getpagesize () if the system does not.
171*60251Shibler    Note that this may depend on symbols defined in a.out.h
172*60251Shibler  */
173*60251Shibler #include "getpagesize.h"
174*60251Shibler 
175*60251Shibler #ifndef makedev			/* Try to detect types.h already loaded */
176*60251Shibler #include <sys/types.h>
177*60251Shibler #endif
178*60251Shibler #include <stdio.h>
179*60251Shibler #include <sys/stat.h>
180*60251Shibler #include <errno.h>
181*60251Shibler 
182*60251Shibler extern char *start_of_text ();		/* Start of text */
183*60251Shibler extern char *start_of_data ();		/* Start of initialized data */
184*60251Shibler 
185*60251Shibler #ifdef COFF
186*60251Shibler #ifndef USG
187*60251Shibler #ifndef STRIDE
188*60251Shibler #ifndef UMAX
189*60251Shibler #ifndef sun386
190*60251Shibler /* I have a suspicion that these are turned off on all systems
191*60251Shibler    and can be deleted.  Try it in version 19.  */
192*60251Shibler #include <filehdr.h>
193*60251Shibler #include <aouthdr.h>
194*60251Shibler #include <scnhdr.h>
195*60251Shibler #include <syms.h>
196*60251Shibler #endif /* not sun386 */
197*60251Shibler #endif /* not UMAX */
198*60251Shibler #endif /* Not STRIDE */
199*60251Shibler #endif /* not USG */
200*60251Shibler static long block_copy_start;		/* Old executable start point */
201*60251Shibler static struct filehdr f_hdr;		/* File header */
202*60251Shibler static struct aouthdr f_ohdr;		/* Optional file header (a.out) */
203*60251Shibler long bias;			/* Bias to add for growth */
204*60251Shibler long lnnoptr;			/* Pointer to line-number info within file */
205*60251Shibler #define SYMS_START block_copy_start
206*60251Shibler 
207*60251Shibler static long text_scnptr;
208*60251Shibler static long data_scnptr;
209*60251Shibler 
210*60251Shibler #else /* not COFF */
211*60251Shibler 
212*60251Shibler extern char *sbrk ();
213*60251Shibler 
214*60251Shibler #define SYMS_START ((long) N_SYMOFF (ohdr))
215*60251Shibler 
216*60251Shibler /* Some machines override the structure name for an a.out header.  */
217*60251Shibler #ifndef EXEC_HDR_TYPE
218*60251Shibler #define EXEC_HDR_TYPE struct exec
219*60251Shibler #endif
220*60251Shibler 
221*60251Shibler #ifdef HPUX
222*60251Shibler #ifdef HP9000S200_ID
223*60251Shibler #define MY_ID HP9000S200_ID
224*60251Shibler #else
225*60251Shibler #include <model.h>
226*60251Shibler #define MY_ID MYSYS
227*60251Shibler #endif /* no HP9000S200_ID */
228*60251Shibler static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};
229*60251Shibler static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};
230*60251Shibler #define N_TXTOFF(x) TEXT_OFFSET(x)
231*60251Shibler #define N_SYMOFF(x) LESYM_OFFSET(x)
232*60251Shibler static EXEC_HDR_TYPE hdr, ohdr;
233*60251Shibler 
234*60251Shibler #else /* not HPUX */
235*60251Shibler 
236*60251Shibler #if defined (USG) && !defined (IBMRTAIX) && !defined (IRIS)
237*60251Shibler static struct bhdr hdr, ohdr;
238*60251Shibler #define a_magic fmagic
239*60251Shibler #define a_text tsize
240*60251Shibler #define a_data dsize
241*60251Shibler #define a_bss bsize
242*60251Shibler #define a_syms ssize
243*60251Shibler #define a_trsize rtsize
244*60251Shibler #define a_drsize rdsize
245*60251Shibler #define a_entry entry
246*60251Shibler #define	N_BADMAG(x) \
247*60251Shibler     (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\
248*60251Shibler      ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC)
249*60251Shibler #define NEWMAGIC FMAGIC
250*60251Shibler #else /* IRIS or IBMRTAIX or not USG */
251*60251Shibler static EXEC_HDR_TYPE hdr, ohdr;
252*60251Shibler #define NEWMAGIC ZMAGIC
253*60251Shibler #endif /* IRIS or IBMRTAIX not USG */
254*60251Shibler #endif /* not HPUX */
255*60251Shibler 
256*60251Shibler static int unexec_text_start;
257*60251Shibler static int unexec_data_start;
258*60251Shibler 
259*60251Shibler #endif /* not COFF */
260*60251Shibler 
261*60251Shibler static int pagemask;
262*60251Shibler 
263*60251Shibler /* Correct an int which is the bit pattern of a pointer to a byte
264*60251Shibler    into an int which is the number of a byte.
265*60251Shibler    This is a no-op on ordinary machines, but not on all.  */
266*60251Shibler 
267*60251Shibler #ifndef ADDR_CORRECT   /* Let m-*.h files override this definition */
268*60251Shibler #define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
269*60251Shibler #endif
270*60251Shibler 
271*60251Shibler #ifdef emacs
272*60251Shibler 
273*60251Shibler static
274*60251Shibler report_error (file, fd)
275*60251Shibler      char *file;
276*60251Shibler      int fd;
277*60251Shibler {
278*60251Shibler   if (fd)
279*60251Shibler     close (fd);
280*60251Shibler   error ("Failure operating on %s", file);
281*60251Shibler }
282*60251Shibler #endif /* emacs */
283*60251Shibler 
284*60251Shibler #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
285*60251Shibler #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
286*60251Shibler #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
287*60251Shibler 
288*60251Shibler static
289*60251Shibler report_error_1 (fd, msg, a1, a2)
290*60251Shibler      int fd;
291*60251Shibler      char *msg;
292*60251Shibler      int a1, a2;
293*60251Shibler {
294*60251Shibler   close (fd);
295*60251Shibler #ifdef emacs
296*60251Shibler   error (msg, a1, a2);
297*60251Shibler #else
298*60251Shibler   fprintf (stderr, msg, a1, a2);
299*60251Shibler   fprintf (stderr, "\n");
300*60251Shibler #endif
301*60251Shibler }
302*60251Shibler 
303*60251Shibler /* ****************************************************************
304*60251Shibler  * unexec
305*60251Shibler  *
306*60251Shibler  * driving logic.
307*60251Shibler  */
308*60251Shibler unexec (new_name, a_name, data_start, bss_start, entry_address)
309*60251Shibler      char *new_name, *a_name;
310*60251Shibler      unsigned data_start, bss_start, entry_address;
311*60251Shibler {
312*60251Shibler   int new, a_out = -1;
313*60251Shibler 
314*60251Shibler   if (a_name && (a_out = open (a_name, 0)) < 0)
315*60251Shibler     {
316*60251Shibler       PERROR (a_name);
317*60251Shibler     }
318*60251Shibler   if ((new = creat (new_name, 0666)) < 0)
319*60251Shibler     {
320*60251Shibler       PERROR (new_name);
321*60251Shibler     }
322*60251Shibler 
323*60251Shibler   if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
324*60251Shibler       || copy_text_and_data (new, a_out) < 0
325*60251Shibler       || copy_sym (new, a_out, a_name, new_name) < 0
326*60251Shibler #ifdef COFF
327*60251Shibler       || adjust_lnnoptrs (new, a_out, new_name) < 0
328*60251Shibler #endif
329*60251Shibler       )
330*60251Shibler     {
331*60251Shibler       close (new);
332*60251Shibler       /* unlink (new_name);	    	/* Failed, unlink new a.out */
333*60251Shibler       return -1;
334*60251Shibler     }
335*60251Shibler 
336*60251Shibler   close (new);
337*60251Shibler   if (a_out >= 0)
338*60251Shibler     close (a_out);
339*60251Shibler   mark_x (new_name);
340*60251Shibler   return 0;
341*60251Shibler }
342*60251Shibler 
343*60251Shibler /* ****************************************************************
344*60251Shibler  * make_hdr
345*60251Shibler  *
346*60251Shibler  * Make the header in the new a.out from the header in core.
347*60251Shibler  * Modify the text and data sizes.
348*60251Shibler  */
349*60251Shibler static int
350*60251Shibler make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
351*60251Shibler      int new, a_out;
352*60251Shibler      unsigned data_start, bss_start, entry_address;
353*60251Shibler      char *a_name;
354*60251Shibler      char *new_name;
355*60251Shibler {
356*60251Shibler   int tem;
357*60251Shibler #ifdef COFF
358*60251Shibler   auto struct scnhdr f_thdr;		/* Text section header */
359*60251Shibler   auto struct scnhdr f_dhdr;		/* Data section header */
360*60251Shibler   auto struct scnhdr f_bhdr;		/* Bss section header */
361*60251Shibler   auto struct scnhdr scntemp;		/* Temporary section header */
362*60251Shibler   register int scns;
363*60251Shibler #endif /* COFF */
364*60251Shibler #ifdef USG_SHARED_LIBRARIES
365*60251Shibler   extern unsigned int bss_end;
366*60251Shibler #else
367*60251Shibler   unsigned int bss_end;
368*60251Shibler #endif
369*60251Shibler 
370*60251Shibler   pagemask = getpagesize () - 1;
371*60251Shibler 
372*60251Shibler   /* Adjust text/data boundary. */
373*60251Shibler #ifdef NO_REMAP
374*60251Shibler   data_start = (int) start_of_data ();
375*60251Shibler #else /* not NO_REMAP */
376*60251Shibler   if (!data_start)
377*60251Shibler     data_start = (int) start_of_data ();
378*60251Shibler #endif /* not NO_REMAP */
379*60251Shibler   data_start = ADDR_CORRECT (data_start);
380*60251Shibler 
381*60251Shibler #ifdef SEGMENT_MASK
382*60251Shibler   data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */
383*60251Shibler #else
384*60251Shibler   data_start = data_start & ~pagemask; /* (Down) to page boundary. */
385*60251Shibler #endif
386*60251Shibler 
387*60251Shibler   bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
388*60251Shibler   bss_end &= ~ pagemask;
389*60251Shibler 
390*60251Shibler   /* Adjust data/bss boundary. */
391*60251Shibler   if (bss_start != 0)
392*60251Shibler     {
393*60251Shibler       bss_start = (ADDR_CORRECT (bss_start) + pagemask);
394*60251Shibler       /* (Up) to page bdry. */
395*60251Shibler       bss_start &= ~ pagemask;
396*60251Shibler       if (bss_start > bss_end)
397*60251Shibler 	{
398*60251Shibler 	  ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
399*60251Shibler 		  bss_start);
400*60251Shibler 	}
401*60251Shibler     }
402*60251Shibler   else
403*60251Shibler     bss_start = bss_end;
404*60251Shibler 
405*60251Shibler   if (data_start > bss_start)	/* Can't have negative data size. */
406*60251Shibler     {
407*60251Shibler       ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
408*60251Shibler 	      data_start, bss_start);
409*60251Shibler     }
410*60251Shibler 
411*60251Shibler #ifdef COFF
412*60251Shibler   /* Salvage as much info from the existing file as possible */
413*60251Shibler   if (a_out >= 0)
414*60251Shibler     {
415*60251Shibler       if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
416*60251Shibler 	{
417*60251Shibler 	  PERROR (a_name);
418*60251Shibler 	}
419*60251Shibler       block_copy_start += sizeof (f_hdr);
420*60251Shibler       if (f_hdr.f_opthdr > 0)
421*60251Shibler 	{
422*60251Shibler 	  if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
423*60251Shibler 	    {
424*60251Shibler 	      PERROR (a_name);
425*60251Shibler 	    }
426*60251Shibler 	  block_copy_start += sizeof (f_ohdr);
427*60251Shibler 	}
428*60251Shibler       /* Loop through section headers, copying them in */
429*60251Shibler       for (scns = f_hdr.f_nscns; scns > 0; scns--) {
430*60251Shibler 	if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
431*60251Shibler 	  {
432*60251Shibler 	    PERROR (a_name);
433*60251Shibler 	  }
434*60251Shibler 	if (scntemp.s_scnptr > 0L)
435*60251Shibler 	  {
436*60251Shibler             if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
437*60251Shibler 	      block_copy_start = scntemp.s_scnptr + scntemp.s_size;
438*60251Shibler 	  }
439*60251Shibler 	if (strcmp (scntemp.s_name, ".text") == 0)
440*60251Shibler 	  {
441*60251Shibler 	    f_thdr = scntemp;
442*60251Shibler 	  }
443*60251Shibler 	else if (strcmp (scntemp.s_name, ".data") == 0)
444*60251Shibler 	  {
445*60251Shibler 	    f_dhdr = scntemp;
446*60251Shibler 	  }
447*60251Shibler 	else if (strcmp (scntemp.s_name, ".bss") == 0)
448*60251Shibler 	  {
449*60251Shibler 	    f_bhdr = scntemp;
450*60251Shibler 	  }
451*60251Shibler       }
452*60251Shibler     }
453*60251Shibler   else
454*60251Shibler     {
455*60251Shibler       ERROR0 ("can't build a COFF file from scratch yet");
456*60251Shibler     }
457*60251Shibler 
458*60251Shibler   /* Now we alter the contents of all the f_*hdr variables
459*60251Shibler      to correspond to what we want to dump.  */
460*60251Shibler 
461*60251Shibler #ifdef USG_SHARED_LIBRARIES
462*60251Shibler 
463*60251Shibler   /* The amount of data we're adding to the file is distance from the
464*60251Shibler    * end of the original .data space to the current end of the .data
465*60251Shibler    * space.
466*60251Shibler    */
467*60251Shibler 
468*60251Shibler   bias = bss_end - (f_ohdr.data_start + f_dhdr.s_size);
469*60251Shibler 
470*60251Shibler #endif
471*60251Shibler 
472*60251Shibler   f_hdr.f_flags |= (F_RELFLG | F_EXEC);
473*60251Shibler #ifdef EXEC_MAGIC
474*60251Shibler   f_ohdr.magic = EXEC_MAGIC;
475*60251Shibler #endif
476*60251Shibler #ifndef NO_REMAP
477*60251Shibler   f_ohdr.text_start = (long) start_of_text ();
478*60251Shibler   f_ohdr.tsize = data_start - f_ohdr.text_start;
479*60251Shibler   f_ohdr.data_start = data_start;
480*60251Shibler #endif /* NO_REMAP */
481*60251Shibler   f_ohdr.dsize = bss_start - f_ohdr.data_start;
482*60251Shibler   f_ohdr.bsize = bss_end - bss_start;
483*60251Shibler   f_thdr.s_size = f_ohdr.tsize;
484*60251Shibler   f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
485*60251Shibler   f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
486*60251Shibler   lnnoptr = f_thdr.s_lnnoptr;
487*60251Shibler #ifdef SECTION_ALIGNMENT
488*60251Shibler   /* Some systems require special alignment
489*60251Shibler      of the sections in the file itself.  */
490*60251Shibler   f_thdr.s_scnptr
491*60251Shibler     = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
492*60251Shibler #endif /* SECTION_ALIGNMENT */
493*60251Shibler   text_scnptr = f_thdr.s_scnptr;
494*60251Shibler   f_dhdr.s_paddr = f_ohdr.data_start;
495*60251Shibler   f_dhdr.s_vaddr = f_ohdr.data_start;
496*60251Shibler   f_dhdr.s_size = f_ohdr.dsize;
497*60251Shibler   f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
498*60251Shibler #ifdef SECTION_ALIGNMENT
499*60251Shibler   /* Some systems require special alignment
500*60251Shibler      of the sections in the file itself.  */
501*60251Shibler   f_dhdr.s_scnptr
502*60251Shibler     = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
503*60251Shibler #endif /* SECTION_ALIGNMENT */
504*60251Shibler #ifdef DATA_SECTION_ALIGNMENT
505*60251Shibler   /* Some systems require special alignment
506*60251Shibler      of the data section only.  */
507*60251Shibler   f_dhdr.s_scnptr
508*60251Shibler     = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT;
509*60251Shibler #endif /* DATA_SECTION_ALIGNMENT */
510*60251Shibler   data_scnptr = f_dhdr.s_scnptr;
511*60251Shibler   f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
512*60251Shibler   f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
513*60251Shibler   f_bhdr.s_size = f_ohdr.bsize;
514*60251Shibler   f_bhdr.s_scnptr = 0L;
515*60251Shibler #ifndef USG_SHARED_LIBRARIES
516*60251Shibler   bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
517*60251Shibler #endif
518*60251Shibler 
519*60251Shibler   if (f_hdr.f_symptr > 0L)
520*60251Shibler     {
521*60251Shibler       f_hdr.f_symptr += bias;
522*60251Shibler     }
523*60251Shibler 
524*60251Shibler   if (f_thdr.s_lnnoptr > 0L)
525*60251Shibler     {
526*60251Shibler       f_thdr.s_lnnoptr += bias;
527*60251Shibler     }
528*60251Shibler 
529*60251Shibler #ifdef ADJUST_EXEC_HEADER
530*60251Shibler   ADJUST_EXEC_HEADER
531*60251Shibler #endif /* ADJUST_EXEC_HEADER */
532*60251Shibler 
533*60251Shibler   if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
534*60251Shibler     {
535*60251Shibler       PERROR (new_name);
536*60251Shibler     }
537*60251Shibler 
538*60251Shibler   if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
539*60251Shibler     {
540*60251Shibler       PERROR (new_name);
541*60251Shibler     }
542*60251Shibler 
543*60251Shibler #ifndef USG_SHARED_LIBRARIES
544*60251Shibler 
545*60251Shibler   if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
546*60251Shibler     {
547*60251Shibler       PERROR (new_name);
548*60251Shibler     }
549*60251Shibler 
550*60251Shibler   if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
551*60251Shibler     {
552*60251Shibler       PERROR (new_name);
553*60251Shibler     }
554*60251Shibler 
555*60251Shibler   if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
556*60251Shibler     {
557*60251Shibler       PERROR (new_name);
558*60251Shibler     }
559*60251Shibler 
560*60251Shibler #else /* USG_SHARED_LIBRARIES */
561*60251Shibler 
562*60251Shibler   /* The purpose of this code is to write out the new file's section
563*60251Shibler    * header table.
564*60251Shibler    *
565*60251Shibler    * Scan through the original file's sections.  If the encountered
566*60251Shibler    * section is one we know (.text, .data or .bss), write out the
567*60251Shibler    * correct header.  If it is a section we do not know (such as
568*60251Shibler    * .lib), adjust the address of where the section data is in the
569*60251Shibler    * file, and write out the header.
570*60251Shibler    *
571*60251Shibler    * If any section preceeds .text or .data in the file, this code
572*60251Shibler    * will not adjust the file pointer for that section correctly.
573*60251Shibler    */
574*60251Shibler 
575*60251Shibler   lseek (a_out, sizeof (f_hdr) + sizeof (f_ohdr), 0);
576*60251Shibler 
577*60251Shibler   for (scns = f_hdr.f_nscns; scns > 0; scns--)
578*60251Shibler     {
579*60251Shibler       if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
580*60251Shibler 	PERROR (a_name);
581*60251Shibler 
582*60251Shibler       if (!strcmp (scntemp.s_name, f_thdr.s_name))	/* .text */
583*60251Shibler 	{
584*60251Shibler 	  if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
585*60251Shibler 	    PERROR (new_name);
586*60251Shibler 	}
587*60251Shibler       else if (!strcmp (scntemp.s_name, f_dhdr.s_name))	/* .data */
588*60251Shibler 	{
589*60251Shibler 	  if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
590*60251Shibler 	    PERROR (new_name);
591*60251Shibler 	}
592*60251Shibler       else if (!strcmp (scntemp.s_name, f_bhdr.s_name))	/* .bss */
593*60251Shibler 	{
594*60251Shibler 	  if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
595*60251Shibler 	    PERROR (new_name);
596*60251Shibler 	}
597*60251Shibler       else
598*60251Shibler 	{
599*60251Shibler 	  if (scntemp.s_scnptr)
600*60251Shibler 	    scntemp.s_scnptr += bias;
601*60251Shibler 	  if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
602*60251Shibler 	    PERROR (new_name);
603*60251Shibler 	}
604*60251Shibler     }
605*60251Shibler #endif /* USG_SHARED_LIBRARIES */
606*60251Shibler 
607*60251Shibler   return (0);
608*60251Shibler 
609*60251Shibler #else /* if not COFF */
610*60251Shibler 
611*60251Shibler   /* Get symbol table info from header of a.out file if given one. */
612*60251Shibler   if (a_out >= 0)
613*60251Shibler     {
614*60251Shibler       if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr)
615*60251Shibler 	{
616*60251Shibler 	  PERROR (a_name);
617*60251Shibler 	}
618*60251Shibler 
619*60251Shibler       if (N_BADMAG (ohdr))
620*60251Shibler 	{
621*60251Shibler 	  ERROR1 ("invalid magic number in %s", a_name);
622*60251Shibler 	}
623*60251Shibler       hdr = ohdr;
624*60251Shibler     }
625*60251Shibler   else
626*60251Shibler     {
627*60251Shibler       bzero (hdr, sizeof hdr);
628*60251Shibler     }
629*60251Shibler 
630*60251Shibler   unexec_text_start = (long) start_of_text ();
631*60251Shibler   unexec_data_start = data_start;
632*60251Shibler 
633*60251Shibler   /* Machine-dependent fixup for header, or maybe for unexec_text_start */
634*60251Shibler #ifdef ADJUST_EXEC_HEADER
635*60251Shibler   ADJUST_EXEC_HEADER;
636*60251Shibler #endif /* ADJUST_EXEC_HEADER */
637*60251Shibler 
638*60251Shibler   hdr.a_trsize = 0;
639*60251Shibler   hdr.a_drsize = 0;
640*60251Shibler   if (entry_address != 0)
641*60251Shibler     hdr.a_entry = entry_address;
642*60251Shibler 
643*60251Shibler   hdr.a_bss = bss_end - bss_start;
644*60251Shibler   hdr.a_data = bss_start - data_start;
645*60251Shibler #ifdef NO_REMAP
646*60251Shibler   hdr.a_text = ohdr.a_text;
647*60251Shibler #else /* not NO_REMAP */
648*60251Shibler   hdr.a_text = data_start - unexec_text_start;
649*60251Shibler 
650*60251Shibler #ifdef A_TEXT_OFFSET
651*60251Shibler   hdr.a_text += A_TEXT_OFFSET (ohdr);
652*60251Shibler #endif
653*60251Shibler 
654*60251Shibler #endif /* not NO_REMAP */
655*60251Shibler 
656*60251Shibler   if (write (new, &hdr, sizeof hdr) != sizeof hdr)
657*60251Shibler     {
658*60251Shibler       PERROR (new_name);
659*60251Shibler     }
660*60251Shibler 
661*60251Shibler #ifdef A_TEXT_OFFSET
662*60251Shibler   hdr.a_text -= A_TEXT_OFFSET (ohdr);
663*60251Shibler #endif
664*60251Shibler 
665*60251Shibler   return 0;
666*60251Shibler 
667*60251Shibler #endif /* not COFF */
668*60251Shibler }
669*60251Shibler 
670*60251Shibler /* ****************************************************************
671*60251Shibler  * copy_text_and_data
672*60251Shibler  *
673*60251Shibler  * Copy the text and data segments from memory to the new a.out
674*60251Shibler  */
675*60251Shibler static int
676*60251Shibler copy_text_and_data (new, a_out)
677*60251Shibler      int new, a_out;
678*60251Shibler {
679*60251Shibler   register char *end;
680*60251Shibler   register char *ptr;
681*60251Shibler 
682*60251Shibler #ifdef COFF
683*60251Shibler 
684*60251Shibler #ifdef USG_SHARED_LIBRARIES
685*60251Shibler 
686*60251Shibler   int scns;
687*60251Shibler   struct scnhdr scntemp;		/* Temporary section header */
688*60251Shibler 
689*60251Shibler   /* The purpose of this code is to write out the new file's section
690*60251Shibler    * contents.
691*60251Shibler    *
692*60251Shibler    * Step through the section table.  If we know the section (.text,
693*60251Shibler    * .data) do the appropriate thing.  Otherwise, if the section has
694*60251Shibler    * no allocated space in the file (.bss), do nothing.  Otherwise,
695*60251Shibler    * the section has space allocated in the file, and is not a section
696*60251Shibler    * we know.  So just copy it.
697*60251Shibler    */
698*60251Shibler 
699*60251Shibler   lseek (a_out, sizeof (struct filehdr) + sizeof (struct aouthdr), 0);
700*60251Shibler 
701*60251Shibler   for (scns = f_hdr.f_nscns; scns > 0; scns--)
702*60251Shibler     {
703*60251Shibler       if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
704*60251Shibler 	PERROR ("temacs");
705*60251Shibler 
706*60251Shibler       if (!strcmp (scntemp.s_name, ".text"))
707*60251Shibler 	{
708*60251Shibler 	  lseek (new, (long) text_scnptr, 0);
709*60251Shibler 	  ptr = (char *) f_ohdr.text_start;
710*60251Shibler 	  end = ptr + f_ohdr.tsize;
711*60251Shibler 	  write_segment (new, ptr, end);
712*60251Shibler 	}
713*60251Shibler       else if (!strcmp (scntemp.s_name, ".data"))
714*60251Shibler 	{
715*60251Shibler 	  lseek (new, (long) data_scnptr, 0);
716*60251Shibler 	  ptr = (char *) f_ohdr.data_start;
717*60251Shibler 	  end = ptr + f_ohdr.dsize;
718*60251Shibler 	  write_segment (new, ptr, end);
719*60251Shibler 	}
720*60251Shibler       else if (!scntemp.s_scnptr)
721*60251Shibler 	; /* do nothing - no data for this section */
722*60251Shibler       else
723*60251Shibler 	{
724*60251Shibler 	  char page[BUFSIZ];
725*60251Shibler 	  int size, n;
726*60251Shibler 	  long old_a_out_ptr = lseek (a_out, 0, 1);
727*60251Shibler 
728*60251Shibler 	  lseek (a_out, scntemp.s_scnptr, 0);
729*60251Shibler 	  for (size = scntemp.s_size; size > 0; size -= sizeof (page))
730*60251Shibler 	    {
731*60251Shibler 	      n = size > sizeof (page) ? sizeof (page) : size;
732*60251Shibler 	      if (read (a_out, page, n) != n || write (new, page, n) != n)
733*60251Shibler 		PERROR ("xemacs");
734*60251Shibler 	    }
735*60251Shibler 	  lseek (a_out, old_a_out_ptr, 0);
736*60251Shibler 	}
737*60251Shibler     }
738*60251Shibler 
739*60251Shibler #else /* COFF, but not USG_SHARED_LIBRARIES */
740*60251Shibler 
741*60251Shibler   lseek (new, (long) text_scnptr, 0);
742*60251Shibler   ptr = (char *) f_ohdr.text_start;
743*60251Shibler   end = ptr + f_ohdr.tsize;
744*60251Shibler   write_segment (new, ptr, end);
745*60251Shibler 
746*60251Shibler   lseek (new, (long) data_scnptr, 0);
747*60251Shibler   ptr = (char *) f_ohdr.data_start;
748*60251Shibler   end = ptr + f_ohdr.dsize;
749*60251Shibler   write_segment (new, ptr, end);
750*60251Shibler 
751*60251Shibler #endif /* USG_SHARED_LIBRARIES */
752*60251Shibler 
753*60251Shibler #else /* if not COFF */
754*60251Shibler 
755*60251Shibler /* Some machines count the header as part of the text segment.
756*60251Shibler    That is to say, the header appears in core
757*60251Shibler    just before the address that start_of_text () returns.
758*60251Shibler    For them, N_TXTOFF is the place where the header goes.
759*60251Shibler    We must adjust the seek to the place after the header.
760*60251Shibler    Note that at this point hdr.a_text does *not* count
761*60251Shibler    the extra A_TEXT_OFFSET bytes, only the actual bytes of code.  */
762*60251Shibler 
763*60251Shibler #ifdef A_TEXT_SEEK
764*60251Shibler   lseek (new, (long) A_TEXT_SEEK (hdr), 0);
765*60251Shibler #else
766*60251Shibler #ifdef A_TEXT_OFFSET
767*60251Shibler   /* Note that on the Sequent machine A_TEXT_OFFSET != sizeof (hdr)
768*60251Shibler      and sizeof (hdr) is the correct amount to add here.  */
769*60251Shibler   /* In version 19, eliminate this case and use A_TEXT_SEEK whenever
770*60251Shibler      N_TXTOFF is not right.  */
771*60251Shibler   lseek (new, (long) N_TXTOFF (hdr) + sizeof (hdr), 0);
772*60251Shibler #else
773*60251Shibler   lseek (new, (long) N_TXTOFF (hdr), 0);
774*60251Shibler #endif /* no A_TEXT_OFFSET */
775*60251Shibler #endif /* no A_TEXT_SEEK */
776*60251Shibler 
777*60251Shibler   ptr = (char *) unexec_text_start;
778*60251Shibler   end = ptr + hdr.a_text;
779*60251Shibler   write_segment (new, ptr, end);
780*60251Shibler 
781*60251Shibler   ptr = (char *) unexec_data_start;
782*60251Shibler   end = ptr + hdr.a_data;
783*60251Shibler /*  This lseek is certainly incorrect when A_TEXT_OFFSET
784*60251Shibler     and I believe it is a no-op otherwise.
785*60251Shibler     Let's see if its absence ever fails.  */
786*60251Shibler /*  lseek (new, (long) N_TXTOFF (hdr) + hdr.a_text, 0); */
787*60251Shibler   write_segment (new, ptr, end);
788*60251Shibler 
789*60251Shibler #endif /* not COFF */
790*60251Shibler 
791*60251Shibler   return 0;
792*60251Shibler }
793*60251Shibler 
794*60251Shibler write_segment (new, ptr, end)
795*60251Shibler      int new;
796*60251Shibler      register char *ptr, *end;
797*60251Shibler {
798*60251Shibler   register int i, nwrite, ret;
799*60251Shibler   char buf[80];
800*60251Shibler   extern int errno;
801*60251Shibler   char zeros[128];
802*60251Shibler 
803*60251Shibler   bzero (zeros, sizeof zeros);
804*60251Shibler 
805*60251Shibler   for (i = 0; ptr < end;)
806*60251Shibler     {
807*60251Shibler       /* distance to next multiple of 128.  */
808*60251Shibler       nwrite = (((int) ptr + 128) & -128) - (int) ptr;
809*60251Shibler       /* But not beyond specified end.  */
810*60251Shibler       if (nwrite > end - ptr) nwrite = end - ptr;
811*60251Shibler       ret = write (new, ptr, nwrite);
812*60251Shibler       /* If write gets a page fault, it means we reached
813*60251Shibler 	 a gap between the old text segment and the old data segment.
814*60251Shibler 	 This gap has probably been remapped into part of the text segment.
815*60251Shibler 	 So write zeros for it.  */
816*60251Shibler       if (ret == -1 && errno == EFAULT)
817*60251Shibler 	write (new, zeros, nwrite);
818*60251Shibler       else if (nwrite != ret)
819*60251Shibler 	{
820*60251Shibler 	  sprintf (buf,
821*60251Shibler 		   "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
822*60251Shibler 		   ptr, new, nwrite, ret, errno);
823*60251Shibler 	  PERROR (buf);
824*60251Shibler 	}
825*60251Shibler       i += nwrite;
826*60251Shibler       ptr += nwrite;
827*60251Shibler     }
828*60251Shibler }
829*60251Shibler 
830*60251Shibler /* ****************************************************************
831*60251Shibler  * copy_sym
832*60251Shibler  *
833*60251Shibler  * Copy the relocation information and symbol table from the a.out to the new
834*60251Shibler  */
835*60251Shibler static int
836*60251Shibler copy_sym (new, a_out, a_name, new_name)
837*60251Shibler      int new, a_out;
838*60251Shibler      char *a_name, *new_name;
839*60251Shibler {
840*60251Shibler   char page[1024];
841*60251Shibler   int n;
842*60251Shibler 
843*60251Shibler   if (a_out < 0)
844*60251Shibler     return 0;
845*60251Shibler 
846*60251Shibler #ifdef COFF
847*60251Shibler   if (SYMS_START == 0L)
848*60251Shibler     return 0;
849*60251Shibler #endif  /* COFF */
850*60251Shibler 
851*60251Shibler #ifdef COFF
852*60251Shibler   if (lnnoptr)			/* if there is line number info */
853*60251Shibler     lseek (a_out, lnnoptr, 0);	/* start copying from there */
854*60251Shibler   else
855*60251Shibler #endif /* COFF */
856*60251Shibler     lseek (a_out, SYMS_START, 0);	/* Position a.out to symtab. */
857*60251Shibler 
858*60251Shibler   while ((n = read (a_out, page, sizeof page)) > 0)
859*60251Shibler     {
860*60251Shibler       if (write (new, page, n) != n)
861*60251Shibler 	{
862*60251Shibler 	  PERROR (new_name);
863*60251Shibler 	}
864*60251Shibler     }
865*60251Shibler   if (n < 0)
866*60251Shibler     {
867*60251Shibler       PERROR (a_name);
868*60251Shibler     }
869*60251Shibler   return 0;
870*60251Shibler }
871*60251Shibler 
872*60251Shibler /* ****************************************************************
873*60251Shibler  * mark_x
874*60251Shibler  *
875*60251Shibler  * After succesfully building the new a.out, mark it executable
876*60251Shibler  */
877*60251Shibler static
878*60251Shibler mark_x (name)
879*60251Shibler      char *name;
880*60251Shibler {
881*60251Shibler   struct stat sbuf;
882*60251Shibler   int um;
883*60251Shibler   int new = 0;  /* for PERROR */
884*60251Shibler 
885*60251Shibler   um = umask (777);
886*60251Shibler   umask (um);
887*60251Shibler   if (stat (name, &sbuf) == -1)
888*60251Shibler     {
889*60251Shibler       PERROR (name);
890*60251Shibler     }
891*60251Shibler   sbuf.st_mode |= 0111 & ~um;
892*60251Shibler   if (chmod (name, sbuf.st_mode) == -1)
893*60251Shibler     PERROR (name);
894*60251Shibler }
895*60251Shibler 
896*60251Shibler /*
897*60251Shibler  *	If the COFF file contains a symbol table and a line number section,
898*60251Shibler  *	then any auxiliary entries that have values for x_lnnoptr must
899*60251Shibler  *	be adjusted by the amount that the line number section has moved
900*60251Shibler  *	in the file (bias computed in make_hdr).  The #@$%&* designers of
901*60251Shibler  *	the auxiliary entry structures used the absolute file offsets for
902*60251Shibler  *	the line number entry rather than an offset from the start of the
903*60251Shibler  *	line number section!
904*60251Shibler  *
905*60251Shibler  *	When I figure out how to scan through the symbol table and pick out
906*60251Shibler  *	the auxiliary entries that need adjustment, this routine will
907*60251Shibler  *	be fixed.  As it is now, all such entries are wrong and sdb
908*60251Shibler  *	will complain.   Fred Fish, UniSoft Systems Inc.
909*60251Shibler  */
910*60251Shibler 
911*60251Shibler #ifdef COFF
912*60251Shibler 
913*60251Shibler /* This function is probably very slow.  Instead of reopening the new
914*60251Shibler    file for input and output it should copy from the old to the new
915*60251Shibler    using the two descriptors already open (WRITEDESC and READDESC).
916*60251Shibler    Instead of reading one small structure at a time it should use
917*60251Shibler    a reasonable size buffer.  But I don't have time to work on such
918*60251Shibler    things, so I am installing it as submitted to me.  -- RMS.  */
919*60251Shibler 
920*60251Shibler adjust_lnnoptrs (writedesc, readdesc, new_name)
921*60251Shibler      int writedesc;
922*60251Shibler      int readdesc;
923*60251Shibler      char *new_name;
924*60251Shibler {
925*60251Shibler   register int nsyms;
926*60251Shibler   register int new;
927*60251Shibler #ifdef amdahl_uts
928*60251Shibler   SYMENT symentry;
929*60251Shibler   AUXENT auxentry;
930*60251Shibler #else
931*60251Shibler   struct syment symentry;
932*60251Shibler   union auxent auxentry;
933*60251Shibler #endif
934*60251Shibler 
935*60251Shibler   if (!lnnoptr || !f_hdr.f_symptr)
936*60251Shibler     return 0;
937*60251Shibler 
938*60251Shibler   if ((new = open (new_name, 2)) < 0)
939*60251Shibler     {
940*60251Shibler       PERROR (new_name);
941*60251Shibler       return -1;
942*60251Shibler     }
943*60251Shibler 
944*60251Shibler   lseek (new, f_hdr.f_symptr, 0);
945*60251Shibler   for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
946*60251Shibler     {
947*60251Shibler       read (new, &symentry, SYMESZ);
948*60251Shibler       if (symentry.n_numaux)
949*60251Shibler 	{
950*60251Shibler 	  read (new, &auxentry, AUXESZ);
951*60251Shibler 	  nsyms++;
952*60251Shibler 	  if (ISFCN (symentry.n_type)) {
953*60251Shibler 	    auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
954*60251Shibler 	    lseek (new, -AUXESZ, 1);
955*60251Shibler 	    write (new, &auxentry, AUXESZ);
956*60251Shibler 	  }
957*60251Shibler 	}
958*60251Shibler     }
959*60251Shibler   close (new);
960*60251Shibler }
961*60251Shibler 
962*60251Shibler #endif /* COFF */
963*60251Shibler 
964*60251Shibler #endif /* not CANNOT_UNEXEC */
965*60251Shibler 
966*60251Shibler #endif /* not CANNOT_DUMP */
967