unexaix.c 16.7 KB
Newer Older
1
/* Dump an executable image.
2
   Copyright (C) 1985, 1986, 1987, 1988, 1999, 2001, 2002, 2003, 2004,
Glenn Morris's avatar
Glenn Morris committed
3
                 2005, 2006, 2007, 2008  Free Software Foundation, 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 <http://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 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

static int pagemask;

#ifdef emacs
107
#include "lisp.h"
Jim Blandy's avatar
Jim Blandy committed
108

109 110
static void
report_error (char *file, int fd)
Jim Blandy's avatar
Jim Blandy committed
111 112 113
{
  if (fd)
    close (fd);
114
  report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil));
Jim Blandy's avatar
Jim Blandy committed
115 116
}
#endif /* emacs */
Jim Blandy's avatar
Jim Blandy committed
117

Jim Blandy's avatar
Jim Blandy committed
118 119 120
#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
121

122 123
static void
report_error_1 (int fd, char *msg, int a1, int a2)
Jim Blandy's avatar
Jim Blandy committed
124
{
Jim Blandy's avatar
Jim Blandy committed
125 126 127 128 129 130 131 132 133
  close (fd);
#ifdef emacs
  error (msg, a1, a2);
#else
  fprintf (stderr, msg, a1, a2);
  fprintf (stderr, "\n");
#endif
}

134 135 136 137 138
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
139 140 141 142 143 144

/* ****************************************************************
 * unexec
 *
 * driving logic.
 */
145
int unexec (char *new_name, char *a_name,
146 147 148
	    unsigned data_start,
	    unsigned bss_start,
	    unsigned entry_address)
Jim Blandy's avatar
Jim Blandy committed
149
{
150
  int new = -1, a_out = -1;
Jim Blandy's avatar
Jim Blandy committed
151

152
  if (a_name && (a_out = open (a_name, O_RDONLY)) < 0)
Jim Blandy's avatar
Jim Blandy committed
153 154 155 156 157 158 159
    {
      PERROR (a_name);
    }
  if ((new = creat (new_name, 0666)) < 0)
    {
      PERROR (new_name);
    }
160 161 162 163
  if (make_hdr (new, a_out,
		data_start, bss_start,
		entry_address,
		a_name, new_name) < 0
Jim Blandy's avatar
Jim Blandy committed
164 165 166
      || copy_text_and_data (new) < 0
      || copy_sym (new, a_out, a_name, new_name) < 0
      || adjust_lnnoptrs (new, a_out, new_name) < 0
167
      || unrelocate_symbols (new, a_out, a_name, new_name) < 0)
Jim Blandy's avatar
Jim Blandy committed
168
    {
Jim Blandy's avatar
Jim Blandy committed
169
      close (new);
170
      return -1;
Jim Blandy's avatar
Jim Blandy committed
171 172
    }

Jim Blandy's avatar
Jim Blandy committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186
  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
187 188 189 190
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
191
{
192
  int scns;
Jim Blandy's avatar
Jim Blandy committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
  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
217
    {
Jim Blandy's avatar
Jim Blandy committed
218 219 220 221
      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
222
	{
Jim Blandy's avatar
Jim Blandy committed
223 224
	  ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
		  bss_start);
Jim Blandy's avatar
Jim Blandy committed
225 226
	}
    }
Jim Blandy's avatar
Jim Blandy committed
227 228
  else
    bss_start = bss_end;
Jim Blandy's avatar
Jim Blandy committed
229

Jim Blandy's avatar
Jim Blandy committed
230 231 232 233 234
  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
235

Jim Blandy's avatar
Jim Blandy committed
236 237 238 239
  /* 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
240
    {
Jim Blandy's avatar
Jim Blandy committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
      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) { \
267 268
      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
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    } \
    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)
	{
287
	  ERROR1 ("unexec: couldn't find \"%s\" section", (int) _TEXT);
Jim Blandy's avatar
Jim Blandy committed
288 289 290
	}
      if (f_dhdr == 0)
	{
291
	  ERROR1 ("unexec: couldn't find \"%s\" section", (int) _DATA);
Jim Blandy's avatar
Jim Blandy committed
292 293 294
	}
      if (f_bhdr == 0)
	{
295
	  ERROR1 ("unexec: couldn't find \"%s\" section", (int) _BSS);
Jim Blandy's avatar
Jim Blandy committed
296
	}
Jim Blandy's avatar
Jim Blandy committed
297
    }
Jim Blandy's avatar
Jim Blandy committed
298
  else
Jim Blandy's avatar
Jim Blandy committed
299
    {
Jim Blandy's avatar
Jim Blandy committed
300
      ERROR0 ("can't build a COFF file from scratch yet");
Jim Blandy's avatar
Jim Blandy committed
301
    }
Jim Blandy's avatar
Jim Blandy committed
302 303 304 305 306
  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.  */
307 308 309 310 311

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

312
  f_ohdr.dsize = bss_start - f_ohdr.data_start;
Jim Blandy's avatar
Jim Blandy committed
313 314 315 316
  f_ohdr.bsize = bss_end - bss_start;

  f_dhdr->s_size = f_ohdr.dsize;
  f_bhdr->s_size = f_ohdr.bsize;
317 318
  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
319 320 321

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

324 325 326 327
    bias = -1;
    for (scns = 0; scns < f_hdr.f_nscns; scns++)
      {
	struct scnhdr *s = &section[scns];
Jim Blandy's avatar
Jim Blandy committed
328

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
	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
344
	  s->s_scnptr = ptr;
345 346 347 348
	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
349

350 351 352
	    s->s_scnptr += bias;
	    ptr = s->s_scnptr;
	  }
353

354 355
	ptr = ptr + s->s_size;
      }
