unexaix.c 17 KB
Newer Older
1 2
/* Dump an executable image.
   Copyright (C) 1985, 1986, 1987, 1988, 1999 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
3

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

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
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Jim Blandy's avatar
Jim Blandy committed
20 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 34 35 36 37 38 39 40 41 42
 * Synopsis:
 *	unexec (new_name, a_name, data_start, bss_start, entry_address)
 *	char *new_name, *a_name;
 *	unsigned data_start, bss_start, entry_address;
 *
 * 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
 * data_start and entry_address are ignored.
Jim Blandy's avatar
Jim Blandy committed
44
 *
45
 * bss_start indicates how much of the data segment is to be saved in the
Jim Blandy's avatar
Jim Blandy committed
46 47 48 49
 * a.out file and restored when the program is executed.  It gives the lowest
 * unsaved address, and is rounded up to a page boundary.  The default when 0
 * is given assumes that the entire data segment is to be stored, including
 * the previous data and bss as well as any additional storage allocated with
50
 * sbrk(2).
Jim Blandy's avatar
Jim Blandy committed
51 52 53 54 55 56
 *
 */

#ifndef emacs
#define PERROR(arg) perror (arg); return -1
#else
57
#include <config.h>
Jim Blandy's avatar
Jim Blandy committed
58 59
#define PERROR(file) report_error (file, new)
#endif
Jim Blandy's avatar
Jim Blandy committed
60

Jim Blandy's avatar
Jim Blandy committed
61 62 63 64 65
#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
66

Jim Blandy's avatar
Jim Blandy committed
67 68 69 70
#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
71 72
#include <unistd.h>
#include <fcntl.h>
Jim Blandy's avatar
Jim Blandy committed
73

74 75
extern char *start_of_text (void);		/* Start of text */
extern char *start_of_data (void);		/* Start of initialized data */
Jim Blandy's avatar
Jim Blandy committed
76 77 78

extern int _data;
extern int _text;
79

Jim Blandy's avatar
Jim Blandy committed
80 81 82 83
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <syms.h>
84

Jim Blandy's avatar
Jim Blandy committed
85 86
static struct filehdr f_hdr;		/* File header */
static struct aouthdr f_ohdr;		/* Optional file header (a.out) */
87 88
static long bias;			/* Bias to add for growth */
static long lnnoptr;			/* Pointer to line-number info within file */
Jim Blandy's avatar
Jim Blandy committed
89 90 91

static long text_scnptr;
static long data_scnptr;
92
#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1))
Jim Blandy's avatar
Jim Blandy committed
93 94 95
static long load_scnptr;
static long orig_load_scnptr;
static long orig_data_scnptr;
96
static int unrelocate_symbols (int, int, char *, char *);
Jim Blandy's avatar
Jim Blandy committed
97 98 99 100 101

#ifndef MAX_SECTIONS
#define MAX_SECTIONS	10
#endif

102
static int adjust_lnnoptrs (int, int, char *);
Jim Blandy's avatar
Jim Blandy committed
103 104 105 106 107 108 109 110 111 112 113 114

static int pagemask;

/* Correct an int which is the bit pattern of a pointer to a byte
   into an int which is the number of a byte.
   This is a no-op on ordinary machines, but not on all.  */

#ifndef ADDR_CORRECT   /* Let m-*.h files override this definition */
#define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
#endif

#ifdef emacs
115
#include "lisp.h"
Jim Blandy's avatar
Jim Blandy committed
116

117 118
static void
report_error (char *file, int fd)
Jim Blandy's avatar
Jim Blandy committed
119 120 121
{
  if (fd)
    close (fd);
122
  report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
Jim Blandy's avatar
Jim Blandy committed
123 124
}
#endif /* emacs */
Jim Blandy's avatar
Jim Blandy committed
125

Jim Blandy's avatar
Jim Blandy committed
126 127 128
#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
Jim Blandy's avatar
Jim Blandy committed
129

130 131
static void
report_error_1 (int fd, char *msg, int a1, int a2)
Jim Blandy's avatar
Jim Blandy committed
132
{
Jim Blandy's avatar
Jim Blandy committed
133 134 135 136 137 138 139 140 141
  close (fd);
#ifdef emacs
  error (msg, a1, a2);
#else
  fprintf (stderr, msg, a1, a2);
  fprintf (stderr, "\n");
#endif
}

