unexaix.c 15.2 KB
Newer Older
1
/* Dump an executable image.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1985-1988, 1999, 2001-2019 Free Software Foundation,
3
   Inc.
Jim Blandy's avatar
Jim Blandy committed
4

5 6
This file is part of GNU Emacs.

7
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
9 10
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
18
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
19

20
/*
Jim Blandy's avatar
Jim Blandy committed
21 22 23 24 25
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them.   Help stamp out software-hoarding!  */


26
/* Originally based on the COFF unexec.c by Spencer W. Thomas.
Jim Blandy's avatar
Jim Blandy committed
27
 *
28 29 30 31
 * Subsequently hacked on by
 * Bill Mann <Bill_Man@praxisint.com>
 * Andrew Vignaux <Andrew.Vignaux@comp.vuw.ac.nz>
 * Mike Sperber <sperber@informatik.uni-tuebingen.de>
32
 *
Jim Blandy's avatar
Jim Blandy committed
33
 * Synopsis:
34
 *	unexec (const char *new_name, const *old_name);
Jim Blandy's avatar
Jim Blandy committed
35 36 37 38 39 40 41 42
 *
 * Takes a snapshot of the program and makes an a.out format file in the
 * file named by the string argument new_name.
 * If a_name is non-NULL, the symbol table will be taken from the given file.
 * On some machines, an existing a_name file is required.
 *
 */

43
#include <config.h>
44
#include "unexec.h"
45
#include "lisp.h"
46

Jim Blandy's avatar
Jim Blandy committed
47 48 49 50 51 52
#define PERROR(file) report_error (file, new)
#include <a.out.h>
/* Define getpagesize () if the system does not.
   Note that this may depend on symbols defined in a.out.h
 */
#include "getpagesize.h"
Jim Blandy's avatar
Jim Blandy committed
53

Jim Blandy's avatar
Jim Blandy committed
54
#include <sys/types.h>
Paul Eggert's avatar
Paul Eggert committed
55 56
#include <inttypes.h>
#include <stdarg.h>
Jim Blandy's avatar
Jim Blandy committed
57 58
#include <stdio.h>
#include <errno.h>
59 60
#include <unistd.h>
#include <fcntl.h>
Jim Blandy's avatar
Jim Blandy committed
61

Paul Eggert's avatar
Paul Eggert committed
62 63
extern char _data[];
extern char _text[];
64

Jim Blandy's avatar
Jim Blandy committed
65 66 67 68
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <syms.h>
69

Jim Blandy's avatar
Jim Blandy committed
70 71
static struct filehdr f_hdr;		/* File header */
static struct aouthdr f_ohdr;		/* Optional file header (a.out) */
Paul Eggert's avatar
Paul Eggert committed
72 73
static off_t bias;			/* Bias to add for growth */
static off_t lnnoptr;			/* Pointer to line-number info within file */
Jim Blandy's avatar
Jim Blandy committed
74

Paul Eggert's avatar
Paul Eggert committed
75 76
static off_t text_scnptr;
static off_t data_scnptr;
77
#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1))
Paul Eggert's avatar
Paul Eggert committed
78 79 80
static off_t load_scnptr;
static off_t orig_load_scnptr;
static off_t orig_data_scnptr;
81
static int unrelocate_symbols (int, int, const char *, const char *);
Jim Blandy's avatar
Jim Blandy committed
82 83 84 85 86

#ifndef MAX_SECTIONS
#define MAX_SECTIONS	10
#endif

87
static int adjust_lnnoptrs (int, int, const char *);
Jim Blandy's avatar
Jim Blandy committed
88 89 90

static int pagemask;

91
#include "lisp.h"
Jim Blandy's avatar
Jim Blandy committed
92

Paul Eggert's avatar
Paul Eggert committed
93
static _Noreturn void
94
report_error (const char *file, int fd)
Jim Blandy's avatar
Jim Blandy committed
95
{
96
  int err = errno;
Jim Blandy's avatar
Jim Blandy committed
97
  if (fd)
98
    emacs_close (fd);
99
  report_file_errno ("Cannot unexec", build_string (file), err);
Jim Blandy's avatar
Jim Blandy committed
100
}
Jim Blandy's avatar
Jim Blandy committed
101

