Annotation of objc/objcedit.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.