int main(int argc, char * argv[]) { KXKextManagerError err; int fd; const char * output_name = NULL; uint32_t i, zero = 0, num_files = 0; uint32_t filenum; uint32_t strx, strtabsize, strtabpad; struct symbol * import_symbols; struct symbol * export_symbols; uint32_t num_import_syms, num_export_syms, num_removed_syms; uint32_t import_idx, export_idx; const NXArchInfo * host_arch; const NXArchInfo * target_arch; boolean_t require_imports = true; boolean_t diff = false; struct { struct mach_header hdr; struct symtab_command symcmd; } load_cmds; struct file { vm_offset_t mapped; vm_size_t mapped_size; uint32_t nsyms; boolean_t import; const char * path; }; struct file files[64]; host_arch = NXGetLocalArchInfo(); target_arch = host_arch; for( i = 1; i < argc; i += 2) { boolean_t import; if (!strcmp("-sect", argv[i])) { require_imports = false; i--; continue; } if (!strcmp("-diff", argv[i])) { require_imports = false; diff = true; i--; continue; } if (i == (argc - 1)) { fprintf(stderr, "bad arguments: %s\n", argv[i]); exit(1); } if (!strcmp("-arch", argv[i])) { target_arch = NXGetArchInfoFromName(argv[i + 1]); if (!target_arch) { fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]); exit(1); } continue; } if (!strcmp("-output", argv[i])) { output_name = argv[i+1]; continue; } if (!strcmp("-import", argv[i])) import = true; else if (!strcmp("-export", argv[i])) import = false; else { fprintf(stderr, "unknown option: %s\n", argv[i]); exit(1); } err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size); if (kKXKextManagerErrorNone != err) exit(1); if (files[num_files].mapped && files[num_files].mapped_size) { files[num_files].import = import; files[num_files].path = argv[i+1]; num_files++; } } if (!output_name) { fprintf(stderr, "no output file\n"); exit(1); } num_import_syms = 0; num_export_syms = 0; for (filenum = 0; filenum < num_files; filenum++) { files[filenum].nsyms = count_symbols((char *) files[filenum].mapped); if (files[filenum].import) num_import_syms += files[filenum].nsyms; else num_export_syms += files[filenum].nsyms; } if (!num_export_syms) { fprintf(stderr, "no export names\n"); exit(1); } import_symbols = calloc(num_import_syms, sizeof(struct symbol)); export_symbols = calloc(num_export_syms, sizeof(struct symbol)); strtabsize = 4; import_idx = 0; export_idx = 0; for (filenum = 0; filenum < num_files; filenum++) { if (files[filenum].import) { store_symbols((char *) files[filenum].mapped, import_symbols, import_idx, num_import_syms); import_idx += files[filenum].nsyms; } else { strtabsize += store_symbols((char *) files[filenum].mapped, export_symbols, export_idx, num_export_syms); export_idx += files[filenum].nsyms; } if (!files[filenum].nsyms) { fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path); } } qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp); qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp); num_removed_syms = 0; if (num_import_syms) { for (export_idx = 0; export_idx < num_export_syms; export_idx++) { boolean_t found = true; if (!bsearch(export_symbols[export_idx].name, import_symbols, num_import_syms, sizeof(struct symbol), &bsearch_cmp)) { if (require_imports) fprintf(stderr, "exported name not in import list: %s\n", export_symbols[export_idx].name); found = false; } if (export_symbols[export_idx].indirect) { if (!bsearch(export_symbols[export_idx].indirect, import_symbols, num_import_syms, sizeof(struct symbol), &bsearch_cmp)) { if (require_imports) fprintf(stderr, "exported name not in import list: %s\n", export_symbols[export_idx].indirect); found = false; } } if (found && !diff) continue; if (!found && diff) continue; num_removed_syms++; strtabsize -= (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); export_symbols[export_idx].name = 0; } } if (require_imports && num_removed_syms) { err = kKXKextManagerErrorUnspecified; goto finish; } fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755); if (-1 == fd) { perror("couldn't write output"); err = kKXKextManagerErrorFileAccess; goto finish; } strtabpad = (strtabsize + 3) & ~3; load_cmds.hdr.magic = MH_MAGIC; load_cmds.hdr.cputype = target_arch->cputype; load_cmds.hdr.cpusubtype = target_arch->cpusubtype; load_cmds.hdr.filetype = MH_OBJECT; load_cmds.hdr.ncmds = 1; load_cmds.hdr.sizeofcmds = sizeof(load_cmds.symcmd); load_cmds.hdr.flags = MH_INCRLINK; load_cmds.symcmd.cmd = LC_SYMTAB; load_cmds.symcmd.cmdsize = sizeof(load_cmds.symcmd); load_cmds.symcmd.symoff = sizeof(load_cmds); load_cmds.symcmd.nsyms = (num_export_syms - num_removed_syms); load_cmds.symcmd.stroff = (num_export_syms - num_removed_syms) * sizeof(struct nlist) + load_cmds.symcmd.symoff; load_cmds.symcmd.strsize = strtabpad; if (target_arch->byteorder != host_arch->byteorder) { swap_mach_header(&load_cmds.hdr, target_arch->byteorder); swap_symtab_command(&load_cmds.symcmd, target_arch->byteorder); } err = writeFile(fd, &load_cmds, sizeof(load_cmds)); if (kKXKextManagerErrorNone != err) goto finish; strx = 4; for (export_idx = 0; export_idx < num_export_syms; export_idx++) { struct nlist nl; if (!export_symbols[export_idx].name) continue; nl.n_sect = 0; nl.n_desc = 0; nl.n_un.n_strx = strx; strx += export_symbols[export_idx].name_len; if (export_symbols[export_idx].indirect) { nl.n_type = N_INDR | N_EXT; nl.n_value = strx; strx += export_symbols[export_idx].indirect_len; } else { nl.n_type = N_UNDF | N_EXT; nl.n_value = 0; } if (target_arch->byteorder != host_arch->byteorder) swap_nlist(&nl, 1, target_arch->byteorder); err = writeFile(fd, &nl, sizeof(nl)); if (kKXKextManagerErrorNone != err) goto finish; } strx = sizeof(uint32_t); err = writeFile(fd, &zero, strx); if (kKXKextManagerErrorNone != err) goto finish; for (export_idx = 0; export_idx < num_export_syms; export_idx++) { if (!export_symbols[export_idx].name) continue; err = writeFile(fd, export_symbols[export_idx].name, export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); if (kKXKextManagerErrorNone != err) goto finish; } err = writeFile(fd, &zero, strtabpad - strtabsize); if (kKXKextManagerErrorNone != err) goto finish; close(fd); finish: if (kKXKextManagerErrorNone != err) { if (output_name) unlink(output_name); exit(1); } else exit(0); return(0); }
/* * select_symbols returns an allocated array of nlist structs as the symbols * that are to be printed based on the flags. The number of symbols in the * array returned in returned indirectly through nsymbols. */ static struct nlist * select_symbols( struct ofile *ofile, struct symtab_command *st, struct dysymtab_command *dyst, struct cmd_flags *cmd_flags, struct process_flags *process_flags, unsigned long *nsymbols) { unsigned long i, flags; struct nlist *all_symbols, *selected_symbols, undefined; struct dylib_module m; struct dylib_reference *refs; all_symbols = (struct nlist *)(ofile->object_addr + st->symoff); selected_symbols = allocate(sizeof(struct nlist) * st->nsyms); *nsymbols = 0; if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(all_symbols, st->nsyms, get_host_byte_sex()); if(ofile->dylib_module != NULL){ m = *ofile->dylib_module; refs = (struct dylib_reference *)(ofile->object_addr + dyst->extrefsymoff); if(ofile->object_byte_sex != get_host_byte_sex()){ swap_dylib_module(&m, 1, get_host_byte_sex()); swap_dylib_reference(refs + m.irefsym, m.nrefsym, get_host_byte_sex()); } for(i = 0; i < m.nrefsym; i++){ flags = refs[i + m.irefsym].flags; if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_UNDEFINED_LAZY || flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){ undefined = all_symbols[refs[i + m.irefsym].isym]; if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_UNDEFINED_LAZY) undefined.n_type = N_UNDF | N_EXT; else undefined.n_type = N_UNDF; undefined.n_desc = (undefined.n_desc &~ REFERENCE_TYPE) | flags; undefined.n_value = 0; selected_symbols[(*nsymbols)++] = undefined; } } for(i = 0; i < m.nextdefsym; i++){ selected_symbols[(*nsymbols)++] = all_symbols[m.iextdefsym + i]; } for(i = 0; i < m.nlocalsym; i++){ selected_symbols[(*nsymbols)++] = all_symbols[m.ilocalsym + i]; } } else{ for(i = 0; i < st->nsyms; i++){ selected_symbols[(*nsymbols)++] = all_symbols[i]; } } if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(all_symbols, st->nsyms, ofile->object_byte_sex); /* * Could reallocate selected symbols to the exact size but it is more * of a time waste than a memory savings. */ return(selected_symbols); }
static void setup_object_symbolic_info( struct object *object) { if(object->st != NULL && object->st->nsyms != 0){ 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_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; object->output_sym_info_size = object->input_sym_info_size; } 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_loc_relocs = (struct relocation_info *) (object->object_addr + object->dyst->locreloff); object->output_ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); object->output_indirect_symtab = (unsigned long *) (object->object_addr + object->dyst->indirectsymoff); object->output_tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); object->output_ntoc = object->dyst->ntoc; object->output_mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); object->output_nmodtab = object->dyst->nmodtab; object->output_refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); object->output_nextrefsyms = object->dyst->nextrefsyms; object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->nindirectsyms * sizeof(unsigned long) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nextrefsyms * sizeof(struct dylib_reference); object->output_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->nindirectsyms * sizeof(unsigned long) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nextrefsyms * sizeof(struct dylib_reference); if(object->hints_cmd != NULL){ object->output_hints = (struct twolevel_hint *) (object->object_addr + object->hints_cmd->offset); object->input_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); object->output_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } } }
static void process( struct arch *archs, unsigned long narchs) { unsigned long i, j, k, offset, size; struct object *object; struct load_command *lc; struct segment_command *sg; for(i = 0; i < narchs; i++){ if(archs[i].type == OFILE_ARCHIVE){ for(j = 0; j < archs[i].nmembers; j++){ if(archs[i].members[j].type == OFILE_Mach_O){ object = archs[i].members[j].object; lc = object->load_commands; for(k = 0; k < object->mh->ncmds; k++){ if(lc->cmd == LC_SYMTAB){ object->st = (struct symtab_command *)lc; } else if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; hack_seg(object, lc, sg); } else if(lc->cmd == LC_DYSYMTAB){ error_arch(archs + i, archs[i].members + j, "can't process -dynamic object: "); return; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(object->st != NULL && object->st->nsyms != 0){ 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_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; object->output_sym_info_size = object->input_sym_info_size; } } } /* * Reset the library offsets and size. */ offset = 0; for(j = 0; j < archs[i].nmembers; j++){ archs[i].members[j].offset = offset; size = 0; if(archs[i].members[j].member_long_name == TRUE){ size = round(archs[i].members[j].member_name_size, sizeof(long)); archs[i].toc_long_name = TRUE; } if(archs[i].members[j].object != NULL){ size += archs[i].members[j].object->object_size - archs[i].members[j].object->input_sym_info_size + archs[i].members[j].object->output_sym_info_size; sprintf(archs[i].members[j].ar_hdr->ar_size, "%-*ld", (int)sizeof(archs[i].members[j].ar_hdr->ar_size), (long)(size)); /* * This has to be done by hand because sprintf puts a * null at the end of the buffer. */ memcpy(archs[i].members[j].ar_hdr->ar_fmag, ARFMAG, (int)sizeof(archs[i].members[j].ar_hdr->ar_fmag)); } else{ size += archs[i].members[j].unknown_size; } offset += sizeof(struct ar_hdr) + size; } archs[i].library_size = offset; } else if(archs[i].type == OFILE_Mach_O){ object = archs[i].object; lc = object->load_commands; for(j = 0; j < object->mh->ncmds; j++){ if(lc->cmd == LC_SYMTAB){ object->st = (struct symtab_command *)lc; } else if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; hack_seg(object, lc, sg); } else if(lc->cmd == LC_DYSYMTAB){ error_arch(archs + i, NULL, "can't process -dynamic " "object: "); return; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(object->st != NULL && object->st->nsyms != 0){ 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_nsymbols = object->st->nsyms; object->output_strings = object->object_addr + object->st->stroff; object->output_strings_size = object->st->strsize; object->input_sym_info_size = object->st->nsyms * sizeof(struct nlist) + object->st->strsize; object->output_sym_info_size = object->input_sym_info_size; } /* * Always clear the prebind checksum if any when creating a new * file. */ if(object->cs != NULL) object->cs->cksum = 0; } } }
/* * setup_code_signature() does the work to add or update the needed * LC_CODE_SIGNATURE load command for the specified broken out ofile if it * is of one of the architecures specifed with a -a command line options. */ static void setup_code_signature( struct arch *arch, struct member *member, struct object *object) { uint32_t i; cpu_type_t cputype; cpu_subtype_t cpusubtype; uint32_t flags, linkedit_end; uint32_t dyld_info_start; uint32_t dyld_info_end; uint32_t align_delta; linkedit_end = 0; /* * First set up all the pointers and sizes of the symbolic info. */ 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->dyld_info != NULL) { /* there are five parts to the dyld info, but codesign_allocate does not alter them, so copy as a block */ dyld_info_start = 0; if (object->dyld_info->rebase_off != 0) dyld_info_start = object->dyld_info->rebase_off; else if (object->dyld_info->bind_off != 0) dyld_info_start = object->dyld_info->bind_off; else if (object->dyld_info->weak_bind_off != 0) dyld_info_start = object->dyld_info->weak_bind_off; else if (object->dyld_info->lazy_bind_off != 0) dyld_info_start = object->dyld_info->lazy_bind_off; else if (object->dyld_info->export_off != 0) dyld_info_start = object->dyld_info->export_off; dyld_info_end = 0; if (object->dyld_info->export_size != 0) dyld_info_end = object->dyld_info->export_off + object->dyld_info->export_size; else if (object->dyld_info->lazy_bind_size != 0) dyld_info_end = object->dyld_info->lazy_bind_off + object->dyld_info->lazy_bind_size; else if (object->dyld_info->weak_bind_size != 0) dyld_info_end = object->dyld_info->weak_bind_off + object->dyld_info->weak_bind_size; else if (object->dyld_info->bind_size != 0) dyld_info_end = object->dyld_info->bind_off + object->dyld_info->bind_size; else if (object->dyld_info->rebase_size != 0) dyld_info_end = object->dyld_info->rebase_off + object->dyld_info->rebase_size; object->output_dyld_info = object->object_addr + dyld_info_start; object->output_dyld_info_size = dyld_info_end - dyld_info_start; object->output_sym_info_size += object->output_dyld_info_size; } 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->split_info_cmd != NULL) { object->output_split_info_data = (object->object_addr + object->split_info_cmd->dataoff); object->output_split_info_data_size = object->split_info_cmd->datasize; } 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; } 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; } 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; } 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->output_ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); object->output_tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); object->output_ntoc = object->dyst->ntoc; if(object->mh != NULL) { object->output_mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); object->output_mods64 = NULL; } else { object->output_mods64 = (struct dylib_module_64 *) (object->object_addr + object->dyst->modtaboff); object->output_mods = NULL; } object->output_nmodtab = object->dyst->nmodtab; object->output_refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); object->output_nextrefsyms = object->dyst->nextrefsyms; if(object->hints_cmd != NULL) { object->output_hints = (struct twolevel_hint *) (object->object_addr + object->hints_cmd->offset); } if(object->dyld_info != NULL) { object->input_sym_info_size += object->dyld_info->rebase_size + object->dyld_info->bind_size + object->dyld_info->weak_bind_size + object->dyld_info->lazy_bind_size + object->dyld_info->export_size; } object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nextrefsyms * sizeof(struct dylib_reference); if(object->split_info_cmd != NULL) object->input_sym_info_size += object->split_info_cmd->datasize; if(object->func_starts_info_cmd != NULL) object->input_sym_info_size += object->func_starts_info_cmd->datasize; if(object->data_in_code_cmd != NULL) object->input_sym_info_size += object->data_in_code_cmd->datasize; if(object->code_sign_drs_cmd != NULL) object->input_sym_info_size += object->code_sign_drs_cmd->datasize; if(object->link_opt_hint_cmd != NULL) object->input_sym_info_size += object->link_opt_hint_cmd->datasize; if(object->mh != NULL) { object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nindirectsyms * sizeof(uint32_t); } else { object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module_64) + object->dyst->nindirectsyms * sizeof(uint32_t) + object->input_indirectsym_pad; } if(object->hints_cmd != NULL) { object->input_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } } object->output_sym_info_size = object->input_sym_info_size; if(object->code_sig_cmd != NULL) { object->input_sym_info_size = rnd(object->input_sym_info_size, 16); object->input_sym_info_size += object->code_sig_cmd->datasize; } /* * Now see if one of the -a flags matches this object. */ if(object->mh != NULL) { cputype = object->mh->cputype; cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh->flags; } else { cputype = object->mh64->cputype; cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK; flags = object->mh64->flags; } for(i = 0; i < narch_signs; i++) { if(arch_signs[i].arch_flag.cputype == cputype && arch_signs[i].arch_flag.cpusubtype == cpusubtype) break; } /* * If we didn't find a matching -a flag then just use the existing * code signature if any. */ if(i >= narch_signs) { if(object->code_sig_cmd != NULL) { object->output_code_sig_data_size = object->code_sig_cmd->datasize; } object->output_sym_info_size = object->input_sym_info_size; return; } /* * We did find a matching -a flag for this object */ arch_signs[i].found = TRUE; /* * We now allow statically linked objects as well as objects that are * input for the dynamic linker or an MH_OBJECT filetypes to have * code signatures. So no checks are done here anymore based on the * flags or filetype in the mach_header. */ /* * If this has a code signature load command reuse it and just change * the size of that data. But do not use the old data. */ if(object->code_sig_cmd != NULL) { if(object->seg_linkedit != NULL) { object->seg_linkedit->filesize += arch_signs[i].datasize - object->code_sig_cmd->datasize; if(object->seg_linkedit->filesize > object->seg_linkedit->vmsize) object->seg_linkedit->vmsize = rnd(object->seg_linkedit->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } else if(object->seg_linkedit64 != NULL) { object->seg_linkedit64->filesize += arch_signs[i].datasize; object->seg_linkedit64->filesize -= object->code_sig_cmd->datasize; if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize) object->seg_linkedit64->vmsize = rnd(object->seg_linkedit64->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } object->code_sig_cmd->datasize = arch_signs[i].datasize; object->output_code_sig_data_size = arch_signs[i].datasize; object->output_code_sig_data = NULL; object->output_sym_info_size = rnd(object->output_sym_info_size, 16); object->output_sym_info_size += object->code_sig_cmd->datasize; } /* * The object does not have a code signature load command we add one. * And if that does not fail we then set the new load command's size and * offset of the code signature data to allocate in the object. We also * adjust the linkedit's segment size. */ else { object->code_sig_cmd = add_code_sig_load_command(arch, arch_signs[i].arch_flag.name); object->code_sig_cmd->datasize = arch_signs[i].datasize; if(object->seg_linkedit != NULL) linkedit_end = object->seg_linkedit->fileoff + object->seg_linkedit->filesize; else if(object->seg_linkedit64 != NULL) linkedit_end = object->seg_linkedit64->fileoff + object->seg_linkedit64->filesize; else if(object->mh_filetype == MH_OBJECT) linkedit_end = object->object_size; else fatal("can't allocate code signature data for: %s (for " "architecture %s) because file does not have a " SEG_LINKEDIT " segment", arch->file_name, arch_signs[i].arch_flag.name); object->code_sig_cmd->dataoff = rnd(linkedit_end, 16); object->output_code_sig_data_size = arch_signs[i].datasize; object->output_code_sig_data = NULL; align_delta = object->code_sig_cmd->dataoff - linkedit_end; if(object->output_sym_info_size != 0) object->output_sym_info_size = rnd(object->output_sym_info_size, 16); else object->output_sym_info_size = align_delta; object->output_sym_info_size += object->code_sig_cmd->datasize; if(object->seg_linkedit != NULL) { object->seg_linkedit->filesize = rnd(object->seg_linkedit->filesize, 16) + object->code_sig_cmd->datasize; if(object->seg_linkedit->filesize > object->seg_linkedit->vmsize) object->seg_linkedit->vmsize = rnd(object->seg_linkedit->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } else if(object->seg_linkedit64 != NULL) { object->seg_linkedit64->filesize = rnd(object->seg_linkedit64->filesize, 16) + object->code_sig_cmd->datasize; if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize) object->seg_linkedit64->vmsize = rnd(object->seg_linkedit64->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag)); } } }
static void setup_object_symbolic_info( struct object *object) { uint32_t output_indirectsym_pad_diff; 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; } } output_indirectsym_pad_diff = 0; 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->split_info_cmd != NULL){ object->output_split_info_data = (object->object_addr + object->split_info_cmd->dataoff); object->output_split_info_data_size = object->split_info_cmd->datasize; } 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; } 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; } 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; } 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->output_ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); object->output_tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); object->output_ntoc = object->dyst->ntoc; if(object->mh != NULL){ object->output_mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); object->output_mods64 = NULL; } else{ object->output_mods64 = (struct dylib_module_64 *) (object->object_addr + object->dyst->modtaboff); object->output_mods = NULL; } object->output_nmodtab = object->dyst->nmodtab; object->output_refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); object->output_nextrefsyms = object->dyst->nextrefsyms; if(object->hints_cmd != NULL){ object->output_hints = (struct twolevel_hint *) (object->object_addr + object->hints_cmd->offset); } if(object->code_sig_cmd != NULL){ object->output_code_sig_data = object->object_addr + object->code_sig_cmd->dataoff; object->output_code_sig_data_size = object->code_sig_cmd->datasize; } object->input_sym_info_size += object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->ntoc * sizeof(struct dylib_table_of_contents)+ object->dyst->nextrefsyms * sizeof(struct dylib_reference); if(object->split_info_cmd != NULL) object->input_sym_info_size += object->split_info_cmd->datasize; if(object->func_starts_info_cmd != NULL) object->input_sym_info_size += object->func_starts_info_cmd->datasize; if(object->data_in_code_cmd != NULL) object->input_sym_info_size += object->data_in_code_cmd->datasize; if(object->code_sign_drs_cmd != NULL) object->input_sym_info_size += object->code_sign_drs_cmd->datasize; if(object->link_opt_hint_cmd != NULL) object->input_sym_info_size += object->link_opt_hint_cmd->datasize; if(object->mh != NULL){ object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module) + object->dyst->nindirectsyms * sizeof(uint32_t); } else{ object->input_sym_info_size += object->dyst->nmodtab * sizeof(struct dylib_module_64)+ object->dyst->nindirectsyms * sizeof(uint32_t) + object->input_indirectsym_pad; if(object->input_indirectsym_pad == 0 && (object->dyst->nindirectsyms % 2) != 0) output_indirectsym_pad_diff = 4; } if(object->hints_cmd != NULL){ object->input_sym_info_size += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } if(object->code_sig_cmd != NULL){ object->input_sym_info_size = rnd(object->input_sym_info_size, 16); object->input_sym_info_size += object->code_sig_cmd->datasize; } if(output_indirectsym_pad_diff != 0){ if(object->output_ntoc != 0) object->dyst->tocoff += output_indirectsym_pad_diff; if(object->output_nmodtab != 0) object->dyst->modtaboff += output_indirectsym_pad_diff; if(object->output_nextrefsyms != 0) object->dyst->extrefsymoff += output_indirectsym_pad_diff; if(object->output_strings_size != 0) object->st->stroff += output_indirectsym_pad_diff; object->seg_linkedit64->filesize += output_indirectsym_pad_diff; if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize) object->seg_linkedit64->vmsize += output_indirectsym_pad_diff; } } object->output_sym_info_size = object->input_sym_info_size + output_indirectsym_pad_diff; }
/* * 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; }
int main(int argc, char * argv[]) { ToolError err; int i, fd; const char * output_name = NULL; uint32_t zero = 0, num_files = 0; uint32_t filenum; uint32_t strx, strtabsize, strtabpad; struct symbol * import_symbols; struct symbol * export_symbols; uint32_t num_import_syms, num_export_syms; uint32_t result_count, num_removed_syms; uint32_t import_idx, export_idx; const NXArchInfo * host_arch; const NXArchInfo * target_arch; boolean_t require_imports = true; boolean_t diff = false; struct file { vm_offset_t mapped; vm_size_t mapped_size; uint32_t nsyms; boolean_t import; const char * path; }; struct file files[64]; host_arch = NXGetLocalArchInfo(); target_arch = host_arch; for( i = 1; i < argc; i += 2) { boolean_t import; if (!strcmp("-sect", argv[i])) { require_imports = false; i--; continue; } if (!strcmp("-diff", argv[i])) { require_imports = false; diff = true; i--; continue; } if (i == (argc - 1)) { fprintf(stderr, "bad arguments: %s\n", argv[i]); exit(1); } if (!strcmp("-arch", argv[i])) { target_arch = DL_NXGetArchInfoFromName(argv[i + 1]); if (!target_arch) { fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]); exit(1); } continue; } if (!strcmp("-output", argv[i])) { output_name = argv[i+1]; continue; } if (!strcmp("-import", argv[i])) import = true; else if (!strcmp("-export", argv[i])) import = false; else { fprintf(stderr, "unknown option: %s\n", argv[i]); exit(1); } err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size); if (kErrorNone != err) exit(1); if (files[num_files].mapped && files[num_files].mapped_size) { files[num_files].import = import; files[num_files].path = argv[i+1]; num_files++; } } if (!output_name) { fprintf(stderr, "no output file\n"); exit(1); } num_import_syms = 0; num_export_syms = 0; for (filenum = 0; filenum < num_files; filenum++) { files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size); if (files[filenum].import) num_import_syms += files[filenum].nsyms; else num_export_syms += files[filenum].nsyms; } if (!num_export_syms) { fprintf(stderr, "no export names\n"); exit(1); } import_symbols = calloc(num_import_syms, sizeof(struct symbol)); export_symbols = calloc(num_export_syms, sizeof(struct symbol)); import_idx = 0; export_idx = 0; for (filenum = 0; filenum < num_files; filenum++) { if (files[filenum].import) { store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size, import_symbols, import_idx, num_import_syms); import_idx += files[filenum].nsyms; } else { store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size, export_symbols, export_idx, num_export_syms); export_idx += files[filenum].nsyms; } if (false && !files[filenum].nsyms) { fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path); } } qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp); qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp); result_count = 0; num_removed_syms = 0; strtabsize = 4; if (num_import_syms) { for (export_idx = 0; export_idx < num_export_syms; export_idx++) { struct symbol * result; char * name; size_t len; boolean_t wild; name = export_symbols[export_idx].indirect; len = export_symbols[export_idx].indirect_len; if (!name) { name = export_symbols[export_idx].name; len = export_symbols[export_idx].name_len; } wild = ((len > 2) && ('*' == name[len-=2])); if (wild) { struct bsearch_key key; key.name = name; key.name_len = len; result = bsearch(&key, import_symbols, num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix); if (result) { struct symbol * first; struct symbol * last; strtabsize += (result->name_len + result->indirect_len); first = result; while (--first >= &import_symbols[0]) { if (bsearch_cmp_prefix(&key, first)) break; strtabsize += (first->name_len + first->indirect_len); } first++; last = result; while (++last < (&import_symbols[0] + num_import_syms)) { if (bsearch_cmp_prefix(&key, last)) break; strtabsize += (last->name_len + last->indirect_len); } result_count += last - first; result = first; export_symbols[export_idx].list = first; export_symbols[export_idx].list_count = last - first; export_symbols[export_idx].flags |= kExported; } } else result = bsearch(name, import_symbols, num_import_syms, sizeof(struct symbol), &bsearch_cmp); if (!result && require_imports) { int status; char * demangled_result = __cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status); fprintf(stderr, "exported name not in import list: %s\n", demangled_result ? demangled_result : export_symbols[export_idx].name); // fprintf(stderr, " : %s\n", export_symbols[export_idx].name); if (demangled_result) { free(demangled_result); } num_removed_syms++; } if (diff) { if (!result) result = &export_symbols[export_idx]; else result = NULL; } if (result && !wild) { export_symbols[export_idx].flags |= kExported; strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len); result_count++; export_symbols[export_idx].list = &export_symbols[export_idx]; export_symbols[export_idx].list_count = 1; } } } strtabpad = (strtabsize + 3) & ~3; if (require_imports && num_removed_syms) { err = kError; goto finish; } fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755); if (-1 == fd) { perror("couldn't write output"); err = kErrorFileAccess; goto finish; } struct symtab_command symcmd; struct uuid_command uuidcmd; symcmd.cmd = LC_SYMTAB; symcmd.cmdsize = sizeof(symcmd); symcmd.symoff = sizeof(symcmd) + sizeof(uuidcmd); symcmd.nsyms = result_count; symcmd.strsize = strtabpad; uuidcmd.cmd = LC_UUID; uuidcmd.cmdsize = sizeof(uuidcmd); uuid_generate(uuidcmd.uuid); if (CPU_ARCH_ABI64 & target_arch->cputype) { struct mach_header_64 hdr; hdr.magic = MH_MAGIC_64; hdr.cputype = target_arch->cputype; hdr.cpusubtype = target_arch->cpusubtype; hdr.filetype = MH_KEXT_BUNDLE; hdr.ncmds = 2; hdr.sizeofcmds = sizeof(symcmd) + sizeof(uuidcmd); hdr.flags = MH_INCRLINK; symcmd.symoff += sizeof(hdr); symcmd.stroff = result_count * sizeof(struct nlist_64) + symcmd.symoff; if (target_arch->byteorder != host_arch->byteorder) swap_mach_header_64(&hdr, target_arch->byteorder); err = writeFile(fd, &hdr, sizeof(hdr)); } else { struct mach_header hdr; hdr.magic = MH_MAGIC; hdr.cputype = target_arch->cputype; hdr.cpusubtype = target_arch->cpusubtype; hdr.filetype = (target_arch->cputype == CPU_TYPE_I386) ? MH_OBJECT : MH_KEXT_BUNDLE; hdr.ncmds = 2; hdr.sizeofcmds = sizeof(symcmd) + sizeof(uuidcmd); hdr.flags = MH_INCRLINK; symcmd.symoff += sizeof(hdr); symcmd.stroff = result_count * sizeof(struct nlist) + symcmd.symoff; if (target_arch->byteorder != host_arch->byteorder) swap_mach_header(&hdr, target_arch->byteorder); err = writeFile(fd, &hdr, sizeof(hdr)); } if (kErrorNone != err) goto finish; if (target_arch->byteorder != host_arch->byteorder) { swap_symtab_command(&symcmd, target_arch->byteorder); swap_uuid_command(&uuidcmd, target_arch->byteorder); } err = writeFile(fd, &symcmd, sizeof(symcmd)); if (kErrorNone != err) goto finish; err = writeFile(fd, &uuidcmd, sizeof(uuidcmd)); if (kErrorNone != err) goto finish; strx = 4; for (export_idx = 0; export_idx < num_export_syms; export_idx++) { if (!export_symbols[export_idx].name) continue; if (!(kExported & export_symbols[export_idx].flags)) continue; if (export_idx && export_symbols[export_idx - 1].name && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name)) { fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name); err = kErrorDuplicate; goto finish; } for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) { if (export_symbols[export_idx].list != &export_symbols[export_idx]) { printf("wild: %s, %s\n", export_symbols[export_idx].name, export_symbols[export_idx].list[import_idx].name); } if (CPU_ARCH_ABI64 & target_arch->cputype) { struct nlist_64 nl; nl.n_sect = 0; nl.n_desc = 0; nl.n_un.n_strx = strx; strx += export_symbols[export_idx].list[import_idx].name_len; if (export_symbols[export_idx].flags & kObsolete) { nl.n_desc |= N_DESC_DISCARDED; } if (export_symbols[export_idx].list[import_idx].indirect) { nl.n_type = N_INDR | N_EXT; nl.n_value = strx; strx += export_symbols[export_idx].list[import_idx].indirect_len; } else { nl.n_type = N_UNDF | N_EXT; nl.n_value = 0; } if (target_arch->byteorder != host_arch->byteorder) swap_nlist_64(&nl, 1, target_arch->byteorder); err = writeFile(fd, &nl, sizeof(nl)); } else { struct nlist nl; nl.n_sect = 0; nl.n_desc = 0; nl.n_un.n_strx = strx; strx += export_symbols[export_idx].list[import_idx].name_len; if (export_symbols[export_idx].flags & kObsolete) { nl.n_desc |= N_DESC_DISCARDED; } if (export_symbols[export_idx].list[import_idx].indirect) { nl.n_type = N_INDR | N_EXT; nl.n_value = strx; strx += export_symbols[export_idx].list[import_idx].indirect_len; } else { nl.n_type = N_UNDF | N_EXT; nl.n_value = 0; } if (target_arch->byteorder != host_arch->byteorder) swap_nlist(&nl, 1, target_arch->byteorder); err = writeFile(fd, &nl, sizeof(nl)); } } if (kErrorNone != err) goto finish; } strx = sizeof(uint32_t); err = writeFile(fd, &zero, strx); if (kErrorNone != err) goto finish; for (export_idx = 0; export_idx < num_export_syms; export_idx++) { if (!export_symbols[export_idx].name) continue; for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++) { err = writeFile(fd, export_symbols[export_idx].list[import_idx].name, export_symbols[export_idx].list[import_idx].name_len); if (kErrorNone != err) goto finish; if (export_symbols[export_idx].list[import_idx].indirect) { err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect, export_symbols[export_idx].list[import_idx].indirect_len); if (kErrorNone != err) goto finish; } } } err = writeFile(fd, &zero, strtabpad - strtabsize); if (kErrorNone != err) goto finish; close(fd); finish: for (filenum = 0; filenum < num_files; filenum++) { // unmap file if (files[filenum].mapped_size) { munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size); files[filenum].mapped = 0; files[filenum].mapped_size = 0; } } if (kErrorNone != err) { if (output_name) unlink(output_name); exit(1); } else exit(0); return(0); }
/* * checksyms() is the routine that gets called by ofile_process() to process * single object files. */ static void checksyms( struct ofile *ofile, char *arch_name, void *cookie) { struct cmd_flags *cmd_flags; unsigned long i; struct load_command *lc; struct symtab_command *st; struct nlist *symbols; unsigned long nsymbols; char *strings; unsigned long strsize; unsigned long nfiledefs, ncats, nlocal, nstabs, nfun; unsigned long filedef_strings, cat_strings, local_strings, stab_strings; enum bool debug; if(ofile->mh == NULL) return; debug = FALSE; cmd_flags = (struct cmd_flags *)cookie; if(cmd_flags->check_dynamic_binary == TRUE) if((ofile->mh->flags & MH_DYLDLINK) == MH_DYLDLINK) check_dynamic_binary(ofile, arch_name, cmd_flags->detail, cmd_flags->verification); if(ofile->mh->filetype == MH_DYLIB || ofile->mh->filetype == MH_DYLIB_STUB) check_dylib(ofile, arch_name, cmd_flags->detail, cmd_flags->verification, &debug); st = NULL; lc = ofile->load_commands; for(i = 0; i < ofile->mh->ncmds; i++){ if(st == NULL && lc->cmd == LC_SYMTAB){ st = (struct symtab_command *)lc; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(st == NULL || st->nsyms == 0){ return; } if(cmd_flags->rldtype == FALSE && cmd_flags->trey == FALSE && (ofile->mh->flags & MH_DYLDLINK) == 0 && (ofile->file_type != OFILE_FAT || ofile->arch_type != OFILE_ARCHIVE) && ofile->file_type != OFILE_ARCHIVE && ofile->mh->filetype != MH_FVMLIB){ if(st->nsyms == 0) return; if(cmd_flags->detail == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->member_ar_hdr != NULL){ printf("%s:%.*s:", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("%s:", ofile->file_name); printf(" has %u symbols and %u string bytes\n", st->nsyms, st->strsize); } if(cmd_flags->verification == TRUE) printf("unstripped_binary\n"); exit_status = EXIT_FAILURE; return; } symbols = (struct nlist *)(ofile->object_addr + st->symoff); nsymbols = st->nsyms; if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(symbols, nsymbols, get_host_byte_sex()); strings = ofile->object_addr + st->stroff; strsize = st->strsize; for(i = 0; i < nsymbols; i++){ if(symbols[i].n_un.n_strx == 0) symbols[i].n_un.n_name = ""; else if(symbols[i].n_un.n_strx < 0 || (unsigned long)symbols[i].n_un.n_strx > st->strsize) symbols[i].n_un.n_name = "bad string index"; else symbols[i].n_un.n_name = symbols[i].n_un.n_strx + strings; if((symbols[i].n_type & N_TYPE) == N_INDR){ if(symbols[i].n_value == 0) symbols[i].n_value = (long)""; else if(symbols[i].n_value > st->strsize) symbols[i].n_value = (long)"bad string index"; else symbols[i].n_value = (long)(symbols[i].n_value + strings); } } nfiledefs = 0; ncats = 0; nlocal = 0; nstabs = 0; nfun = 0; filedef_strings = 0; cat_strings = 0; local_strings = 0; stab_strings = 0; for(i = 0; i < nsymbols; i++){ if(ofile->mh->filetype == MH_EXECUTE){ if(symbols[i].n_type == (N_ABS | N_EXT) && symbols[i].n_value == 0){ if(strncmp(symbols[i].n_un.n_name, ".file_definition_", sizeof(".file_definition_") - 1) == 0){ nfiledefs++; filedef_strings += strlen(symbols[i].n_un.n_name); } if(strncmp(symbols[i].n_un.n_name, ".objc_category_name_", sizeof(".objc_category_name_") - 1) == 0){ ncats++; cat_strings += strlen(symbols[i].n_un.n_name); } } } if((symbols[i].n_type & N_EXT) == 0){ nlocal++; local_strings += strlen(symbols[i].n_un.n_name); } if(symbols[i].n_type & N_STAB){ nstabs++; stab_strings += strlen(symbols[i].n_un.n_name); if(symbols[i].n_type == N_FUN) nfun++; } } if(nfiledefs == 0 && ncats == 0 && nlocal == 0 && nstabs == 0) return; if(cmd_flags->rldtype == TRUE && nstabs == 0) return; if((ofile->mh->flags & MH_DYLDLINK) == MH_DYLDLINK && (nstabs == 0 && nlocal == 0)) return; if(nstabs == 0 && ((ofile->file_type == OFILE_FAT && ofile->arch_type == OFILE_ARCHIVE) || ofile->file_type == OFILE_ARCHIVE || ofile->mh->filetype == MH_FVMLIB)) return; if((ofile->mh->filetype == MH_DYLIB || ofile->mh->filetype == MH_DYLIB_STUB || ofile->mh->filetype == MH_FVMLIB) && (nfun == 0 || debug == TRUE)) return; if(cmd_flags->detail == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->member_ar_hdr != NULL){ printf("%s:%.*s:", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("%s:", ofile->file_name); printf("\n"); if(nfiledefs != 0) printf(" has %lu .file_definition_ symbols and %lu string " "bytes\n", nfiledefs, filedef_strings); if(ncats != 0) printf(" has %lu .objc_category_name_ symbols and %lu string " "bytes\n", ncats, cat_strings); if(nlocal != 0) printf(" has %lu local symbols and %lu string " "bytes\n", nlocal, local_strings); if(nstabs != 0) printf(" has %lu debugging symbols and %lu string " "bytes\n", nstabs, stab_strings); } if(cmd_flags->verification == TRUE) printf("unstripped_binary\n"); if(cmd_flags->trey == TRUE && nstabs == 0) return; exit_status = EXIT_FAILURE; return; }