Paul Eggert's avatar
Paul Eggert committed
102 103 104
#define ERROR0(msg) report_error_1 (new, msg)
#define ERROR1(msg,x) report_error_1 (new, msg, x)
#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y)
Jim Blandy's avatar
Jim Blandy committed
105

Paul Eggert's avatar
Paul Eggert committed
106 107
static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (2, 3)
report_error_1 (int fd, const char *msg, ...)
Jim Blandy's avatar
Jim Blandy committed
108
{
Paul Eggert's avatar
Paul Eggert committed
109
  va_list ap;
110
  emacs_close (fd);
Paul Eggert's avatar
Paul Eggert committed
111 112 113
  va_start (ap, msg);
  verror (msg, ap);
  va_end (ap);
Jim Blandy's avatar
Jim Blandy committed
114 115
}

116 117
static int make_hdr (int, int, const char *, const char *);
static void mark_x (const char *);
118
static int copy_text_and_data (int);
119
static int copy_sym (int, int, const char *, const char *);
120
static void write_segment (int, char *, char *);
Jim Blandy's avatar
Jim Blandy committed
121 122 123 124 125 126

/* ****************************************************************
 * unexec
 *
 * driving logic.
 */
127 128
void
unexec (const char *new_name, const char *a_name)
Jim Blandy's avatar
Jim Blandy committed
129
{
130
  int new = -1, a_out = -1;
Jim Blandy's avatar
Jim Blandy committed
131

132
  if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0)
Jim Blandy's avatar
Jim Blandy committed
133 134 135
    {
      PERROR (a_name);
    }
136
  if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0)
Jim Blandy's avatar
Jim Blandy committed
137 138 139
    {
      PERROR (new_name);
    }
140 141
  if (make_hdr (new, a_out,
		a_name, new_name) < 0
Jim Blandy's avatar
Jim Blandy committed
142 143 144
      || copy_text_and_data (new) < 0
      || copy_sym (new, a_out, a_name, new_name) < 0
      || adjust_lnnoptrs (new, a_out, new_name) < 0
145
      || unrelocate_symbols (new, a_out, a_name, new_name) < 0)
Jim Blandy's avatar
Jim Blandy committed
146
    {
147
      emacs_close (new);
148
      return;
Jim Blandy's avatar
Jim Blandy committed
149 150
    }

151
  emacs_close (new);
Jim Blandy's avatar
Jim Blandy committed
152
  if (a_out >= 0)
153
    emacs_close (a_out);
Jim Blandy's avatar
Jim Blandy committed
154 155 156 157 158 159 160 161 162
}

/* ****************************************************************
 * make_hdr
 *
 * Make the header in the new a.out from the header in core.
 * Modify the text and data sizes.
 */
static int
163
make_hdr (int new, int a_out,
164
	  const char *a_name, const char *new_name)
