Commit | Line | Data |
---|---|---|
0248680a | 1 | /* Dump an executable image. |
ab422c4d PE |
2 | Copyright (C) 1985-1988, 1999, 2001-2013 Free Software Foundation, |
3 | Inc. | |
4e3a36cd | 4 | |
3b7ad313 EN |
5 | This file is part of GNU Emacs. |
6 | ||
9ec0b715 | 7 | GNU Emacs is free software: you can redistribute it and/or modify |
3b7ad313 | 8 | it under the terms of the GNU General Public License as published by |
9ec0b715 GM |
9 | the Free Software Foundation, either version 3 of the License, or |
10 | (at your option) any later version. | |
3b7ad313 EN |
11 | |
12 | GNU Emacs is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
9ec0b715 | 18 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ |
4e3a36cd | 19 | |
9ec0b715 | 20 | /* |
4e3a36cd JB |
21 | In other words, you are welcome to use, share and improve this program. |
22 | You are forbidden to forbid anyone else to use, share and improve | |
23 | what you give them. Help stamp out software-hoarding! */ | |
24 | ||
25 | ||
0248680a | 26 | /* Originally based on the COFF unexec.c by Spencer W. Thomas. |
4e3a36cd | 27 | * |
0248680a DL |
28 | * Subsequently hacked on by |
29 | * Bill Mann <Bill_Man@praxisint.com> | |
30 | * Andrew Vignaux <Andrew.Vignaux@comp.vuw.ac.nz> | |
31 | * Mike Sperber <sperber@informatik.uni-tuebingen.de> | |
4a438fc5 | 32 | * |
4e3a36cd | 33 | * Synopsis: |
dd5ecd6b | 34 | * unexec (const char *new_name, const *old_name); |
4e3a36cd JB |
35 | * |
36 | * Takes a snapshot of the program and makes an a.out format file in the | |
37 | * file named by the string argument new_name. | |
38 | * If a_name is non-NULL, the symbol table will be taken from the given file. | |
39 | * On some machines, an existing a_name file is required. | |
40 | * | |
4e3a36cd JB |
41 | */ |
42 | ||
18160b98 | 43 | #include <config.h> |
ce701a33 | 44 | #include "unexec.h" |
406af475 | 45 | #include "lisp.h" |
ce701a33 | 46 | |
4e3a36cd | 47 | #define PERROR(file) report_error (file, new) |
4e3a36cd JB |
48 | #include <a.out.h> |
49 | /* Define getpagesize () if the system does not. | |
50 | Note that this may depend on symbols defined in a.out.h | |
51 | */ | |
52 | #include "getpagesize.h" | |
76998edb | 53 | |
4e3a36cd | 54 | #include <sys/types.h> |
227be86d PE |
55 | #include <inttypes.h> |
56 | #include <stdarg.h> | |
4e3a36cd JB |
57 | #include <stdio.h> |
58 | #include <sys/stat.h> | |
59 | #include <errno.h> | |
0248680a DL |
60 | #include <unistd.h> |
61 | #include <fcntl.h> | |
4e3a36cd | 62 | |
f53f992a PE |
63 | extern char _data[]; |
64 | extern char _text[]; | |
0248680a | 65 | |
4e3a36cd JB |
66 | #include <filehdr.h> |
67 | #include <aouthdr.h> | |
68 | #include <scnhdr.h> | |
69 | #include <syms.h> | |
0248680a | 70 | |
4e3a36cd JB |
71 | static struct filehdr f_hdr; /* File header */ |
72 | static struct aouthdr f_ohdr; /* Optional file header (a.out) */ | |
f53f992a PE |
73 | static off_t bias; /* Bias to add for growth */ |
74 | static off_t lnnoptr; /* Pointer to line-number info within file */ | |
4e3a36cd | 75 | |
f53f992a PE |
76 | static off_t text_scnptr; |
77 | static off_t data_scnptr; | |
4a438fc5 | 78 | #define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1)) |
f53f992a PE |
79 | static off_t load_scnptr; |
80 | static off_t orig_load_scnptr; | |
81 | static off_t orig_data_scnptr; | |
dc44c39a | 82 | static int unrelocate_symbols (int, int, const char *, const char *); |
4e3a36cd JB |
83 | |
84 | #ifndef MAX_SECTIONS | |
85 | #define MAX_SECTIONS 10 | |
86 | #endif | |
87 | ||
dc44c39a | 88 | static int adjust_lnnoptrs (int, int, const char *); |
4e3a36cd JB |
89 | |
90 | static int pagemask; | |
91 | ||
8eca17c9 | 92 | #include "lisp.h" |
4e3a36cd | 93 | |
227be86d | 94 | static _Noreturn void |
dc44c39a | 95 | report_error (const char *file, int fd) |
4e3a36cd JB |
96 | { |
97 | if (fd) | |
227be86d PE |
98 | { |
99 | int failed_errno = errno; | |
bacba3c2 | 100 | emacs_close (fd); |
227be86d PE |
101 | errno = failed_errno; |
102 | } | |
8eca17c9 | 103 | report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil)); |
4e3a36cd | 104 | } |
76998edb | 105 | |
227be86d PE |
106 | #define ERROR0(msg) report_error_1 (new, msg) |
107 | #define ERROR1(msg,x) report_error_1 (new, msg, x) | |
108 | #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y) | |
76998edb | 109 | |
227be86d PE |
110 | static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (2, 3) |
111 | report_error_1 (int fd, const char *msg, ...) | |
76998edb | 112 | { |
227be86d | 113 | va_list ap; |
bacba3c2 | 114 | emacs_close (fd); |
227be86d PE |
115 | va_start (ap, msg); |
116 | verror (msg, ap); | |
117 | va_end (ap); | |
4e3a36cd JB |
118 | } |
119 | ||
dc44c39a PE |
120 | static int make_hdr (int, int, const char *, const char *); |
121 | static void mark_x (const char *); | |
0248680a | 122 | static int copy_text_and_data (int); |
dc44c39a | 123 | static int copy_sym (int, int, const char *, const char *); |
0248680a | 124 | static void write_segment (int, char *, char *); |
4e3a36cd JB |
125 | \f |
126 | /* **************************************************************** | |
127 | * unexec | |
128 | * | |
129 | * driving logic. | |
130 | */ | |
381259ef PE |
131 | void |
132 | unexec (const char *new_name, const char *a_name) | |
76998edb | 133 | { |
0248680a | 134 | int new = -1, a_out = -1; |
4e3a36cd | 135 | |
406af475 | 136 | if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0) |
4e3a36cd JB |
137 | { |
138 | PERROR (a_name); | |
139 | } | |
406af475 | 140 | if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) |
4e3a36cd JB |
141 | { |
142 | PERROR (new_name); | |
143 | } | |
0248680a | 144 | if (make_hdr (new, a_out, |
0248680a | 145 | a_name, new_name) < 0 |
4e3a36cd JB |
146 | || copy_text_and_data (new) < 0 |
147 | || copy_sym (new, a_out, a_name, new_name) < 0 | |
4e3a36cd | 148 | || adjust_lnnoptrs (new, a_out, new_name) < 0 |
0248680a | 149 | || unrelocate_symbols (new, a_out, a_name, new_name) < 0) |
76998edb | 150 | { |
bacba3c2 | 151 | emacs_close (new); |
fffe2e14 | 152 | return; |
76998edb | 153 | } |
76998edb | 154 | |
bacba3c2 | 155 | emacs_close (new); |
4e3a36cd | 156 | if (a_out >= 0) |
bacba3c2 | 157 | emacs_close (a_out); |
4e3a36cd | 158 | mark_x (new_name); |
4e3a36cd JB |
159 | } |
160 | ||
161 | /* **************************************************************** | |
162 | * make_hdr | |
163 | * | |
164 | * Make the header in the new a.out from the header in core. | |
165 | * Modify the text and data sizes. | |
166 | */ | |
167 | static int | |
0248680a | 168 | make_hdr (int new, int a_out, |
dc44c39a | 169 | const char *a_name, const char *new_name) |
4e3a36cd | 170 | { |
0248680a | 171 | int scns; |
227be86d PE |
172 | uintptr_t bss_start; |
173 | uintptr_t data_start; | |
4e3a36cd JB |
174 | |
175 | struct scnhdr section[MAX_SECTIONS]; | |
176 | struct scnhdr * f_thdr; /* Text section header */ | |
177 | struct scnhdr * f_dhdr; /* Data section header */ | |
178 | struct scnhdr * f_bhdr; /* Bss section header */ | |
179 | struct scnhdr * f_lhdr; /* Loader section header */ | |
180 | struct scnhdr * f_tchdr; /* Typechk section header */ | |
181 | struct scnhdr * f_dbhdr; /* Debug section header */ | |
182 | struct scnhdr * f_xhdr; /* Except section header */ | |
183 | ||
184 | load_scnptr = orig_load_scnptr = lnnoptr = 0; | |
185 | pagemask = getpagesize () - 1; | |
186 | ||
187 | /* Adjust text/data boundary. */ | |
f53f992a | 188 | data_start = (uintptr_t) _data; |
4e3a36cd | 189 | |
4e3a36cd | 190 | data_start = data_start & ~pagemask; /* (Down) to page boundary. */ |
4e3a36cd | 191 | |
227be86d | 192 | bss_start = (uintptr_t) sbrk (0) + pagemask; |
dd5ecd6b | 193 | bss_start &= ~ pagemask; |
76998edb | 194 | |
4e3a36cd JB |
195 | if (data_start > bss_start) /* Can't have negative data size. */ |
196 | { | |
227be86d PE |
197 | ERROR2 (("unexec: data_start (0x%"PRIxPTR |
198 | ") can't be greater than bss_start (0x%"PRIxPTR")"), | |
4e3a36cd JB |
199 | data_start, bss_start); |
200 | } | |
76998edb | 201 | |
4e3a36cd | 202 | /* Salvage as much info from the existing file as possible */ |
4e3a36cd JB |
203 | f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL; |
204 | f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL; | |
205 | if (a_out >= 0) | |
76998edb | 206 | { |
4e3a36cd JB |
207 | if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) |
208 | { | |
209 | PERROR (a_name); | |
210 | } | |
4e3a36cd JB |
211 | if (f_hdr.f_opthdr > 0) |
212 | { | |
213 | if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) | |
214 | { | |
215 | PERROR (a_name); | |
216 | } | |
4e3a36cd JB |
217 | } |
218 | if (f_hdr.f_nscns > MAX_SECTIONS) | |
219 | { | |
220 | ERROR0 ("unexec: too many section headers -- increase MAX_SECTIONS"); | |
221 | } | |
222 | /* Loop through section headers */ | |
223 | for (scns = 0; scns < f_hdr.f_nscns; scns++) { | |
224 | struct scnhdr *s = §ion[scns]; | |
225 | if (read (a_out, s, sizeof (*s)) != sizeof (*s)) | |
226 | { | |
227 | PERROR (a_name); | |
228 | } | |
4e3a36cd JB |
229 | |
230 | #define CHECK_SCNHDR(ptr, name, flags) \ | |
5e617bc2 | 231 | if (strcmp (s->s_name, name) == 0) { \ |
4e3a36cd | 232 | if (s->s_flags != flags) { \ |
5e617bc2 JB |
233 | fprintf (stderr, "unexec: %lx flags where %x expected in %s section.\n", \ |
234 | (unsigned long)s->s_flags, flags, name); \ | |
4e3a36cd JB |
235 | } \ |
236 | if (ptr) { \ | |
5e617bc2 JB |
237 | fprintf (stderr, "unexec: duplicate section header for section %s.\n", \ |
238 | name); \ | |
4e3a36cd JB |
239 | } \ |
240 | ptr = s; \ | |
241 | } | |
5e617bc2 JB |
242 | CHECK_SCNHDR (f_thdr, _TEXT, STYP_TEXT); |
243 | CHECK_SCNHDR (f_dhdr, _DATA, STYP_DATA); | |
244 | CHECK_SCNHDR (f_bhdr, _BSS, STYP_BSS); | |
245 | CHECK_SCNHDR (f_lhdr, _LOADER, STYP_LOADER); | |
246 | CHECK_SCNHDR (f_dbhdr, _DEBUG, STYP_DEBUG); | |
247 | CHECK_SCNHDR (f_tchdr, _TYPCHK, STYP_TYPCHK); | |
248 | CHECK_SCNHDR (f_xhdr, _EXCEPT, STYP_EXCEPT); | |
4e3a36cd JB |
249 | } |
250 | ||
251 | if (f_thdr == 0) | |
252 | { | |
0248680a | 253 | ERROR1 ("unexec: couldn't find \"%s\" section", (int) _TEXT); |
4e3a36cd JB |
254 | } |
255 | if (f_dhdr == 0) | |
256 | { | |
0248680a | 257 | ERROR1 ("unexec: couldn't find \"%s\" section", (int) _DATA); |
4e3a36cd JB |
258 | } |
259 | if (f_bhdr == 0) | |
260 | { | |
0248680a | 261 | ERROR1 ("unexec: couldn't find \"%s\" section", (int) _BSS); |
4e3a36cd | 262 | } |
76998edb | 263 | } |
4e3a36cd | 264 | else |
76998edb | 265 | { |
4e3a36cd | 266 | ERROR0 ("can't build a COFF file from scratch yet"); |
76998edb | 267 | } |
4e3a36cd JB |
268 | orig_data_scnptr = f_dhdr->s_scnptr; |
269 | orig_load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; | |
270 | ||
271 | /* Now we alter the contents of all the f_*hdr variables | |
272 | to correspond to what we want to dump. */ | |
4a438fc5 RS |
273 | |
274 | /* Indicate that the reloc information is no longer valid for ld (bind); | |
275 | we only update it enough to fake out the exec-time loader. */ | |
276 | f_hdr.f_flags |= (F_RELFLG | F_EXEC); | |
277 | ||
0248680a | 278 | f_ohdr.dsize = bss_start - f_ohdr.data_start; |
dd5ecd6b | 279 | f_ohdr.bsize = 0; |
4e3a36cd JB |
280 | |
281 | f_dhdr->s_size = f_ohdr.dsize; | |
282 | f_bhdr->s_size = f_ohdr.bsize; | |
4a438fc5 RS |
283 | f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize; |
284 | f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize; | |
4e3a36cd JB |
285 | |
286 | /* fix scnptr's */ | |
287 | { | |
f53f992a | 288 | off_t ptr = section[0].s_scnptr; |
4e3a36cd | 289 | |
4a438fc5 RS |
290 | bias = -1; |
291 | for (scns = 0; scns < f_hdr.f_nscns; scns++) | |
292 | { | |
293 | struct scnhdr *s = §ion[scns]; | |
4e3a36cd | 294 | |
4a438fc5 RS |
295 | if (s->s_flags & STYP_PAD) /* .pad sections omitted in AIX 4.1 */ |
296 | { | |
297 | /* | |
298 | * the text_start should probably be o_algntext but that doesn't | |
299 | * seem to change | |
300 | */ | |
301 | if (f_ohdr.text_start != 0) /* && scns != 0 */ | |
302 | { | |
303 | s->s_size = 512 - (ptr % 512); | |
304 | if (s->s_size == 512) | |
305 | s->s_size = 0; | |
306 | } | |
307 | s->s_scnptr = ptr; | |
308 | } | |
309 | else if (s->s_flags & STYP_DATA) | |
4e3a36cd | 310 | s->s_scnptr = ptr; |
4a438fc5 RS |
311 | else if (!(s->s_flags & (STYP_TEXT | STYP_BSS))) |
312 | { | |
313 | if (bias == -1) /* if first section after bss */ | |
314 | bias = ptr - s->s_scnptr; | |
4e3a36cd | 315 | |
4a438fc5 RS |
316 | s->s_scnptr += bias; |
317 | ptr = s->s_scnptr; | |
318 | } | |
177c0ea7 | 319 | |
4a438fc5 RS |
320 | ptr = ptr + s->s_size; |
321 | } | |
4e3a36cd JB |
322 | } |
323 | ||
324 | /* fix other pointers */ | |
4a438fc5 RS |
325 | for (scns = 0; scns < f_hdr.f_nscns; scns++) |
326 | { | |
327 | struct scnhdr *s = §ion[scns]; | |
4e3a36cd | 328 | |
4a438fc5 RS |
329 | if (s->s_relptr != 0) |
330 | { | |
331 | s->s_relptr += bias; | |
332 | } | |
333 | if (s->s_lnnoptr != 0) | |
334 | { | |
335 | if (lnnoptr == 0) lnnoptr = s->s_lnnoptr; | |
336 | s->s_lnnoptr += bias; | |
337 | } | |
338 | } | |
4e3a36cd JB |
339 | |
340 | if (f_hdr.f_symptr > 0L) | |
76998edb | 341 | { |
4e3a36cd | 342 | f_hdr.f_symptr += bias; |
76998edb JB |
343 | } |
344 | ||
4e3a36cd JB |
345 | text_scnptr = f_thdr->s_scnptr; |
346 | data_scnptr = f_dhdr->s_scnptr; | |
347 | load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; | |
76998edb | 348 | |
4e3a36cd JB |
349 | if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) |
350 | { | |
351 | PERROR (new_name); | |
352 | } | |
76998edb | 353 | |
4e3a36cd JB |
354 | if (f_hdr.f_opthdr > 0) |
355 | { | |
356 | if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) | |
76998edb | 357 | { |
4e3a36cd JB |
358 | PERROR (new_name); |
359 | } | |
360 | } | |
76998edb | 361 | |
4e3a36cd JB |
362 | for (scns = 0; scns < f_hdr.f_nscns; scns++) { |
363 | struct scnhdr *s = §ion[scns]; | |
364 | if (write (new, s, sizeof (*s)) != sizeof (*s)) | |
365 | { | |
366 | PERROR (new_name); | |
367 | } | |
368 | } | |
76998edb | 369 | |
4e3a36cd | 370 | return (0); |
4e3a36cd JB |
371 | } |
372 | \f | |
373 | /* **************************************************************** | |
177c0ea7 | 374 | |
4e3a36cd JB |
375 | * |
376 | * Copy the text and data segments from memory to the new a.out | |
377 | */ | |
378 | static int | |
0248680a | 379 | copy_text_and_data (int new) |
4e3a36cd | 380 | { |
0248680a DL |
381 | char *end; |
382 | char *ptr; | |
4e3a36cd | 383 | |
f53f992a PE |
384 | lseek (new, text_scnptr, SEEK_SET); |
385 | ptr = _text + text_scnptr; | |
4e3a36cd JB |
386 | end = ptr + f_ohdr.tsize; |
387 | write_segment (new, ptr, end); | |
388 | ||
f53f992a | 389 | lseek (new, data_scnptr, SEEK_SET); |
0248680a | 390 | ptr = (char *) f_ohdr.data_start; |
4e3a36cd JB |
391 | end = ptr + f_ohdr.dsize; |
392 | write_segment (new, ptr, end); | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
91b97ddb | 397 | #define UnexBlockSz (1<<12) /* read/write block size */ |
0248680a DL |
398 | static void |
399 | write_segment (int new, char *ptr, char *end) | |
4e3a36cd | 400 | { |
0248680a | 401 | int i, nwrite, ret; |
91b97ddb | 402 | char zeros[UnexBlockSz]; |
4e3a36cd JB |
403 | |
404 | for (i = 0; ptr < end;) | |
405 | { | |
91b97ddb RS |
406 | /* distance to next block. */ |
407 | nwrite = (((int) ptr + UnexBlockSz) & -UnexBlockSz) - (int) ptr; | |
4e3a36cd JB |
408 | /* But not beyond specified end. */ |
409 | if (nwrite > end - ptr) nwrite = end - ptr; | |
410 | ret = write (new, ptr, nwrite); | |
411 | /* If write gets a page fault, it means we reached | |
412 | a gap between the old text segment and the old data segment. | |
413 | This gap has probably been remapped into part of the text segment. | |
414 | So write zeros for it. */ | |
415 | if (ret == -1 && errno == EFAULT) | |
76998edb | 416 | { |
0248680a | 417 | memset (zeros, 0, nwrite); |
91b97ddb | 418 | write (new, zeros, nwrite); |
76998edb | 419 | } |
4e3a36cd | 420 | else if (nwrite != ret) |
76998edb | 421 | { |
227be86d PE |
422 | int write_errno = errno; |
423 | char buf[1000]; | |
424 | void *addr = ptr; | |
4e3a36cd | 425 | sprintf (buf, |
227be86d PE |
426 | "unexec write failure: addr %p, fileno %d, size 0x%x, wrote 0x%x, errno %d", |
427 | addr, new, nwrite, ret, errno); | |
428 | errno = write_errno; | |
4e3a36cd | 429 | PERROR (buf); |
76998edb | 430 | } |
4e3a36cd JB |
431 | i += nwrite; |
432 | ptr += nwrite; | |
433 | } | |
434 | } | |
435 | \f | |
436 | /* **************************************************************** | |
437 | * copy_sym | |
438 | * | |
439 | * Copy the relocation information and symbol table from the a.out to the new | |
440 | */ | |
441 | static int | |
dc44c39a | 442 | copy_sym (int new, int a_out, const char *a_name, const char *new_name) |
4e3a36cd | 443 | { |
91b97ddb | 444 | char page[UnexBlockSz]; |
4e3a36cd | 445 | int n; |
76998edb | 446 | |
4e3a36cd JB |
447 | if (a_out < 0) |
448 | return 0; | |
76998edb | 449 | |
4a438fc5 | 450 | if (orig_load_scnptr == 0L) |
4e3a36cd | 451 | return 0; |
76998edb | 452 | |
4a438fc5 | 453 | if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info */ |
0248680a | 454 | lseek (a_out, lnnoptr, SEEK_SET); /* start copying from there */ |
4e3a36cd | 455 | else |
0248680a | 456 | lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */ |
4e3a36cd JB |
457 | |
458 | while ((n = read (a_out, page, sizeof page)) > 0) | |
459 | { | |
460 | if (write (new, page, n) != n) | |
76998edb | 461 | { |
4e3a36cd | 462 | PERROR (new_name); |
76998edb JB |
463 | } |
464 | } | |
4e3a36cd JB |
465 | if (n < 0) |
466 | { | |
467 | PERROR (a_name); | |
468 | } | |
469 | return 0; | |
470 | } | |
471 | \f | |
472 | /* **************************************************************** | |
473 | * mark_x | |
474 | * | |
eb8c3be9 | 475 | * After successfully building the new a.out, mark it executable |
4e3a36cd JB |
476 | */ |
477 | static void | |
dc44c39a | 478 | mark_x (const char *name) |
4e3a36cd JB |
479 | { |
480 | struct stat sbuf; | |
481 | int um; | |
482 | int new = 0; /* for PERROR */ | |
76998edb | 483 | |
4e3a36cd JB |
484 | um = umask (777); |
485 | umask (um); | |
486 | if (stat (name, &sbuf) == -1) | |
487 | { | |
488 | PERROR (name); | |
489 | } | |
490 | sbuf.st_mode |= 0111 & ~um; | |
491 | if (chmod (name, sbuf.st_mode) == -1) | |
492 | PERROR (name); | |
493 | } | |
494 | \f | |
0248680a | 495 | static int |
dc44c39a | 496 | adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name) |
4e3a36cd | 497 | { |
0248680a DL |
498 | int nsyms; |
499 | int naux; | |
500 | int new; | |
4e3a36cd JB |
501 | struct syment symentry; |
502 | union auxent auxentry; | |
4e3a36cd JB |
503 | |
504 | if (!lnnoptr || !f_hdr.f_symptr) | |
505 | return 0; | |
506 | ||
406af475 | 507 | if ((new = emacs_open (new_name, O_RDWR, 0)) < 0) |
4e3a36cd JB |
508 | { |
509 | PERROR (new_name); | |
510 | return -1; | |
511 | } | |
512 | ||
0248680a | 513 | lseek (new, f_hdr.f_symptr, SEEK_SET); |
4e3a36cd JB |
514 | for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) |
515 | { | |
516 | read (new, &symentry, SYMESZ); | |
91b97ddb RS |
517 | if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL) |
518 | { | |
519 | symentry.n_value += bias; | |
0248680a | 520 | lseek (new, -SYMESZ, SEEK_CUR); |
91b97ddb RS |
521 | write (new, &symentry, SYMESZ); |
522 | } | |
523 | ||
4a438fc5 | 524 | for (naux = symentry.n_numaux; naux-- != 0; ) |
4e3a36cd JB |
525 | { |
526 | read (new, &auxentry, AUXESZ); | |
527 | nsyms++; | |
4a438fc5 RS |
528 | if (naux != 0 /* skip csect auxentry (last entry) */ |
529 | && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT)) | |
530 | { | |
531 | auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; | |
0248680a | 532 | lseek (new, -AUXESZ, SEEK_CUR); |
4a438fc5 RS |
533 | write (new, &auxentry, AUXESZ); |
534 | } | |
4e3a36cd JB |
535 | } |
536 | } | |
bacba3c2 | 537 | emacs_close (new); |
76998edb | 538 | |
0248680a DL |
539 | return 0; |
540 | } | |
4e3a36cd | 541 | |
0248680a | 542 | static int |
dc44c39a PE |
543 | unrelocate_symbols (int new, int a_out, |
544 | const char *a_name, const char *new_name) | |
76998edb | 545 | { |
0248680a | 546 | int i; |
4e3a36cd | 547 | LDHDR ldhdr; |
0248680a | 548 | LDREL ldrel; |
f53f992a | 549 | off_t t_reloc = (intptr_t) _text - f_ohdr.text_start; |
0248680a | 550 | #ifndef ALIGN_DATA_RELOC |
f53f992a | 551 | off_t d_reloc = (intptr_t) _data - f_ohdr.data_start; |
0248680a | 552 | #else |
177c0ea7 | 553 | /* This worked (and was needed) before AIX 4.2. |
0248680a | 554 | I have no idea why. -- Mike */ |
f53f992a | 555 | off_t d_reloc = (intptr_t) _data - ALIGN (f_ohdr.data_start, 2); |
0248680a | 556 | #endif |
4e3a36cd | 557 | int * p; |
4e3a36cd JB |
558 | |
559 | if (load_scnptr == 0) | |
560 | return 0; | |
561 | ||
0248680a | 562 | lseek (a_out, orig_load_scnptr, SEEK_SET); |
4e3a36cd JB |
563 | if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr)) |
564 | { | |
565 | PERROR (new_name); | |
566 | } | |
567 | ||
568 | #define SYMNDX_TEXT 0 | |
569 | #define SYMNDX_DATA 1 | |
570 | #define SYMNDX_BSS 2 | |
4e3a36cd | 571 | |
0248680a DL |
572 | for (i = 0; i < ldhdr.l_nreloc; i++) |
573 | { | |
574 | lseek (a_out, | |
575 | orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, | |
576 | SEEK_SET); | |
4e3a36cd | 577 | |
0248680a DL |
578 | if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ) |
579 | { | |
580 | PERROR (a_name); | |
581 | } | |
4e3a36cd JB |
582 | |
583 | /* move the BSS loader symbols to the DATA segment */ | |
0248680a | 584 | if (ldrel.l_symndx == SYMNDX_BSS) |
4e3a36cd | 585 | { |
0248680a | 586 | ldrel.l_symndx = SYMNDX_DATA; |
91b97ddb | 587 | |
4e3a36cd JB |
588 | lseek (new, |
589 | load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, | |
0248680a | 590 | SEEK_SET); |
4e3a36cd | 591 | |
0248680a | 592 | if (write (new, &ldrel, LDRELSZ) != LDRELSZ) |
4e3a36cd JB |
593 | { |
594 | PERROR (new_name); | |
595 | } | |
596 | } | |
597 | ||
0248680a | 598 | if (ldrel.l_rsecnm == f_ohdr.o_sndata) |
4e3a36cd JB |
599 | { |
600 | int orig_int; | |
601 | ||
4a438fc5 | 602 | lseek (a_out, |
0248680a DL |
603 | orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start), |
604 | SEEK_SET); | |
4e3a36cd | 605 | |
0248680a DL |
606 | if (read (a_out, (void *) &orig_int, sizeof (orig_int)) |
607 | != sizeof (orig_int)) | |
4e3a36cd JB |
608 | { |
609 | PERROR (a_name); | |
610 | } | |
611 | ||
0248680a | 612 | p = (int *) (ldrel.l_vaddr + d_reloc); |
4a438fc5 | 613 | |
0248680a | 614 | switch (ldrel.l_symndx) { |
4e3a36cd | 615 | case SYMNDX_TEXT: |
4a438fc5 | 616 | orig_int = * p - t_reloc; |
4e3a36cd JB |
617 | break; |
618 | ||
619 | case SYMNDX_DATA: | |
620 | case SYMNDX_BSS: | |
4a438fc5 | 621 | orig_int = * p - d_reloc; |
4e3a36cd JB |
622 | break; |
623 | } | |
624 | ||
4a438fc5 RS |
625 | if (orig_int != * p) |
626 | { | |
627 | lseek (new, | |
0248680a DL |
628 | data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start), |
629 | SEEK_SET); | |
4a438fc5 RS |
630 | if (write (new, (void *) &orig_int, sizeof (orig_int)) |
631 | != sizeof (orig_int)) | |
632 | { | |
633 | PERROR (new_name); | |
634 | } | |
635 | } | |
4e3a36cd JB |
636 | } |
637 | } | |
0248680a | 638 | return 0; |
76998edb | 639 | } |