142 143 144 145 146
static int make_hdr (int, int, unsigned, unsigned, unsigned, char *, char *);
static void mark_x (char *);
static int copy_text_and_data (int);
static int copy_sym (int, int, char *, char *);
static void write_segment (int, char *, char *);
Jim Blandy's avatar
Jim Blandy committed
147 148 149 150 151 152

/* ****************************************************************
 * unexec
 *
 * driving logic.
 */
153
int unexec (char *new_name, char *a_name,
154 155 156
	    unsigned data_start,
	    unsigned bss_start,
	    unsigned entry_address)
Jim Blandy's avatar
Jim Blandy committed
157
{
158
  int new = -1, a_out = -1;
Jim Blandy's avatar
Jim Blandy committed
159

160
  if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
Jim Blandy's avatar
Jim Blandy committed
161 162 163 164 165 166 167
    {
      PERROR (a_name);
    }
  if ((new = creat (new_name, 0666)) < 0)
    {
      PERROR (new_name);
    }
168 169 170 171
  if (make_hdr (new, a_out,
		data_start, bss_start,
		entry_address,
		a_name, new_name) < 0
Jim Blandy's avatar
Jim Blandy committed
172 173 174
      || copy_text_and_data (new) < 0
      || copy_sym (new, a_out, a_name, new_name) < 0
      || adjust_lnnoptrs (new, a_out, new_name) < 0
175
      || unrelocate_symbols (new, a_out, a_name, new_name) < 0)
Jim Blandy's avatar
Jim Blandy committed
176
    {
Jim Blandy's avatar
Jim Blandy committed
177
      close (new);
178
      return -1;
Jim Blandy's avatar
Jim Blandy committed
179 180
    }

Jim Blandy's avatar
Jim Blandy committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194
  close (new);
  if (a_out >= 0)
    close (a_out);
  mark_x (new_name);
  return 0;
}

/* ****************************************************************
 * make_hdr
 *
 * Make the header in the new a.out from the header in core.
 * Modify the text and data sizes.
 */
static int
195 196 197 198
make_hdr (int new, int a_out,
	  unsigned data_start, unsigned bss_start,
	  unsigned entry_address,
	  char *a_name, char *new_name)
Jim Blandy's avatar
Jim Blandy committed
199
{
200
  int scns;
Jim Blandy's avatar
Jim Blandy committed
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
  unsigned int bss_end;

  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. */
  data_start = (long) start_of_data ();
  data_start = ADDR_CORRECT (data_start);

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

  bss_end = ADDR_CORRECT (sbrk (0)) + pagemask;
  bss_end &= ~ pagemask;
  /* Adjust data/bss boundary. */
  if (bss_start != 0)
Jim Blandy's avatar
Jim Blandy committed
225
    {
Jim Blandy's avatar
Jim Blandy committed
226 227 228 229
      bss_start = (ADDR_CORRECT (bss_start) + pagemask);
      /* (Up) to page bdry. */
      bss_start &= ~ pagemask;
      if (bss_start > bss_end)
Jim Blandy's avatar
Jim Blandy committed
230
	{
Jim Blandy's avatar
Jim Blandy committed
231 232
	  ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
		  bss_start);
Jim Blandy's avatar
Jim Blandy committed
233 234
	}
    }
Jim Blandy's avatar
Jim Blandy committed
235 236
  else
    bss_start = bss_end;
Jim Blandy's avatar
Jim Blandy committed
237

Jim Blandy's avatar
Jim Blandy committed
238 239 240 241 242
  if (data_start > bss_start)	/* Can't have negative data size. */
    {
      ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
	      data_start, bss_start);
    }
Jim Blandy's avatar
Jim Blandy committed
243

Jim Blandy's avatar
Jim Blandy committed
244 245 246 247
  /* 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
248
    {
Jim Blandy's avatar
Jim Blandy committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
      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) \
  if (strcmp(s->s_name, name) == 0) { \
    if (s->s_flags != flags) { \
275 276
      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
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
    } \
    if (ptr) { \
      fprintf(stderr, "unexec: duplicate section header for section %s.\n", \
	      name); \
    } \
    ptr = s; \
  }
	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);
      }

      if (f_thdr == 0)
	{
295
	  ERROR1 ("unexec: couldn't find \"%s\" section", (int) _TEXT);
Jim Blandy's avatar
Jim Blandy committed
296 297 298
	}
      if (f_dhdr == 0)
	{
299
	  ERROR1 ("unexec: couldn't find \"%s\" section", (int) _DATA);
Jim Blandy's avatar
Jim Blandy committed
300 301 302
	}
      if (f_bhdr == 0)
	{
303
	  ERROR1 ("unexec: couldn't find \"%s\" section", (int) _BSS);
Jim Blandy's avatar
Jim Blandy committed
304
	}
Jim Blandy's avatar
Jim Blandy committed
305
    }
Jim Blandy's avatar
Jim Blandy committed
306
  else
Jim Blandy's avatar
Jim Blandy committed
307
    {
Jim Blandy's avatar
Jim Blandy committed
308
      ERROR0 ("can't build a COFF file from scratch yet");
Jim Blandy's avatar
Jim Blandy committed
309
    }
Jim Blandy's avatar
Jim Blandy committed
310 311 312 313 314
  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.  */
