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