Mercurial > hg > xemacs-beta
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 = §ion[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 = §ion[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 = §ion[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 = §ion[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 */ |