indr.c   [plain text]


/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  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 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <libc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mach-o/nlist.h>
#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 <arch> <listfile> 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 */
    long 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;
    unsigned long 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 */
    unsigned long used;		/* the number used in the list */
    unsigned long 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;
    unsigned long size;
    unsigned long index;
} string_table;

struct undef_map {
    enum bool old_symbol;
    unsigned long 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,
    unsigned long narchs,
    struct arch_flag *arch_flags,
    unsigned long 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,
    long 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 long 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;
    unsigned long j;
    enum bool no_flags_left;
    char *list_filename, *output_file, *input_file;
    struct arch_flag *arch_flags;
    unsigned long narch_flags;
    enum bool all_archs;
    enum bool nflag;
    struct arch *archs;
    unsigned long 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 ==
				arch_flags[narch_flags].cpusubtype &&
			   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 ==
			    arch_flags[narch_flags].cpusubtype &&
		       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] ...] "
		"<symbol list file> <input file> <output file>\n", progname);
	fprintf(stderr, "Usage: %s [-n] [[-arch_indr arch_flag "
		"<symbol list file>] ...] <input file> <output file>\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;
	long 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, "%05ld", 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,
unsigned long narchs,
struct arch_flag *arch_flags,
unsigned long narch_flags,
enum bool all_archs,
enum bool nflag)
{
    unsigned long 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 == cpusubtype){
			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 == cpusubtype)
		    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(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){
		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)
{

    unsigned long i, j;

    enum byte_sex host_byte_sex;
    struct nlist *symbols, *nlistp;
    unsigned long nsyms, offset;
    char *strings;
    unsigned long strings_size;
    struct symbol *sp;

    long 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(unsigned long);
	}

	/*
	 * 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 &&
		       (unsigned long)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 %lu in: ", i);
		}
	    }
	    else{
		if(nlistp->n_un.n_strx){
		    if(nlistp->n_un.n_strx > 0 && nlistp->n_un.n_strx <
							    (long)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 %lu 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(unsigned long);
	}

	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 = ULONG_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 = (unsigned long *)
		    (object->object_addr + object->dyst->indirectsymoff);
		object->dyst->indirectsymoff = offset;
		offset += object->dyst->nindirectsyms *
			  sizeof(unsigned long);
	    }
	    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;
    unsigned long i, inew_syms, inew_undefsyms, inew_mods, indr_iextdefsym;
    unsigned long new_ext_strsize, len, offset;
    unsigned long *map;
    struct symbol *sp;
    char *p, *q;
    struct scattered_relocation_info *sreloc;

    struct nlist *symbols;
    unsigned long nsyms;
    char *strings;
    unsigned long strsize;
    struct dylib_table_of_contents *tocs;
    unsigned long ntoc;
    struct dylib_module *mods;
    unsigned long nmodtab;
    struct dylib_reference *refs;
    unsigned long nextrefsyms;
    struct relocation_info *ext_relocs;
    unsigned long *indirect_symtab;

    struct nlist *new_symbols;
    unsigned long new_nsyms;
    char *new_strings;
    unsigned long new_strsize;
    unsigned long new_nlocalsym;
    unsigned long new_nextdefsym;
    unsigned long new_nundefsym;
    struct dylib_table_of_contents *new_tocs;
    unsigned long new_ntoc;
    struct dylib_module *new_mods;
    unsigned long new_nmodtab;
    struct dylib_reference *new_refs;
    unsigned long 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 = (unsigned long *)
			   (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(long);
	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 ||
		   (unsigned long)symbols[i].n_un.n_strx > strsize){
		    error_arch(arch, NULL, "bad string index for symbol "
			       "table entry %ld 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 %ld 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 %ld 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(long));
	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(long));
	p = new_strings + sizeof(long);
	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 = (unsigned long *)allocate(nsyms * sizeof(unsigned long));
	memset(map, '\0', nsyms * sizeof(unsigned long));
	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 %ld in: ", i);
		}
		ext_relocs[i].r_symbolnum = map[ext_relocs[i].r_symbolnum];
	    }
	    else{
		fatal_arch(arch, NULL, "bad external relocation entry "
		    "%ld (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 %ld "
			"(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(unsigned long) +
	    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(unsigned long) +
	    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->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->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);
	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->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->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(unsigned long);
	}
	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;
	}
}

/*
 * 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)
{
    unsigned long 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;
    unsigned long object_size;
    struct mach_header *mh;
    struct symtab_command *st;
    struct ar_hdr *ar_hdr;
    unsigned long 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,
long type,
char *indr,
struct indr_object *io)
{
    long 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)
{
    long 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(long));
	string_table.index = sizeof(long);
}

/*
 * This routine adds the specified string to the string table structure and
 * returns the index of the string in the table.
 */
static
long
add_to_string_table(
char *p)
{
    long 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()
{
    unsigned long length;

	length = round(string_table.index, sizeof(unsigned long));
	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;
}