Jim Blandy's avatar
Jim Blandy committed
356 357 358
  }

  /* fix other pointers */
359 360 361
  for (scns = 0; scns < f_hdr.f_nscns; scns++)
    {
      struct scnhdr *s = &section[scns];
Jim Blandy's avatar
Jim Blandy committed
362

363 364 365 366 367 368 369 370 371 372
      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
373 374

  if (f_hdr.f_symptr > 0L)
Jim Blandy's avatar
Jim Blandy committed
375
    {
Jim Blandy's avatar
Jim Blandy committed
376
      f_hdr.f_symptr += bias;
Jim Blandy's avatar
Jim Blandy committed
377 378
    }

Jim Blandy's avatar
Jim Blandy committed
379 380 381
  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
382

Jim Blandy's avatar
Jim Blandy committed
383 384 385 386
  if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
    {
      PERROR (new_name);
    }
Jim Blandy's avatar
Jim Blandy committed
387

Jim Blandy's avatar
Jim Blandy committed
388 389 390
  if (f_hdr.f_opthdr > 0)
    {
      if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
Jim Blandy's avatar
Jim Blandy committed
391
	{
Jim Blandy's avatar
Jim Blandy committed
392 393 394
	  PERROR (new_name);
	}
    }
Jim Blandy's avatar
Jim Blandy committed
395

Jim Blandy's avatar
Jim Blandy committed
396 397 398 399 400 401 402
  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
403

Jim Blandy's avatar
Jim Blandy committed
404 405 406 407
  return (0);
}

/* ****************************************************************
408

Jim Blandy's avatar
Jim Blandy committed
409 410 411 412
 *
 * Copy the text and data segments from memory to the new a.out
 */
static int
413
copy_text_and_data (int new)
Jim Blandy's avatar
Jim Blandy committed
414
{
415 416
  char *end;
  char *ptr;
Jim Blandy's avatar
Jim Blandy committed
417

418
  lseek (new, (long) text_scnptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
419 420 421 422
  ptr = start_of_text () + text_scnptr;
  end = ptr + f_ohdr.tsize;
  write_segment (new, ptr, end);

423 424
  lseek (new, (long) data_scnptr, SEEK_SET);
  ptr = (char *) f_ohdr.data_start;
Jim Blandy's avatar
Jim Blandy committed
425 426 427 428 429 430
  end = ptr + f_ohdr.dsize;
  write_segment (new, ptr, end);

  return 0;
}

431
#define UnexBlockSz (1<<12)			/* read/write block size */
432 433
static void
write_segment (int new, char *ptr, char *end)
Jim Blandy's avatar
Jim Blandy committed
434
{
435
  int i, nwrite, ret;
Jim Blandy's avatar
Jim Blandy committed
436 437
  char buf[80];
  extern int errno;
438
  char zeros[UnexBlockSz];
Jim Blandy's avatar
Jim Blandy committed
439 440 441

  for (i = 0; ptr < end;)
    {
442 443
      /* distance to next block.  */
      nwrite = (((int) ptr + UnexBlockSz) & -UnexBlockSz) - (int) ptr;
Jim Blandy's avatar
Jim Blandy committed
444 445 446 447 448 449 450 451
      /* 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
452
	{
453
	  memset (zeros, 0, nwrite);
454
	  write (new, zeros, nwrite);
Jim Blandy's avatar
Jim Blandy committed
455
	}
Jim Blandy's avatar
Jim Blandy committed
456
      else if (nwrite != ret)
Jim Blandy's avatar
Jim Blandy committed
457
	{
Jim Blandy's avatar
Jim Blandy committed
458
	  sprintf (buf,
459 460
		   "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
461
	  PERROR (buf);
Jim Blandy's avatar
Jim Blandy committed
462
	}
Jim Blandy's avatar
Jim Blandy committed
463 464 465 466 467 468 469 470 471 472 473
      i += nwrite;
      ptr += nwrite;
    }
}

/* ****************************************************************
 * copy_sym
 *
 * Copy the relocation information and symbol table from the a.out to the new
 */
static int
474
copy_sym (int new, int a_out, char *a_name, char *new_name)
Jim Blandy's avatar
Jim Blandy committed
475
{
476
  char page[UnexBlockSz];
Jim Blandy's avatar
Jim Blandy committed
477
  int n;
Jim Blandy's avatar
Jim Blandy committed
478

Jim Blandy's avatar
Jim Blandy committed
479 480
  if (a_out < 0)
    return 0;
Jim Blandy's avatar
Jim Blandy committed
481

482
  if (orig_load_scnptr == 0L)
Jim Blandy's avatar
Jim Blandy committed
483
    return 0;
Jim Blandy's avatar
Jim Blandy committed
484

485
  if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info  */
486
    lseek (a_out, lnnoptr, SEEK_SET);  /* start copying from there */
Jim Blandy's avatar
Jim Blandy committed
487
  else
488
    lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */
Jim Blandy's avatar
Jim Blandy committed
489 490 491 492

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

Jim Blandy's avatar
Jim Blandy committed
516 517 518 519 520 521 522 523 524 525 526
  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);
}

527 528
static int
adjust_lnnoptrs (int writedesc, int readdesc, char *new_name)
Jim Blandy's avatar
Jim Blandy committed
529
{
530 531 532
  int nsyms;
  int naux;
  int new;
Jim Blandy's avatar
Jim Blandy committed
533 534 535 536 537 538
  struct syment symentry;
  union auxent auxentry;

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

539
  if ((new = open (new_name, O_RDWR)) < 0)
Jim Blandy's avatar
Jim Blandy committed
540 541 542 543 544
    {
      PERROR (new_name);
      return -1;
    }

545
  lseek (new, f_hdr.f_symptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
546 547 548
  for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
    {
      read (new, &symentry, SYMESZ);
549 550 551
      if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL)
	{
	  symentry.n_value += bias;
552
	  lseek (new, -SYMESZ, SEEK_CUR);
553 554 555
	  write (new, &symentry, SYMESZ);
	}

556
      for (naux = symentry.n_numaux; naux-- != 0; )
Jim Blandy's avatar
Jim Blandy committed
557 558 559
	{
	  read (new, &auxentry, AUXESZ);
	  nsyms++;
560 561 562 563
	  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;
564
              lseek (new, -AUXESZ, SEEK_CUR);
565 566
              write (new, &auxentry, AUXESZ);
            }
Jim Blandy's avatar
Jim Blandy committed
567 568 569
	}
    }
  close (new);
Jim Blandy's avatar
Jim Blandy committed
570

571 572
  return 0;
}
Jim Blandy's avatar
Jim Blandy committed
573

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

  if (load_scnptr == 0)
    return 0;

593
  lseek (a_out, orig_load_scnptr, SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
594 595 596 597 598 599 600 601 602
  if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr))
    {
      PERROR (new_name);
    }

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