315 316 317 318 319

  /* 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);

320
  f_ohdr.dsize = bss_start - f_ohdr.data_start;
Jim Blandy's avatar
Jim Blandy committed
321 322 323 324
  f_ohdr.bsize = bss_end - bss_start;

  f_dhdr->s_size = f_ohdr.dsize;
  f_bhdr->s_size = f_ohdr.bsize;
325 326
  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
327 328 329

  /* fix scnptr's */
  {
330
    ulong ptr = section[0].s_scnptr;
Jim Blandy's avatar
Jim Blandy committed
331

332 333 334 335
    bias = -1;
    for (scns = 0; scns < f_hdr.f_nscns; scns++)
      {
	struct scnhdr *s = &section[scns];
Jim Blandy's avatar
Jim Blandy committed
336

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	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
352
	  s->s_scnptr = ptr;
353 354 355 356
	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
357

358 359 360
	    s->s_scnptr += bias;
	    ptr = s->s_scnptr;
	  }
361

362 363
	ptr = ptr + s->s_size;
      }
Jim Blandy's avatar
Jim Blandy committed
364 365 366
  }

  /* fix other pointers */
367 368 369
  for (scns = 0; scns < f_hdr.f_nscns; scns++)
    {
      struct scnhdr *s = &section[scns];
Jim Blandy's avatar
Jim Blandy committed
370

371 372 373 374 375 376 377 378 379 380
      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
381 382

  if (f_hdr.f_symptr > 0L)
Jim Blandy's avatar
Jim Blandy committed
383
    {
Jim Blandy's avatar
Jim Blandy committed
384
      f_hdr.f_symptr += bias;
Jim Blandy's avatar
Jim Blandy committed
385 386
    }

Jim Blandy's avatar
Jim Blandy committed
387 388 389
  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
390

Jim Blandy's avatar
Jim Blandy committed
391 392 393 394
  if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
    {
      PERROR (new_name);
    }
Jim Blandy's avatar
Jim Blandy committed
395

Jim Blandy's avatar
Jim Blandy committed
396 397 398
  if (f_hdr.f_opthdr > 0)
    {
      if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
Jim Blandy's avatar
Jim Blandy committed
399
	{
Jim Blandy's avatar
Jim Blandy committed
400 401 402
	  PERROR (new_name);
	}
    }
Jim Blandy's avatar
Jim Blandy committed
403

Jim Blandy's avatar
Jim Blandy committed
404 405 406 407 408 409 410
  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
411

Jim Blandy's avatar
Jim Blandy committed
412 413 414 415
  return (0);
}

/* ****************************************************************
416

Jim Blandy's avatar
Jim Blandy committed
417 418 419 420
 *
 * Copy the text and data segments from memory to the new a.out
 */
