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