|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.0 (the 'License'). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License." ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: #include <stdlib.h> ! 25: #include <stdarg.h> ! 26: #include <string.h> ! 27: #include <errno.h> ! 28: #include <stdio.h> ! 29: #include <sys/file.h> ! 30: #include <mach-o/loader.h> ! 31: #define SECT_OBJC_RUNTIME "__runtime_setup" ! 32: #include <sys/types.h> ! 33: #include <sys/stat.h> ! 34: #include <mach/mach.h> ! 35: #include <mach/mach_error.h> ! 36: #include <libc.h> ! 37: ! 38: /* ! 39: * This really is the segment alignment of the input file and is an assumption ! 40: * on what the segment alignment is since it can't exactly be determined from ! 41: * the file itself. ! 42: */ ! 43: const long SEGALIGN = 0x2000; ! 44: ! 45: /* This is set in the routine main() */ ! 46: extern char *progname; ! 47: ! 48: /* These variables are set in the routine map_input() */ ! 49: static char *input_addr = NULL; /* address of where the input file is mapped */ ! 50: static long input_size = 0; /* size of the input file */ ! 51: static long input_mode = 0; /* mode of the input file */ ! 52: static struct mach_header ! 53: *mhp = NULL; /* pointer to the input file's mach header */ ! 54: static struct load_command ! 55: *load_commands = NULL; /* pointer to the input file's load commands */ ! 56: static int swapped; /* TRUE if the input is to be swapped */ ! 57: static enum NXByteOrder host_byte_order = NX_UnknownByteOrder; ! 58: static enum NXByteOrder target_byte_order = NX_UnknownByteOrder; ! 59: ! 60: /* ! 61: * Structures used in objc_runtime_setup in updating sections in the segments ! 62: * of the input file. There is one such structure for each segment and section. ! 63: */ ! 64: struct rep_seg { ! 65: long fileoff; /* original file offset */ ! 66: long filesize; /* original file size */ ! 67: long vmsize; /* original vm size */ ! 68: long padsize; /* new pad size */ ! 69: struct segment_command *sgp;/* pointer to the segment_command */ ! 70: }; ! 71: static struct rep_seg *segs = NULL; ! 72: ! 73: struct rep_sect { ! 74: long offset; /* original file offset */ ! 75: struct section *sp; /* pointer to the section structure */ ! 76: }; ! 77: static struct rep_sect *sects = NULL; ! 78: ! 79: /* Internal routines */ ! 80: static long map_input( ! 81: char *input); ! 82: static long objc_runtime_setup( ! 83: char *input, ! 84: char *output, ! 85: char *objc_runtime_setup_contents, ! 86: unsigned long objc_runtime_setup_size); ! 87: static int qsort_vmaddr( ! 88: const struct rep_seg *seg1, ! 89: const struct rep_seg *seg2); ! 90: static int qsort_fileoff( ! 91: const struct rep_seg *seg1, ! 92: const struct rep_seg *seg2); ! 93: static int qsort_offset( ! 94: const struct rep_sect *sect1, ! 95: const struct rep_sect *sect2); ! 96: static void *allocate( ! 97: long size); ! 98: static void error( ! 99: const char *format, ! 100: ...); ! 101: static void fatal( ! 102: const char *format, ! 103: ...); ! 104: static void system_error( ! 105: const char *format, ! 106: ...); ! 107: static void system_fatal( ! 108: const char *format, ! 109: ...); ! 110: static void machkern_error( ! 111: kern_return_t r, ! 112: char *format, ! 113: ...); ! 114: long round( ! 115: long v, ! 116: unsigned long r); ! 117: ! 118: /* ! 119: * add_objc_runtime_setup is passed a name of an object file and pointer to the ! 120: * contents of the objc_runtime_setup section and it's size and creates an ! 121: * output file with that section added or releaced. It returns 1 if successfull ! 122: * and zero otherwize. ! 123: */ ! 124: long ! 125: add_objc_runtime_setup( ! 126: char *input, ! 127: char *output, ! 128: char *contents, ! 129: long size) ! 130: { ! 131: /* map in the input */ ! 132: if(map_input(input) == 0) ! 133: return(0); ! 134: ! 135: /* create the output with the contents */ ! 136: if(objc_runtime_setup(input, output, contents, size) == 0) ! 137: return(0); ! 138: ! 139: return(1); ! 140: } ! 141: ! 142: /* ! 143: * map_input maps the input file into memory. The address it is mapped at is ! 144: * left in input_addr and the size is left in input_size. The input file is ! 145: * checked to be an object file and that the headers are checked to be correct ! 146: * enough to loop through them. The pointer to the mach header is left in mhp ! 147: * and the pointer to the load commands is left in load_commands. It returns ! 148: * 1 if it is successfull and zero otherwise. ! 149: */ ! 150: static ! 151: long ! 152: map_input( ! 153: char *input) ! 154: { ! 155: int fd; ! 156: long i; ! 157: struct stat stat_buf; ! 158: kern_return_t r; ! 159: struct load_command l, *lcp; ! 160: struct segment_command *sgp; ! 161: struct section *sp; ! 162: struct symtab_command *stp; ! 163: struct symseg_command *ssp; ! 164: ! 165: /* Open the input file and map it in */ ! 166: if((fd = open(input, O_RDONLY)) == -1){ ! 167: system_error("can't open input file: %s", input); ! 168: return(0); ! 169: } ! 170: if(fstat(fd, &stat_buf) == -1){ ! 171: system_error("Can't stat input file: %s", input); ! 172: close(fd); ! 173: return(0); ! 174: } ! 175: input_size = stat_buf.st_size; ! 176: input_mode = stat_buf.st_mode; ! 177: if((r = map_fd(fd, 0, (vm_offset_t *) &input_addr, TRUE, input_size)) ! 178: != KERN_SUCCESS){ ! 179: machkern_error(r, "Can't map input file: %s", input); ! 180: close(fd); ! 181: return(0); ! 182: } ! 183: close(fd); ! 184: ! 185: if(sizeof(struct mach_header) > input_size){ ! 186: error("truncated or malformed object (mach header would extend " ! 187: "past the end of the file) in: %s", input); ! 188: goto map_input_cleanup; ! 189: } ! 190: mhp = (struct mach_header *)input_addr; ! 191: host_byte_order = NXHostByteOrder(); ! 192: if(mhp->magic == NXSwapLong(MH_MAGIC)){ ! 193: swapped = 1; ! 194: target_byte_order = host_byte_order == NX_BigEndian ? ! 195: NX_LittleEndian : NX_BigEndian; ! 196: swap_mach_header(mhp, host_byte_order); ! 197: } ! 198: else if(mhp->magic == MH_MAGIC){ ! 199: swapped = 0; ! 200: target_byte_order = host_byte_order; ! 201: } ! 202: else{ ! 203: error("bad magic number (file is not a Mach-O file) in: %s", input); ! 204: goto map_input_cleanup; ! 205: } ! 206: ! 207: if(mhp->sizeofcmds + sizeof(struct mach_header) > input_size) ! 208: fatal("truncated or malformed object (load commands would extend " ! 209: "past the end of the file) in: %s", input); ! 210: load_commands = (struct load_command *)((char *)input_addr + ! 211: sizeof(struct mach_header)); ! 212: lcp = load_commands; ! 213: for(i = 0; i < mhp->ncmds; i++){ ! 214: l = *lcp; ! 215: if(swapped) ! 216: swap_load_command(&l, host_byte_order); ! 217: if(l.cmdsize % sizeof(long) != 0){ ! 218: error("load command %ld size not a multiple of sizeof(long) " ! 219: "in: %s", i, input); ! 220: goto map_input_cleanup; ! 221: } ! 222: if(l.cmdsize <= 0){ ! 223: error("load command %ld size is less than or equal to zero " ! 224: "in: %s", i, input); ! 225: goto map_input_cleanup; ! 226: } ! 227: if((char *)lcp + l.cmdsize > ! 228: (char *)load_commands + mhp->sizeofcmds){ ! 229: error("load command %ld extends past end of all load commands " ! 230: "in: %s", i, input); ! 231: goto map_input_cleanup; ! 232: } ! 233: switch(l.cmd){ ! 234: case LC_SEGMENT: ! 235: sgp = (struct segment_command *)lcp; ! 236: sp = (struct section *)((char *)sgp + ! 237: sizeof(struct segment_command)); ! 238: if(swapped) ! 239: swap_segment_command(sgp, host_byte_order); ! 240: if(swapped) ! 241: swap_section(sp, sgp->nsects, host_byte_order); ! 242: break; ! 243: case LC_SYMTAB: ! 244: stp = (struct symtab_command *)lcp; ! 245: if(swapped) ! 246: swap_symtab_command(stp, host_byte_order); ! 247: break; ! 248: case LC_SYMSEG: ! 249: ssp = (struct symseg_command *)lcp; ! 250: if(swapped) ! 251: swap_symseg_command(ssp, host_byte_order); ! 252: break; ! 253: default: ! 254: *lcp = l; ! 255: break; ! 256: } ! 257: lcp = (struct load_command *)((char *)lcp + l.cmdsize); ! 258: } ! 259: return(1); ! 260: ! 261: map_input_cleanup: ! 262: /* ! 263: * Cleanup if there were errors in map_input(). ! 264: */ ! 265: if(input_addr != NULL){ ! 266: if((r = vm_deallocate(task_self(), (vm_address_t)input_addr, ! 267: input_size)) != KERN_SUCCESS) ! 268: machkern_error(r,"Can't deallocate input file's mapped memory"); ! 269: } ! 270: return(0); ! 271: } ! 272: ! 273: /* ! 274: * objc_runtime_setup writes a modified version of the input file to output ! 275: * adding or replacing the (__OBJC,__runtime_setup) section with the contents ! 276: * passed to it. ! 277: */ ! 278: static ! 279: long ! 280: objc_runtime_setup( ! 281: char *input, ! 282: char *output, ! 283: char *objc_runtime_setup_contents, ! 284: unsigned long objc_runtime_setup_size) ! 285: { ! 286: long i, j, k, nsegs, nsects; ! 287: long high_reloc_seg, low_noreloc_seg, high_noreloc_seg, low_linkedit; ! 288: long oldvmaddr, oldoffset, newvmaddr, newoffset, newsectsize; ! 289: struct mach_header *new_mhp; ! 290: struct load_command lc, *lcp, *new_lcp, *new_load_commands; ! 291: struct segment_command *sgp, *linkedit_sgp, *objc_sgp; ! 292: struct section *sp, *first_sp, *objc_runtime_setup_sp, *last_objc_sp; ! 293: struct symtab_command *stp; ! 294: struct symseg_command *ssp; ! 295: int outfd; ! 296: vm_address_t pad_addr; ! 297: long size; ! 298: kern_return_t r; ! 299: ! 300: segs = NULL; ! 301: new_mhp = NULL; ! 302: sects = NULL; ! 303: pad_addr = 0; ! 304: outfd = -1; ! 305: ! 306: high_reloc_seg = 0; ! 307: low_noreloc_seg = input_size; ! 308: high_noreloc_seg = 0; ! 309: low_linkedit = input_size; ! 310: ! 311: nsegs = 0; ! 312: segs = allocate(mhp->ncmds * sizeof(struct rep_seg)); ! 313: bzero(segs, mhp->ncmds * sizeof(struct rep_seg)); ! 314: nsects = 0; ! 315: ! 316: stp = NULL; ! 317: ssp = NULL; ! 318: linkedit_sgp = NULL; ! 319: first_sp = NULL; ! 320: objc_sgp = NULL; ! 321: objc_runtime_setup_sp = NULL; ! 322: ! 323: /* ! 324: * First pass over the load commands and determine if the file is laided ! 325: * out in an order that the new section can be replaced or added. ! 326: */ ! 327: lcp = load_commands; ! 328: for(i = 0; i < mhp->ncmds; i++){ ! 329: switch(lcp->cmd){ ! 330: case LC_SEGMENT: ! 331: sgp = (struct segment_command *)lcp; ! 332: sp = (struct section *)((char *)sgp + ! 333: sizeof(struct segment_command)); ! 334: segs[nsegs++].sgp = sgp; ! 335: nsects += sgp->nsects; ! 336: if(strcmp(sgp->segname, SEG_LINKEDIT) != 0){ ! 337: if(strncmp(SEG_OBJC, sgp->segname, ! 338: sizeof(sgp->segname)) == 0){ ! 339: if(objc_sgp != NULL){ ! 340: error("more than one " SEG_OBJC " segment found " ! 341: "in: %s", input); ! 342: goto objc_runtime_setup_cleanup; ! 343: } ! 344: objc_sgp = sgp; ! 345: } ! 346: if(sgp->flags & SG_NORELOC){ ! 347: if(sgp->filesize != 0){ ! 348: if(sgp->fileoff + sgp->filesize > high_noreloc_seg) ! 349: high_noreloc_seg = sgp->fileoff + sgp->filesize; ! 350: if(sgp->fileoff < low_noreloc_seg) ! 351: low_noreloc_seg = sgp->fileoff; ! 352: } ! 353: } ! 354: else{ ! 355: if(sgp->filesize != 0 && ! 356: sgp->fileoff + sgp->filesize > high_reloc_seg) ! 357: high_reloc_seg = sgp->fileoff + sgp->filesize; ! 358: } ! 359: } ! 360: else{ ! 361: if(linkedit_sgp != NULL){ ! 362: error("more than one " SEG_LINKEDIT " segment found " ! 363: "in: %s", input); ! 364: goto objc_runtime_setup_cleanup; ! 365: } ! 366: linkedit_sgp = sgp; ! 367: } ! 368: for(j = 0; j < sgp->nsects; j++){ ! 369: if(sp->nreloc != 0 && sp->reloff < low_linkedit) ! 370: low_linkedit = sp->reloff; ! 371: if(first_sp == NULL) ! 372: first_sp = sp; ! 373: if(strncmp(SEG_OBJC, sp->segname, ! 374: sizeof(sp->segname)) == 0 && ! 375: strncmp(SECT_OBJC_RUNTIME, sp->sectname, ! 376: sizeof(sp->sectname)) == 0){ ! 377: if(objc_runtime_setup_sp != NULL){ ! 378: error("more than one (%0.16s,%0.16s) section in: " ! 379: "%s", sp->segname, sp->sectname, input); ! 380: goto objc_runtime_setup_cleanup; ! 381: } ! 382: objc_runtime_setup_sp = sp; ! 383: if(sp->flags & S_ZEROFILL){ ! 384: error("(%0.16s,%0.16s) is a fill section in: %s", ! 385: sp->segname, sp->sectname, input); ! 386: goto objc_runtime_setup_cleanup; ! 387: } ! 388: if(j != sgp->nsects - 1){ ! 389: error("(%0.16s,%0.16s) is not the last section in " ! 390: "the " SEG_OBJC " segment in: %s", ! 391: sp->segname, sp->sectname, input); ! 392: goto objc_runtime_setup_cleanup; ! 393: } ! 394: if(sp->offset + sp->size > input_size) ! 395: error("truncated or malformed object (section " ! 396: "contents of (%0.16s,%0.16s) extends " ! 397: "past the end of the file) in: %s", ! 398: sp->segname, sp->sectname, input); ! 399: } ! 400: sp++; ! 401: } ! 402: break; ! 403: case LC_SYMTAB: ! 404: if(stp != NULL) ! 405: fatal("more than one symtab_command found in: %s", input); ! 406: stp = (struct symtab_command *)lcp; ! 407: if(stp->nsyms != 0 && stp->symoff < low_linkedit) ! 408: low_linkedit = stp->symoff; ! 409: if(stp->strsize != 0 && stp->stroff < low_linkedit) ! 410: low_linkedit = stp->stroff; ! 411: break; ! 412: case LC_SYMSEG: ! 413: if(ssp != NULL) ! 414: fatal("more than one symseg_command found in: %s", input); ! 415: ssp = (struct symseg_command *)lcp; ! 416: if(ssp->size != 0 && ssp->offset < low_linkedit) ! 417: low_linkedit = ssp->offset; ! 418: break; ! 419: case LC_THREAD: ! 420: case LC_UNIXTHREAD: ! 421: case LC_LOADFVMLIB: ! 422: case LC_IDFVMLIB: ! 423: case LC_IDENT: ! 424: break; ! 425: default: ! 426: error("unknown load command %d in: %s (result maybe bad)", i, ! 427: input); ! 428: break; ! 429: } ! 430: lcp = (struct load_command *)((char *)lcp + lcp->cmdsize); ! 431: } ! 432: ! 433: if(objc_sgp == NULL){ ! 434: error("file: %s does not contain an " SEG_OBJC " segment", input); ! 435: goto objc_runtime_setup_cleanup; ! 436: } ! 437: if(objc_runtime_setup_sp == NULL && ! 438: first_sp->offset - (sizeof(struct mach_header) + mhp->sizeofcmds) < ! 439: sizeof(struct section)){ ! 440: error("file: %s does not have enough header padding to add a " ! 441: "section", input); ! 442: goto objc_runtime_setup_cleanup; ! 443: } ! 444: if(high_reloc_seg > low_noreloc_seg || ! 445: high_reloc_seg > low_linkedit || ! 446: high_noreloc_seg > low_linkedit){ ! 447: error("contents of input file: %s not in an order that the " ! 448: "new section can be added or replaced by this program", ! 449: input); ! 450: goto objc_runtime_setup_cleanup; ! 451: } ! 452: if(low_noreloc_seg != input_size && ! 453: low_noreloc_seg != objc_sgp->fileoff + objc_sgp->filesize){ ! 454: error("file's: %s " SEG_OBJC " segment is not the last segment " ! 455: "before the segments requiring no relocation", input); ! 456: goto objc_runtime_setup_cleanup; ! 457: } ! 458: ! 459: /* ! 460: * If the section must be added rather than just updated then rebuild ! 461: * the headers with the new section in it. And reset the pointers into ! 462: * the load commands to point to the newly allocated load commands. ! 463: */ ! 464: if(objc_runtime_setup_sp == NULL){ ! 465: new_mhp = (struct mach_header *)allocate( ! 466: sizeof(struct mach_header) + mhp->sizeofcmds + ! 467: sizeof(struct section)); ! 468: *new_mhp = *mhp; ! 469: new_mhp->sizeofcmds += sizeof(struct section); ! 470: new_load_commands = (struct load_command *)((char *)new_mhp + ! 471: sizeof(struct mach_header)); ! 472: lcp = load_commands; ! 473: new_lcp = new_load_commands; ! 474: nsegs = 0; ! 475: ! 476: for(i = 0; i < mhp->ncmds; i++){ ! 477: memcpy((char *)new_lcp, (char *)lcp, lcp->cmdsize); ! 478: if(new_lcp->cmd == LC_SEGMENT){ ! 479: segs[nsegs++].sgp = (struct segment_command *)new_lcp; ! 480: if((struct segment_command *)lcp == linkedit_sgp) ! 481: linkedit_sgp = (struct segment_command *)new_lcp; ! 482: } ! 483: if((struct symtab_command *)lcp == stp) ! 484: stp = (struct symtab_command *)new_lcp; ! 485: if((struct symseg_command *)lcp == ssp) ! 486: ssp = (struct symseg_command *)new_lcp; ! 487: if((struct segment_command *)lcp == objc_sgp){ ! 488: objc_sgp = (struct segment_command *)new_lcp; ! 489: objc_runtime_setup_sp = ! 490: (struct section *)((char *)objc_sgp + ! 491: sizeof(struct segment_command) + ! 492: objc_sgp->nsects * sizeof(struct section)); ! 493: last_objc_sp = (struct section *)((char *)objc_sgp + ! 494: sizeof(struct segment_command) + ! 495: (objc_sgp->nsects - 1) * ! 496: sizeof(struct section)); ! 497: objc_sgp->cmdsize += sizeof(struct section); ! 498: objc_sgp->nsects++; ! 499: nsects++; ! 500: memset(objc_runtime_setup_sp, '\0', sizeof(struct section)); ! 501: strcpy(objc_runtime_setup_sp->sectname, SECT_OBJC_RUNTIME); ! 502: strcpy(objc_runtime_setup_sp->segname, SEG_OBJC); ! 503: objc_runtime_setup_sp->addr = round(last_objc_sp->addr + ! 504: last_objc_sp->size, ! 505: sizeof(long)); ! 506: objc_runtime_setup_sp->size = 0; ! 507: objc_runtime_setup_sp->offset = last_objc_sp->offset + ! 508: objc_runtime_setup_sp->addr- ! 509: last_objc_sp->addr; ! 510: objc_runtime_setup_sp->align = 2; ! 511: objc_runtime_setup_sp->reloff = 0; ! 512: objc_runtime_setup_sp->nreloc = 0; ! 513: objc_runtime_setup_sp->flags = 0; ! 514: } ! 515: new_lcp = (struct load_command *)((char *)new_lcp + ! 516: new_lcp->cmdsize); ! 517: lcp = (struct load_command *)((char *)lcp + lcp->cmdsize); ! 518: } ! 519: mhp = new_mhp; ! 520: load_commands = new_load_commands; ! 521: } ! 522: ! 523: qsort(segs, nsegs, sizeof(struct rep_seg), ! 524: (int (*)(const void *, const void *))qsort_vmaddr); ! 525: ! 526: sects = allocate(nsects * sizeof(struct rep_sect)); ! 527: bzero(sects, nsects * sizeof(struct rep_sect)); ! 528: ! 529: /* ! 530: * First go through the segments and adjust the segment offsets, sizes ! 531: * and addresses without adjusting the offset to the relocation entries. ! 532: * This program can only handle object files that have contigious ! 533: * address spaces starting at zero and that the offsets in the file for ! 534: * the contents of the segments also being contiguious and in the same ! 535: * order as the vmaddresses. ! 536: */ ! 537: oldvmaddr = 0; ! 538: newvmaddr = 0; ! 539: k = 0; ! 540: for(i = 0; i < nsegs; i++){ ! 541: if(segs[i].sgp->vmaddr != oldvmaddr){ ! 542: newvmaddr = segs[i].sgp->vmaddr; ! 543: oldvmaddr = newvmaddr; ! 544: } ! 545: segs[i].filesize = segs[i].sgp->filesize; ! 546: segs[i].vmsize = segs[i].sgp->vmsize; ! 547: segs[i].sgp->vmaddr = newvmaddr; ! 548: sp = (struct section *)((char *)(segs[i].sgp) + ! 549: sizeof(struct segment_command)); ! 550: if(segs[i].sgp->filesize != 0){ ! 551: newsectsize = 0; ! 552: if(segs[i].sgp == objc_sgp || segs[i].sgp->flags == SG_NORELOC){ ! 553: for(j = 0; j < segs[i].sgp->nsects; j++){ ! 554: ! 555: /* begin bug fix - snaroff (8/3/90) */ ! 556: if ((sp->offset == 0) && (sp->flags != S_ZEROFILL)) ! 557: sp->offset = (sp+1)->offset; ! 558: /* end bug fix - snaroff (8/3/90) */ ! 559: ! 560: sects[k + j].sp = sp; ! 561: if(sp == objc_runtime_setup_sp) ! 562: sp->size = objc_runtime_setup_size; ! 563: sp->addr += newvmaddr - oldvmaddr; ! 564: newsectsize = (sp->addr - newvmaddr) + sp->size; ! 565: sp++; ! 566: } ! 567: if(strcmp(segs[i].sgp->segname, SEG_LINKEDIT) != 0){ ! 568: segs[i].sgp->filesize = round(newsectsize, SEGALIGN); ! 569: segs[i].sgp->vmsize = round(newsectsize, SEGALIGN); ! 570: segs[i].padsize = segs[i].sgp->filesize - newsectsize; ! 571: } ! 572: } ! 573: else{ ! 574: for(j = 0; j < segs[i].sgp->nsects; j++) ! 575: sects[k + j].sp = sp; ! 576: } ! 577: } ! 578: else{ ! 579: for(j = 0; j < segs[i].sgp->nsects; j++) ! 580: sects[k + j].sp = sp; ! 581: } ! 582: oldvmaddr += segs[i].vmsize; ! 583: newvmaddr += segs[i].sgp->vmsize; ! 584: k += segs[i].sgp->nsects; ! 585: } ! 586: ! 587: qsort(segs, nsegs, sizeof(struct rep_seg), ! 588: (int (*)(const void *, const void *))qsort_fileoff); ! 589: qsort(sects, nsects, sizeof(struct rep_sect), ! 590: (int (*)(const void *, const void *))qsort_offset); ! 591: ! 592: oldoffset = 0; ! 593: newoffset = 0; ! 594: k = 0; ! 595: for(i = 0; i < nsegs; i++){ ! 596: if(segs[i].sgp->filesize != 0){ ! 597: if(segs[i].sgp->fileoff != oldoffset){ ! 598: oldoffset = segs[i].sgp->fileoff; ! 599: newoffset = oldoffset; ! 600: } ! 601: segs[i].fileoff = segs[i].sgp->fileoff; ! 602: if(strcmp(segs[i].sgp->segname, SEG_LINKEDIT) != 0) ! 603: segs[i].sgp->fileoff = newoffset; ! 604: sp = (struct section *)((char *)(segs[i].sgp) + ! 605: sizeof(struct segment_command)); ! 606: if(segs[i].sgp == objc_sgp || segs[i].sgp->flags == SG_NORELOC){ ! 607: for(j = 0; j < segs[i].sgp->nsects; j++){ ! 608: sects[k + j].offset = sp->offset; ! 609: sp->offset += newoffset - oldoffset; ! 610: sp++; ! 611: } ! 612: } ! 613: /* ! 614: * If it is not the LINKEDIT segment or the last segment then ! 615: * move up the offsets. ! 616: */ ! 617: if(strcmp(segs[i].sgp->segname, SEG_LINKEDIT) != 0 || ! 618: i != nsegs - 1){ ! 619: oldoffset += segs[i].filesize; ! 620: newoffset += segs[i].sgp->filesize; ! 621: } ! 622: } ! 623: k += segs[i].sgp->nsects; ! 624: } ! 625: ! 626: /* ! 627: * Now update the offsets to the linkedit information. ! 628: */ ! 629: if(oldoffset != low_linkedit){ ! 630: error("contents of input file: %s not in an order that the " ! 631: "specified sections can be replaced by this program", input); ! 632: goto objc_runtime_setup_cleanup; ! 633: } ! 634: for(i = 0; i < nsegs; i++){ ! 635: sp = (struct section *)((char *)(segs[i].sgp) + ! 636: sizeof(struct segment_command)); ! 637: for(j = 0; j < segs[i].sgp->nsects; j++){ ! 638: if(sp->nreloc != 0) ! 639: sp->reloff += newoffset - oldoffset; ! 640: sp++; ! 641: } ! 642: } ! 643: if(stp != NULL){ ! 644: if(stp->nsyms != 0); ! 645: stp->symoff += newoffset - oldoffset; ! 646: if(stp->strsize != 0) ! 647: stp->stroff += newoffset - oldoffset; ! 648: } ! 649: if(ssp != NULL){ ! 650: if(ssp->size != 0) ! 651: ssp->offset += newoffset - oldoffset; ! 652: } ! 653: if(linkedit_sgp != NULL){ ! 654: linkedit_sgp->fileoff += newoffset - oldoffset; ! 655: } ! 656: ! 657: /* ! 658: * Now write the new file by writing the header and modified load ! 659: * commands, then the segments with any new sections and finally ! 660: * the link edit info. ! 661: */ ! 662: if((outfd = open(output, O_CREAT | O_WRONLY | O_TRUNC ,input_mode)) == ! 663: -1){ ! 664: system_error("can't create output file: %s", output); ! 665: goto objc_runtime_setup_cleanup; ! 666: } ! 667: ! 668: if(r = vm_allocate(task_self(), &pad_addr, SEGALIGN, 1) != ! 669: KERN_SUCCESS){ ! 670: machkern_error(r, "vm_allocate() failed"); ! 671: goto objc_runtime_setup_cleanup; ! 672: } ! 673: ! 674: k = 0; ! 675: for(i = 0; i < nsegs; i++){ ! 676: if(segs[i].sgp == objc_sgp){ ! 677: for(j = 0; j < segs[i].sgp->nsects; j++){ ! 678: sp = sects[k + j].sp; ! 679: if(sp == objc_runtime_setup_sp){ ! 680: lseek(outfd, sp->offset, L_SET); ! 681: if(write(outfd, objc_runtime_setup_contents, ! 682: objc_runtime_setup_size) != ! 683: objc_runtime_setup_size){ ! 684: system_error("can't write section contents for " ! 685: "section (%s,%s) to output file: %s", ! 686: sp->segname, sp->sectname, output); ! 687: goto objc_runtime_setup_cleanup; ! 688: } ! 689: } ! 690: else{ ! 691: /* write the original section */ ! 692: if(sects[k + j].offset + sp->size > input_size){ ! 693: error("truncated or malformed object file: %s " ! 694: "(section (%0.16s,%0.16s) extends past the " ! 695: "end of the file)",input, sp->segname, ! 696: sp->sectname); ! 697: goto objc_runtime_setup_cleanup; ! 698: } ! 699: lseek(outfd, sp->offset, L_SET); ! 700: ! 701: if(write(outfd,(char *)input_addr + sects[k + j].offset, ! 702: sp->size) != sp->size){ ! 703: system_fatal("can't write section contents for " ! 704: "section (%s,%s) to output file: %s", ! 705: sp->segname, sp->sectname, output); ! 706: goto objc_runtime_setup_cleanup; ! 707: } ! 708: } ! 709: } ! 710: /* write the segment padding */ ! 711: if(write(outfd, (char *)pad_addr, segs[i].padsize) != ! 712: segs[i].padsize){ ! 713: system_error("can't write segment padding for segment %s to" ! 714: " output file: %s", segs[i].sgp->segname, ! 715: output); ! 716: goto objc_runtime_setup_cleanup; ! 717: } ! 718: } ! 719: else{ ! 720: /* write the original segment */ ! 721: if(strcmp(segs[i].sgp->segname, SEG_LINKEDIT) != 0 || ! 722: i != nsegs - 1){ ! 723: if(segs[i].fileoff + segs[i].sgp->filesize > input_size){ ! 724: error("truncated or malformed object file: %s " ! 725: "(segment: %s extends past the end of " ! 726: "the file)", input, segs[i].sgp->segname); ! 727: goto objc_runtime_setup_cleanup; ! 728: } ! 729: if(write(outfd, (char *)input_addr + segs[i].fileoff, ! 730: segs[i].sgp->filesize) != segs[i].sgp->filesize){ ! 731: system_error("can't write segment contents for " ! 732: "segment: %s to output file: %s", ! 733: segs[i].sgp->segname, output); ! 734: goto objc_runtime_setup_cleanup; ! 735: } ! 736: } ! 737: } ! 738: k += segs[i].sgp->nsects; ! 739: } ! 740: /* write the linkedit info */ ! 741: size = input_size - low_linkedit; ! 742: if(write(outfd, (char *)input_addr + low_linkedit, size) != size){ ! 743: system_error("can't write link edit information to output file: %s", ! 744: output); ! 745: goto objc_runtime_setup_cleanup; ! 746: } ! 747: lseek(outfd, 0, L_SET); ! 748: size = sizeof(struct mach_header) + mhp->sizeofcmds; ! 749: if(swapped){ ! 750: lcp = load_commands; ! 751: for(i = 0; i < mhp->ncmds; i++){ ! 752: lc = *lcp; ! 753: switch(lcp->cmd){ ! 754: case LC_SEGMENT: ! 755: sgp = (struct segment_command *)lcp; ! 756: sp = (struct section *)((char *)sgp + ! 757: sizeof(struct segment_command)); ! 758: swap_section(sp, sgp->nsects, host_byte_order); ! 759: swap_segment_command(sgp, host_byte_order); ! 760: break; ! 761: case LC_SYMTAB: ! 762: stp = (struct symtab_command *)lcp; ! 763: swap_symtab_command(stp, host_byte_order); ! 764: break; ! 765: case LC_SYMSEG: ! 766: ssp = (struct symseg_command *)lcp; ! 767: swap_symseg_command(ssp, host_byte_order); ! 768: break; ! 769: default: ! 770: swap_load_command(lcp, host_byte_order); ! 771: break; ! 772: } ! 773: lcp = (struct load_command *)((char *)lcp + lc.cmdsize); ! 774: } ! 775: swap_mach_header(mhp, host_byte_order); ! 776: } ! 777: ! 778: if(write(outfd, mhp, size) != size){ ! 779: system_error("can't write headers to output file: %s", output); ! 780: goto objc_runtime_setup_cleanup; ! 781: } ! 782: ! 783: if(close(outfd) == -1){ ! 784: system_error("can't close output file: %s", output); ! 785: outfd = -1; ! 786: goto objc_runtime_setup_cleanup; ! 787: } ! 788: ! 789: /* ! 790: if(segs != NULL) ! 791: free(segs); ! 792: if(sects != NULL) ! 793: free(sects); ! 794: if(new_mhp != NULL) ! 795: free(new_mhp); ! 796: if(pad_addr != 0){ ! 797: if((r = vm_deallocate(task_self(), (vm_address_t)pad_addr, ! 798: SEGALIGN)) != KERN_SUCCESS){ ! 799: machkern_error(r, "Can't deallocate segment pad buffer"); ! 800: return(0); ! 801: } ! 802: } ! 803: */ ! 804: return(1); ! 805: ! 806: objc_runtime_setup_cleanup: ! 807: /* ! 808: * Cleanup if there were errors. ! 809: */ ! 810: if(outfd != -1) ! 811: close(outfd); ! 812: if(segs != NULL) ! 813: free(segs); ! 814: if(sects != NULL) ! 815: free(sects); ! 816: if(new_mhp != NULL) ! 817: free(new_mhp); ! 818: if(pad_addr != 0){ ! 819: if((r = vm_deallocate(task_self(), (vm_address_t)pad_addr, ! 820: SEGALIGN)) != KERN_SUCCESS){ ! 821: machkern_error(r, "Can't deallocate segment pad buffer"); ! 822: } ! 823: } ! 824: return(0); ! 825: } ! 826: ! 827: /* ! 828: * Function for qsort for comparing segments vmaddr feilds ! 829: */ ! 830: static ! 831: int ! 832: qsort_vmaddr( ! 833: const struct rep_seg *seg1, ! 834: const struct rep_seg *seg2) ! 835: { ! 836: return((long)(seg1->sgp->vmaddr) - (long)(seg2->sgp->vmaddr)); ! 837: } ! 838: ! 839: /* ! 840: * Function for qsort for comparing segments fileoff fields ! 841: */ ! 842: static ! 843: int ! 844: qsort_fileoff( ! 845: const struct rep_seg *seg1, ! 846: const struct rep_seg *seg2) ! 847: { ! 848: return((long)(seg1->sgp->fileoff) - (long)(seg2->sgp->fileoff)); ! 849: } ! 850: ! 851: /* ! 852: * Function for qsort for comparing sections offset fields ! 853: */ ! 854: static ! 855: int ! 856: qsort_offset( ! 857: const struct rep_sect *sect1, ! 858: const struct rep_sect *sect2) ! 859: { ! 860: return((long)(sect1->sp->offset) - (long)(sect2->sp->offset)); ! 861: } ! 862: ! 863: /* ! 864: * allocate is just a wrapper around malloc that prints and error message and ! 865: * exits if the malloc fails. ! 866: */ ! 867: static ! 868: void * ! 869: allocate( ! 870: long size) ! 871: { ! 872: void *p; ! 873: ! 874: if((p = (void *)malloc(size)) == (char *)0) ! 875: system_fatal("virtual memory exhausted (malloc failed)"); ! 876: return(p); ! 877: } ! 878: ! 879: /* ! 880: * Print the error message and set the non-fatal error indication. ! 881: */ ! 882: static ! 883: void ! 884: error( ! 885: const char *format, ! 886: ...) ! 887: { ! 888: va_list ap; ! 889: ! 890: va_start(ap, format); ! 891: fprintf(stderr, "%s: ", progname); ! 892: vfprintf(stderr, format, ap); ! 893: fprintf(stderr, "\n"); ! 894: va_end(ap); ! 895: } ! 896: ! 897: /* ! 898: * Print the fatal error message, and exit non-zero. ! 899: */ ! 900: static ! 901: void ! 902: fatal( ! 903: const char *format, ! 904: ...) ! 905: { ! 906: va_list ap; ! 907: ! 908: va_start(ap, format); ! 909: fprintf(stderr, "%s: ", progname); ! 910: vfprintf(stderr, format, ap); ! 911: fprintf(stderr, "\n"); ! 912: va_end(ap); ! 913: exit(1); ! 914: } ! 915: ! 916: /* ! 917: * Print the error message along with the system error message, set the ! 918: * non-fatal error indication. ! 919: */ ! 920: static ! 921: void ! 922: system_error( ! 923: const char *format, ! 924: ...) ! 925: { ! 926: va_list ap; ! 927: ! 928: va_start(ap, format); ! 929: fprintf(stderr, "%s: ", progname); ! 930: vfprintf(stderr, format, ap); ! 931: fprintf(stderr, " (%s)\n", strerror(errno)); ! 932: va_end(ap); ! 933: } ! 934: ! 935: /* ! 936: * Print the fatal message along with the system error message, and exit ! 937: * non-zero. ! 938: */ ! 939: static ! 940: void ! 941: system_fatal( ! 942: const char *format, ! 943: ...) ! 944: { ! 945: va_list ap; ! 946: ! 947: va_start(ap, format); ! 948: fprintf(stderr, "%s: ", progname); ! 949: vfprintf(stderr, format, ap); ! 950: fprintf(stderr, " (%s)\n", strerror(errno)); ! 951: va_end(ap); ! 952: exit(1); ! 953: } ! 954: ! 955: /* ! 956: * Print the error message along with the mach error string. ! 957: */ ! 958: static ! 959: void ! 960: machkern_error( ! 961: kern_return_t r, ! 962: char *format, ! 963: ...) ! 964: { ! 965: va_list ap; ! 966: ! 967: va_start(ap, format); ! 968: fprintf(stderr, "%s: ", progname); ! 969: vfprintf(stderr, format, ap); ! 970: fprintf(stderr, " (%s)\n", mach_error_string(r)); ! 971: va_end(ap); ! 972: } ! 973: ! 974: /* ! 975: * Round v to a multiple of r. ! 976: */ ! 977: ! 978: long ! 979: round( ! 980: long v, ! 981: unsigned long r) ! 982: { ! 983: r--; ! 984: v += r; ! 985: v &= ~(long)r; ! 986: return(v); ! 987: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.