Jim Blandy's avatar
Jim Blandy committed
165
{
166
  int scns;
Paul Eggert's avatar
Paul Eggert committed
167 168
  uintptr_t bss_start;
  uintptr_t data_start;
Jim Blandy's avatar
Jim Blandy committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182

  struct scnhdr section[MAX_SECTIONS];
  struct scnhdr * f_thdr;		/* Text section header */
  struct scnhdr * f_dhdr;		/* Data section header */
  struct scnhdr * f_bhdr;		/* Bss section header */
  struct scnhdr * f_lhdr;		/* Loader section header */
  struct scnhdr * f_tchdr;		/* Typechk section header */
  struct scnhdr * f_dbhdr;		/* Debug section header */
  struct scnhdr * f_xhdr;		/* Except section header */

  load_scnptr = orig_load_scnptr = lnnoptr = 0;
  pagemask = getpagesize () - 1;

  /* Adjust text/data boundary. */
Paul Eggert's avatar
Paul Eggert committed
183
  data_start = (uintptr_t) _data;
Jim Blandy's avatar
Jim Blandy committed
184 185 186

  data_start = data_start & ~pagemask; /* (Down) to page boundary. */

Paul Eggert's avatar
Paul Eggert committed
187
  bss_start = (uintptr_t) sbrk (0) + pagemask;
188
  bss_start &= ~ pagemask;
Jim Blandy's avatar
Jim Blandy committed
189

Jim Blandy's avatar
Jim Blandy committed
190 191
  if (data_start > bss_start)	/* Can't have negative data size. */
    {
Paul Eggert's avatar
Paul Eggert committed
192 193
      ERROR2 (("unexec: data_start (0x%"PRIxPTR
	       ") can't be greater than bss_start (0x%"PRIxPTR")"),
Jim Blandy's avatar
Jim Blandy committed
194 195
	      data_start, bss_start);
    }
Jim Blandy's avatar
Jim Blandy committed
196

Jim Blandy's avatar
Jim Blandy committed
197 198 199 200
  /* Salvage as much info from the existing file as possible */
  f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL;
  f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL;
  if (a_out >= 0)
Jim Blandy's avatar
Jim Blandy committed
201
    {
Jim Blandy's avatar
Jim Blandy committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
      if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
	{
	  PERROR (a_name);
	}
      if (f_hdr.f_opthdr > 0)
	{
	  if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
	    {
	      PERROR (a_name);
	    }
	}
      if (f_hdr.f_nscns > MAX_SECTIONS)
	{
	  ERROR0 ("unexec: too many section headers -- increase MAX_SECTIONS");
	}
      /* Loop through section headers */
      for (scns = 0; scns < f_hdr.f_nscns; scns++) {
	struct scnhdr *s = &section[scns];
	if (read (a_out, s, sizeof (*s)) != sizeof (*s))
	  {
	    PERROR (a_name);
	  }

#define CHECK_SCNHDR(ptr, name, flags) \
Juanma Barranquero's avatar
Juanma Barranquero committed
226
  if (strcmp (s->s_name, name) == 0) { \
Jim Blandy's avatar
Jim Blandy committed
227
    if (s->s_flags != flags) { \
Juanma Barranquero's avatar
Juanma Barranquero committed
228 229
      fprintf (stderr, "unexec: %lx flags where %x expected in %s section.\n", \
               (unsigned long)s->s_flags, flags, name);                 \
Jim Blandy's avatar
Jim Blandy committed
230 231
    } \
    if (ptr) { \
Juanma Barranquero's avatar
Juanma Barranquero committed
232 233
      fprintf (stderr, "unexec: duplicate section header for section %s.\n", \
               name);                                                   \
Jim Blandy's avatar
Jim Blandy committed
234 235 236
    } \
    ptr = s; \
  }
Juanma Barranquero's avatar
Juanma Barranquero committed
237 238 239 240 241 242 243
	CHECK_SCNHDR (f_thdr, _TEXT, STYP_TEXT);
	CHECK_SCNHDR (f_dhdr, _DATA, STYP_DATA);
	CHECK_SCNHDR (f_bhdr, _BSS, STYP_BSS);
	CHECK_SCNHDR (f_lhdr, _LOADER, STYP_LOADER);
	CHECK_SCNHDR (f_dbhdr, _DEBUG,  STYP_DEBUG);
	CHECK_SCNHDR (f_tchdr, _TYPCHK,  STYP_TYPCHK);
	CHECK_SCNHDR (f_xhdr, _EXCEPT,  STYP_EXCEPT);
Jim Blandy's avatar
Jim Blandy committed
244 245 246 247
      }

      if (f_thdr == 0)
	{
248
	  ERROR1 ("unexec: couldn't find \"%s\" section", _TEXT);
Jim Blandy's avatar
Jim Blandy committed
249 250 251
	}
      if (f_dhdr == 0)
	{
252
	  ERROR1 ("unexec: couldn't find \"%s\" section", _DATA);
Jim Blandy's avatar
Jim Blandy committed
253 254 255
	}
      if (f_bhdr == 0)
	{
256
	  ERROR1 ("unexec: couldn't find \"%s\" section", _BSS);
Jim Blandy's avatar
Jim Blandy committed
257
	}
Jim Blandy's avatar
Jim Blandy committed
258
    }
Jim Blandy's avatar
Jim Blandy committed
259
  else
Jim Blandy's avatar
Jim Blandy committed
260
    {
Jim Blandy's avatar
Jim Blandy committed
261
      ERROR0 ("can't build a COFF file from scratch yet");
Jim Blandy's avatar
Jim Blandy committed
262
    }
Jim Blandy's avatar
Jim Blandy committed
263 264 265 266 267
  orig_data_scnptr = f_dhdr->s_scnptr;
  orig_load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;

  /* Now we alter the contents of all the f_*hdr variables
     to correspond to what we want to dump.  */
268 269 270 271 272

  /* Indicate that the reloc information is no longer valid for ld (bind);
     we only update it enough to fake out the exec-time loader.  */
  f_hdr.f_flags |= (F_RELFLG | F_EXEC);

273
  f_ohdr.dsize = bss_start - f_ohdr.data_start;
274
  f_ohdr.bsize = 0;
Jim Blandy's avatar
Jim Blandy committed
275 276 277

  f_dhdr->s_size = f_ohdr.dsize;
  f_bhdr->s_size = f_ohdr.bsize;
278 279
  f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize;
  f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
Jim Blandy's avatar
Jim Blandy committed
280 281 282

  /* fix scnptr's */
  {
Paul Eggert's avatar
Paul Eggert committed
283
    off_t ptr = section[0].s_scnptr;
Jim Blandy's avatar
Jim Blandy committed
284

285 286 287 288
    bias = -1;
    for (scns = 0; scns < f_hdr.f_nscns; scns++)
      {
	struct scnhdr *s = &section[scns];
Jim Blandy's avatar
Jim Blandy committed
289

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
	if (s->s_flags & STYP_PAD)        /* .pad sections omitted in AIX 4.1 */
	  {
	    /*
	     * the text_start should probably be o_algntext but that doesn't
	     * seem to change
	     */
	    if (f_ohdr.text_start != 0) /* && scns != 0 */
	      {
		s->s_size = 512 - (ptr % 512);
		if (s->s_size == 512)
		  s->s_size = 0;
	      }
	    s->s_scnptr = ptr;
	  }
	else if (s->s_flags & STYP_DATA)
Jim Blandy's avatar
Jim Blandy committed
305
	  s->s_scnptr = ptr;
306 307 308 309
	else if (!(s->s_flags & (STYP_TEXT | STYP_BSS)))
	  {
	    if (bias == -1)                /* if first section after bss */
	      bias = ptr - s->s_scnptr;
Jim Blandy's avatar
Jim Blandy committed
310

311 312 313
	    s->s_scnptr += bias;
	    ptr = s->s_scnptr;
	  }
314

315 316
	ptr = ptr + s->s_size;
      }
Jim Blandy's avatar
Jim Blandy committed
317 318 319
  }

  /* fix other pointers */
320 321 322
  for (scns = 0; scns < f_hdr.f_nscns; scns++)
    {
      struct scnhdr *s = &section[scns];
Jim Blandy's avatar
Jim Blandy committed
323

324 325 326 327 328 329 330 331 332 333
      if (s->s_relptr != 0)
	{
	  s->s_relptr += bias;
	}
      if (s->s_lnnoptr != 0)
	{
	  if (lnnoptr == 0) lnnoptr = s->s_lnnoptr;
	  s->s_lnnoptr += bias;
	}
    }
Jim Blandy's avatar
Jim Blandy committed
334 335

  if (f_hdr.f_symptr > 0L)
Jim Blandy's avatar
Jim Blandy committed
336
    {
Jim Blandy's avatar
Jim Blandy committed
337
      f_hdr.f_symptr += bias;
Jim Blandy's avatar
Jim Blandy committed
338 339
    }

Jim Blandy's avatar
Jim Blandy committed
340 341 342
  text_scnptr = f_thdr->s_scnptr;
  data_scnptr = f_dhdr->s_scnptr;
  load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0;
Jim Blandy's avatar
Jim Blandy committed
343

Jim Blandy's avatar
Jim Blandy committed
344 345 346 347
  if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
    {
      PERROR (new_name);
    }
Jim Blandy's avatar
Jim Blandy committed
348

Jim Blandy's avatar
Jim Blandy committed
349 350 351
  if (f_hdr.f_opthdr > 0)
    {
      if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
Jim Blandy's avatar
Jim Blandy committed
352
	{
Jim Blandy's avatar
Jim Blandy committed
353 354 355
	  PERROR (new_name);
	}
    }
Jim Blandy's avatar
Jim Blandy committed
356

Jim Blandy's avatar
Jim Blandy committed
357 358 359 360 361 362 363
  for (scns = 0; scns < f_hdr.f_nscns; scns++) {
    struct scnhdr *s = &section[scns];
    if (write (new, s, sizeof (*s)) != sizeof (*s))
      {
	PERROR (new_name);
      }
  }
Jim Blandy's avatar
Jim Blandy committed
364

Jim Blandy's avatar
Jim Blandy committed
365 366 367 368
  return (0);
}

