static void order_error( struct arch *arch, struct member *member, char *reason) { fatal_arch(arch, member, "file not in an order that can be processed " "(%s): ", reason); }
/* * process() walks the archs and calls ctf_insert() to do the work. */ static void process( struct arch *archs, uint32_t narchs) { uint32_t i; for(i = 0; i < narchs; i++){ if(archs[i].type == OFILE_Mach_O) ctf_insert(archs + i, NULL, archs[i].object); else fatal_arch(archs + i, NULL, "file type not valid input for " "this this program to process: "); } }
/* * ctf_insert() does the work to add the ctf section in the specified broken * out ofile for the architecure specifed with a -arch command line option. */ static void ctf_insert( struct arch *arch, struct member *member, struct object *object) { uint32_t i, move_size; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t flags, offset; uint64_t addr; if(object->mh != NULL){ cputype = object->mh->cputype; cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh->flags; offset = object->seg_linkedit->fileoff; addr = object->seg_linkedit->vmaddr; } else{ cputype = object->mh64->cputype; cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh64->flags; offset = object->seg_linkedit64->fileoff; addr = object->seg_linkedit64->vmaddr; } /* * Make sure this object is valid to process. Since the input should * be a mach_kernel that is statically linked we should not see any * dynamic symbol table info. Or a code signature at the point this * program is called in the build process. */ if((flags & MH_DYLDLINK) == MH_DYLDLINK || object->dyld_info != NULL || object->split_info_cmd != NULL || object->hints_cmd != NULL) fatal_arch(arch, member, "file is input for the dynamic linker so " "not a valid input for this program to process: "); /* * Allow a dynamic symbol table load command where it only has an * indirect symbol table and no other tables. */ if(object->dyst != NULL && (object->dyst->ntoc != 0 || object->dyst->nmodtab != 0 || object->dyst->nmodtab != 0 || object->dyst->nextrefsyms != 0 || object->dyst->nextrel != 0)) fatal_arch(arch, member, "file is input for the dynamic linker so " "not a valid input for this program to process: "); if(object->mh_filetype != MH_EXECUTE) fatal_arch(arch, member, "file type is not MH_EXECUTE so " "not a valid input for this program to process: "); if(object->seg_linkedit == NULL && object->seg_linkedit64 == NULL) fatal_arch(arch, member, "file type does not have a __LINKEDIT " "segment so not a valid input for this program to " "process: "); if(object->code_sig_cmd != NULL) fatal_arch(arch, member, "file type has code signature " "so not a valid input for this program to process: "); /* * Now see if one of the -arch flags matches this object. */ for(i = 0; i < narch_ctfs; i++){ if(arch_ctfs[i].arch_flag.cputype == cputype && arch_ctfs[i].arch_flag.cpusubtype == cpusubtype) break; } /* * If we didn't find a matching -arch flag it is an error. */ if(i >= narch_ctfs){ fatal_arch(arch, member, "no matching -arch option for this slice " "of file: "); return; } arch_ctfs[i].arch_found = TRUE; /* * Add the section for the ctf data for this arch. It is placed in * the file where the linkedit info was and that info will then be * moved. */ add_ctf_section(arch, arch_ctfs[i].arch_flag.name, offset, addr, arch_ctfs[i].size); /* * Now set up all the pointers and sizes of the symbol and string table. */ if(object->st != NULL && object->st->nsyms != 0){ if(object->mh != NULL){ object->output_symbols = (struct nlist *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist(object->output_symbols, object->st->nsyms, get_host_byte_sex()); object->output_symbols64 = NULL; } else{ object->output_symbols64 = (struct nlist_64 *) (object->object_addr + object->st->symoff); if(object->object_byte_sex != get_host_byte_sex()) swap_nlist_64(object->output_symbols64, object->st->nsyms, get_host_byte_sex()); object->output_symbols = NULL; } object->output_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; if(object->mh != NULL){ object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; } else{ object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist_64) + object->st->strsize; } } if(object->dyst != NULL){ object->output_ilocalsym = object->dyst->ilocalsym; object->output_nlocalsym = object->dyst->nlocalsym; object->output_iextdefsym = object->dyst->iextdefsym; object->output_nextdefsym = object->dyst->nextdefsym; object->output_iundefsym = object->dyst->iundefsym; object->output_nundefsym = object->dyst->nundefsym; object->output_indirect_symtab = (uint32_t *) (object->object_addr + object->dyst->indirectsymoff); object->output_loc_relocs = (struct relocation_info *) (object->object_addr + object->dyst->locreloff); if(object->mh != NULL){ object->input_sym_info_size += object->dyst->nindirectsyms * sizeof(uint32_t); } else{ object->input_sym_info_size += object->dyst->nindirectsyms * sizeof(uint32_t) + object->input_indirectsym_pad; } object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info); } if(object->func_starts_info_cmd != NULL){ object->output_func_start_info_data = object->object_addr + object->func_starts_info_cmd->dataoff; object->output_func_start_info_data_size = object->func_starts_info_cmd->datasize; object->input_sym_info_size += object->func_starts_info_cmd->datasize; } if(object->data_in_code_cmd != NULL){ object->output_data_in_code_info_data = object->object_addr + object->data_in_code_cmd->dataoff; object->output_data_in_code_info_data_size = object->data_in_code_cmd->datasize; object->input_sym_info_size += object->data_in_code_cmd->datasize; } if(object->code_sign_drs_cmd != NULL){ object->output_code_sign_drs_info_data = object->object_addr + object->code_sign_drs_cmd->dataoff; object->output_code_sign_drs_info_data_size = object->code_sign_drs_cmd->datasize; object->input_sym_info_size += object->code_sign_drs_cmd->datasize; } if(object->link_opt_hint_cmd != NULL){ object->output_link_opt_hint_info_data = object->object_addr + object->link_opt_hint_cmd->dataoff; object->output_link_opt_hint_info_data_size = object->link_opt_hint_cmd->datasize; object->input_sym_info_size += object->link_opt_hint_cmd->datasize; } object->output_sym_info_size = object->input_sym_info_size; /* * Now move the link edit info by the size of the ctf for this arch * rounded to the load command size for this arch. */ if(object->mh != NULL){ move_size = rnd(arch_ctfs[i].size, sizeof(uint32_t)); object->seg_linkedit->fileoff += move_size; } else{ move_size = rnd(arch_ctfs[i].size, sizeof(uint64_t)); object->seg_linkedit64->fileoff += move_size; } if(object->st != NULL && object->st->nsyms != 0){ object->st->symoff += move_size; object->st->stroff += move_size; } if(object->dyst != NULL){ if(object->dyst->nindirectsyms != 0) object->dyst->indirectsymoff += move_size; if(object->dyst->nlocrel != 0) object->dyst->locreloff += move_size; } if(object->func_starts_info_cmd != NULL) object->func_starts_info_cmd->dataoff += move_size; if(object->data_in_code_cmd != NULL) object->data_in_code_cmd->dataoff += move_size; if(object->code_sign_drs_cmd != NULL) object->code_sign_drs_cmd->dataoff += move_size; if(object->link_opt_hint_cmd != NULL) object->link_opt_hint_cmd->dataoff += move_size; /* * Record the new content for writeout() to put in to the output file. */ object->output_new_content = arch_ctfs[i].contents; object->output_new_content_size = move_size; }
static void check_object( struct arch *arch, struct member *member, struct object *object) { unsigned long i, ncmds, flags; struct load_command *lc; struct segment_command *sg; struct segment_command_64 *sg64; struct dylib_command *dl_id; /* * Set up the symtab load command field and link edit segment feilds in * the object structure. */ object->st = NULL; object->dyst = NULL; object->hints_cmd = NULL; object->seg_linkedit = NULL; object->seg_linkedit64 = NULL; object->code_sig_cmd = NULL; dl_id = NULL; lc = object->load_commands; if(object->mh != NULL){ ncmds = object->mh->ncmds; flags = object->mh->flags; } else{ ncmds = object->mh64->ncmds; flags = object->mh64->flags; } for(i = 0; i < ncmds; i++){ if(lc->cmd == LC_SYMTAB){ if(object->st != NULL) fatal_arch(arch, member, "malformed file (more than one " "LC_SYMTAB load command): "); object->st = (struct symtab_command *)lc; } else if(lc->cmd == LC_DYSYMTAB){ if(object->dyst != NULL) fatal_arch(arch, member, "malformed file (more than one " "LC_DYSYMTAB load command): "); object->dyst = (struct dysymtab_command *)lc; } else if(lc->cmd == LC_TWOLEVEL_HINTS){ if(object->hints_cmd != NULL) fatal_arch(arch, member, "malformed file (more than one " "LC_TWOLEVEL_HINTS load command): "); object->hints_cmd = (struct twolevel_hints_command *)lc; } else if(lc->cmd == LC_CODE_SIGNATURE){ if(object->code_sig_cmd != NULL) fatal_arch(arch, member, "malformed file (more than one " "LC_CODE_SIGNATURE load command): "); object->code_sig_cmd = (struct linkedit_data_command *)lc; } else if(lc->cmd == LC_SEGMENT_SPLIT_INFO){ if(object->split_info_cmd != NULL) fatal_arch(arch, member, "malformed file (more than one " "LC_SEGMENT_SPLIT_INFO load command): "); object->split_info_cmd = (struct linkedit_data_command *)lc; } else if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; if(strcmp(sg->segname, SEG_LINKEDIT) == 0){ if(object->seg_linkedit != NULL) fatal_arch(arch, member, "malformed file (more than " "one " SEG_LINKEDIT "segment): "); object->seg_linkedit = sg; } } else if(lc->cmd == LC_SEGMENT_64){ sg64 = (struct segment_command_64 *)lc; if(strcmp(sg64->segname, SEG_LINKEDIT) == 0){ if(object->seg_linkedit64 != NULL) fatal_arch(arch, member, "malformed file (more than " "one " SEG_LINKEDIT "segment): "); object->seg_linkedit64 = sg64; } } else if(lc->cmd == LC_ID_DYLIB){ if(dl_id != NULL) fatal_arch(arch, member, "malformed file (more than one " "LC_ID_DYLIB load command): "); dl_id = (struct dylib_command *)lc; if(dl_id->dylib.name.offset >= dl_id->cmdsize) fatal_arch(arch, member, "malformed file (name.offset of " "load command %lu extends past the end of the load " "command): ", i); } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if((object->mh_filetype == MH_DYLIB || (object->mh_filetype == MH_DYLIB_STUB && ncmds > 0)) && dl_id == NULL) fatal_arch(arch, member, "malformed file (no LC_ID_DYLIB load " "command in %s file): ", object->mh_filetype == MH_DYLIB ? "MH_DYLIB" : "MH_DYLIB_STUB"); if(object->hints_cmd != NULL){ if(object->dyst == NULL && object->hints_cmd->nhints != 0) fatal_arch(arch, member, "malformed file (LC_TWOLEVEL_HINTS " "load command present without an LC_DYSYMTAB load command):"); if(object->hints_cmd->nhints != 0 && object->hints_cmd->nhints != object->dyst->nundefsym) fatal_arch(arch, member, "malformed file (LC_TWOLEVEL_HINTS " "load command's nhints does not match LC_DYSYMTAB load " "command's nundefsym):"); } /* * For objects without a dynamic symbol table check to see that the * string table is at the end of the file and that the symbol table is * just before it. */ if(object->dyst == NULL){ symbol_string_at_end(arch, member, object); } else{ /* * This file has a dynamic symbol table command. We handle three * cases, a dynamic shared library, a file for the dynamic linker, * and a relocatable object file. Since it has a dynamic symbol * table command it could have an indirect symbol table. */ if(object->mh_filetype == MH_DYLIB /* || object->mh_filetype == MH_DYLIB_STUB */ ){ /* * This is a dynamic shared library. * The order of the symbolic info is: * local relocation entries * symbol table * local symbols * defined external symbols * undefined symbols * two-level namespace hints * external relocation entries * indirect symbol table * table of contents * module table * reference table * string table * strings for external symbols * strings for local symbols * code signature data (16 byte aligned) */ dyld_order(arch, member, object); } else if(flags & MH_DYLDLINK){ /* * This is a file for the dynamic linker (output of ld(1) with * -output_for_dyld . That is the relocation entries are split * into local and external and hanging off the dysymtab not off * the sections. * The order of the symbolic info is: * local relocation entries * symbol table * local symbols (in order as appeared in stabs) * defined external symbols (sorted by name) * undefined symbols (sorted by name) * external relocation entries * indirect symbol table * string table * strings for external symbols * strings for local symbols * code signature data (16 byte aligned) */ dyld_order(arch, member, object); } else{ /* * This is a relocatable object file either the output of the * assembler or output of ld(1) with -r. For the output of * the assembler: * The order of the symbolic info is: * relocation entries (by section) * indirect symbol table * symbol table * local symbols (in order as appeared in stabs) * defined external symbols (sorted by name) * undefined symbols (sorted by name) * string table * strings for external symbols * strings for local symbols * With this order the symbol table can be replaced and the * relocation entries and the indirect symbol table entries * can be updated in the file and not moved. * For the output of ld -r: * The order of the symbolic info is: * relocation entries (by section) * symbol table * local symbols (in order as appeared in stabs) * defined external symbols (sorted by name) * undefined symbols (sorted by name) * indirect symbol table * string table * strings for external symbols * strings for local symbols */ symbol_string_at_end(arch, member, object); } } }
static void symbol_string_at_end( struct arch *arch, struct member *member, struct object *object) { unsigned long end, strend, rounded_strend; unsigned long indirectend, rounded_indirectend; if(object->st != NULL && object->st->nsyms != 0){ end = object->object_size; if(object->st->strsize != 0){ strend = object->st->stroff + object->st->strsize; /* * Since archive member sizes are now rounded to 8 bytes the * string table may not be exactly at the end of the * object_size due to rounding. */ rounded_strend = round(strend, 8); if(strend != end && rounded_strend != end) fatal_arch(arch, member, "string table not at the end " "of the file (can't be processed) in file: "); /* * To make the code work that assumes the end of string table is * at the end of the object file change the object_size to be * the end of the string table here. This could be done at the * end of this routine but since all the later checks are fatal * we'll just do this here. */ if(rounded_strend != strend) object->object_size = strend; end = object->st->stroff; } if(object->dyst != NULL && object->dyst->nindirectsyms != 0 && object->st->nsyms != 0 && object->dyst->indirectsymoff > object->st->symoff){ indirectend = object->dyst->indirectsymoff + object->dyst->nindirectsyms * sizeof(uint32_t); /* * If this is a 64-bit Mach-O file and has an odd number of indirect * symbol table entries the next offset MAYBE rounded to a multiple of * 8 or MAY NOT BE. This should done to keep all the tables aligned but * was not done for 64-bit Mach-O in Mac OS X 10.4. */ if(object->mh64 != NULL && (object->dyst->nindirectsyms % 2) != 0){ rounded_indirectend = round(indirectend, 8); } else{ rounded_indirectend = indirectend; } if(indirectend != end && rounded_indirectend != end){ fatal_arch(arch, member, "indirect symbol table does not " "directly preceed the string table (can't be " "processed) in file: "); } object->input_indirectsym_pad = end - indirectend; end = object->dyst->indirectsymoff; if(object->mh != NULL){ if(object->st->symoff + object->st->nsyms * sizeof(struct nlist) != end) fatal_arch(arch, member, "symbol table does not " "directly preceed the indirect symbol table (can't " "be processed) in file: "); } else{ if(object->st->symoff + object->st->nsyms * sizeof(struct nlist_64) != end) fatal_arch(arch, member, "symbol table does not " "directly preceed the indirect symbol table (can't " "be processed) in file: "); } } else{ if(object->mh != NULL){ if(object->st->symoff + object->st->nsyms * sizeof(struct nlist) != end) fatal_arch(arch, member, "symbol table and string " "table not at the end of the file (can't be " "processed) in file: "); } else{ if(object->st->symoff + object->st->nsyms * sizeof(struct nlist_64) != end) fatal_arch(arch, member, "symbol table and string " "table not at the end of the file (can't be " "processed) in file: "); } } if(object->seg_linkedit != NULL && (object->seg_linkedit->flags & SG_FVMLIB) != SG_FVMLIB && object->seg_linkedit->filesize != 0){ if(object->seg_linkedit->fileoff + object->seg_linkedit->filesize != object->object_size) fatal_arch(arch, member, "the " SEG_LINKEDIT " segment " "does not cover the symbol and string table (can't " "be processed) in file: "); } } }
static void dyld_order( struct arch *arch, struct member *member, struct object *object) { unsigned long offset, rounded_offset, isym; if(object->mh != NULL){ if(object->seg_linkedit == NULL) fatal_arch(arch, member, "malformed file (no " SEG_LINKEDIT " segment): "); if(object->seg_linkedit->filesize != 0 && object->seg_linkedit->fileoff + object->seg_linkedit->filesize != object->object_size) fatal_arch(arch, member, "the " SEG_LINKEDIT " segment " "does not cover the end of the file (can't " "be processed) in: "); offset = object->seg_linkedit->fileoff; } else{ if(object->seg_linkedit64 == NULL) fatal_arch(arch, member, "malformed file (no " SEG_LINKEDIT " segment): "); if(object->seg_linkedit64->filesize != 0 && object->seg_linkedit64->fileoff + object->seg_linkedit64->filesize != object->object_size) fatal_arch(arch, member, "the " SEG_LINKEDIT " segment " "does not cover the end of the file (can't " "be processed) in: "); offset = object->seg_linkedit64->fileoff; } if(object->dyst->nlocrel != 0){ if(object->dyst->locreloff != offset) order_error(arch, member, "local relocation entries " "out of place"); offset += object->dyst->nlocrel * sizeof(struct relocation_info); } if(object->split_info_cmd != NULL){ if(object->split_info_cmd->dataoff != offset) order_error(arch, member, "split info data out of place"); offset += object->split_info_cmd->datasize; } if(object->st->nsyms != 0){ if(object->st->symoff != offset) order_error(arch, member, "symbol table out of place"); if(object->mh != NULL) offset += object->st->nsyms * sizeof(struct nlist); else offset += object->st->nsyms * sizeof(struct nlist_64); } isym = 0; if(object->dyst->nlocalsym != 0){ if(object->dyst->ilocalsym != isym) order_error(arch, member, "local symbols out of place"); isym += object->dyst->nlocalsym; } if(object->dyst->nextdefsym != 0){ if(object->dyst->iextdefsym != isym) order_error(arch, member, "externally defined symbols out of " "place"); isym += object->dyst->nextdefsym; } if(object->dyst->nundefsym != 0){ if(object->dyst->iundefsym != isym) order_error(arch, member, "undefined symbols out of place"); isym += object->dyst->nundefsym; } if(object->hints_cmd != NULL && object->hints_cmd->nhints != 0){ if(object->hints_cmd->offset != offset) order_error(arch, member, "hints table out of place"); offset += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } if(object->dyst->nextrel != 0){ if(object->dyst->extreloff != offset) order_error(arch, member, "external relocation entries" " out of place"); offset += object->dyst->nextrel * sizeof(struct relocation_info); } if(object->dyst->nindirectsyms != 0){ if(object->dyst->indirectsymoff != offset) order_error(arch, member, "indirect symbol table " "out of place"); offset += object->dyst->nindirectsyms * sizeof(uint32_t); } /* * If this is a 64-bit Mach-O file and has an odd number of indirect * symbol table entries the next offset MAYBE rounded to a multiple of * 8 or MAY NOT BE. This should done to keep all the tables aligned but * was not done for 64-bit Mach-O in Mac OS X 10.4. */ object->input_indirectsym_pad = 0; if(object->mh64 != NULL && (object->dyst->nindirectsyms % 2) != 0){ rounded_offset = round(offset, 8); } else{ rounded_offset = offset; } if(object->dyst->ntoc != 0){ if(object->dyst->tocoff != offset && object->dyst->tocoff != rounded_offset) order_error(arch, member, "table of contents out of place"); if(object->dyst->tocoff == offset){ offset += object->dyst->ntoc * sizeof(struct dylib_table_of_contents); rounded_offset = offset; } else if(object->dyst->tocoff == rounded_offset){ object->input_indirectsym_pad = rounded_offset - offset; rounded_offset += object->dyst->ntoc * sizeof(struct dylib_table_of_contents); offset = rounded_offset; } } if(object->dyst->nmodtab != 0){ if(object->dyst->modtaboff != offset && object->dyst->modtaboff != rounded_offset) order_error(arch, member, "module table out of place"); if(object->mh != NULL){ offset += object->dyst->nmodtab * sizeof(struct dylib_module); rounded_offset = offset; } else{ if(object->dyst->modtaboff == offset){ offset += object->dyst->nmodtab * sizeof(struct dylib_module_64); rounded_offset = offset; } else if(object->dyst->modtaboff == rounded_offset){ object->input_indirectsym_pad = rounded_offset - offset; rounded_offset += object->dyst->nmodtab * sizeof(struct dylib_module_64); offset = rounded_offset; } } } if(object->dyst->nextrefsyms != 0){ if(object->dyst->extrefsymoff != offset && object->dyst->extrefsymoff != rounded_offset) order_error(arch, member, "reference table out of place"); if(object->dyst->extrefsymoff == offset){ offset += object->dyst->nextrefsyms * sizeof(struct dylib_reference); rounded_offset = offset; } else if(object->dyst->extrefsymoff == rounded_offset){ object->input_indirectsym_pad = rounded_offset - offset; rounded_offset += object->dyst->nextrefsyms * sizeof(struct dylib_reference); offset = rounded_offset; } } if(object->st->strsize != 0){ if(object->st->stroff != offset && object->st->stroff != rounded_offset) order_error(arch, member, "string table out of place"); if(object->st->stroff == offset){ offset += object->st->strsize; rounded_offset = offset; } else if(object->st->stroff == rounded_offset){ object->input_indirectsym_pad = rounded_offset - offset; rounded_offset += object->st->strsize; offset = rounded_offset; } } if(object->code_sig_cmd != NULL){ rounded_offset = round(rounded_offset, 16); if(object->code_sig_cmd->dataoff != rounded_offset) order_error(arch, member, "code signature data out of place"); rounded_offset += object->code_sig_cmd->datasize; offset = rounded_offset; } if(offset != object->object_size && rounded_offset != object->object_size) order_error(arch, member, "link edit information does not fill the " SEG_LINKEDIT " segment"); }