|
|
1.1 ! root 1: /* Modified by [email protected] to get it to work :-) */ ! 2: ! 3: /* Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc. ! 4: ! 5: This program is free software; you can redistribute it and/or modify ! 6: it under the terms of the GNU General Public License as published by ! 7: the Free Software Foundation; either version 1, or (at your option) ! 8: any later version. ! 9: ! 10: This program is distributed in the hope that it will be useful, ! 11: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 13: GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 18: ! 19: In other words, you are welcome to use, share and improve this program. ! 20: You are forbidden to forbid anyone else to use, share and improve ! 21: what you give them. Help stamp out software-hoarding! */ ! 22: ! 23: ! 24: /* ! 25: * unexec.c - Convert a running program into an a.out file. ! 26: * ! 27: * Author: Spencer W. Thomas ! 28: * Computer Science Dept. ! 29: * University of Utah ! 30: * Date: Tue Mar 2 1982 ! 31: * Modified heavily since then. ! 32: * ! 33: * Synopsis: ! 34: * unexec (new_name, a_name, data_start, bss_start, entry_address) ! 35: * char *new_name, *a_name; ! 36: * unsigned data_start, bss_start, entry_address; ! 37: * ! 38: * Takes a snapshot of the program and makes an a.out format file in the ! 39: * file named by the string argument new_name. ! 40: * If a_name is non-NULL, the symbol table will be taken from the given file. ! 41: * On some machines, an existing a_name file is required. ! 42: * ! 43: * The boundaries within the a.out file may be adjusted with the data_start ! 44: * and bss_start arguments. Either or both may be given as 0 for defaults. ! 45: * ! 46: * Data_start gives the boundary between the text segment and the data ! 47: * segment of the program. The text segment can contain shared, read-only ! 48: * program code and literal data, while the data segment is always unshared ! 49: * and unprotected. Data_start gives the lowest unprotected address. ! 50: * The value you specify may be rounded down to a suitable boundary ! 51: * as required by the machine you are using. ! 52: * ! 53: * Specifying zero for data_start means the boundary between text and data ! 54: * should not be the same as when the program was loaded. ! 55: * If NO_REMAP is defined, the argument data_start is ignored and the ! 56: * segment boundaries are never changed. ! 57: * ! 58: * Bss_start indicates how much of the data segment is to be saved in the ! 59: * a.out file and restored when the program is executed. It gives the lowest ! 60: * unsaved address, and is rounded up to a page boundary. The default when 0 ! 61: * is given assumes that the entire data segment is to be stored, including ! 62: * the previous data and bss as well as any additional storage allocated with ! 63: * break (2). ! 64: * ! 65: * The new file is set up to start at entry_address. ! 66: * ! 67: * If you make improvements I'd like to get them too. ! 68: * harpo!utah-cs!thomas, thomas@Utah-20 ! 69: * ! 70: */ ! 71: ! 72: /* There are several compilation parameters affecting unexec: ! 73: ! 74: * COFF ! 75: ! 76: Define this if your system uses COFF for executables. ! 77: Otherwise we assume you use Berkeley format. ! 78: ! 79: * NO_REMAP ! 80: ! 81: Define this if you do not want to try to save Emacs's pure data areas ! 82: as part of the text segment. ! 83: ! 84: Saving them as text is good because it allows users to share more. ! 85: ! 86: However, on machines that locate the text area far from the data area, ! 87: the boundary cannot feasibly be moved. Such machines require ! 88: NO_REMAP. ! 89: ! 90: Also, remapping can cause trouble with the built-in startup routine ! 91: /lib/crt0.o, which defines `environ' as an initialized variable. ! 92: Dumping `environ' as pure does not work! So, to use remapping, ! 93: you must write a startup routine for your machine in Emacs's crt0.c. ! 94: If NO_REMAP is defined, Emacs uses the system's crt0.o. ! 95: ! 96: * SECTION_ALIGNMENT ! 97: ! 98: Some machines that use COFF executables require that each section ! 99: start on a certain boundary *in the COFF file*. Such machines should ! 100: define SECTION_ALIGNMENT to a mask of the low-order bits that must be ! 101: zero on such a boundary. This mask is used to control padding between ! 102: segments in the COFF file. ! 103: ! 104: If SECTION_ALIGNMENT is not defined, the segments are written ! 105: consecutively with no attempt at alignment. This is right for ! 106: unmodified system V. ! 107: ! 108: * SEGMENT_MASK ! 109: ! 110: Some machines require that the beginnings and ends of segments ! 111: *in core* be on certain boundaries. For most machines, a page ! 112: boundary is sufficient. That is the default. When a larger ! 113: boundary is needed, define SEGMENT_MASK to a mask of ! 114: the bits that must be zero on such a boundary. ! 115: ! 116: * A_TEXT_OFFSET(HDR) ! 117: ! 118: Some machines count the a.out header as part of the size of the text ! 119: segment (a_text); they may actually load the header into core as the ! 120: first data in the text segment. Some have additional padding between ! 121: the header and the real text of the program that is counted in a_text. ! 122: ! 123: For these machines, define A_TEXT_OFFSET(HDR) to examine the header ! 124: structure HDR and return the number of bytes to add to `a_text' ! 125: before writing it (above and beyond the number of bytes of actual ! 126: program text). HDR's standard fields are already correct, except that ! 127: this adjustment to the `a_text' field has not yet been made; ! 128: thus, the amount of offset can depend on the data in the file. ! 129: ! 130: * A_TEXT_SEEK(HDR) ! 131: ! 132: If defined, this macro specifies the number of bytes to seek into the ! 133: a.out file before starting to write the text segment.a ! 134: ! 135: * EXEC_MAGIC ! 136: ! 137: For machines using COFF, this macro, if defined, is a value stored ! 138: into the magic number field of the output file. ! 139: ! 140: * ADJUST_EXEC_HEADER ! 141: ! 142: This macro can be used to generate statements to adjust or ! 143: initialize nonstandard fields in the file header ! 144: ! 145: * ADDR_CORRECT(ADDR) ! 146: ! 147: Macro to correct an int which is the bit pattern of a pointer to a byte ! 148: into an int which is the number of a byte. ! 149: ! 150: This macro has a default definition which is usually right. ! 151: This default definition is a no-op on most machines (where a ! 152: pointer looks like an int) but not on all machines. ! 153: ! 154: */ ! 155: ! 156: #define XCOFF ! 157: #define COFF ! 158: #define NO_REMAP ! 159: ! 160: #ifndef emacs ! 161: #define PERROR(arg) perror (arg); return -1 ! 162: #else ! 163: #include "config.h" ! 164: #define PERROR(file) report_error (file, new) ! 165: #endif ! 166: ! 167: #ifndef CANNOT_DUMP /* all rest of file! */ ! 168: ! 169: #ifndef CANNOT_UNEXEC /* most of rest of file */ ! 170: ! 171: #include <a.out.h> ! 172: /* Define getpagesize () if the system does not. ! 173: Note that this may depend on symbols defined in a.out.h ! 174: */ ! 175: #include "getpagesize.h" ! 176: ! 177: #ifndef makedev /* Try to detect types.h already loaded */ ! 178: #include <sys/types.h> ! 179: #endif ! 180: #include <stdio.h> ! 181: #include <sys/stat.h> ! 182: #include <errno.h> ! 183: ! 184: static int make_hdr (); ! 185: static mark_x (); ! 186: static int copy_text_and_data (), copy_sym (); ! 187: ! 188: extern char *start_of_text (); /* Start of text */ ! 189: extern char *start_of_data (); /* Start of initialized data */ ! 190: ! 191: extern int _data; ! 192: extern int _edata; ! 193: extern int _text; ! 194: extern int _etext; ! 195: extern int _end; ! 196: #ifdef COFF ! 197: #ifndef USG ! 198: #ifndef STRIDE ! 199: #ifndef UMAX ! 200: #ifndef sun386 ! 201: /* I have a suspicion that these are turned off on all systems ! 202: and can be deleted. Try it in version 19. */ ! 203: #include <filehdr.h> ! 204: #include <aouthdr.h> ! 205: #include <scnhdr.h> ! 206: #include <syms.h> ! 207: #endif /* not sun386 */ ! 208: #endif /* not UMAX */ ! 209: #endif /* Not STRIDE */ ! 210: #endif /* not USG */ ! 211: static long block_copy_start; /* Old executable start point */ ! 212: static struct filehdr f_hdr; /* File header */ ! 213: static struct aouthdr f_ohdr; /* Optional file header (a.out) */ ! 214: long bias; /* Bias to add for growth */ ! 215: long lnnoptr; /* Pointer to line-number info within file */ ! 216: #define SYMS_START block_copy_start ! 217: ! 218: static long text_scnptr; ! 219: static long data_scnptr; ! 220: #ifdef XCOFF ! 221: static long load_scnptr; ! 222: static long orig_load_scnptr; ! 223: static long orig_data_scnptr; ! 224: #endif ! 225: static long data_st; ! 226: ! 227: #ifndef MAX_SECTIONS ! 228: #define MAX_SECTIONS 10 ! 229: #endif ! 230: ! 231: #endif /* COFF */ ! 232: ! 233: static int pagemask; ! 234: ! 235: /* Correct an int which is the bit pattern of a pointer to a byte ! 236: into an int which is the number of a byte. ! 237: This is a no-op on ordinary machines, but not on all. */ ! 238: ! 239: #ifndef ADDR_CORRECT /* Let m-*.h files override this definition */ ! 240: #define ADDR_CORRECT(x) ((char *)(x) - (char*)0) ! 241: #endif ! 242: ! 243: #ifdef emacs ! 244: ! 245: static ! 246: report_error (file, fd) ! 247: char *file; ! 248: int fd; ! 249: { ! 250: if (fd) ! 251: close (fd); ! 252: error ("Failure operating on %s", file); ! 253: } ! 254: #endif /* emacs */ ! 255: ! 256: #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1 ! 257: #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1 ! 258: #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1 ! 259: ! 260: static ! 261: report_error_1 (fd, msg, a1, a2) ! 262: int fd; ! 263: char *msg; ! 264: int a1, a2; ! 265: { ! 266: close (fd); ! 267: #ifdef emacs ! 268: error (msg, a1, a2); ! 269: #else ! 270: fprintf (stderr, msg, a1, a2); ! 271: fprintf (stderr, "\n"); ! 272: #endif ! 273: } ! 274: ! 275: /* **************************************************************** ! 276: * unexec ! 277: * ! 278: * driving logic. ! 279: */ ! 280: unexec (new_name, a_name, data_start, bss_start, entry_address) ! 281: char *new_name, *a_name; ! 282: unsigned data_start, bss_start, entry_address; ! 283: { ! 284: int new, a_out = -1; ! 285: ! 286: if (a_name && (a_out = open (a_name, 0)) < 0) ! 287: { ! 288: PERROR (a_name); ! 289: } ! 290: if ((new = creat (new_name, 0666)) < 0) ! 291: { ! 292: PERROR (new_name); ! 293: } ! 294: if (make_hdr (new,a_out,data_start,bss_start,entry_address,a_name,new_name) < 0 ! 295: || copy_text_and_data (new) < 0 ! 296: || copy_sym (new, a_out, a_name, new_name) < 0 ! 297: #ifdef COFF ! 298: || adjust_lnnoptrs (new, a_out, new_name) < 0 ! 299: #endif ! 300: #ifdef XCOFF ! 301: || unrelocate_symbols (new, a_out, a_name, new_name) < 0 ! 302: #endif ! 303: ) ! 304: { ! 305: close (new); ! 306: /* unlink (new_name); /* Failed, unlink new a.out */ ! 307: return -1; ! 308: } ! 309: ! 310: close (new); ! 311: if (a_out >= 0) ! 312: close (a_out); ! 313: mark_x (new_name); ! 314: return 0; ! 315: } ! 316: ! 317: /* **************************************************************** ! 318: * make_hdr ! 319: * ! 320: * Make the header in the new a.out from the header in core. ! 321: * Modify the text and data sizes. ! 322: */ ! 323: static int ! 324: make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) ! 325: int new, a_out; ! 326: unsigned data_start, bss_start, entry_address; ! 327: char *a_name; ! 328: char *new_name; ! 329: { ! 330: register int scns; ! 331: unsigned int bss_end; ! 332: ! 333: struct scnhdr section[MAX_SECTIONS]; ! 334: struct scnhdr * f_thdr; /* Text section header */ ! 335: struct scnhdr * f_dhdr; /* Data section header */ ! 336: struct scnhdr * f_bhdr; /* Bss section header */ ! 337: struct scnhdr * f_lhdr; /* Loader section header */ ! 338: struct scnhdr * f_tchdr; /* Typechk section header */ ! 339: struct scnhdr * f_dbhdr; /* Debug section header */ ! 340: struct scnhdr * f_xhdr; /* Except section header */ ! 341: ! 342: load_scnptr = orig_load_scnptr = lnnoptr = 0; ! 343: pagemask = getpagesize () - 1; ! 344: ! 345: /* Adjust text/data boundary. */ ! 346: #ifdef NO_REMAP ! 347: data_start = (long) start_of_data (); ! 348: #endif /* NO_REMAP */ ! 349: data_start = ADDR_CORRECT (data_start); ! 350: ! 351: #ifdef SEGMENT_MASK ! 352: data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */ ! 353: #else ! 354: data_start = data_start & ~pagemask; /* (Down) to page boundary. */ ! 355: #endif ! 356: ! 357: ! 358: bss_end = ADDR_CORRECT (sbrk (0)) + pagemask; ! 359: bss_end &= ~ pagemask; ! 360: /* Adjust data/bss boundary. */ ! 361: if (bss_start != 0) ! 362: { ! 363: bss_start = (ADDR_CORRECT (bss_start) + pagemask); ! 364: /* (Up) to page bdry. */ ! 365: bss_start &= ~ pagemask; ! 366: if (bss_start > bss_end) ! 367: { ! 368: ERROR1 ("unexec: Specified bss_start (%u) is past end of program", ! 369: bss_start); ! 370: } ! 371: } ! 372: else ! 373: bss_start = bss_end; ! 374: ! 375: if (data_start > bss_start) /* Can't have negative data size. */ ! 376: { ! 377: ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)", ! 378: data_start, bss_start); ! 379: } ! 380: ! 381: #ifdef COFF ! 382: /* Salvage as much info from the existing file as possible */ ! 383: block_copy_start = 0; ! 384: f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL; ! 385: f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL; ! 386: if (a_out >= 0) ! 387: { ! 388: if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) ! 389: { ! 390: PERROR (a_name); ! 391: } ! 392: block_copy_start += sizeof (f_hdr); ! 393: if (f_hdr.f_opthdr > 0) ! 394: { ! 395: if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) ! 396: { ! 397: PERROR (a_name); ! 398: } ! 399: block_copy_start += sizeof (f_ohdr); ! 400: } ! 401: if (f_hdr.f_nscns > MAX_SECTIONS) ! 402: { ! 403: ERROR0 ("unexec: too many section headers -- increase MAX_SECTIONS"); ! 404: } ! 405: /* Loop through section headers */ ! 406: for (scns = 0; scns < f_hdr.f_nscns; scns++) { ! 407: struct scnhdr *s = §ion[scns]; ! 408: if (read (a_out, s, sizeof (*s)) != sizeof (*s)) ! 409: { ! 410: PERROR (a_name); ! 411: } ! 412: if (s->s_scnptr > 0L) ! 413: { ! 414: if (block_copy_start < s->s_scnptr + s->s_size) ! 415: block_copy_start = s->s_scnptr + s->s_size; ! 416: } ! 417: ! 418: #define CHECK_SCNHDR(ptr, name, flags) \ ! 419: if (strcmp(s->s_name, name) == 0) { \ ! 420: if (s->s_flags != flags) { \ ! 421: fprintf(stderr, "unexec: %x flags where %x expected in %s section.\n", \ ! 422: s->s_flags, flags, name); \ ! 423: } \ ! 424: if (ptr) { \ ! 425: fprintf(stderr, "unexec: duplicate section header for section %s.\n", \ ! 426: name); \ ! 427: } \ ! 428: ptr = s; \ ! 429: } ! 430: CHECK_SCNHDR(f_thdr, _TEXT, STYP_TEXT); ! 431: CHECK_SCNHDR(f_dhdr, _DATA, STYP_DATA); ! 432: CHECK_SCNHDR(f_bhdr, _BSS, STYP_BSS); ! 433: CHECK_SCNHDR(f_lhdr, _LOADER, STYP_LOADER); ! 434: CHECK_SCNHDR(f_dbhdr, _DEBUG, STYP_DEBUG); ! 435: CHECK_SCNHDR(f_tchdr, _TYPCHK, STYP_TYPCHK); ! 436: CHECK_SCNHDR(f_xhdr, _EXCEPT, STYP_EXCEPT); ! 437: } ! 438: ! 439: if (f_thdr == 0) ! 440: { ! 441: ERROR1 ("unexec: couldn't find \"%s\" section", _TEXT); ! 442: } ! 443: if (f_dhdr == 0) ! 444: { ! 445: ERROR1 ("unexec: couldn't find \"%s\" section", _DATA); ! 446: } ! 447: if (f_bhdr == 0) ! 448: { ! 449: ERROR1 ("unexec: couldn't find \"%s\" section", _BSS); ! 450: } ! 451: } ! 452: else ! 453: { ! 454: ERROR0 ("can't build a COFF file from scratch yet"); ! 455: } ! 456: orig_data_scnptr = f_dhdr->s_scnptr; ! 457: orig_load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; ! 458: ! 459: /* Now we alter the contents of all the f_*hdr variables ! 460: to correspond to what we want to dump. */ ! 461: f_hdr.f_flags |= (F_RELFLG | F_EXEC); /* Why? */ ! 462: #ifdef EXEC_MAGIC ! 463: f_ohdr.magic = EXEC_MAGIC; ! 464: #endif ! 465: #ifndef NO_REMAP ! 466: f_ohdr.tsize = data_start - f_ohdr.text_start; ! 467: f_ohdr.text_start = (long) start_of_text (); ! 468: #endif ! 469: f_ohdr.dsize = bss_start - ((unsigned) &_data); ! 470: f_ohdr.bsize = bss_end - bss_start; ! 471: ! 472: f_dhdr->s_size = f_ohdr.dsize; ! 473: f_bhdr->s_size = f_ohdr.bsize; ! 474: f_bhdr->s_paddr = f_ohdr.dsize; ! 475: f_bhdr->s_vaddr = f_ohdr.dsize; ! 476: ! 477: /* fix scnptr's */ ! 478: { ! 479: long ptr; ! 480: ! 481: for (scns = 0; scns < f_hdr.f_nscns; scns++) { ! 482: struct scnhdr *s = §ion[scns]; ! 483: if (scns == 0) ! 484: ptr = s->s_scnptr; ! 485: ! 486: if (s->s_scnptr != 0) ! 487: { ! 488: s->s_scnptr = ptr; ! 489: } ! 490: ! 491: if ((s->s_flags & 0xffff) == STYP_PAD) ! 492: { ! 493: /* ! 494: * the text_start should probably be o_algntext but that doesn't ! 495: * seem to change ! 496: */ ! 497: if (f_ohdr.text_start != 0) /* && scns != 0 */ ! 498: { ! 499: s->s_size = 512 - (s->s_scnptr % 512); ! 500: if (s->s_size == 512) ! 501: s->s_size = 0; ! 502: } ! 503: } ! 504: ! 505: ptr = ptr + s->s_size; ! 506: } ! 507: ! 508: bias = ptr - block_copy_start; ! 509: } ! 510: ! 511: /* fix other pointers */ ! 512: for (scns = 0; scns < f_hdr.f_nscns; scns++) { ! 513: struct scnhdr *s = §ion[scns]; ! 514: ! 515: if (s->s_relptr != 0) ! 516: { ! 517: s->s_relptr += bias; ! 518: } ! 519: if (s->s_lnnoptr != 0) ! 520: { ! 521: if (lnnoptr == 0) lnnoptr = s->s_lnnoptr; ! 522: s->s_lnnoptr += bias; ! 523: } ! 524: } ! 525: ! 526: if (f_hdr.f_symptr > 0L) ! 527: { ! 528: f_hdr.f_symptr += bias; ! 529: } ! 530: ! 531: data_st = data_start; ! 532: text_scnptr = f_thdr->s_scnptr; ! 533: data_scnptr = f_dhdr->s_scnptr; ! 534: load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; ! 535: block_copy_start = orig_load_scnptr; ! 536: ! 537: #ifdef ADJUST_EXEC_HEADER ! 538: ADJUST_EXEC_HEADER ! 539: #endif /* ADJUST_EXEC_HEADER */ ! 540: ! 541: if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) ! 542: { ! 543: PERROR (new_name); ! 544: } ! 545: ! 546: if (f_hdr.f_opthdr > 0) ! 547: { ! 548: if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) ! 549: { ! 550: PERROR (new_name); ! 551: } ! 552: } ! 553: ! 554: for (scns = 0; scns < f_hdr.f_nscns; scns++) { ! 555: struct scnhdr *s = §ion[scns]; ! 556: if (write (new, s, sizeof (*s)) != sizeof (*s)) ! 557: { ! 558: PERROR (new_name); ! 559: } ! 560: } ! 561: ! 562: return (0); ! 563: ! 564: #endif /* COFF */ ! 565: } ! 566: ! 567: /* **************************************************************** ! 568: ! 569: * ! 570: * Copy the text and data segments from memory to the new a.out ! 571: */ ! 572: static int ! 573: copy_text_and_data (new) ! 574: int new; ! 575: { ! 576: register char *end; ! 577: register char *ptr; ! 578: ! 579: lseek (new, (long) text_scnptr, 0); ! 580: ptr = start_of_text () + text_scnptr; ! 581: end = ptr + f_ohdr.tsize; ! 582: write_segment (new, ptr, end); ! 583: ! 584: lseek (new, (long) data_scnptr, 0); ! 585: ptr = (char *) &_data; ! 586: end = ptr + f_ohdr.dsize; ! 587: write_segment (new, ptr, end); ! 588: ! 589: return 0; ! 590: } ! 591: ! 592: write_segment (new, ptr, end) ! 593: int new; ! 594: register char *ptr, *end; ! 595: { ! 596: register int i, nwrite, ret; ! 597: char buf[80]; ! 598: extern int errno; ! 599: char zeros[128]; ! 600: ! 601: bzero (zeros, sizeof zeros); ! 602: ! 603: for (i = 0; ptr < end;) ! 604: { ! 605: /* distance to next multiple of 128. */ ! 606: nwrite = (((int) ptr + 128) & -128) - (int) ptr; ! 607: /* But not beyond specified end. */ ! 608: if (nwrite > end - ptr) nwrite = end - ptr; ! 609: ret = write (new, ptr, nwrite); ! 610: /* If write gets a page fault, it means we reached ! 611: a gap between the old text segment and the old data segment. ! 612: This gap has probably been remapped into part of the text segment. ! 613: So write zeros for it. */ ! 614: if (ret == -1 && errno == EFAULT) ! 615: { ! 616: write (new, zeros, nwrite); ! 617: } ! 618: else if (nwrite != ret) ! 619: { ! 620: sprintf (buf, ! 621: "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d", ! 622: ptr, new, nwrite, ret, errno); ! 623: PERROR (buf); ! 624: } ! 625: i += nwrite; ! 626: ptr += nwrite; ! 627: } ! 628: } ! 629: ! 630: /* **************************************************************** ! 631: * copy_sym ! 632: * ! 633: * Copy the relocation information and symbol table from the a.out to the new ! 634: */ ! 635: static int ! 636: copy_sym (new, a_out, a_name, new_name) ! 637: int new, a_out; ! 638: char *a_name, *new_name; ! 639: { ! 640: char page[1024]; ! 641: int n; ! 642: ! 643: if (a_out < 0) ! 644: return 0; ! 645: ! 646: if (SYMS_START == 0L) ! 647: return 0; ! 648: ! 649: if (lnnoptr && lnnoptr < SYMS_START) /* if there is line number info */ ! 650: lseek (a_out, lnnoptr, 0); /* start copying from there */ ! 651: else ! 652: lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */ ! 653: ! 654: while ((n = read (a_out, page, sizeof page)) > 0) ! 655: { ! 656: if (write (new, page, n) != n) ! 657: { ! 658: PERROR (new_name); ! 659: } ! 660: } ! 661: if (n < 0) ! 662: { ! 663: PERROR (a_name); ! 664: } ! 665: return 0; ! 666: } ! 667: ! 668: /* **************************************************************** ! 669: * mark_x ! 670: * ! 671: * After succesfully building the new a.out, mark it executable ! 672: */ ! 673: static ! 674: mark_x (name) ! 675: char *name; ! 676: { ! 677: struct stat sbuf; ! 678: int um; ! 679: int new = 0; /* for PERROR */ ! 680: ! 681: um = umask (777); ! 682: umask (um); ! 683: if (stat (name, &sbuf) == -1) ! 684: { ! 685: PERROR (name); ! 686: } ! 687: sbuf.st_mode |= 0111 & ~um; ! 688: if (chmod (name, sbuf.st_mode) == -1) ! 689: PERROR (name); ! 690: } ! 691: ! 692: /* ! 693: * If the COFF file contains a symbol table and a line number section, ! 694: * then any auxiliary entries that have values for x_lnnoptr must ! 695: * be adjusted by the amount that the line number section has moved ! 696: * in the file (bias computed in make_hdr). The #@$%&* designers of ! 697: * the auxiliary entry structures used the absolute file offsets for ! 698: * the line number entry rather than an offset from the start of the ! 699: * line number section! ! 700: * ! 701: * When I figure out how to scan through the symbol table and pick out ! 702: * the auxiliary entries that need adjustment, this routine will ! 703: * be fixed. As it is now, all such entries are wrong and sdb ! 704: * will complain. Fred Fish, UniSoft Systems Inc. ! 705: */ ! 706: ! 707: #ifdef COFF ! 708: ! 709: /* This function is probably very slow. Instead of reopening the new ! 710: file for input and output it should copy from the old to the new ! 711: using the two descriptors already open (WRITEDESC and READDESC). ! 712: Instead of reading one small structure at a time it should use ! 713: a reasonable size buffer. But I don't have time to work on such ! 714: things, so I am installing it as submitted to me. -- RMS. */ ! 715: ! 716: adjust_lnnoptrs (writedesc, readdesc, new_name) ! 717: int writedesc; ! 718: int readdesc; ! 719: char *new_name; ! 720: { ! 721: register int nsyms; ! 722: register int new; ! 723: #ifdef amdahl_uts ! 724: SYMENT symentry; ! 725: AUXENT auxentry; ! 726: #else ! 727: struct syment symentry; ! 728: union auxent auxentry; ! 729: #endif ! 730: ! 731: if (!lnnoptr || !f_hdr.f_symptr) ! 732: return 0; ! 733: ! 734: if ((new = open (new_name, 2)) < 0) ! 735: { ! 736: PERROR (new_name); ! 737: return -1; ! 738: } ! 739: ! 740: lseek (new, f_hdr.f_symptr, 0); ! 741: for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) ! 742: { ! 743: read (new, &symentry, SYMESZ); ! 744: if (symentry.n_numaux) ! 745: { ! 746: read (new, &auxentry, AUXESZ); ! 747: nsyms++; ! 748: if (ISFCN (symentry.n_type)) { ! 749: auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; ! 750: lseek (new, -AUXESZ, 1); ! 751: write (new, &auxentry, AUXESZ); ! 752: } ! 753: } ! 754: } ! 755: close (new); ! 756: } ! 757: ! 758: #endif /* COFF */ ! 759: ! 760: #ifdef XCOFF ! 761: ! 762: /* It is probably a false economy to optimise this routine (it used to ! 763: read one LDREL and do do two lseeks per iteration) but the wrath of ! 764: RMS (see above :-) would be too much to bear */ ! 765: ! 766: unrelocate_symbols (new, a_out, a_name, new_name) ! 767: int new, a_out; ! 768: char *a_name, *new_name; ! 769: { ! 770: register int i; ! 771: register int l; ! 772: register LDREL *ldrel; ! 773: LDHDR ldhdr; ! 774: LDREL ldrel_buf [20]; ! 775: ulong t_start = (ulong) &_text; ! 776: ulong d_start = (ulong) &_data; ! 777: int * p; ! 778: int dirty; ! 779: ! 780: if (load_scnptr == 0) ! 781: return 0; ! 782: ! 783: lseek (a_out, orig_load_scnptr, 0); ! 784: if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr)) ! 785: { ! 786: PERROR (new_name); ! 787: } ! 788: ! 789: #define SYMNDX_TEXT 0 ! 790: #define SYMNDX_DATA 1 ! 791: #define SYMNDX_BSS 2 ! 792: l = 0; ! 793: for (i = 0; i < ldhdr.l_nreloc; i++, l--, ldrel++) ! 794: { ! 795: if (l == 0) { ! 796: lseek (a_out, ! 797: orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, ! 798: 0); ! 799: ! 800: l = ldhdr.l_nreloc - i; ! 801: if (l > sizeof (ldrel_buf) / LDRELSZ) ! 802: l = sizeof (ldrel_buf) / LDRELSZ; ! 803: ! 804: if (read (a_out, ldrel_buf, l * LDRELSZ) != l * LDRELSZ) ! 805: { ! 806: PERROR (a_name); ! 807: } ! 808: ldrel = ldrel_buf; ! 809: } ! 810: dirty = 0; ! 811: ! 812: /* this code may not be necessary */ ! 813: /* I originally had == in the "assignment" and it still unrelocated */ ! 814: ! 815: /* move the BSS loader symbols to the DATA segment */ ! 816: if (ldrel->l_rsecnm == f_ohdr.o_snbss) ! 817: ldrel->l_rsecnm = f_ohdr.o_sndata, dirty++; ! 818: ! 819: if (ldrel->l_symndx == SYMNDX_BSS) ! 820: ldrel->l_symndx = SYMNDX_DATA, dirty++; ! 821: ! 822: if (dirty) ! 823: { ! 824: lseek (new, ! 825: load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, ! 826: 0); ! 827: ! 828: if (write (new, ldrel, LDRELSZ) != LDRELSZ) ! 829: { ! 830: PERROR (new_name); ! 831: } ! 832: } ! 833: ! 834: if (ldrel->l_rsecnm == f_ohdr.o_sndata) ! 835: { ! 836: int orig_int; ! 837: ! 838: lseek (a_out, orig_data_scnptr + ldrel->l_vaddr, 0); ! 839: ! 840: if (read (a_out, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int)) ! 841: { ! 842: PERROR (a_name); ! 843: } ! 844: ! 845: switch (ldrel->l_symndx) { ! 846: case SYMNDX_TEXT: ! 847: p = (int *) (d_start + ldrel->l_vaddr); ! 848: orig_int = * p - (t_start - f_ohdr.text_start); ! 849: break; ! 850: ! 851: case SYMNDX_DATA: ! 852: case SYMNDX_BSS: ! 853: p = (int *) (d_start + ldrel->l_vaddr); ! 854: orig_int = * p - (d_start - f_ohdr.data_start); ! 855: break; ! 856: } ! 857: ! 858: lseek (new, data_scnptr + ldrel->l_vaddr, 0); ! 859: if (write (new, (void *) &orig_int, sizeof (orig_int)) != sizeof (orig_int)) ! 860: { ! 861: PERROR (new_name); ! 862: } ! 863: } ! 864: } ! 865: } ! 866: #endif /* XCOFF */ ! 867: ! 868: #endif /* not CANNOT_UNEXEC */ ! 869: ! 870: #endif /* not CANNOT_DUMP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.