/* ****************************************************************
369

Jim Blandy's avatar
Jim Blandy committed
370 371 372 373
 *
 * Copy the text and data segments from memory to the new a.out
 */
static int
374
copy_text_and_data (int new)
Jim Blandy's avatar
Jim Blandy committed
375
{
376 377
  char *end;
  char *ptr;
Jim Blandy's avatar
Jim Blandy committed
378

Paul Eggert's avatar
Paul Eggert committed
379
  lseek (new, text_scnptr, SEEK_SET);
Paul Eggert's avatar
Paul Eggert committed
380
  ptr = _text;
Jim Blandy's avatar
Jim Blandy committed
381 382 383
  end = ptr + f_ohdr.tsize;
  write_segment (new, ptr, end);

Paul Eggert's avatar
Paul Eggert committed
384
  lseek (new, data_scnptr, SEEK_SET);
385
  ptr = (char *) (ptrdiff_t) f_ohdr.data_start;
Jim Blandy's avatar
Jim Blandy committed
386 387 388 389 390 391
  end = ptr + f_ohdr.dsize;
  write_segment (new, ptr, end);

  return 0;
}

392
#define UnexBlockSz (1<<12)			/* read/write block size */
393 394
static void
write_segment (int new, char *ptr, char *end)
Jim Blandy's avatar
Jim Blandy committed
395
{
396
  int i, nwrite, ret;
397
  char zeros[UnexBlockSz];
Jim Blandy's avatar
Jim Blandy committed
398 399 400

  for (i = 0; ptr < end;)
    {
401
      /* distance to next block.  */
402
      nwrite = (((ptrdiff_t) ptr + UnexBlockSz) & -UnexBlockSz) - (ptrdiff_t) ptr;
Jim Blandy's avatar
Jim Blandy committed
403 404 405 406 407 408 409 410
      /* But not beyond specified end.  */
      if (nwrite > end - ptr) nwrite = end - ptr;
      ret = write (new, ptr, nwrite);
      /* If write gets a page fault, it means we reached
	 a gap between the old text segment and the old data segment.
	 This gap has probably been remapped into part of the text segment.
	 So write zeros for it.  */
      if (ret == -1 && errno == EFAULT)
Jim Blandy's avatar
Jim Blandy committed
411
	{
412
	  memset (zeros, 0, nwrite);
413
	  write (new, zeros, nwrite);
Jim Blandy's avatar
Jim Blandy committed
414
	}
Jim Blandy's avatar
Jim Blandy committed
415
      else if (nwrite != ret)
Jim Blandy's avatar
Jim Blandy committed
416
	{
Paul Eggert's avatar
Paul Eggert committed
417 418 419
	  int write_errno = errno;
	  char buf[1000];
	  void *addr = ptr;
Jim Blandy's avatar
Jim Blandy committed
420
	  sprintf (buf,
Paul Eggert's avatar
Paul Eggert committed
421 422 423
		   "unexec write failure: addr %p, fileno %d, size 0x%x, wrote 0x%x, errno %d",
		   addr, new, nwrite, ret, errno);
	  errno = write_errno;
Jim Blandy's avatar
Jim Blandy committed
424
	  PERROR (buf);
Jim Blandy's avatar
Jim Blandy committed
425
	}
Jim Blandy's avatar
Jim Blandy committed
426 427 428 429 430 431 432 433 434 435 436
      i += nwrite;
      ptr += nwrite;
    }
}

