Annotation of objc/objcedit.c, revision 1.1.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.