Fix races with threads and file descriptors.
[bpt/emacs.git] / src / unexaix.c
CommitLineData
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
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
3b7ad313
EN
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
4e3a36cd 19
9ec0b715 20/*
4e3a36cd
JB
21In other words, you are welcome to use, share and improve this program.
22You are forbidden to forbid anyone else to use, share and improve
23what 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
63extern char _data[];
64extern 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
71static struct filehdr f_hdr; /* File header */
72static struct aouthdr f_ohdr; /* Optional file header (a.out) */
f53f992a
PE
73static off_t bias; /* Bias to add for growth */
74static off_t lnnoptr; /* Pointer to line-number info within file */
4e3a36cd 75
f53f992a
PE
76static off_t text_scnptr;
77static off_t data_scnptr;
4a438fc5 78#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1))
f53f992a
PE
79static off_t load_scnptr;
80static off_t orig_load_scnptr;
81static off_t orig_data_scnptr;
dc44c39a 82static 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 88static int adjust_lnnoptrs (int, int, const char *);
4e3a36cd
JB
89
90static int pagemask;
91
8eca17c9 92#include "lisp.h"
4e3a36cd 93
227be86d 94static _Noreturn void
dc44c39a 95report_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
110static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (2, 3)
111report_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
120static int make_hdr (int, int, const char *, const char *);
121static void mark_x (const char *);
0248680a 122static int copy_text_and_data (int);
dc44c39a 123static int copy_sym (int, int, const char *, const char *);
0248680a 124static void write_segment (int, char *, char *);
4e3a36cd
JB
125\f
126/* ****************************************************************
127 * unexec
128 *
129 * driving logic.
130 */
381259ef
PE
131void
132unexec (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 */
167static int
0248680a 168make_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 = &section[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 = &section[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 = &section[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 = &section[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 */
378static int
0248680a 379copy_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
398static void
399write_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 */
441static int
dc44c39a 442copy_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 */
477static void
dc44c39a 478mark_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 495static int
dc44c39a 496adjust_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 542static int
dc44c39a
PE
543unrelocate_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}