/* ****************************************************************
 * copy_sym
 *
 * Copy the relocation information and symbol table from the a.out to the new
 */
static int
437
copy_sym (int new, int a_out, const char *a_name, const char *new_name)
Jim Blandy's avatar
Jim Blandy committed
438
{
439
  char page[UnexBlockSz];
Jim Blandy's avatar
Jim Blandy committed
440
  int n;
Jim Blandy's avatar
Jim Blandy committed
441

Jim Blandy's avatar
Jim Blandy committed
442 443
  if (a_out < 0)
    return 0;
Jim Blandy's avatar
Jim Blandy committed
444

445
  if (orig_load_scnptr == 0L)
Jim Blandy's avatar
Jim Blandy committed
446
    return 0;
Jim Blandy's avatar
Jim Blandy committed
447

448
  if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info  */
449
    lseek (a_out, lnnoptr, SEEK_SET);  /* start copying from there */
Jim Blandy's avatar
Jim Blandy committed
450
  else
451
    lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */
Jim Blandy's avatar
Jim Blandy committed
452 453 454 455

  while ((n = read (a_out, page, sizeof page)) > 0)
    {
      if (write (new, page, n) != n)
Jim Blandy's avatar
Jim Blandy committed
456
	{
Jim Blandy's avatar
Jim Blandy committed
457
	  PERROR (new_name);
Jim Blandy's avatar
Jim Blandy committed
458 459
	}
    }
Jim Blandy's avatar
Jim Blandy committed
460 461 462 463 464 465 466
  if (n < 0)
    {
      PERROR (a_name);
    }
  return 0;
}

