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