603 604 605 606 607
  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
608

609 610 611 612
      if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ)
	{
	  PERROR (a_name);
	}
Jim Blandy's avatar
Jim Blandy committed
613 614

      /* move the BSS loader symbols to the DATA segment */
615
      if (ldrel.l_symndx == SYMNDX_BSS)
Jim Blandy's avatar
Jim Blandy committed
616
	{
617
	  ldrel.l_symndx = SYMNDX_DATA;
618

Jim Blandy's avatar
Jim Blandy committed
619 620
	  lseek (new,
		 load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i,
621
		 SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
622

623
	  if (write (new, &ldrel, LDRELSZ) != LDRELSZ)
Jim Blandy's avatar
Jim Blandy committed
624 625 626 627 628
	    {
	      PERROR (new_name);
	    }
	}

629
      if (ldrel.l_rsecnm == f_ohdr.o_sndata)
Jim Blandy's avatar
Jim Blandy committed
630 631 632
	{
	  int orig_int;

633
	  lseek (a_out,
634 635
                 orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
		 SEEK_SET);
Jim Blandy's avatar
Jim Blandy committed
636

637 638
	  if (read (a_out, (void *) &orig_int, sizeof (orig_int))
	      != sizeof (orig_int))
Jim Blandy's avatar
Jim Blandy committed
639 640 641 642
	    {
	      PERROR (a_name);
	    }

643
          p = (int *) (ldrel.l_vaddr + d_reloc);
644

645
	  switch (ldrel.l_symndx) {
Jim Blandy's avatar
Jim Blandy committed
646
	  case SYMNDX_TEXT:
647
	    orig_int = * p - t_reloc;
Jim Blandy's avatar
Jim Blandy committed
648 649 650 651
	    break;

	  case SYMNDX_DATA:
	  case SYMNDX_BSS:
652
	    orig_int = * p - d_reloc;
Jim Blandy's avatar
Jim Blandy committed
653 654 655
	    break;
	  }

656 657 658
          if (orig_int != * p)
            {
              lseek (new,
659 660
                     data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start),
		     SEEK_SET);
661 662 663 664 665 666
              if (write (new, (void *) &orig_int, sizeof (orig_int))
                  != sizeof (orig_int))
                {
                  PERROR (new_name);
                }
            }
Jim Blandy's avatar
Jim Blandy committed
667 668
	}
    }
669
  return 0;
Jim Blandy's avatar
Jim Blandy committed
670
}
Miles Bader's avatar
Miles Bader committed
671 672 673

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