467
static int
468
adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name)
Jim Blandy's avatar
Jim Blandy committed
469
{
470 471 472
  int nsyms;
  int naux;
  int new;
Jim Blandy's avatar
Jim Blandy committed
473 474 475 476 477 478
  struct syment symentry;
  union auxent auxentry;

  if (!lnnoptr || !f_hdr.f_symptr)
    return 0;

479
  if ((new = emacs_open (new_name, O_RDWR, 0)) < 0)
Jim Blandy's avatar
Jim Blandy committed
480 481 482 483 484
    {
      PERROR (new_name);
      return -1;
    }

485
  lseek (new, f_hdr.f_symptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
486 487 488
  for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
    {
      read (new, &symentry, SYMESZ);
489 490 491
      if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL)
	{
	  symentry.n_value += bias;
492
	  lseek (new, -SYMESZ, SEEK_CUR);
493 494 495
	  write (new, &symentry, SYMESZ);
	}

496
      for (naux = symentry.n_numaux; naux-- != 0; )
Jim Blandy's avatar
Jim Blandy committed
497 498 499
	{
	  read (new, &auxentry, AUXESZ);
	  nsyms++;
500 501 502 503
	  if (naux != 0              /* skip csect auxentry (last entry) */
              && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT))
            {
              auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
504
              lseek (new, -AUXESZ, SEEK_CUR);
505 506
              write (new, &auxentry, AUXESZ);
            }
Jim Blandy's avatar
Jim Blandy committed
507 508
	}
    }
509
  emacs_close (new);
Jim Blandy's avatar
Jim Blandy committed
510

