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