comparison src/unexaix.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children e45d5e7c476e
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
2
3 This file is part of XEmacs.
4
5 XEmacs is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
9
10 XEmacs is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with XEmacs; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 /* Synched up with: FSF 19.31. */
21
22 /* Modified by Andrew.Vignaux@comp.vuw.ac.nz to get it to work :-) */
23
24 /*
25 * unexec.c - Convert a running program into an a.out file.
26 *
27 * Author: Spencer W. Thomas
28 * Computer Science Dept.
29 * University of Utah
30 * Date: Tue Mar 2 1982
31 * Modified heavily since then.
32 *
33 * Updated for AIX 4.1.3 by Bill_Mann @ PraxisInt.com, Feb 1996
34 * As of AIX 4.1, text, data, and bss are pre-relocated by the binder in
35 * such a way that the file can be mapped with code in one segment and
36 * data/bss in another segment, without reading or copying the file, by
37 * the AIX exec loader. Padding sections are omitted, nevertheless
38 * small amounts of 'padding' still occurs between sections in the file.
39 * As modified, this code handles both 3.2 and 4.1 conventions.
40 *
41 * Synopsis:
42 * unexec (new_name, a_name, data_start, bss_start, entry_address)
43 * char *new_name, *a_name;
44 * unsigned data_start, bss_start, entry_address;
45 *
46 * Takes a snapshot of the program and makes an a.out format file in the
47 * file named by the string argument new_name.
48 * If a_name is non-NULL, the symbol table will be taken from the given file.
49 * On some machines, an existing a_name file is required.
50 *
51 * The boundaries within the a.out file may be adjusted with the data_start
52 * and bss_start arguments. Either or both may be given as 0 for defaults.
53 *
54 * Data_start gives the boundary between the text segment and the data
55 * segment of the program. The text segment can contain shared, read-only
56 * program code and literal data, while the data segment is always unshared
57 * and unprotected. Data_start gives the lowest unprotected address.
58 * The value you specify may be rounded down to a suitable boundary
59 * as required by the machine you are using.
60 *
61 * Specifying zero for data_start means the boundary between text and data
62 * should not be the same as when the program was loaded.
63 * If NO_REMAP is defined, the argument data_start is ignored and the
64 * segment boundaries are never changed.
65 *
66 * Bss_start indicates how much of the data segment is to be saved in the
67 * a.out file and restored when the program is executed. It gives the lowest
68 * unsaved address, and is rounded up to a page boundary. The default when 0
69 * is given assumes that the entire data segment is to be stored, including
70 * the previous data and bss as well as any additional storage allocated with
71 * break (2).
72 *
73 * The new file is set up to start at entry_address.
74 *
75 * If you make improvements I'd like to get them too.
76 * harpo!utah-cs!thomas, thomas@Utah-20
77 *
78 */
79
80 /* There are several compilation parameters affecting unexec:
81
82 * COFF
83
84 Define this if your system uses COFF for executables.
85 Otherwise we assume you use Berkeley format.
86
87 * NO_REMAP
88
89 Define this if you do not want to try to save Emacs's pure data areas
90 as part of the text segment.
91
92 Saving them as text is good because it allows users to share more.
93
94 However, on machines that locate the text area far from the data area,
95 the boundary cannot feasibly be moved. Such machines require
96 NO_REMAP.
97
98 Also, remapping can cause trouble with the built-in startup routine
99 /lib/crt0.o, which defines `environ' as an initialized variable.
100 Dumping `environ' as pure does not work! So, to use remapping,
101 you must write a startup routine for your machine in Emacs's crt0.c.
102 If NO_REMAP is defined, Emacs uses the system's crt0.o.
103
104 * SECTION_ALIGNMENT
105
106 Some machines that use COFF executables require that each section
107 start on a certain boundary *in the COFF file*. Such machines should
108 define SECTION_ALIGNMENT to a mask of the low-order bits that must be
109 zero on such a boundary. This mask is used to control padding between
110 segments in the COFF file.
111
112 If SECTION_ALIGNMENT is not defined, the segments are written
113 consecutively with no attempt at alignment. This is right for
114 unmodified system V.
115
116 * SEGMENT_MASK
117
118 Some machines require that the beginnings and ends of segments
119 *in core* be on certain boundaries. For most machines, a page
120 boundary is sufficient. That is the default. When a larger
121 boundary is needed, define SEGMENT_MASK to a mask of
122 the bits that must be zero on such a boundary.
123
124 * A_TEXT_OFFSET(HDR)
125
126 Some machines count the a.out header as part of the size of the text
127 segment (a_text); they may actually load the header into core as the
128 first data in the text segment. Some have additional padding between
129 the header and the real text of the program that is counted in a_text.
130
131 For these machines, define A_TEXT_OFFSET(HDR) to examine the header
132 structure HDR and return the number of bytes to add to `a_text'
133 before writing it (above and beyond the number of bytes of actual
134 program text). HDR's standard fields are already correct, except that
135 this adjustment to the `a_text' field has not yet been made;
136 thus, the amount of offset can depend on the data in the file.
137
138 * A_TEXT_SEEK(HDR)
139
140 If defined, this macro specifies the number of bytes to seek into the
141 a.out file before starting to write the text segment.a
142
143 * EXEC_MAGIC
144
145 For machines using COFF, this macro, if defined, is a value stored
146 into the magic number field of the output file.
147
148 * ADJUST_EXEC_HEADER
149
150 This macro can be used to generate statements to adjust or
151 initialize nonstandard fields in the file header
152
153 * ADDR_CORRECT(ADDR)
154
155 Macro to correct an int which is the bit pattern of a pointer to a byte
156 into an int which is the number of a byte.
157
158 This macro has a default definition which is usually right.
159 This default definition is a no-op on most machines (where a
160 pointer looks like an int) but not on all machines.
161
162 */
163
164 #define XCOFF
165 #define COFF
166 #define NO_REMAP
167
168 #ifndef emacs
169 #define PERROR(arg) perror (arg); return -1
170 #else
171 #include <config.h>
172 #define PERROR(file) report_error (file, new)
173 #endif
174
175 #include <a.out.h>
176 /* Define getpagesize () if the system does not.
177 Note that this may depend on symbols defined in a.out.h
178 */
179 #include "getpagesize.h"
180
181 #ifndef makedev /* Try to detect types.h already loaded */
182 #include <sys/types.h>
183 #endif
184 #include <stdio.h>
185 #include <sys/stat.h>
186 #include <errno.h>
187
188 extern char *start_of_text (); /* Start of text */
189 extern char *start_of_data (); /* Start of initialized data */
190
191 extern int _data;
192 extern int _edata;
193 extern int _text;
194 extern int _etext;
195 extern int _end;
196 #ifdef COFF
197 #ifndef USG
198 #ifndef STRIDE
199 #ifndef UMAX
200 #ifndef sun386
201 /* I have a suspicion that these are turned off on all systems
202 and can be deleted. Try it in version 19. */
203 #include <filehdr.h>
204 #include <aouthdr.h>
205 #include <scnhdr.h>
206 #include <syms.h>
207 #endif /* not sun386 */
208 #endif /* not UMAX */
209 #endif /* Not STRIDE */
210 #endif /* not USG */
211 static struct filehdr f_hdr; /* File header */
212 static struct aouthdr f_ohdr; /* Optional file header (a.out) */
213 long bias; /* Bias to add for growth */
214 long lnnoptr; /* Pointer to line-number info within file */
215
216 static long text_scnptr;
217 static long data_scnptr;
218 #ifdef XCOFF
219 #define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1))
220 static long load_scnptr;
221 static long orig_load_scnptr;
222 static long orig_data_scnptr;
223 #endif
224 static ulong data_st; /* start of data area written out */
225
226 #ifndef MAX_SECTIONS
227 #define MAX_SECTIONS 10
228 #endif
229
230 #endif /* COFF */
231
232 static int pagemask;
233
234 /* Correct an int which is the bit pattern of a pointer to a byte
235 into an int which is the number of a byte.
236 This is a no-op on ordinary machines, but not on all. */
237
238 #ifndef ADDR_CORRECT /* Let m-*.h files override this definition */
239 #define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
240 #endif
241
242 #ifdef emacs
243 #include "lisp.h"
244
245 static
246 report_error (file, fd)
247 char *file;
248 int fd;
249 {
250 if (fd)
251 close (fd);
252 report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
253 }
254 #endif /* emacs */
255
256 #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
257 #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
258 #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
259
260 static
261 report_error_1 (fd, msg, a1, a2)
262 int fd;
263 char *msg;
264 int a1, a2;
265 {
266 close (fd);
267 #ifdef emacs
268 error (msg, a1, a2);
269 #else
270 fprintf (stderr, msg, a1, a2);
271 fprintf (stderr, "\n");
272 #endif
273 }
274
275 static int make_hdr ();
276 static void mark_x ();
277 static int copy_text_and_data ();
278 static int copy_sym ();
279
280 /* ****************************************************************
281 * unexec
282 *
283 * driving logic.
284 */
285 unexec (new_name, a_name, data_start, bss_start, entry_address)
286 char *new_name, *a_name;
287 unsigned data_start, bss_start, entry_address;
288 {
289 int new, a_out = -1;
290
291 if (a_name && (a_out = open (a_name, 0)) < 0)
292 {
293 PERROR (a_name);
294 }
295 if ((new = creat (new_name, 0666)) < 0)
296 {
297 PERROR (new_name);
298 }
299 if (make_hdr (new,a_out,data_start,bss_start,entry_address,a_name,new_name) < 0
300 || copy_text_and_data (new) < 0
301 || copy_sym (new, a_out, a_name, new_name) < 0
302 #ifdef COFF
303 || adjust_lnnoptrs (new, a_out, new_name) < 0
304 #endif
305 #ifdef XCOFF
306 || unrelocate_symbols (new, a_out, a_name, new_name) < 0
307 #endif
308 )
309 {
310 close (new);
311 /* unlink (new_name); /* Failed, unlink new a.out */
312 return -1;
313 }
314
315 close (new);
316 if (a_out >= 0)
317 close (a_out);
318 mark_x (new_name);
319 return 0;
320 }
321
322 /* ****************************************************************
323 * make_hdr
324 *
325 * Make the header in the new a.out from the header in core.
326 * Modify the text and data sizes.
327 */
328 static int
329 make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
330 int new, a_out;
331 unsigned data_start, bss_start, entry_address;
332 char *a_name;
333 char *new_name;
334 {
335 int scns;
336 unsigned int bss_end;
337
338 struct scnhdr section[MAX_SECTIONS];
339 struct scnhdr * f_thdr; /* Text section header */
340 struct scnhdr * f_dhdr; /* Data section header */
341 struct scnhdr * f_bhdr; /* Bss section header */
342 struct scnhdr * f_lhdr; /* Loader section header */
343 struct scnhdr * f_tchdr; /* Typechk section header */
344 struct scnhdr * f_dbhdr; /* Debug section header */
345 struct scnhdr * f_xhdr; /* Except section header */
346
347 load_scnptr = orig_load_scnptr = lnnoptr = 0;
348 pagemask = getpagesize () - 1;
349
350 /* Adjust text/data boundary. */
351 #ifdef NO_REMAP
352 data_start = (long) start_of_data ();
353 #endif /* NO_REMAP */
354 data_start = ADDR_CORRECT (data_start);
355
356 #ifdef SEGMENT_MASK
357 data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */
358 #else
359 data_start = data_start & ~pagemask; /* (Down) to page boundary. */
360 #endif
361
362
363 bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
364 bss_end &= ~ pagemask;
365 /* Adjust data/bss boundary. */
366 if (bss_start != 0)
367 {
368 bss_start = (ADDR_CORRECT (bss_start) + pagemask);
369 /* (Up) to page bdry. */
370 bss_start &= ~ pagemask;
371 if (bss_start > bss_end)
372 {
373 ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
374 bss_start);
375 }
376 }
377 else
378 bss_start = bss_end;
379
380 if (data_start > bss_start) /* Can't have negative data size. */
381 {
382 ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
383 data_start, bss_start);
384 }
385
386 #ifdef COFF
387 /* Salvage as much info from the existing file as possible */
388 f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL;
389 f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL;
390 if (a_out >= 0)
391 {
392 if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
393 {
394 PERROR (a_name);
395 }
396 if (f_hdr.f_opthdr > 0)
397 {
398 if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
399 {
400 PERROR (a_name);
401 }
402 }
403 if (f_hdr.f_nscns > MAX_SECTIONS)
404 {
405 ERROR0 ("unexec: too many section headers -- increase MAX_SECTIONS");
406 }
407 /* Loop through section headers */
408 for (scns = 0; scns < f_hdr.f_nscns; scns++) {
409 struct scnhdr *s = &section[scns];
410 if (read (a_out, s, sizeof (*s)) != sizeof (*s))
411 {
412 PERROR (a_name);
413 }
414
415 #define CHECK_SCNHDR(ptr, name, flags) \
416 if (strcmp(s->s_name, name) == 0) { \
417 if (s->s_flags != flags) { \
418 fprintf(stderr, "unexec: %lx flags where %x expected in %s section.\n", \
419 (unsigned long)s->s_flags, flags, name); \
420 } \
421 if (ptr) { \
422 fprintf(stderr, "unexec: duplicate section header for section %s.\n", \
423 name); \
424 } \
425 ptr = s; \
426 }
427 CHECK_SCNHDR(f_thdr, _TEXT, STYP_TEXT);
428 CHECK_SCNHDR(f_dhdr, _DATA, STYP_DATA);
429 CHECK_SCNHDR(f_bhdr, _BSS, STYP_BSS);
430 CHECK_SCNHDR(f_lhdr, _LOADER, STYP_LOADER);
431 CHECK_SCNHDR(f_dbhdr, _DEBUG, STYP_DEBUG);
432 CHECK_SCNHDR(f_tchdr, _TYPCHK, STYP_TYPCHK);
433 CHECK_SCNHDR(f_xhdr, _EXCEPT, STYP_EXCEPT);
434 }
435
436 if (f_thdr == 0)
437 {
438 ERROR1 ("unexec: couldn't find \"%s\" section", _TEXT);
439 }
440 if (f_dhdr == 0)
441 {
442 ERROR1 ("unexec: couldn't find \"%s\" section", _DATA);
443 }
444 if (f_bhdr == 0)
445 {
446 ERROR1 ("unexec: couldn't find \"%s\" section", _BSS);
447 }
448 }
449 else
450 {
451 ERROR0 ("can't build a COFF file from scratch yet");
452 }
453 orig_data_scnptr = f_dhdr->s_scnptr;
454 orig_load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;
455
456 /* Now we alter the contents of all the f_*hdr variables
457 to correspond to what we want to dump. */
458
459 /* Indicate that the reloc information is no longer valid for ld (bind);
460 we only update it enough to fake out the exec-time loader. */
461 f_hdr.f_flags |= (F_RELFLG | F_EXEC);
462
463 #ifdef EXEC_MAGIC
464 f_ohdr.magic = EXEC_MAGIC;
465 #endif
466 #ifndef NO_REMAP
467 f_ohdr.tsize = data_start - f_ohdr.text_start;
468 f_ohdr.text_start = (long) start_of_text ();
469 #endif
470 data_st = f_ohdr.data_start ? f_ohdr.data_start : (ulong) &_data;
471 f_ohdr.dsize = bss_start - data_st;
472 f_ohdr.bsize = bss_end - bss_start;
473
474 f_dhdr->s_size = f_ohdr.dsize;
475 f_bhdr->s_size = f_ohdr.bsize;
476 f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize;
477 f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
478
479 /* fix scnptr's */
480 {
481 ulong ptr = section[0].s_scnptr;
482
483 bias = -1;
484 for (scns = 0; scns < f_hdr.f_nscns; scns++)
485 {
486 struct scnhdr *s = &section[scns];
487
488 if (s->s_flags & STYP_PAD) /* .pad sections omitted in AIX 4.1 */
489 {
490 /*
491 * the text_start should probably be o_algntext but that doesn't
492 * seem to change
493 */
494 if (f_ohdr.text_start != 0) /* && scns != 0 */
495 {
496 s->s_size = 512 - (ptr % 512);
497 if (s->s_size == 512)
498 s->s_size = 0;
499 }
500 s->s_scnptr = ptr;
501 }
502 else if (s->s_flags & STYP_DATA)
503 s->s_scnptr = ptr;
504 else if (!(s->s_flags & (STYP_TEXT | STYP_BSS)))
505 {
506 if (bias == -1) /* if first section after bss */
507 bias = ptr - s->s_scnptr;
508
509 s->s_scnptr += bias;
510 ptr = s->s_scnptr;
511 }
512
513 ptr = ptr + s->s_size;
514 }
515 }
516
517 /* fix other pointers */
518 for (scns = 0; scns < f_hdr.f_nscns; scns++)
519 {
520 struct scnhdr *s = &section[scns];
521
522 if (s->s_relptr != 0)
523 {
524 s->s_relptr += bias;
525 }
526 if (s->s_lnnoptr != 0)
527 {
528 if (lnnoptr == 0) lnnoptr = s->s_lnnoptr;
529 s->s_lnnoptr += bias;
530 }
531 }
532
533 if (f_hdr.f_symptr > 0L)
534 {
535 f_hdr.f_symptr += bias;
536 }
537
538 text_scnptr = f_thdr->s_scnptr;
539 data_scnptr = f_dhdr->s_scnptr;
540 load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;
541
542 #ifdef ADJUST_EXEC_HEADER
543 ADJUST_EXEC_HEADER
544 #endif /* ADJUST_EXEC_HEADER */
545
546 if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
547 {
548 PERROR (new_name);
549 }
550
551 if (f_hdr.f_opthdr > 0)
552 {
553 if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
554 {
555 PERROR (new_name);
556 }
557 }
558
559 for (scns = 0; scns < f_hdr.f_nscns; scns++) {
560 struct scnhdr *s = &section[scns];
561 if (write (new, s, sizeof (*s)) != sizeof (*s))
562 {
563 PERROR (new_name);
564 }
565 }
566
567 return (0);
568
569 #endif /* COFF */
570 }
571
572 /* ****************************************************************
573
574 *
575 * Copy the text and data segments from memory to the new a.out
576 */
577 static int
578 copy_text_and_data (new)
579 int new;
580 {
581 char *end;
582 char *ptr;
583
584 lseek (new, (long) text_scnptr, 0);
585 ptr = start_of_text () + text_scnptr;
586 end = ptr + f_ohdr.tsize;
587 write_segment (new, ptr, end);
588
589 lseek (new, (long) data_scnptr, 0);
590 ptr = (char *) data_st;
591 end = ptr + f_ohdr.dsize;
592 write_segment (new, ptr, end);
593
594 return 0;
595 }
596
597 #define UnexBlockSz (1<<12) /* read/write block size */
598 write_segment (new, ptr, end)
599 int new;
600 char *ptr, *end;
601 {
602 int i, nwrite, ret;
603 char buf[80];
604 extern int errno;
605 char zeros[UnexBlockSz];
606
607 for (i = 0; ptr < end;)
608 {
609 /* distance to next block. */
610 nwrite = (((int) ptr + UnexBlockSz) & -UnexBlockSz) - (int) ptr;
611 /* But not beyond specified end. */
612 if (nwrite > end - ptr) nwrite = end - ptr;
613 ret = write (new, ptr, nwrite);
614 /* If write gets a page fault, it means we reached
615 a gap between the old text segment and the old data segment.
616 This gap has probably been remapped into part of the text segment.
617 So write zeros for it. */
618 if (ret == -1 && errno == EFAULT)
619 {
620 bzero (zeros, nwrite);
621 write (new, zeros, nwrite);
622 }
623 else if (nwrite != ret)
624 {
625 sprintf (buf,
626 "unexec write failure: addr 0x%lx, fileno %d, size 0x%x, wrote 0x%x, errno %d",
627 (unsigned long)ptr, new, nwrite, ret, errno);
628 PERROR (buf);
629 }
630 i += nwrite;
631 ptr += nwrite;
632 }
633 }
634
635 /* ****************************************************************
636 * copy_sym
637 *
638 * Copy the relocation information and symbol table from the a.out to the new
639 */
640 static int
641 copy_sym (new, a_out, a_name, new_name)
642 int new, a_out;
643 char *a_name, *new_name;
644 {
645 char page[UnexBlockSz];
646 int n;
647
648 if (a_out < 0)
649 return 0;
650
651 if (orig_load_scnptr == 0L)
652 return 0;
653
654 if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info */
655 lseek (a_out, lnnoptr, 0); /* start copying from there */
656 else
657 lseek (a_out, orig_load_scnptr, 0); /* Position a.out to symtab. */
658
659 while ((n = read (a_out, page, sizeof page)) > 0)
660 {
661 if (write (new, page, n) != n)
662 {
663 PERROR (new_name);
664 }
665 }
666 if (n < 0)
667 {
668 PERROR (a_name);
669 }
670 return 0;
671 }
672
673 /* ****************************************************************
674 * mark_x
675 *
676 * After successfully building the new a.out, mark it executable
677 */
678 static void
679 mark_x (name)
680 char *name;
681 {
682 struct stat sbuf;
683 int um;
684 int new = 0; /* for PERROR */
685
686 um = umask (777);
687 umask (um);
688 if (stat (name, &sbuf) == -1)
689 {
690 PERROR (name);
691 }
692 sbuf.st_mode |= 0111 & ~um;
693 if (chmod (name, sbuf.st_mode) == -1)
694 PERROR (name);
695 }
696
697 /*
698 * If the COFF file contains a symbol table and a line number section,
699 * then any auxiliary entries that have values for x_lnnoptr must
700 * be adjusted by the amount that the line number section has moved
701 * in the file (bias computed in make_hdr). The #@$%&* designers of
702 * the auxiliary entry structures used the absolute file offsets for
703 * the line number entry rather than an offset from the start of the
704 * line number section!
705 *
706 * When I figure out how to scan through the symbol table and pick out
707 * the auxiliary entries that need adjustment, this routine will
708 * be fixed. As it is now, all such entries are wrong and sdb
709 * will complain. Fred Fish, UniSoft Systems Inc.
710 *
711 * I believe this is now fixed correctly. Bill Mann
712 */
713
714 #ifdef COFF
715
716 /* This function is probably very slow. Instead of reopening the new
717 file for input and output it should copy from the old to the new
718 using the two descriptors already open (WRITEDESC and READDESC).
719 Instead of reading one small structure at a time it should use
720 a reasonable size buffer. But I don't have time to work on such
721 things, so I am installing it as submitted to me. -- RMS. */
722
723 adjust_lnnoptrs (writedesc, readdesc, new_name)
724 int writedesc;
725 int readdesc;
726 char *new_name;
727 {
728 int nsyms;
729 int naux;
730 int new;
731 #ifdef amdahl_uts
732 SYMENT symentry;
733 AUXENT auxentry;
734 #else
735 struct syment symentry;
736 union auxent auxentry;
737 #endif
738
739 if (!lnnoptr || !f_hdr.f_symptr)
740 return 0;
741
742 if ((new = open (new_name, 2)) < 0)
743 {
744 PERROR (new_name);
745 return -1;
746 }
747
748 lseek (new, f_hdr.f_symptr, 0);
749 for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
750 {
751 read (new, &symentry, SYMESZ);
752 if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL)
753 {
754 symentry.n_value += bias;
755 lseek (new, -SYMESZ, 1);
756 write (new, &symentry, SYMESZ);
757 }
758
759 for (naux = symentry.n_numaux; naux-- != 0; )
760 {
761 read (new, &auxentry, AUXESZ);
762 nsyms++;
763 if (naux != 0 /* skip csect auxentry (last entry) */
764 && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT))
765 {
766 auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
767 lseek (new, -AUXESZ, 1);
768 write (new, &auxentry, AUXESZ);
769 }
770 }
771 }
772 close (new);
773 }
774
775 #endif /* COFF */
776
777 #ifdef XCOFF
778
779 /* It is probably a false economy to optimise this routine (it used to
780 read one LDREL and do do two lseeks per iteration) but the wrath of
781 RMS (see above :-) would be too much to bear */
782
783 unrelocate_symbols (new, a_out, a_name, new_name)
784 int new, a_out;
785 char *a_name, *new_name;
786 {
787 int i;
788 int l;
789 LDREL *ldrel;
790 LDHDR ldhdr;
791 LDREL ldrel_buf [20];
792 ulong t_reloc = (ulong) &_text - f_ohdr.text_start;
793 ulong d_reloc = (ulong) &_data - ALIGN(f_ohdr.data_start, 2);
794 int * p;
795
796 if (load_scnptr == 0)
797 return 0;
798
799 lseek (a_out, orig_load_scnptr, 0);
800 if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr))
801 {
802 PERROR (new_name);
803 }
804
805 #define SYMNDX_TEXT 0
806 #define SYMNDX_DATA 1
807 #define SYMNDX_BSS 2
808 l = 0;
809 for (i = 0; i < ldhdr.l_nreloc; i++, l--, ldrel++)
810 {
811 if (l == 0) {
812 lseek (a_out,
813 orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
814 0);
815
816 l = ldhdr.l_nreloc - i;
817 if (l > sizeof (ldrel_buf) / LDRELSZ)
818 l = sizeof (ldrel_buf) / LDRELSZ;
819
820 if (read (a_out, ldrel_buf, l * LDRELSZ) != l * LDRELSZ)
821 {
822 PERROR (a_name);
823 }
824 ldrel = ldrel_buf;
825 }
826
827 /* move the BSS loader symbols to the DATA segment */
828 if (ldrel->l_symndx == SYMNDX_BSS)
829 {
830 ldrel->l_symndx = SYMNDX_DATA;
831
832 lseek (new,
833 load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
834 0);
835
836 if (write (new, ldrel, LDRELSZ) != LDRELSZ)
837 {
838 PERROR (new_name);
839 }
840 }
841
842 if (ldrel->l_rsecnm == f_ohdr.o_sndata)
843 {
844 int orig_int;
845
846 lseek (a_out,
847 orig_data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0);
848
849 if (read (a_out, (void *) &orig_int, sizeof (orig_int))
850 != sizeof (orig_int))
851 {
852 PERROR (a_name);
853 }
854
855 p = (int *) (ldrel->l_vaddr + d_reloc);
856
857 switch (ldrel->l_symndx) {
858 case SYMNDX_TEXT:
859 orig_int = * p - t_reloc;
860 break;
861
862 case SYMNDX_DATA:
863 case SYMNDX_BSS:
864 orig_int = * p - d_reloc;
865 break;
866 }
867
868 if (orig_int != * p)
869 {
870 lseek (new,
871 data_scnptr + (ldrel->l_vaddr - f_ohdr.data_start), 0);
872 if (write (new, (void *) &orig_int, sizeof (orig_int))
873 != sizeof (orig_int))
874 {
875 PERROR (new_name);
876 }
877 }
878 }
879 }
880 }
881 #endif /* XCOFF */