/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include "stuff/breakout.h" #include "stuff/hash_string.h" #include "stuff/allocate.h" #include "stuff/errors.h" #include "stuff/round.h" #include "stuff/reloc.h" char *progname = NULL; /* name of the program for error messages (argv[0]) */ /* * If -arch_indr is used then this is an allocated array of * the names of the listfiles. */ char **list_filenames = NULL; /* * Data structures to hold the symbol names (both the indirect and undefined * symbol names) from the list file. */ struct symbol { char *name; /* name of the symbol */ int32_t type; /* type of this symbol (N_INDR or N_UNDF) */ char *indr; /* name for indirection if N_INDR type */ struct indr_object *io; /* pointer to indr_object for this */ struct symbol *next; /* next symbol in the hash chain */ }; /* The symbol hash table is hashed on the name field */ #define SYMBOL_HASH_SIZE 250 static struct symbol *symbol_hash[SYMBOL_HASH_SIZE]; /* * Data structures to hold the object names (both the names from the archive * and the names created for indirect symbols). If this is for indirect symbols * then the indr and undef fields are non-zero. */ struct indr_object { char *membername; /* the base name of the object file */ char *indr; /* the name of the indirect symbol */ char *undef; /* the name of the undefined symbol */ enum bool existing_symbol; uint32_t index; }; /* * The ordered list of the indr objects to be created. The objects created for * indirect symbols are placed in first in the archive in the order the symbol * names appear in the list file (so to get known order). Then all of the * original objects from the old archive are placed in the archive preserving * their order. */ #define INITIAL_LIST_SIZE 250 struct list { struct indr_object **list; /* the order list */ uint32_t used; /* the number used in the list */ uint32_t size; /* the current size of the list */ }; static struct list indr_list; /* * The string table maintained by start_string_table(), add_to_string_table() * and end_string_table(); */ #define INITIAL_STRING_TABLE_SIZE 40960 static struct { char *strings; uint32_t size; uint32_t index; } string_table; struct undef_map { enum bool old_symbol; uint32_t index; struct nlist symbol; }; static struct undef_map *undef_map; static char *qsort_strings = NULL; static struct nlist *qsort_symbols = NULL; static void usage( void); static void process_list( char *list_filename, enum bool nflag); static void translate_input( struct arch *archs, uint32_t narchs, struct arch_flag *arch_flags, uint32_t narch_flags, enum bool all_archs, enum bool nflag); static void translate_object( struct arch *arch, struct member *member, struct object *object); static void translate_dylib( struct arch *arch, struct object *object); static int cmp_qsort_undef_map( const struct undef_map *sym1, const struct undef_map *sym2); static int cmp_qsort_toc( const struct dylib_table_of_contents *toc1, const struct dylib_table_of_contents *toc2); static void make_indr_objects( struct arch *arch); static void enter_symbol( char *name, int32_t type, char *indr, struct indr_object *io); static struct symbol *lookup_symbol( char *name); static struct indr_object *enter_object( char *membername, char *indr, char *undef, struct list *list); static void start_string_table( void); static int32_t add_to_string_table( char *p); static void end_string_table( void); static void add_list( struct list *list, struct indr_object *item); /* * The indr(l) program takes the following options: * * % indr [-n] list_filename input_file output_file * * It builds the output file by translating each symbol name listed in * list file to the same name with and underbar prepended to it in all the * objects in the input file. Then it if the input file is an archive and the * -n flag is not specified then it creates an object for each of these * symbols with an indirect symbol for the symbol name with an underbar and * adds that to the output archive. * * The -n flag is to suppress creating the indirect objects. */ int main( int argc, char *argv[], char *envp[]) { int i; uint32_t j; enum bool no_flags_left; char *list_filename, *output_file, *input_file; struct arch_flag *arch_flags; uint32_t narch_flags; enum bool all_archs; enum bool nflag; struct arch *archs; uint32_t narchs; struct stat stat_buf; progname = argv[0]; arch_flags = NULL; narch_flags = 0; all_archs = FALSE; archs = NULL; narchs = 0; list_filenames = NULL; list_filename = NULL; input_file = NULL; output_file = NULL; nflag = FALSE; /* * Parse the flags. */ no_flags_left = FALSE; for(i = 1; i < argc ; i++){ if(argv[i][0] != '-' || no_flags_left){ if(list_filename == NULL && list_filenames == NULL) list_filename = argv[i]; else if(input_file == NULL) input_file = argv[i]; else if(output_file == NULL) output_file = argv[i]; else usage(); continue; } if(argv[i][1] == '\0'){ no_flags_left = TRUE; continue; } if(strcmp(argv[i], "-arch") == 0){ if(list_filenames != NULL) fatal("can't mix -arch_indr and -arch arguments"); if(i + 1 >= argc){ error("missing argument(s) to %s option", argv[i]); usage(); } if(strcmp("all", argv[i+1]) == 0){ all_archs = TRUE; } else{ arch_flags = reallocate(arch_flags, (narch_flags + 1) * sizeof(struct arch_flag)); if(get_arch_from_flag(argv[i+1], arch_flags + narch_flags) == 0){ error("unknown architecture specification flag: " "%s %s", argv[i], argv[i+1]); arch_usage(); usage(); } for(j = 0; j < narch_flags; j++){ if(arch_flags[j].cputype == arch_flags[narch_flags].cputype && (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) == (arch_flags[narch_flags].cpusubtype & ~CPU_SUBTYPE_MASK) && strcmp(arch_flags[j].name, arch_flags[narch_flags].name) == 0) break; } if(j == narch_flags) narch_flags++; } i++; continue; } if(strcmp(argv[i], "-arch_indr") == 0){ if(list_filenames == NULL && narch_flags != 0) fatal("can't mix -arch_indr and -arch arguments"); if(i + 2 >= argc){ error("missing argument(s) to %s option", argv[i]); usage(); } arch_flags = reallocate(arch_flags, (narch_flags + 1) * sizeof(struct arch_flag)); list_filenames = reallocate(list_filenames, (narch_flags + 1) * sizeof(char *)); if(get_arch_from_flag(argv[i+1], arch_flags + narch_flags) == 0){ error("unknown architecture specification flag: " "%s %s %s", argv[i], argv[i+1], argv[i+2]); arch_usage(); usage(); } list_filenames[narch_flags] = argv[i+2]; for(j = 0; j < narch_flags; j++){ if(arch_flags[j].cputype == arch_flags[narch_flags].cputype && (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) == (arch_flags[narch_flags].cpusubtype & ~CPU_SUBTYPE_MASK) && strcmp(arch_flags[j].name, arch_flags[narch_flags].name) == 0) break; } if(j == narch_flags) narch_flags++; i += 2; continue; } for(j = 1; argv[i][j] != '\0'; j++){ switch(argv[i][j]){ case 'n': nflag = TRUE; break; default: error("unknown flag -%c", argv[i][j]); usage(); } } } if((list_filename == NULL && list_filenames == NULL) || input_file == NULL || output_file == NULL) usage(); /* * Now do the work. */ /* process the list of symbols and create the data structures */ if(list_filenames == NULL) process_list(list_filename, nflag); /* breakout the input file for processing */ breakout(input_file, &archs, &narchs, FALSE); if(errors) exit(EXIT_FAILURE); /* checkout the input file for symbol table replacement processing */ checkout(archs, narchs); /* translate the symbols in the input file */ translate_input(archs, narchs, arch_flags, narch_flags, all_archs, nflag); if(errors) exit(EXIT_FAILURE); /* create the output file */ if(stat(input_file, &stat_buf) == -1) system_error("can't stat input file: %s", input_file); writeout(archs, narchs, output_file, stat_buf.st_mode & 0777, TRUE, FALSE, FALSE, NULL); if(errors) return(EXIT_FAILURE); else return(EXIT_SUCCESS); } /* * Print the current usage message and exit non-zero. */ static void usage() { fprintf(stderr, "Usage: %s [-n] [[-arch arch_flag] ...] " " \n", progname); fprintf(stderr, "Usage: %s [-n] [[-arch_indr arch_flag " "] ...] \n", progname); exit(EXIT_FAILURE); } /* * process the symbols listed in list_filename. This enters each symbol as an * indirect symbol into the symbol hash table as well as the undefined symbol * for the indirection. Then it creates the name of the object file that will * be used to put these symbols in. */ static void process_list( char *list_filename, enum bool nflag) { FILE *list; char buf[BUFSIZ], *symbol_name, *_symbol_name, *membername; int32_t i, len, symbol_number; struct indr_object *io; /* * Reset things first. */ for(i = 0; i < SYMBOL_HASH_SIZE; i++) symbol_hash[i] = NULL; memset(&indr_list, '\0', sizeof(struct list)); if((list = fopen(list_filename, "r")) == NULL) system_fatal("can't open: %s", list_filename); io = NULL; symbol_number = 0; buf[BUFSIZ-1] = '\0'; while(fgets(buf, BUFSIZ-1, list) != NULL){ len = strlen(buf); if(buf[len-1] != '\n') fatal("symbol name: %s too long from file: %s", buf, list_filename); buf[len-1] = '\0'; symbol_name = makestr(buf, NULL); _symbol_name = makestr("_", symbol_name, NULL); if(nflag == FALSE){ sprintf(buf, "%05d", symbol_number++); membername = makestr("INDR", buf, ".o", NULL); io = enter_object(membername, symbol_name, _symbol_name, &indr_list); } enter_symbol(symbol_name, N_INDR, _symbol_name, io); enter_symbol(_symbol_name, N_UNDF, NULL, io); } if(ferror(list)) system_fatal("can't read: %s", list_filename); fclose(list); } /* * Translate the objects in the input file by changing the external symbols * that match indirect symbols in the symbol hash table to the symbol that the * indirect symbol is for. */ static void translate_input( struct arch *archs, uint32_t narchs, struct arch_flag *arch_flags, uint32_t narch_flags, enum bool all_archs, enum bool nflag) { uint32_t i, j, offset, size; cpu_type_t cputype; cpu_subtype_t cpusubtype; struct arch_flag host_arch_flag; enum bool arch_process, any_processing, *arch_flag_processed; char *list_filename; arch_flag_processed = NULL; /* * Using the specified arch_flags process specified objects for those * architecures. */ any_processing = FALSE; if(narch_flags != 0) arch_flag_processed = allocate(narch_flags * sizeof(enum bool)); memset(arch_flag_processed, '\0', narch_flags * sizeof(enum bool)); for(i = 0; i < narchs; i++){ /* * Determine the architecture (cputype and cpusubtype) of arch[i] */ cputype = 0; cpusubtype = 0; if(archs[i].type == OFILE_ARCHIVE){ for(j = 0; j < archs[i].nmembers; j++){ if(archs[i].members[j].type == OFILE_Mach_O){ cputype = archs[i].members[j].object->mh_cputype; cpusubtype = archs[i].members[j].object->mh_cpusubtype; break; } } } else if(archs[i].type == OFILE_Mach_O){ cputype = archs[i].object->mh_cputype; cpusubtype = archs[i].object->mh_cpusubtype; } else if(archs[i].fat_arch != NULL){ cputype = archs[i].fat_arch->cputype; cpusubtype = archs[i].fat_arch->cpusubtype; } arch_process = FALSE; list_filename = NULL; if(all_archs == TRUE){ arch_process = TRUE; } else if(narch_flags != 0){ for(j = 0; j < narch_flags; j++){ if(arch_flags[j].cputype == cputype && (arch_flags[j].cpusubtype & ~CPU_SUBTYPE_MASK) == (cpusubtype & ~CPU_SUBTYPE_MASK)){ arch_process = TRUE; arch_flag_processed[j] = TRUE; if(list_filenames != NULL) list_filename = list_filenames[j]; break; } } } else{ (void)get_arch_from_host(&host_arch_flag, NULL); if(host_arch_flag.cputype == cputype && (host_arch_flag.cpusubtype & ~CPU_SUBTYPE_MASK) == (cpusubtype & ~CPU_SUBTYPE_MASK)) arch_process = TRUE; } if(narchs != 1 && arch_process == FALSE) continue; any_processing = TRUE; if(list_filename != NULL) process_list(list_filename, nflag); /* * Now this arch[i] has been selected to be processed so process it * according to it's type. */ if(archs[i].type == OFILE_ARCHIVE){ for(j = 0; j < archs[i].nmembers; j++){ if(archs[i].members[j].type == OFILE_Mach_O){ translate_object(archs + i, archs[i].members + j, archs[i].members[j].object); } } /* * Make the objects for the indirect symbols in the -n flag is * not specified since this architecure is an archive. */ if(nflag == FALSE) make_indr_objects(archs + i); /* * 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(int32_t)); 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){ translate_object(archs + i, NULL, archs[i].object); } else { fatal_arch(archs + i, NULL, "can't process non-object and " "non-archive file: "); } } if(all_archs == FALSE && narch_flags != 0){ for(i = 0; i < narch_flags; i++){ if(arch_flag_processed[i] == FALSE) error("file: %s does not contain architecture: %s", archs[0].file_name, arch_flags[i].name); } free(arch_flag_processed); } if(any_processing == FALSE) fatal("no processing done on input file: %s (specify a -arch flag)", archs[0].file_name); } /* * translate the one object's symbols which match the symbols for which indirect * symbols are to be created. */ static void translate_object( struct arch *arch, struct member *member, struct object *object) { uint32_t i, j; enum byte_sex host_byte_sex; struct nlist *symbols, *nlistp; uint32_t nsyms, offset; char *strings; uint32_t strings_size; struct symbol *sp; int32_t new_nsyms; struct nlist *new_symbols; if(object->mh_filetype == MH_DYLIB || object->mh_filetype == MH_DYLIB_STUB){ if(member != NULL) fatal_arch(arch, member, "is a dynamic library which is not " "allowed as a member of an archive"); translate_dylib(arch, object); return; } host_byte_sex = get_host_byte_sex(); if(object->st == NULL || object->st->nsyms == 0) return; symbols = (struct nlist *)(object->object_addr + object->st->symoff); nsyms = object->st->nsyms; if(object->object_byte_sex != host_byte_sex) swap_nlist(symbols, nsyms, host_byte_sex); strings = object->object_addr + object->st->stroff; strings_size = object->st->strsize; object->output_symbols = symbols; object->output_nsymbols = nsyms; object->input_sym_info_size = nsyms * sizeof(struct nlist) + object->st->strsize; if(object->dyst != NULL){ object->input_sym_info_size += object->dyst->nindirectsyms * sizeof(uint32_t); } /* * Always clear the prebind checksum if any when creating a new file. */ if(object->cs != NULL) object->cs->cksum = 0; start_string_table(); nlistp = symbols; for(i = 0; i < nsyms; i++){ if(nlistp->n_type & N_EXT){ if(nlistp->n_un.n_strx){ if(nlistp->n_un.n_strx > 0 && (uint32_t)nlistp->n_un.n_strx < strings_size){ sp = lookup_symbol(strings + nlistp->n_un.n_strx); if(sp != NULL){ if(sp->type == N_UNDF) fatal_arch(arch, member, "symbol name: " "%s conflicts with symbol name created for " "indirection in: ", sp->name); nlistp->n_un.n_strx = add_to_string_table(sp->indr); } else{ nlistp->n_un.n_strx = add_to_string_table( strings + nlistp->n_un.n_strx); } } else fatal_arch(arch, member, "bad string table " "index in symbol %u in: ", i); } } else{ if(nlistp->n_un.n_strx){ if(nlistp->n_un.n_strx > 0 && nlistp->n_un.n_strx < (int32_t)strings_size) nlistp->n_un.n_strx = add_to_string_table( strings + nlistp->n_un.n_strx); else fatal_arch(arch, member, "bad string table " "index in symbol %u in: ", i); } } nlistp++; } /* * This is a hack to keep the full reference object of a host shared * library correct when it is processed by this program. To do this * The name of the object, "__.FVMLIB_REF", is checked for and if this * is it an undefined symbol for each indirect symbol is added so to * cause all the indrect objects to be loaded. */ new_symbols = NULL; if(member != NULL && strncmp(member->ar_hdr->ar_name, "__.FVMLIB_REF", sizeof("__.FVMLIB_REF") - 1) == 0){ new_nsyms = 0; for(i = 0; i < SYMBOL_HASH_SIZE; i++){ sp = symbol_hash[i]; while(sp != NULL){ if(sp->type == N_INDR) new_nsyms++; sp = sp->next; } } new_symbols = allocate((nsyms + new_nsyms) * sizeof(struct nlist)); memcpy(new_symbols, symbols, nsyms * sizeof(struct nlist)); j = nsyms; for(i = 0; i < SYMBOL_HASH_SIZE; i++){ sp = symbol_hash[i]; while(sp != NULL){ if(sp->type == N_INDR){ new_symbols[j].n_un.n_strx = add_to_string_table(sp->name); new_symbols[j].n_type = N_UNDF | N_EXT; new_symbols[j].n_sect = NO_SECT; new_symbols[j].n_desc = 0; new_symbols[j].n_value = 0; j++; } sp = sp->next; } } symbols = new_symbols; object->output_symbols = symbols; nsyms += new_nsyms; object->output_nsymbols = nsyms; } end_string_table(); object->output_strings = allocate(string_table.index); memcpy(object->output_strings, string_table.strings,string_table.index); object->output_strings_size = string_table.index; object->output_sym_info_size = nsyms * sizeof(struct nlist) + string_table.index; if(object->dyst != NULL){ object->output_sym_info_size += object->dyst->nindirectsyms * sizeof(uint32_t); } if(object->seg_linkedit != NULL){ object->seg_linkedit->filesize += object->output_sym_info_size - object->input_sym_info_size; object->seg_linkedit->vmsize = object->seg_linkedit->filesize; } if(object->dyst != NULL){ object->st->nsyms = nsyms; object->st->strsize = string_table.index; offset = UINT_MAX; if(object->st->nsyms != 0 && object->st->symoff < offset) offset = object->st->symoff; if(object->dyst->nindirectsyms != 0 && object->dyst->indirectsymoff < offset) offset = object->dyst->indirectsymoff; if(object->st->strsize != 0 && object->st->stroff < offset) offset = object->st->stroff; if(object->st->nsyms != 0){ object->st->symoff = offset; offset += object->st->nsyms * sizeof(struct nlist); } else object->st->symoff = 0; if(object->dyst->nindirectsyms != 0){ object->output_indirect_symtab = (uint32_t *) (object->object_addr + object->dyst->indirectsymoff); object->dyst->indirectsymoff = offset; offset += object->dyst->nindirectsyms * sizeof(uint32_t); } else object->dyst->indirectsymoff = 0;; if(object->st->strsize != 0){ object->st->stroff = offset; offset += object->st->strsize; } else object->st->stroff = 0; } else{ object->st->nsyms = nsyms; object->st->stroff = object->st->symoff + nsyms * sizeof(struct nlist); object->st->strsize = string_table.index; } } /* * translate the dynamic library. */ static void translate_dylib( struct arch *arch, struct object *object) { enum byte_sex host_byte_sex; uint32_t i, inew_syms, inew_undefsyms, inew_mods, indr_iextdefsym; uint32_t new_ext_strsize, len, offset; uint32_t *map; struct symbol *sp; char *p, *q; struct scattered_relocation_info *sreloc; struct nlist *symbols; uint32_t nsyms; char *strings; uint32_t strsize; struct dylib_table_of_contents *tocs; uint32_t ntoc; struct dylib_module *mods; uint32_t nmodtab; struct dylib_reference *refs; uint32_t nextrefsyms; struct relocation_info *ext_relocs; uint32_t *indirect_symtab; struct nlist *new_symbols; uint32_t new_nsyms; char *new_strings; uint32_t new_strsize; uint32_t new_nlocalsym; uint32_t new_nextdefsym; uint32_t new_nundefsym; struct dylib_table_of_contents *new_tocs; uint32_t new_ntoc; struct dylib_module *new_mods; uint32_t new_nmodtab; struct dylib_reference *new_refs; uint32_t new_nextrefsyms; /* * Break out all the old tables. */ symbols = (struct nlist *)(object->object_addr + object->st->symoff); nsyms = object->st->nsyms; strings = object->object_addr + object->st->stroff; strsize = object->st->strsize; tocs = (struct dylib_table_of_contents *) (object->object_addr + object->dyst->tocoff); ntoc = object->dyst->ntoc; mods = (struct dylib_module *) (object->object_addr + object->dyst->modtaboff); nmodtab = object->dyst->nmodtab; refs = (struct dylib_reference *) (object->object_addr + object->dyst->extrefsymoff); nextrefsyms = object->dyst->nextrefsyms; ext_relocs = (struct relocation_info *) (object->object_addr + object->dyst->extreloff); indirect_symtab = (uint32_t *) (object->object_addr + object->dyst->indirectsymoff); /* * Swap them if needed. */ host_byte_sex = get_host_byte_sex(); if(object->object_byte_sex != host_byte_sex){ swap_nlist(symbols, nsyms, host_byte_sex); swap_dylib_table_of_contents(tocs, ntoc, host_byte_sex); swap_dylib_module(mods, nmodtab, host_byte_sex); swap_dylib_reference(refs, nextrefsyms, host_byte_sex); swap_relocation_info(ext_relocs, object->dyst->nextrel, host_byte_sex); swap_indirect_symbols(indirect_symtab, object->dyst->nindirectsyms, host_byte_sex); } /* * First pass, figrure out the new sizes of the new tables. */ /* * For the symbol table and string table recalculate the their sizes * with the names of the symbols listed in the indr file renamed and * an indirect symbol added. * Look to make sure no symbols exist that would colide with the * indirect's undefined symbol names that will be created. This is so * the symbols can be renamed. */ new_nsyms = 0; new_strsize = sizeof(int32_t); new_nlocalsym = 0; new_nextdefsym = 0; new_nundefsym = 0; new_ext_strsize = 0; for(i = 0; i < nsyms; i++){ if(symbols[i].n_un.n_strx != 0){ if(symbols[i].n_un.n_strx < 0 || (uint32_t)symbols[i].n_un.n_strx > strsize){ error_arch(arch, NULL, "bad string index for symbol " "table entry %d in: ", i); return; } } if((symbols[i].n_type & N_TYPE) == N_INDR){ if(symbols[i].n_value != 0){ if(symbols[i].n_value > strsize){ error_arch(arch, NULL, "bad string index for " "indirect symbol table entry %d in: ", i); return; } } } if((symbols[i].n_type & N_EXT) == 0){ /* local symbol */ if(symbols[i].n_un.n_strx != 0) new_strsize += strlen(strings + symbols[i].n_un.n_strx) + 1; new_nlocalsym++; new_nsyms++; } else{ /* global symbol */ len = 0; if(symbols[i].n_un.n_strx != 0){ sp = lookup_symbol(strings + symbols[i].n_un.n_strx); if(sp != NULL){ if(sp->type == N_UNDF) fatal_arch(arch, NULL, "symbol name: %s conflicts " "with symbol name created for indirection in: ", sp->name); else{ len = strlen(sp->indr) + 1; sp->io->existing_symbol = TRUE; sp->io->index = i; } } else len = strlen(strings + symbols[i].n_un.n_strx) + 1; } if((symbols[i].n_type & N_TYPE) == N_INDR) len += strlen(strings + symbols[i].n_value) + 1; new_strsize += len; new_ext_strsize += len; new_nsyms++; if(((symbols[i].n_type & N_TYPE) == N_UNDF && symbols[i].n_value == 0) || (symbols[i].n_type & N_TYPE) == N_PBUD) new_nundefsym++; else new_nextdefsym++; } } /* * The new symbol table will have 1 new defined external for each * indirect symbol name on the indr list. And 1 new undefined symbol * if the undefined symbol name does not exist. */ for(i = 0; i < indr_list.used; i++){ new_nsyms++; new_nextdefsym++; /* if there is not an existing symbol there will be a new undef */ if(indr_list.list[i]->existing_symbol == FALSE){ new_nsyms++; new_nundefsym++; } len = strlen(indr_list.list[i]->indr) + 1; len += strlen(indr_list.list[i]->undef) + 1; new_strsize += len; new_ext_strsize += len; } /* * The module table's module names are placed with the external strings. * So size them and add this to the external string size. */ for(i = 0; i < nmodtab; i++){ if(mods[i].module_name == 0 || mods[i].module_name > strsize){ error_arch(arch, NULL, "bad string index for module_name " "of module table entry %d in: ", i); return; } len = strlen(strings + mods[i].module_name) + 1; new_strsize += len; new_ext_strsize += len; } /* * A new module will be created for each indr symbol so add the sizes * of those module names to the external string size. */ for(i = 0; i < indr_list.used; i++){ len = strlen(indr_list.list[i]->membername) + 1; new_strsize += len; new_ext_strsize += len; } /* * The new module table will have one extra entry for each indr symbol. */ new_nmodtab = nmodtab + indr_list.used; /* * The new reference table will have two extra entries for each indr * symbol. One for the definition of the indr and one for the undefined * that it refers to. */ new_nextrefsyms = nextrefsyms + 2 * indr_list.used; /* * The new table of contents will have extra entry for each indr symbol. */ new_ntoc = ntoc + indr_list.used; /* * Second pass, create the new tables. */ new_symbols =(struct nlist *)allocate(new_nsyms * sizeof(struct nlist)); new_strsize = round(new_strsize, sizeof(int32_t)); new_strings = (char *)allocate(new_strsize); new_strings[new_strsize - 3] = '\0'; new_strings[new_strsize - 2] = '\0'; new_strings[new_strsize - 1] = '\0'; memset(new_strings, '\0', sizeof(int32_t)); p = new_strings + sizeof(int32_t); q = p + new_ext_strsize; /* * Now create the new symbol table and string table in this order * symbol table * local symbols (sorted by module) * external defined symbols (sorted by module) * undefined symbols (sorted by name) * string table * external strings * local strings */ map = (uint32_t *)allocate(nsyms * sizeof(uint32_t)); memset(map, '\0', nsyms * sizeof(uint32_t)); inew_syms = 0; for(i = 0; i < nsyms; i++){ /* loop for local symbols */ if((symbols[i].n_type & N_EXT) == 0){ new_symbols[inew_syms] = symbols[i]; if(symbols[i].n_un.n_strx != 0){ strcpy(q, strings + symbols[i].n_un.n_strx); new_symbols[inew_syms].n_un.n_strx = q - new_strings; q += strlen(q) + 1; } map[i] = inew_syms; inew_syms++; } } for(i = 0; i < nsyms; i++){ /* loop for external defined symbols */ if((symbols[i].n_type & N_EXT) == N_EXT && ((symbols[i].n_type & N_TYPE) != N_UNDF && (symbols[i].n_type & N_TYPE) != N_PBUD)){ new_symbols[inew_syms] = symbols[i]; if(symbols[i].n_un.n_strx != 0){ sp = lookup_symbol(strings + symbols[i].n_un.n_strx); if(sp != NULL) strcpy(p, sp->indr); else strcpy(p, strings + symbols[i].n_un.n_strx); new_symbols[inew_syms].n_un.n_strx = p - new_strings; p += strlen(p) + 1; } if((symbols[i].n_type & N_TYPE) == N_INDR){ if(symbols[i].n_value != 0){ strcpy(p, strings + symbols[i].n_value); new_symbols[inew_syms].n_value = p - new_strings; p += strlen(p) + 1; } } map[i] = inew_syms; inew_syms++; } } indr_iextdefsym = inew_syms; for(i = 0; i < indr_list.used; i++){ /* loop for new defined symbols*/ strcpy(p, indr_list.list[i]->indr); new_symbols[inew_syms].n_un.n_strx = p - new_strings; p += strlen(p) + 1; new_symbols[inew_syms].n_type = N_INDR | N_EXT; new_symbols[inew_syms].n_desc = 0; new_symbols[inew_syms].n_sect = NO_SECT; /* Note this name is used below for the undefined */ strcpy(p, indr_list.list[i]->undef); indr_list.list[i]->undef = p; new_symbols[inew_syms].n_value = p - new_strings; p += strlen(p) + 1; inew_syms++; } /* * To get the undefined symbols in order sorted by name they are first * copied into the undef_map, sorted and then copied into the * new_symbols in the sorted order. */ undef_map = (struct undef_map *)allocate(new_nundefsym * sizeof(struct undef_map)); inew_undefsyms = 0; for(i = 0; i < indr_list.used; i++){ /* loop for new undef symbols */ if(indr_list.list[i]->existing_symbol == FALSE){ /* Note this name is used from above for the undefined */ undef_map[inew_undefsyms].symbol.n_un.n_strx = indr_list.list[i]->undef - new_strings; undef_map[inew_undefsyms].symbol.n_type = N_UNDF | N_EXT; undef_map[inew_undefsyms].symbol.n_desc = 0; undef_map[inew_undefsyms].symbol.n_sect = NO_SECT; undef_map[inew_undefsyms].symbol.n_value = 0; undef_map[inew_undefsyms].old_symbol = FALSE; undef_map[inew_undefsyms].index = i; inew_undefsyms++; } } for(i = 0; i < nsyms; i++){ /* loop for undefined symbols */ if((symbols[i].n_type & N_EXT) == N_EXT && ((symbols[i].n_type & N_TYPE) == N_UNDF || (symbols[i].n_type & N_TYPE) == N_PBUD)){ undef_map[inew_undefsyms].symbol = symbols[i]; if(symbols[i].n_un.n_strx != 0){ sp = lookup_symbol(strings + symbols[i].n_un.n_strx); if(sp != NULL) strcpy(p, sp->indr); else strcpy(p, strings + symbols[i].n_un.n_strx); undef_map[inew_undefsyms].symbol.n_un.n_strx = p - new_strings; p += strlen(p) + 1; } undef_map[inew_undefsyms].old_symbol = TRUE; undef_map[inew_undefsyms].index = i; inew_undefsyms++; } } /* Sort the undefined symbols by name */ qsort_strings = new_strings; qsort(undef_map, new_nundefsym, sizeof(struct undef_map), (int (*)(const void *, const void *))cmp_qsort_undef_map); /* Copy the symbols now in sorted order into new_symbols */ for(i = 0; i < new_nundefsym; i++){ new_symbols[inew_syms] = undef_map[i].symbol; /* update the map for these symbols */ if(undef_map[i].old_symbol == TRUE) map[undef_map[i].index] = inew_syms; else indr_list.list[undef_map[i].index]->index = inew_syms; inew_syms++; } /* * Fill in the new module table. First copy in the old table, and * module names. Then add the new module table entries for the * indr modules. */ new_mods = (struct dylib_module *)allocate( new_nmodtab * sizeof(struct dylib_module)); inew_mods = 0; for(i = 0; i < nmodtab; i++){ new_mods[inew_mods] = mods[i]; strcpy(p, strings + mods[i].module_name); new_mods[inew_mods].module_name = p - new_strings; p += strlen(p) + 1; inew_mods++; } for(i = 0; i < indr_list.used; i++){ memset(new_mods + inew_mods, '\0', sizeof(struct dylib_module)); strcpy(p, indr_list.list[i]->membername); new_mods[inew_mods].module_name = p - new_strings; p += strlen(p) + 1; new_mods[inew_mods].iextdefsym = indr_iextdefsym + i; new_mods[inew_mods].nextdefsym = 1; new_mods[inew_mods].irefsym = nextrefsyms + i * 2; new_mods[inew_mods].nrefsym = 2; inew_mods++; } /* * Fill in the new reference table. First copy in the old table. Then * create entries for the indr modules. */ new_refs = (struct dylib_reference *)allocate( new_nextrefsyms * sizeof(struct dylib_reference)); for(i = 0; i < nextrefsyms; i++){ new_refs[i].isym = map[refs[i].isym]; new_refs[i].flags = refs[i].flags; } for(i = 0; i < indr_list.used; i++){ new_refs[nextrefsyms + i*2].isym = indr_iextdefsym + i; new_refs[nextrefsyms + i*2].flags = REFERENCE_FLAG_DEFINED; if(indr_list.list[i]->existing_symbol == TRUE) new_refs[nextrefsyms + i*2 + 1].isym = map[indr_list.list[i]->index]; else new_refs[nextrefsyms + i*2 + 1].isym = indr_list.list[i]->index; new_refs[nextrefsyms + i*2 + 1].flags = REFERENCE_FLAG_UNDEFINED_NON_LAZY; } /* * Fill in the new table of contents. First copy in the old table. * Then create entries for the indr symbols. */ new_tocs = (struct dylib_table_of_contents *)allocate( new_ntoc * sizeof(struct dylib_table_of_contents)); for(i = 0; i < ntoc; i++){ new_tocs[i].symbol_index = map[tocs[i].symbol_index]; new_tocs[i].module_index = tocs[i].module_index; } for(i = 0; i < indr_list.used; i++){ new_tocs[ntoc + i].symbol_index = indr_iextdefsym + i; new_tocs[ntoc + i].module_index = nmodtab + i; } qsort_strings = new_strings; qsort_symbols = new_symbols; qsort(new_tocs, new_ntoc, sizeof(struct dylib_table_of_contents), (int (*)(const void *, const void *))cmp_qsort_toc); /* * Remap indexes into symbol table in the external relocation entries. */ for(i = 0; i < object->dyst->nextrel; i++){ if((ext_relocs[i].r_address & R_SCATTERED) == 0 && ext_relocs[i].r_extern == 1){ if(ext_relocs[i].r_symbolnum > nsyms){ fatal_arch(arch, NULL, "bad r_symbolnum for external " "relocation entry %d in: ", i); } ext_relocs[i].r_symbolnum = map[ext_relocs[i].r_symbolnum]; } else{ fatal_arch(arch, NULL, "bad external relocation entry " "%d (not external) in: ", i); } if((ext_relocs[i].r_address & R_SCATTERED) == 0){ if(reloc_has_pair(object->mh_cputype, ext_relocs[i].r_type)) i++; } else{ sreloc = (struct scattered_relocation_info *)ext_relocs + i; if(reloc_has_pair(object->mh_cputype, sreloc->r_type)) i++; } } /* * Remap indexes into symbol table in the indirect symbol table. */ for(i = 0; i < object->dyst->nindirectsyms; i++){ if(indirect_symtab[i] != INDIRECT_SYMBOL_LOCAL && indirect_symtab[i] != INDIRECT_SYMBOL_ABS){ if(indirect_symtab[i] > nsyms) fatal_arch(arch, NULL, "indirect symbol table entry %d " "(past the end of the symbol table) in: ", i); indirect_symtab[i] = map[indirect_symtab[i]]; } } /* * Now that all the new tables have been built and existing table * updated set the object struct to use them. */ object->input_sym_info_size = object->dyst->nlocrel * sizeof(struct relocation_info) + object->dyst->nextrel * sizeof(struct relocation_info) + object->dyst->nindirectsyms * sizeof(uint32_t) + nsyms * sizeof(struct nlist) + strsize + ntoc * sizeof(struct dylib_table_of_contents)+ nmodtab * sizeof(struct dylib_module) + 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(uint32_t) + new_nsyms * sizeof(struct nlist) + new_strsize + new_ntoc * sizeof(struct dylib_table_of_contents)+ new_nmodtab * sizeof(struct dylib_module) + new_nextrefsyms * sizeof(struct dylib_reference); if(object->split_info_cmd != NULL){ object->input_sym_info_size += object->split_info_cmd->datasize; object->output_sym_info_size += object->split_info_cmd->datasize; } if(object->hints_cmd != NULL){ 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); } if(object->code_sig_cmd != NULL){ object->input_sym_info_size = round(object->input_sym_info_size, 16); object->input_sym_info_size += object->code_sig_cmd->datasize; object->output_sym_info_size = round(object->output_sym_info_size, 16); object->output_sym_info_size += object->code_sig_cmd->datasize; } if(object->seg_linkedit != NULL){ object->seg_linkedit->filesize += object->output_sym_info_size - object->input_sym_info_size; object->seg_linkedit->vmsize = object->seg_linkedit->filesize; } object->output_symbols = new_symbols; object->output_nsymbols = new_nsyms; object->output_strings = new_strings; object->output_strings_size = new_strsize; object->output_tocs = new_tocs; object->output_ntoc = new_ntoc; object->output_mods = new_mods; object->output_nmodtab = new_nmodtab; object->output_refs = new_refs; object->output_nextrefsyms = new_nextrefsyms; 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; } object->output_ext_relocs = ext_relocs; object->output_indirect_symtab = indirect_symtab; 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; } if(object->object_byte_sex != host_byte_sex){ /* the symbol table gets swapped by writeout() */ swap_dylib_table_of_contents(new_tocs, new_ntoc, object->object_byte_sex); swap_dylib_module(new_mods, new_nmodtab, object->object_byte_sex); swap_dylib_reference(new_refs, new_nextrefsyms, object->object_byte_sex); swap_relocation_info(ext_relocs, object->dyst->nextrel, object->object_byte_sex); swap_indirect_symbols(indirect_symtab, object->dyst->nindirectsyms, object->object_byte_sex); } object->st->nsyms = new_nsyms; object->st->strsize = new_strsize; object->dyst->ilocalsym = 0; object->dyst->nlocalsym = new_nlocalsym; object->dyst->iextdefsym = new_nlocalsym; object->dyst->nextdefsym = new_nextdefsym; object->dyst->iundefsym = new_nlocalsym + new_nextdefsym; object->dyst->nundefsym = new_nundefsym; object->dyst->ntoc = new_ntoc; object->dyst->nmodtab = new_nmodtab; object->dyst->nextrefsyms = new_nextrefsyms; offset = object->seg_linkedit->fileoff; if(object->dyst->nlocrel != 0){ object->dyst->locreloff = offset; offset += object->dyst->nlocrel * sizeof(struct relocation_info); } if(object->split_info_cmd != NULL){ object->split_info_cmd->dataoff = offset; offset += object->split_info_cmd->datasize; } if(object->st->nsyms != 0){ object->st->symoff = offset; offset += object->st->nsyms * sizeof(struct nlist); } if(object->hints_cmd != NULL){ if(object->hints_cmd->nhints != 0){ object->hints_cmd->offset = offset; offset += object->hints_cmd->nhints * sizeof(struct twolevel_hint); } } if(object->dyst->nextrel != 0){ object->dyst->extreloff = offset; offset += object->dyst->nextrel * sizeof(struct relocation_info); } if(object->dyst->nindirectsyms != 0){ object->dyst->indirectsymoff = offset; offset += object->dyst->nindirectsyms * sizeof(uint32_t); } if(object->dyst->ntoc != 0){ object->dyst->tocoff = offset; offset += object->dyst->ntoc * sizeof(struct dylib_table_of_contents); } if(object->dyst->nmodtab != 0){ object->dyst->modtaboff = offset; offset += object->dyst->nmodtab * sizeof(struct dylib_module); } if(object->dyst->nextrefsyms != 0){ object->dyst->extrefsymoff = offset; offset += object->dyst->nextrefsyms * sizeof(struct dylib_reference); } if(object->st->strsize != 0){ object->st->stroff = offset; offset += object->st->strsize; } if(object->code_sig_cmd != NULL){ offset = round(offset, 16); object->code_sig_cmd->dataoff = offset; offset += object->code_sig_cmd->datasize; } } /* * Function for qsort for comparing undefined map entries. */ static int cmp_qsort_undef_map( const struct undef_map *sym1, const struct undef_map *sym2) { return(strcmp(qsort_strings + sym1->symbol.n_un.n_strx, qsort_strings + sym2->symbol.n_un.n_strx)); } /* * Function for qsort for comparing table of contents entries. */ static int cmp_qsort_toc( const struct dylib_table_of_contents *toc1, const struct dylib_table_of_contents *toc2) { return(strcmp( qsort_strings + qsort_symbols[toc1->symbol_index].n_un.n_strx, qsort_strings + qsort_symbols[toc2->symbol_index].n_un.n_strx)); } /* * make_indr_objects writes an object file for each symbol name that was in the * list file. The object contains an indirect symbol for the symbol_name. The * symbol name used as the indirect symbol has been constructed by prepending * an underbar to symbol_name previously in process_list(). */ static void make_indr_objects( struct arch *arch) { int32_t i; cpu_type_t cputype; cpu_subtype_t cpusubtype; enum byte_sex target_byte_sex; struct indr_object *io; struct nlist *output_symbols, *undef, *indr; char *output_strings, *object_addr; uint32_t object_size; struct mach_header *mh; struct symtab_command *st; struct ar_hdr *ar_hdr; uint32_t indr_time, size; unsigned short indr_mode; int oumask; gid_t gid; uid_t uid; struct object *object; /* * Make room for the indr objects in this arch's member list. The * indr objects will be place first in the list so the exising members * will be moved to the end of the end of the newly realloced list. */ arch->members = reallocate(arch->members, (arch->nmembers + indr_list.used) * sizeof(struct member)); cputype = 0; cpusubtype = 0; target_byte_sex = UNKNOWN_BYTE_SEX; for(i = arch->nmembers - 1; i >= 0 ;i--){ if(arch->members[i].object != NULL){ if(cputype == 0){ cputype = arch->members[i].object->mh_cputype; cpusubtype = arch->members[i].object->mh_cpusubtype; } if(target_byte_sex == UNKNOWN_BYTE_SEX){ target_byte_sex = arch->members[i].object->object_byte_sex; } } arch->members[i + indr_list.used] = arch->members[i]; } memset(arch->members, '\0', indr_list.used * sizeof(struct member)); arch->nmembers += indr_list.used; if(cputype == 0 || target_byte_sex == UNKNOWN_BYTE_SEX) fatal_arch(arch, NULL, "can't determine the cputype and/or the " "byte sex for: "); /* * Now loop through the indr list creating the objects for each indirect * symbol to be added to this archive. */ indr_time = time(0); oumask = umask(0); indr_mode = S_IFREG | (0666 & ~oumask); (void)umask(oumask); gid = getgid(); uid = getuid(); for(i = 0; i < indr_list.used; i++){ io = indr_list.list[i]; output_symbols = allocate(2 * sizeof(struct nlist)); undef = output_symbols + 0; indr = output_symbols + 1; start_string_table(); undef->n_un.n_strx = add_to_string_table(io->undef); undef->n_type = N_UNDF | N_EXT; undef->n_sect = NO_SECT; undef->n_desc = 0; undef->n_value = 0; indr->n_un.n_strx = add_to_string_table(io->indr); indr->n_type = N_INDR | N_EXT; indr->n_sect = NO_SECT; indr->n_desc = 0; indr->n_value = undef->n_un.n_strx; end_string_table(); output_strings = allocate(string_table.index); memcpy(output_strings, string_table.strings, string_table.index); object_size = sizeof(struct mach_header) + sizeof(struct symtab_command); object_addr = allocate(object_size); mh = (struct mach_header *)object_addr; st = (struct symtab_command *)(object_addr + sizeof(struct mach_header)); mh->magic = MH_MAGIC; mh->cputype = cputype; mh->cpusubtype = cpusubtype; mh->filetype = MH_OBJECT; mh->ncmds = 1; mh->sizeofcmds = sizeof(struct symtab_command); mh->flags = 0; st->cmd = LC_SYMTAB; st->cmdsize = sizeof(struct symtab_command); st->symoff = sizeof(struct mach_header) + sizeof(struct symtab_command); st->nsyms = 2; st->stroff = sizeof(struct mach_header) + sizeof(struct symtab_command) + 2 * sizeof(struct nlist); st->strsize = string_table.index; size = sizeof(struct mach_header) + sizeof(struct symtab_command) + 2 * sizeof(struct nlist) + string_table.index; arch->members[i].type = OFILE_Mach_O; ar_hdr = allocate(sizeof(struct ar_hdr) + 1); arch->members[i].ar_hdr = ar_hdr; sprintf((char *)ar_hdr, "%-*s%-*ld%-*u%-*u%-*o%-*ld%-*s", (int)sizeof(ar_hdr->ar_name), io->membername, (int)sizeof(ar_hdr->ar_date), (long)indr_time, (int)sizeof(ar_hdr->ar_uid), (unsigned int)uid, (int)sizeof(ar_hdr->ar_gid), (unsigned int)gid, (int)sizeof(ar_hdr->ar_mode), (unsigned int)indr_mode, (int)sizeof(ar_hdr->ar_size), (long)(size), (int)sizeof(ar_hdr->ar_fmag), ARFMAG); object = allocate(sizeof(struct object)); memset(object, '\0', sizeof(struct object)); arch->members[i].object = object; object->object_addr = object_addr; object->object_size = object_size; object->object_byte_sex = target_byte_sex; object->mh = mh; object->load_commands = (struct load_command *)st; object->st = NULL; object->input_sym_info_size = 0; object->output_sym_info_size = 2 * sizeof(struct nlist) + string_table.index; object->output_symbols = output_symbols; object->output_nsymbols = 2; object->output_strings = output_strings; object->output_strings_size = string_table.index; arch->members[i].input_file_name = arch->file_name; arch->members[i].input_ar_hdr = ar_hdr; } } /* * enter a symbol and it's type into the symbol hash table checking for * duplicates. Duplicates cause a fatal error to be printed. */ static void enter_symbol( char *name, int32_t type, char *indr, struct indr_object *io) { int32_t hash_key; struct symbol *sp; hash_key = hash_string(name) % SYMBOL_HASH_SIZE; sp = symbol_hash[hash_key]; while(sp != NULL){ if(strcmp(name, sp->name) == 0){ fatal("to create %s symbol: %s would conflict with also to be " "created %s symbol: %s", type == N_INDR ? "indirect" : "undefined", name, sp->type == N_INDR ? "indirect" : "undefined", sp->name); } sp = sp->next; } sp = (struct symbol *)allocate(sizeof(struct symbol)); sp->name = name; sp->type = type; sp->indr = indr; sp->io = io; sp->next = symbol_hash[hash_key]; symbol_hash[hash_key] = sp; } /* * lookup a symbol name in the symbol hash table returning a pointer to the * symbol structure for it. A NULL pointer is returned if not found. */ static struct symbol * lookup_symbol( char *name) { int32_t hash_key; struct symbol *sp; hash_key = hash_string(name) % SYMBOL_HASH_SIZE; sp = symbol_hash[hash_key]; while(sp != NULL){ if(strcmp(name, sp->name) == 0){ return(sp); } sp = sp->next; } return(NULL); } /* * Create and enter an indr object and it's informaton into the specified list. */ static struct indr_object * enter_object( char *membername, char *indr, char *undef, struct list *list) { struct indr_object *io; io = allocate(sizeof(struct indr_object)); io->membername = membername; io->indr = indr; io->undef = undef; io->existing_symbol = FALSE; io->index = 0; add_list(list, io); return(io); } /* * This routine is called before calls to add_to_string_table() are made to * setup or reset the string table structure. The first four bytes string * table are zeroed and the first string is placed after that (this was for * the string table length in a 4.3bsd a.out along time ago). The first four * bytes are kept zero even thought only the first byte can't be used as valid * string offset (because that is defined to be a NULL string) but to avoid * breaking programs that don't know this the first byte is left zero and the * first 4 bytes are not stuffed with the size because on a little endian * machine that first byte is likely to be non-zero. */ static void start_string_table() { if(string_table.size == 0){ string_table.size = INITIAL_STRING_TABLE_SIZE; string_table.strings = (char *)allocate(string_table.size); } memset(string_table.strings, '\0', sizeof(int32_t)); string_table.index = sizeof(int32_t); } /* * This routine adds the specified string to the string table structure and * returns the index of the string in the table. */ static int32_t add_to_string_table( char *p) { int32_t len, index; len = strlen(p) + 1; if(string_table.size < string_table.index + len){ string_table.strings = (char *)reallocate(string_table.strings, string_table.size * 2); string_table.size *= 2; } index = string_table.index; strcpy(string_table.strings + string_table.index, p); string_table.index += len; return(index); } /* * This routine is called after all calls to add_to_string_table() are made * to round off the size of the string table. It zeros the rounded bytes. */ static void end_string_table() { uint32_t length; length = round(string_table.index, sizeof(uint32_t)); memset(string_table.strings + string_table.index, '\0', length - string_table.index); string_table.index = length; } /* * Add the item to the specified list. Lists can be reused just by setting * list->used to zero. The item after the last item is allways set to NULL * so that list->list can be used for things like execv() calls directly. */ static void add_list( struct list *list, struct indr_object *item) { if(list->used + 1 >= list->size){ if(list->size == 0){ list->list = allocate(INITIAL_LIST_SIZE * sizeof(void *)); list->size = INITIAL_LIST_SIZE; list->used = 0; } else{ list->list = reallocate(list->list, list->size * 2 * sizeof(void *)); list->size *= 2; } } list->list[list->used++] = item; list->list[list->used] = NULL; }