static int
421
copy_text_and_data (int new)
Jim Blandy's avatar
Jim Blandy committed
422
{
423 424
  char *end;
  char *ptr;
Jim Blandy's avatar
Jim Blandy committed
425

426
  lseek (new, (long) text_scnptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
427 428 429 430
  ptr = start_of_text () + text_scnptr;
  end = ptr + f_ohdr.tsize;
  write_segment (new, ptr, end);

431 432
  lseek (new, (long) data_scnptr, SEEK_SET);
  ptr = (char *) f_ohdr.data_start;
Jim Blandy's avatar
Jim Blandy committed
433 434 435 436 437 438
  end = ptr + f_ohdr.dsize;
  write_segment (new, ptr, end);

  return 0;
}

439
#define UnexBlockSz (1<<12)			/* read/write block size */
440 441
static void
write_segment (int new, char *ptr, char *end)
Jim Blandy's avatar
Jim Blandy committed
442
{
443
  int i, nwrite, ret;
Jim Blandy's avatar
Jim Blandy committed
444 445
  char buf[80];
  extern int errno;
446
  char zeros[UnexBlockSz];
Jim Blandy's avatar
Jim Blandy committed
447 448 449

  for (i = 0; ptr < end;)
    {
450 451
      /* distance to next block.  */
      nwrite = (((int) ptr + UnexBlockSz) & -UnexBlockSz) - (int) ptr;
Jim Blandy's avatar
Jim Blandy committed
452 453 454 455 456 457 458 459
      /* 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
460
	{
461
	  memset (zeros, 0, nwrite);
462
	  write (new, zeros, nwrite);
Jim Blandy's avatar
Jim Blandy committed
463
	}
Jim Blandy's avatar
Jim Blandy committed
464
      else if (nwrite != ret)
Jim Blandy's avatar
Jim Blandy committed
465
	{
Jim Blandy's avatar
Jim Blandy committed
466
	  sprintf (buf,
467 468
		   "unexec write failure: addr 0x%lx, fileno %d, size 0x%x, wrote 0x%x, errno %d",
		   (unsigned long)ptr, new, nwrite, ret, errno);
Jim Blandy's avatar
Jim Blandy committed
469
	  PERROR (buf);
Jim Blandy's avatar
Jim Blandy committed
470
	}
Jim Blandy's avatar
Jim Blandy committed
471 472 473 474 475 476 477 478 479 480 481
      i += nwrite;
      ptr += nwrite;
    }
}

/* ****************************************************************
 * copy_sym
 *
 * Copy the relocation information and symbol table from the a.out to the new
 */
static int
482
copy_sym (int new, int a_out, char *a_name, char *new_name)
Jim Blandy's avatar
Jim Blandy committed
483
{
484
  char page[UnexBlockSz];
Jim Blandy's avatar
Jim Blandy committed
485
  int n;
Jim Blandy's avatar
Jim Blandy committed
486

Jim Blandy's avatar
Jim Blandy committed
487 488
  if (a_out < 0)
    return 0;
Jim Blandy's avatar
Jim Blandy committed
489

490
  if (orig_load_scnptr == 0L)
Jim Blandy's avatar
Jim Blandy committed
491
    return 0;
Jim Blandy's avatar
Jim Blandy committed
492

493
  if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info  */
494
    lseek (a_out, lnnoptr, SEEK_SET);  /* start copying from there */
Jim Blandy's avatar
Jim Blandy committed
495
  else
496
    lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */
Jim Blandy's avatar
Jim Blandy committed
497 498 499 500

  while ((n = read (a_out, page, sizeof page)) > 0)
    {
      if (write (new, page, n) != n)
Jim Blandy's avatar
Jim Blandy committed
501
	{
Jim Blandy's avatar
Jim Blandy committed
502
	  PERROR (new_name);
Jim Blandy's avatar
Jim Blandy committed
503 504
	}
    }
Jim Blandy's avatar
Jim Blandy committed
505 506 507 508 509 510 511 512 513 514
  if (n < 0)
    {
      PERROR (a_name);
    }
  return 0;
}

/* ****************************************************************
 * mark_x
 *
515
 * After successfully building the new a.out, mark it executable
Jim Blandy's avatar
Jim Blandy committed
516 517
 */
static void
518
mark_x (char *name)
Jim Blandy's avatar
Jim Blandy committed
519 520 521 522
{
  struct stat sbuf;
  int um;
  int new = 0;  /* for PERROR */
Jim Blandy's avatar
Jim Blandy committed
523

Jim Blandy's avatar
Jim Blandy committed
524 525 526 527 528 529 530 531 532 533 534
  um = umask (777);
  umask (um);
  if (stat (name, &sbuf) == -1)
    {
      PERROR (name);
    }
  sbuf.st_mode |= 0111 & ~um;
  if (chmod (name, sbuf.st_mode) == -1)
    PERROR (name);
}

535 536
static int
adjust_lnnoptrs (int writedesc, int readdesc, char *new_name)
Jim Blandy's avatar
Jim Blandy committed
537
{
538 539 540
  int nsyms;
  int naux;
  int new;
Jim Blandy's avatar
Jim Blandy committed
541 542 543 544 545 546
  struct syment symentry;
  union auxent auxentry;

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

547
  if ((new = open (new_name, O_RDWR)) < 0)
Jim Blandy's avatar
Jim Blandy committed
548 549 550 551 552
    {
      PERROR (new_name);
      return -1;
    }

553
  lseek (new, f_hdr.f_symptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
554 555 556
  for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
    {
      read (new, &symentry, SYMESZ);
557 558 559
      if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL)
	{
	  symentry.n_value += bias;
560
	  lseek (new, -SYMESZ, SEEK_CUR);
561 562 563
	  write (new, &symentry, SYMESZ);
	}

564
      for (naux = symentry.n_numaux; naux-- != 0; )
Jim Blandy's avatar
Jim Blandy committed
565 566 567
	{
	  read (new, &auxentry, AUXESZ);
	  nsyms++;
568 569 570 571
	  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;
572
              lseek (new, -AUXESZ, SEEK_CUR);
573 574
              write (new, &auxentry, AUXESZ);
            }
Jim Blandy's avatar
Jim Blandy committed
575 576 577
	}
    }
  close (new);
Jim Blandy's avatar
Jim Blandy committed
578

579 580
  return 0;
}
Jim Blandy's avatar
Jim Blandy committed
581

582 583
static int
unrelocate_symbols (int new, int a_out, char *a_name, char *new_name)
Jim Blandy's avatar
Jim Blandy committed
584
{
585
  int i;
Jim Blandy's avatar
Jim Blandy committed
586
  LDHDR ldhdr;
587
  LDREL ldrel;
588
  ulong t_reloc = (ulong) &_text - f_ohdr.text_start;
589 590 591
#ifndef ALIGN_DATA_RELOC
  ulong d_reloc = (ulong) &_data - f_ohdr.data_start;
#else
592
  /* This worked (and was needed) before AIX 4.2.
593
     I have no idea why. -- Mike */
594
  ulong d_reloc = (ulong) &_data - ALIGN(f_ohdr.data_start, 2);
595
#endif
Jim Blandy's avatar
Jim Blandy committed
596 597 598 599 600
  int * p;

  if (load_scnptr == 0)
    return 0;

601
  lseek (a_out, orig_load_scnptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
602 603 604 605 606 607 608 609 610
  if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr))
    {
      PERROR (new_name);
    }

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

611 612 613 614 615
  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
616

617 618 619 620
      if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ)
	{
	  PERROR (a_name);
	}
Jim Blandy's avatar
Jim Blandy committed
621 622

      /* move the BSS loader symbols to the DATA segment */
623
      if (ldrel.l_symndx == SYMNDX_BSS)
Jim Blandy's avatar
Jim Blandy committed
624
	{
625
	  ldrel.l_symndx = SYMNDX_DATA;
626

Jim Blandy's avatar
Jim Blandy committed
627 628
	  lseek (new,
		 load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
629
		 SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
630

631
	  if (write (new, &ldrel, LDRELSZ) != LDRELSZ)
Jim Blandy's avatar
Jim Blandy committed
632 633 634 635 636
	    {
	      PERROR (new_name);
	    }
	}

637
      if (ldrel.l_rsecnm == f_ohdr.o_sndata)
Jim Blandy's avatar
Jim Blandy committed
638 639 640
	{
	  int orig_int;

641
	  lseek (a_out,
642 643
                 orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
		 SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
644

645 646
	  if (read (a_out, (void *) &orig_int, sizeof (orig_int))
	      != sizeof (orig_int))
Jim Blandy's avatar
Jim Blandy committed
647 648 649 650
	    {
	      PERROR (a_name);
	    }

651
          p = (int *) (ldrel.l_vaddr + d_reloc);
652

653
	  switch (ldrel.l_symndx) {
Jim Blandy's avatar
Jim Blandy committed
654
	  case SYMNDX_TEXT:
655
	    orig_int = * p - t_reloc;
Jim Blandy's avatar
Jim Blandy committed
656 657 658 659
	    break;

	  case SYMNDX_DATA:
	  case SYMNDX_BSS:
660
	    orig_int = * p - d_reloc;
Jim Blandy's avatar
Jim Blandy committed
661 662 663
	    break;
	  }

664 665 666
          if (orig_int != * p)
            {
              lseek (new,
667 668
                     data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
		     SEEK_SET);
669 670 671 672 673 674
              if (write (new, (void *) &orig_int, sizeof (orig_int))
                  != sizeof (orig_int))
                {
                  PERROR (new_name);
                }
            }
Jim Blandy's avatar
Jim Blandy committed
675 676
	}
    }
677
  return 0;
Jim Blandy's avatar
Jim Blandy committed
678
}
Miles Bader's avatar
Miles Bader committed
679 680 681

/* arch-tag: 0783857a-7c2d-456f-a426-58b722d69fd0
   (do not change this comment) */