~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to o/unexlin.c

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

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