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