511 512
  return 0;
}
Jim Blandy's avatar
Jim Blandy committed
513

514
static int
515 516
unrelocate_symbols (int new, int a_out,
		    const char *a_name, const char *new_name)
Jim Blandy's avatar
Jim Blandy committed
517
{
518
  int i;
Jim Blandy's avatar
Jim Blandy committed
519
  LDHDR ldhdr;
520
  LDREL ldrel;
Paul Eggert's avatar
Paul Eggert committed
521
  off_t t_reloc = (intptr_t) _text - f_ohdr.text_start;
522
#ifndef ALIGN_DATA_RELOC
Paul Eggert's avatar
Paul Eggert committed
523
  off_t d_reloc = (intptr_t) _data - f_ohdr.data_start;
524
#else
525
  /* This worked (and was needed) before AIX 4.2.
526
     I have no idea why. -- Mike */
Paul Eggert's avatar
Paul Eggert committed
527
  off_t d_reloc = (intptr_t) _data - ALIGN (f_ohdr.data_start, 2);
528
#endif
Jim Blandy's avatar
Jim Blandy committed
529 530 531 532 533
  int * p;

  if (load_scnptr == 0)
    return 0;

534
  lseek (a_out, orig_load_scnptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
535 536 537 538 539 540 541 542 543
  if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr))
    {
      PERROR (new_name);
    }

#define SYMNDX_TEXT	0
#define SYMNDX_DATA	1
#define SYMNDX_BSS	2

544 545 546 547 548
  for (i = 0; i < ldhdr.l_nreloc; i++)
    {
      lseek (a_out,
	     orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
	     SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
549

550 551 552 553
      if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ)
	{
	  PERROR (a_name);
	}
Jim Blandy's avatar
Jim Blandy committed
554 555

      /* move the BSS loader symbols to the DATA segment */
556
      if (ldrel.l_symndx == SYMNDX_BSS)
Jim Blandy's avatar
Jim Blandy committed
557
	{
558
	  ldrel.l_symndx = SYMNDX_DATA;
559

Jim Blandy's avatar
Jim Blandy committed
560 561
	  lseek (new,
		 load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
562
		 SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
563

564
	  if (write (new, &ldrel, LDRELSZ) != LDRELSZ)
Jim Blandy's avatar
Jim Blandy committed
565 566 567 568 569
	    {
	      PERROR (new_name);
	    }
	}

570
      if (ldrel.l_rsecnm == f_ohdr.o_sndata)
Jim Blandy's avatar
Jim Blandy committed
571 572 573
	{
	  int orig_int;

574
	  lseek (a_out,
575 576
                 orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
		 SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
577

578 579
	  if (read (a_out, (void *) &orig_int, sizeof (orig_int))
	      != sizeof (orig_int))
Jim Blandy's avatar
Jim Blandy committed
580 581 582 583
	    {
	      PERROR (a_name);
	    }

Paul Eggert's avatar
Paul Eggert committed
584
          p = (int *) (intptr_t) (ldrel.l_vaddr + d_reloc);
585

586
	  switch (ldrel.l_symndx) {
Jim Blandy's avatar
Jim Blandy committed
587
	  case SYMNDX_TEXT:
588
	    orig_int = * p - t_reloc;
Jim Blandy's avatar
Jim Blandy committed
589 590 591 592
	    break;

	  case SYMNDX_DATA:
	  case SYMNDX_BSS:
593
	    orig_int = * p - d_reloc;
Jim Blandy's avatar
Jim Blandy committed
594 595 596
	    break;
	  }

597 598 599
          if (orig_int != * p)
            {
              lseek (new,
600 601
                     data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
		     SEEK_SET);
602 603 604 605 606 607
              if (write (new, (void *) &orig_int, sizeof (orig_int))
                  != sizeof (orig_int))
                {
                  PERROR (new_name);
                }
            }
Jim Blandy's avatar
Jim Blandy committed
608 609
	}
    }
610
  return 0;
Jim Blandy's avatar
Jim Blandy committed
611
}