Remove support for DJGPP v1.x (bug#5813).
[bpt/emacs.git] / src / unexec.c
1 /* Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 2001, 2002, 2003,
2 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /*
21 * unexec.c - Convert a running program into an a.out file.
22 *
23 * Author: Spencer W. Thomas
24 * Computer Science Dept.
25 * University of Utah
26 * Date: Tue Mar 2 1982
27 * Modified heavily since then.
28 *
29 * Synopsis:
30 * unexec (new_name, a_name, data_start, bss_start, entry_address)
31 * char *new_name, *a_name;
32 * unsigned data_start, bss_start, entry_address;
33 *
34 * Takes a snapshot of the program and makes an a.out format file in the
35 * file named by the string argument new_name.
36 * If a_name is non-NULL, the symbol table will be taken from the given file.
37 * On some machines, an existing a_name file is required.
38 *
39 * The boundaries within the a.out file may be adjusted with the data_start
40 * and bss_start arguments. Either or both may be given as 0 for defaults.
41 *
42 * Data_start gives the boundary between the text segment and the data
43 * segment of the program. The text segment can contain shared, read-only
44 * program code and literal data, while the data segment is always unshared
45 * and unprotected. Data_start gives the lowest unprotected address.
46 * The value you specify may be rounded down to a suitable boundary
47 * as required by the machine you are using.
48 *
49 * Specifying zero for data_start means the boundary between text and data
50 * should not be the same as when the program was loaded.
51 * If NO_REMAP is defined, the argument data_start is ignored and the
52 * segment boundaries are never changed.
53 *
54 * Bss_start indicates how much of the data segment is to be saved in the
55 * a.out file and restored when the program is executed. It gives the lowest
56 * unsaved address, and is rounded up to a page boundary. The default when 0
57 * is given assumes that the entire data segment is to be stored, including
58 * the previous data and bss as well as any additional storage allocated with
59 * break (2).
60 *
61 * The new file is set up to start at entry_address.
62 *
63 * If you make improvements I'd like to get them too.
64 * harpo!utah-cs!thomas, thomas@Utah-20
65 *
66 */
67
68 /* Modified to support SysVr3 shared libraries by James Van Artsdalen
69 * of Dell Computer Corporation. james@bigtex.cactus.org.
70 */
71
72 /* There are several compilation parameters affecting unexec:
73
74 * COFF
75
76 Define this if your system uses COFF for executables.
77
78 * NO_REMAP
79
80 Define this if you do not want to try to save Emacs's pure data areas
81 as part of the text segment.
82
83 Saving them as text is good because it allows users to share more.
84
85 However, on machines that locate the text area far from the data area,
86 the boundary cannot feasibly be moved. Such machines require
87 NO_REMAP.
88
89 Also, remapping can cause trouble with the built-in startup routine
90 /lib/crt0.o, which defines `environ' as an initialized variable.
91 Dumping `environ' as pure does not work! So, to use remapping,
92 you must write a startup routine for your machine in Emacs's crt0.c.
93 If NO_REMAP is defined, Emacs uses the system's crt0.o.
94
95 * SECTION_ALIGNMENT
96
97 Some machines that use COFF executables require that each section
98 start on a certain boundary *in the COFF file*. Such machines should
99 define SECTION_ALIGNMENT to a mask of the low-order bits that must be
100 zero on such a boundary. This mask is used to control padding between
101 segments in the COFF file.
102
103 If SECTION_ALIGNMENT is not defined, the segments are written
104 consecutively with no attempt at alignment. This is right for
105 unmodified system V.
106
107 * SEGMENT_MASK
108
109 Some machines require that the beginnings and ends of segments
110 *in core* be on certain boundaries. For most machines, a page
111 boundary is sufficient. That is the default. When a larger
112 boundary is needed, define SEGMENT_MASK to a mask of
113 the bits that must be zero on such a boundary.
114
115 * ADJUST_EXEC_HEADER
116
117 This macro can be used to generate statements to adjust or
118 initialize nonstandard fields in the file header
119
120 */
121
122 #ifndef emacs
123 #define PERROR(arg) perror (arg); return -1
124 #else
125 #include <config.h>
126 #define PERROR(file) report_error (file, new)
127 #endif
128
129 #ifndef CANNOT_DUMP /* all rest of file! */
130
131 #ifdef HAVE_COFF_H
132 #include <coff.h>
133 #ifdef MSDOS
134 #include <fcntl.h> /* for O_RDONLY, O_RDWR */
135 #include <crt0.h> /* for _crt0_startup_flags and its bits */
136 static int save_djgpp_startup_flags;
137 #define filehdr external_filehdr
138 #define scnhdr external_scnhdr
139 #define syment external_syment
140 #define auxent external_auxent
141 #define n_numaux e_numaux
142 #define n_type e_type
143 struct aouthdr
144 {
145 unsigned short magic; /* type of file */
146 unsigned short vstamp; /* version stamp */
147 unsigned long tsize; /* text size in bytes, padded to FW bdry*/
148 unsigned long dsize; /* initialized data " " */
149 unsigned long bsize; /* uninitialized data " " */
150 unsigned long entry; /* entry pt. */
151 unsigned long text_start;/* base of text used for this file */
152 unsigned long data_start;/* base of data used for this file */
153 };
154 #endif /* not MSDOS */
155 #else /* not HAVE_COFF_H */
156 #include <a.out.h>
157 #endif /* not HAVE_COFF_H */
158
159 /* Define getpagesize if the system does not.
160 Note that this may depend on symbols defined in a.out.h. */
161 #include "getpagesize.h"
162
163 #ifndef makedev /* Try to detect types.h already loaded */
164 #include <sys/types.h>
165 #endif /* makedev */
166 #include <stdio.h>
167 #include <sys/stat.h>
168 #include <errno.h>
169
170 #include <sys/file.h>
171
172 #ifndef O_RDONLY
173 #define O_RDONLY 0
174 #endif
175 #ifndef O_RDWR
176 #define O_RDWR 2
177 #endif
178
179
180 extern char *start_of_text (); /* Start of text */
181 extern char *start_of_data (); /* Start of initialized data */
182
183 static long block_copy_start; /* Old executable start point */
184 static struct filehdr f_hdr; /* File header */
185 static struct aouthdr f_ohdr; /* Optional file header (a.out) */
186 long bias; /* Bias to add for growth */
187 long lnnoptr; /* Pointer to line-number info within file */
188 #define SYMS_START block_copy_start
189
190 static long text_scnptr;
191 static long data_scnptr;
192
193 static long coff_offset;
194
195 static int pagemask;
196
197 /* Correct an int which is the bit pattern of a pointer to a byte
198 into an int which is the number of a byte.
199 This is a no-op on ordinary machines, but not on all. */
200
201 #define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
202
203 #ifdef emacs
204
205 #include <setjmp.h>
206 #include "lisp.h"
207
208 static
209 report_error (file, fd)
210 char *file;
211 int fd;
212 {
213 if (fd)
214 close (fd);
215 report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
216 }
217 #endif /* emacs */
218
219 #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
220 #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
221 #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
222
223 static
224 report_error_1 (fd, msg, a1, a2)
225 int fd;
226 char *msg;
227 int a1, a2;
228 {
229 close (fd);
230 #ifdef emacs
231 error (msg, a1, a2);
232 #else
233 fprintf (stderr, msg, a1, a2);
234 fprintf (stderr, "\n");
235 #endif
236 }
237 \f
238 static int make_hdr ();
239 static int copy_text_and_data ();
240 static int copy_sym ();
241 static void mark_x ();
242
243 /* ****************************************************************
244 * make_hdr
245 *
246 * Make the header in the new a.out from the header in core.
247 * Modify the text and data sizes.
248 */
249 static int
250 make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
251 int new, a_out;
252 unsigned data_start, bss_start, entry_address;
253 char *a_name;
254 char *new_name;
255 {
256 int tem;
257 auto struct scnhdr f_thdr; /* Text section header */
258 auto struct scnhdr f_dhdr; /* Data section header */
259 auto struct scnhdr f_bhdr; /* Bss section header */
260 auto struct scnhdr scntemp; /* Temporary section header */
261 register int scns;
262 unsigned int bss_end;
263
264 pagemask = getpagesize () - 1;
265
266 /* Adjust text/data boundary. */
267 #ifdef NO_REMAP
268 data_start = (int) start_of_data ();
269 #else /* not NO_REMAP */
270 if (!data_start)
271 data_start = (int) start_of_data ();
272 #endif /* not NO_REMAP */
273 data_start = ADDR_CORRECT (data_start);
274
275 #ifdef SEGMENT_MASK
276 data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */
277 #else
278 data_start = data_start & ~pagemask; /* (Down) to page boundary. */
279 #endif
280
281 bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
282 bss_end &= ~ pagemask;
283
284 /* Adjust data/bss boundary. */
285 if (bss_start != 0)
286 {
287 bss_start = (ADDR_CORRECT (bss_start) + pagemask);
288 /* (Up) to page bdry. */
289 bss_start &= ~ pagemask;
290 if (bss_start > bss_end)
291 {
292 ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
293 bss_start);
294 }
295 }
296 else
297 bss_start = bss_end;
298
299 if (data_start > bss_start) /* Can't have negative data size. */
300 {
301 ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
302 data_start, bss_start);
303 }
304
305 coff_offset = 0L; /* stays zero, except in DJGPP */
306
307 /* Salvage as much info from the existing file as possible */
308 if (a_out >= 0)
309 {
310 #ifdef MSDOS
311 /* Support the coff-go32-exe format with a prepended stub, since
312 this is what GCC 2.8.0 and later generates by default in DJGPP. */
313 unsigned short mz_header[3];
314
315 if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header))
316 {
317 PERROR (a_name);
318 }
319 if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a) /* "MZ" or "ZM" */
320 {
321 coff_offset = (long)mz_header[2] * 512L;
322 if (mz_header[1])
323 coff_offset += (long)mz_header[1] - 512L;
324 lseek (a_out, coff_offset, 0);
325 }
326 else
327 lseek (a_out, 0L, 0);
328 #endif /* MSDOS */
329 if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
330 {
331 PERROR (a_name);
332 }
333 block_copy_start += sizeof (f_hdr);
334 if (f_hdr.f_opthdr > 0)
335 {
336 if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
337 {
338 PERROR (a_name);
339 }
340 block_copy_start += sizeof (f_ohdr);
341 }
342 /* Loop through section headers, copying them in */
343 lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0);
344 for (scns = f_hdr.f_nscns; scns > 0; scns--) {
345 if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
346 {
347 PERROR (a_name);
348 }
349 if (scntemp.s_scnptr > 0L)
350 {
351 if (block_copy_start < scntemp.s_scnptr + scntemp.s_size)
352 block_copy_start = scntemp.s_scnptr + scntemp.s_size;
353 }
354 if (strcmp (scntemp.s_name, ".text") == 0)
355 {
356 f_thdr = scntemp;
357 }
358 else if (strcmp (scntemp.s_name, ".data") == 0)
359 {
360 f_dhdr = scntemp;
361 }
362 else if (strcmp (scntemp.s_name, ".bss") == 0)
363 {
364 f_bhdr = scntemp;
365 }
366 }
367 }
368 else
369 {
370 ERROR0 ("can't build a COFF file from scratch yet");
371 }
372
373 /* Now we alter the contents of all the f_*hdr variables
374 to correspond to what we want to dump. */
375
376 f_hdr.f_flags |= (F_RELFLG | F_EXEC);
377 #ifndef NO_REMAP
378 f_ohdr.text_start = (long) start_of_text ();
379 f_ohdr.tsize = data_start - f_ohdr.text_start;
380 f_ohdr.data_start = data_start;
381 #endif /* NO_REMAP */
382 f_ohdr.dsize = bss_start - f_ohdr.data_start;
383 f_ohdr.bsize = bss_end - bss_start;
384 /* On some machines, the old values are right.
385 ??? Maybe on all machines with NO_REMAP. */
386 f_thdr.s_size = f_ohdr.tsize;
387 f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
388 f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
389 lnnoptr = f_thdr.s_lnnoptr;
390 #ifdef SECTION_ALIGNMENT
391 /* Some systems require special alignment
392 of the sections in the file itself. */
393 f_thdr.s_scnptr
394 = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
395 #endif /* SECTION_ALIGNMENT */
396 text_scnptr = f_thdr.s_scnptr;
397 f_dhdr.s_paddr = f_ohdr.data_start;
398 f_dhdr.s_vaddr = f_ohdr.data_start;
399 f_dhdr.s_size = f_ohdr.dsize;
400 f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
401 #ifdef SECTION_ALIGNMENT
402 /* Some systems require special alignment
403 of the sections in the file itself. */
404 f_dhdr.s_scnptr
405 = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT;
406 #endif /* SECTION_ALIGNMENT */
407 #ifdef DATA_SECTION_ALIGNMENT
408 /* Some systems require special alignment
409 of the data section only. */
410 f_dhdr.s_scnptr
411 = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT;
412 #endif /* DATA_SECTION_ALIGNMENT */
413 data_scnptr = f_dhdr.s_scnptr;
414 f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
415 f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
416 f_bhdr.s_size = f_ohdr.bsize;
417 f_bhdr.s_scnptr = 0L;
418 bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
419
420 if (f_hdr.f_symptr > 0L)
421 {
422 f_hdr.f_symptr += bias;
423 }
424
425 if (f_thdr.s_lnnoptr > 0L)
426 {
427 f_thdr.s_lnnoptr += bias;
428 }
429
430 #ifdef ADJUST_EXEC_HEADER
431 ADJUST_EXEC_HEADER;
432 #endif /* ADJUST_EXEC_HEADER */
433
434 if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
435 {
436 PERROR (new_name);
437 }
438
439 if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
440 {
441 PERROR (new_name);
442 }
443
444 if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
445 {
446 PERROR (new_name);
447 }
448
449 if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
450 {
451 PERROR (new_name);
452 }
453
454 if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
455 {
456 PERROR (new_name);
457 }
458
459 return (0);
460
461 }
462 \f
463 write_segment (new, ptr, end)
464 int new;
465 register char *ptr, *end;
466 {
467 register int i, nwrite, ret;
468 char buf[80];
469 #ifndef USE_CRT_DLL
470 extern int errno;
471 #endif
472 /* This is the normal amount to write at once.
473 It is the size of block that NFS uses. */
474 int writesize = 1 << 13;
475 int pagesize = getpagesize ();
476 char zeros[1 << 13];
477
478 bzero (zeros, sizeof (zeros));
479
480 for (i = 0; ptr < end;)
481 {
482 /* Distance to next multiple of writesize. */
483 nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr;
484 /* But not beyond specified end. */
485 if (nwrite > end - ptr) nwrite = end - ptr;
486 ret = write (new, ptr, nwrite);
487 /* If write gets a page fault, it means we reached
488 a gap between the old text segment and the old data segment.
489 This gap has probably been remapped into part of the text segment.
490 So write zeros for it. */
491 if (ret == -1
492 #ifdef EFAULT
493 && errno == EFAULT
494 #endif
495 )
496 {
497 /* Write only a page of zeros at once,
498 so that we don't overshoot the start
499 of the valid memory in the old data segment. */
500 if (nwrite > pagesize)
501 nwrite = pagesize;
502 write (new, zeros, nwrite);
503 }
504 #if 0 /* Now that we have can ask `write' to write more than a page,
505 it is legit for write do less than the whole amount specified. */
506 else if (nwrite != ret)
507 {
508 sprintf (buf,
509 "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
510 ptr, new, nwrite, ret, errno);
511 PERROR (buf);
512 }
513 #endif
514 i += nwrite;
515 ptr += nwrite;
516 }
517 }
518 /* ****************************************************************
519 * copy_text_and_data
520 *
521 * Copy the text and data segments from memory to the new a.out
522 */
523 static int
524 copy_text_and_data (new, a_out)
525 int new, a_out;
526 {
527 register char *end;
528 register char *ptr;
529
530 #ifdef MSDOS
531 /* Dump the original table of exception handlers, not the one
532 where our exception hooks are registered. */
533 __djgpp_exception_toggle ();
534
535 /* Switch off startup flags that might have been set at runtime
536 and which might change the way that dumped Emacs works. */
537 save_djgpp_startup_flags = _crt0_startup_flags;
538 _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR);
539 #endif
540
541 lseek (new, (long) text_scnptr, 0);
542 ptr = (char *) f_ohdr.text_start;
543 end = ptr + f_ohdr.tsize;
544 write_segment (new, ptr, end);
545
546 lseek (new, (long) data_scnptr, 0);
547 ptr = (char *) f_ohdr.data_start;
548 end = ptr + f_ohdr.dsize;
549 write_segment (new, ptr, end);
550
551 #ifdef MSDOS
552 /* Restore our exception hooks. */
553 __djgpp_exception_toggle ();
554
555 /* Restore the startup flags. */
556 _crt0_startup_flags = save_djgpp_startup_flags;
557 #endif
558
559
560 return 0;
561 }
562 \f
563 /* ****************************************************************
564 * copy_sym
565 *
566 * Copy the relocation information and symbol table from the a.out to the new
567 */
568 static int
569 copy_sym (new, a_out, a_name, new_name)
570 int new, a_out;
571 char *a_name, *new_name;
572 {
573 char page[1024];
574 int n;
575
576 if (a_out < 0)
577 return 0;
578
579 if (SYMS_START == 0L)
580 return 0;
581
582 if (lnnoptr) /* if there is line number info */
583 lseek (a_out, coff_offset + lnnoptr, 0); /* start copying from there */
584 else
585 lseek (a_out, coff_offset + SYMS_START, 0); /* Position a.out to symtab. */
586
587 while ((n = read (a_out, page, sizeof page)) > 0)
588 {
589 if (write (new, page, n) != n)
590 {
591 PERROR (new_name);
592 }
593 }
594 if (n < 0)
595 {
596 PERROR (a_name);
597 }
598 return 0;
599 }
600 \f
601 /* ****************************************************************
602 * mark_x
603 *
604 * After successfully building the new a.out, mark it executable
605 */
606 static void
607 mark_x (name)
608 char *name;
609 {
610 struct stat sbuf;
611 int um;
612 int new = 0; /* for PERROR */
613
614 um = umask (777);
615 umask (um);
616 if (stat (name, &sbuf) == -1)
617 {
618 PERROR (name);
619 }
620 sbuf.st_mode |= 0111 & ~um;
621 if (chmod (name, sbuf.st_mode) == -1)
622 PERROR (name);
623 }
624 \f
625
626 /*
627 * If the COFF file contains a symbol table and a line number section,
628 * then any auxiliary entries that have values for x_lnnoptr must
629 * be adjusted by the amount that the line number section has moved
630 * in the file (bias computed in make_hdr). The #@$%&* designers of
631 * the auxiliary entry structures used the absolute file offsets for
632 * the line number entry rather than an offset from the start of the
633 * line number section!
634 *
635 * When I figure out how to scan through the symbol table and pick out
636 * the auxiliary entries that need adjustment, this routine will
637 * be fixed. As it is now, all such entries are wrong and sdb
638 * will complain. Fred Fish, UniSoft Systems Inc.
639 */
640
641 /* This function is probably very slow. Instead of reopening the new
642 file for input and output it should copy from the old to the new
643 using the two descriptors already open (WRITEDESC and READDESC).
644 Instead of reading one small structure at a time it should use
645 a reasonable size buffer. But I don't have time to work on such
646 things, so I am installing it as submitted to me. -- RMS. */
647
648 adjust_lnnoptrs (writedesc, readdesc, new_name)
649 int writedesc;
650 int readdesc;
651 char *new_name;
652 {
653 register int nsyms;
654 register int new;
655 struct syment symentry;
656 union auxent auxentry;
657
658 if (!lnnoptr || !f_hdr.f_symptr)
659 return 0;
660
661 #ifdef MSDOS
662 if ((new = writedesc) < 0)
663 #else
664 if ((new = open (new_name, O_RDWR)) < 0)
665 #endif
666 {
667 PERROR (new_name);
668 return -1;
669 }
670
671 lseek (new, f_hdr.f_symptr, 0);
672 for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
673 {
674 read (new, &symentry, SYMESZ);
675 if (symentry.n_numaux)
676 {
677 read (new, &auxentry, AUXESZ);
678 nsyms++;
679 if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400)
680 {
681 auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
682 lseek (new, -AUXESZ, 1);
683 write (new, &auxentry, AUXESZ);
684 }
685 }
686 }
687 #ifndef MSDOS
688 close (new);
689 #endif
690 return 0;
691 }
692
693 /* ****************************************************************
694 * unexec
695 *
696 * driving logic.
697 */
698 unexec (new_name, a_name, data_start, bss_start, entry_address)
699 char *new_name, *a_name;
700 unsigned data_start, bss_start, entry_address;
701 {
702 int new, a_out = -1;
703
704 if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
705 {
706 PERROR (a_name);
707 }
708 if ((new = creat (new_name, 0666)) < 0)
709 {
710 PERROR (new_name);
711 }
712
713 if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
714 || copy_text_and_data (new, a_out) < 0
715 || copy_sym (new, a_out, a_name, new_name) < 0
716 || adjust_lnnoptrs (new, a_out, new_name) < 0
717 )
718 {
719 close (new);
720 /* unlink (new_name); /* Failed, unlink new a.out */
721 return -1;
722 }
723
724 close (new);
725 if (a_out >= 0)
726 close (a_out);
727 mark_x (new_name);
728 return 0;
729 }
730
731 #endif /* not CANNOT_DUMP */
732
733 /* arch-tag: 62409b69-e27a-4a7c-9413-0210d6b54e7f
734 (do not change this comment) */