Пример #1
0
/*
 * literal_pointer_merge() merges literal pointers from the specified section
 * in the current object file (cur_obj).  It allocates a fine relocation map and
 * sets the fine_relocs field in the section_map to it (as well as the count).
 */
__private_extern__
void
literal_pointer_merge(
struct literal_pointer_data *data, 
struct merged_section *ms,
struct section *s, 
struct section_map *section_map)
{
    long i;
    unsigned long nliterals, j;
    char *literals;
    struct fine_reloc *fine_relocs;
    struct relocation_info *relocs;
    struct relocation_info *reloc;
    struct scattered_relocation_info *sreloc;
    unsigned long r_address, r_symbolnum, r_pcrel, r_length, r_extern,
		  r_scattered, r_value;
    struct undefined_map *undefined_map;
    struct nlist *nlists;
    char *strings;
    enum bool defined, new;

    struct merged_symbol *merged_symbol, **hash_pointer;
    struct section_map *literal_map;
    struct merged_section *literal_ms;
    struct section *literal_s;
    unsigned long section_value, input_section_offset, merged_section_offset,
		  offset;

    if(s->size == 0){
	section_map->fine_relocs = NULL;
	section_map->nfine_relocs = 0;
	return;
    }
    if(s->size % 4 != 0){
	error_with_cur_obj("literal pointer section (%.16s,%.16s) size is "
			   "not a multiple of 4 bytes",s->segname, s->sectname);
	return;
    }
    nliterals = s->size / 4;
    if(s->nreloc != nliterals){
	error_with_cur_obj("literal pointer section (%.16s,%.16s) does not "
			   "have is exactly one relocation entry for each "
			   "pointer\n", s->segname, s->sectname);
	return;
    }
#ifdef DEBUG
    data->nfiles++;
    data->nliterals += nliterals;
#endif /* DEBUG */
    /*
     * The size is not zero an it has as many relocation entries as literals so
     * this section is being relocated.
     */
    ms->relocated = TRUE;

    /*
     * Set the output_offset to -1 here so that when going through the
     * relocation entries to merge the literals the error of having more than
     * one relocation entry for each literal can be caught.
     */
    fine_relocs = allocate(nliterals * sizeof(struct fine_reloc));
    memset(fine_relocs, '\0', nliterals * sizeof(struct fine_reloc));
    for(j = 0; j < nliterals; j++){
	fine_relocs[j].output_offset = -1;
    }
    section_map->fine_relocs = fine_relocs;
    section_map->nfine_relocs = nliterals;

    /*
     * Because at this point it is known that their are exactly as many literals
     * in the section as relocation entries either could be used to merge the
     * the literals themselves.  The loop is driven off the relocation entries
     * for two reasons: first if it looped throught the literals themselfs a
     * costly search would result in trying to find the relocation entry for it
     * and by doing it the way it is done here the r_address (really an offset)
     * can be used directly to get the literal, secondly by looping through the
     * relocation entries checking for the error case of more than one
     * relocation entry refering to the same literal can be caught easily.  So
     * if everything goes without error then their must have been exactly one
     * relocation entry for each literal pointer in this section.  The reason
     * that this loop runs backwards through the relocation entries is to get
     * this implementation of merging literal pointers to match the previous
     * one so a binary compare can be done (the previous implemention went
     * through the literals and the current assembler puts out the relocation
     * entries in reverse order so these two implementions just happen to get
     * the exact same result).
     */
    relocs = (struct relocation_info *)(cur_obj->obj_addr + s->reloff);
    literals = (char *)(cur_obj->obj_addr + s->offset);
    if(cur_obj->swapped)
	swap_relocation_info(relocs, s->nreloc, host_byte_sex);
    merged_symbol = NULL;
    for(i = s->nreloc - 1; i >= 0 ; i--){
	/*
	 * Break out the fields of the relocation entry.
	 */
	if((relocs[i].r_address & R_SCATTERED) != 0){
	    sreloc = (struct scattered_relocation_info *)(relocs + i);
	    reloc = NULL;
	    r_scattered = 1;
	    r_address = sreloc->r_address;
	    r_pcrel = sreloc->r_pcrel;
	    r_length = sreloc->r_length;
	    r_value = sreloc->r_value;
	    r_extern = 0;
	    /* calculate the r_symbolnum (n_sect) from the r_value */
	    r_symbolnum = 0;
	    for(j = 0; j < cur_obj->nsection_maps; j++){
		if(r_value >= cur_obj->section_maps[j].s->addr &&
		   r_value < cur_obj->section_maps[j].s->addr +
			     cur_obj->section_maps[j].s->size){
		    r_symbolnum = j + 1;
		    break;
		}
	    }
	    if(r_symbolnum == 0){
		/*
		 * The edge case where the last address past then end of
		 * of the last section is referenced.
		 */
		for(j = 0; j < cur_obj->nsection_maps; j++){
		    if(r_value == cur_obj->section_maps[j].s->addr +
				  cur_obj->section_maps[j].s->size){
			r_symbolnum = j + 1;
			break;
		    }
		}
		if(r_symbolnum == 0){
		    error_with_cur_obj("r_value (0x%x) field of relocation "
			"entry %lu in section (%.16s,%.16s) out of range",
			(unsigned int)r_value, i, s->segname, s->sectname);
		    continue;
		}
	    }
	}
	else{
	    reloc = relocs + i;
	    sreloc = NULL;
	    r_scattered = 0;
	    r_address = reloc->r_address;
	    r_pcrel = reloc->r_pcrel;
	    r_length = reloc->r_length;
	    r_extern = reloc->r_extern;
	    r_symbolnum = reloc->r_symbolnum;
	    r_value = 0;
	}
	/*
	 * The r_address field is really an offset into the contents of the
	 * section and must reference something inside the section.
	 */
	if(r_address >= s->size){
	    error_with_cur_obj("r_address (0x%x) field of relocation entry "
		"%ld in section (%.16s,%.16s) out of range",
		(unsigned int)r_address, i, s->segname, s->sectname);
	    continue;
	}
	/*
	 * For a literal pointer section all relocation entries must be for one
	 * of the pointers and therefore the offset must be a multiple of 4,
	 * have an r_length field of 2 (long) and a r_pcrel field of 0 (FALSE).
	 */
	if(r_address % 4 != 0){
	    error_with_cur_obj("r_address (0x%x) field of relocation entry "
		"%ld in literal pointer section (%.16s,%.16s) is not a "
		"multiple of 4", (unsigned int)r_address, i, s->segname,
		s->sectname);
	    continue;
	}
	if(r_length != 2){
	    error_with_cur_obj("r_length (0x%x) field of relocation entry "
		"%ld in literal pointer section (%.16s,%.16s) is not 2 (long)",
		(unsigned int)r_length, i, s->segname, s->sectname);
	    continue;
	}
	if(r_pcrel != 0){
	    error_with_cur_obj("r_pcrel (0x%x) field of relocation entry "
		"%ld in literal pointer section (%.16s,%.16s) is not 0 "
		"(FALSE)", (unsigned int)r_pcrel, i, s->segname, s->sectname);
	    continue;
	}
	defined = TRUE;
	/*
	 * If r_extern is set this relocation entry is an external entry
	 * else it is a local entry (or scattered entry).
	 */
	if(r_extern){
	    /*
	     * This is an external relocation entry.  So the value to be
	     * added to the item to be relocated is the value of the symbol.
	     * r_symbolnum is an index into the input file's symbol table
	     * of the symbol being refered to.  The symbol must be an
	     * undefined symbol to be used in an external relocation entry.
	     */
	    if(r_symbolnum >= cur_obj->symtab->nsyms){
		error_with_cur_obj("r_symbolnum (%lu) field of external "
		    "relocation entry %ld in section (%.16s,%.16s) out of "
		    "range", r_symbolnum, i, s->segname, s->sectname);
		continue;
	    }
	    undefined_map = bsearch(&r_symbolnum, cur_obj->undefined_maps,
		cur_obj->nundefineds, sizeof(struct undefined_map),
		(int (*)(const void *, const void *))undef_bsearch);
	    if(undefined_map != NULL){
		merged_symbol = undefined_map->merged_symbol;
	    }
	    else{
		nlists = (struct nlist *)(cur_obj->obj_addr +
					  cur_obj->symtab->symoff);
		strings = cur_obj->obj_addr + cur_obj->symtab->stroff;
		if((nlists[r_symbolnum].n_type & N_EXT) != N_EXT){
		    error_with_cur_obj("r_symbolnum (%lu) field of external "
			"relocation entry %lu in section (%.16s,%.16s) refers "
			"to a non-external symbol", r_symbolnum, i, s->segname,
			s->sectname);
		    continue;
		}
		/*
		 * We must correctly catch the errors of a literal pointer
		 * refering defined global coalesced symbols with external
		 * relocation entries.
		 */
		if((nlists[r_symbolnum].n_type & N_TYPE) == N_SECT &&
		   (cur_obj->section_maps[nlists[r_symbolnum].
		    n_sect-1].s->flags & SECTION_TYPE) == S_COALESCED){
		    hash_pointer = lookup_symbol(strings +
				       nlists[r_symbolnum].n_un.n_strx);
		    if(hash_pointer == NULL){
			fatal("internal error, in literal_pointer_merge() "
			      "failed to lookup coalesced symbol %s",
			      strings + nlists[r_symbolnum].n_un.n_strx);
		    }
		    merged_symbol = *hash_pointer;
		    error_with_cur_obj("exteral symbol (%s) for external "
			"relocation entry %ld in section (%.16s,%.16s) refers "
			"a symbol not defined in a literal section",
			merged_symbol->nlist.n_un.n_name, i, s->segname,
			s->sectname);
		    continue;
		}
		else{
		    if(nlists[r_symbolnum].n_type != (N_EXT | N_UNDF)){
			error_with_cur_obj("r_symbolnum (%lu) field of "
			    "external relocation entry %lu in section "
			    "(%.16s,%.16s) refers to a non-undefined symbol",
			    r_symbolnum, i, s->segname, s->sectname);
			continue;
		    }
		    print_obj_name(cur_obj);
		    fatal("internal error, in literal_pointer_merge() symbol "
			  "index %lu in above file not in undefined map",
			  r_symbolnum);
		}
	    }
	    /*
	     * If this is an indirect symbol resolve indirection (all chains
	     * of indirect symbols have been resolved so that they point at
	     * a symbol that is not an indirect symbol).
	     */
	    if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
		merged_symbol = (struct merged_symbol *)
				merged_symbol->nlist.n_value;
	    /*
	     * If the symbol is a common symbol it is an error
	     * because it not a pointer to a literal.
	     */
	    if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF) &&
	       merged_symbol->nlist.n_value != 0){
		error_with_cur_obj("r_symbolnum (%lu) field of external "
		    "relocation entry %ld in section (%.16s,%.16s) refers to "
		    "a common symbol (%s) and is not in a literal section",
		    r_symbolnum, i, s->segname, s->sectname,
		    merged_symbol->nlist.n_un.n_name);
		continue;
	    }
	    /*
	     * If the symbol is an absolute symbol it is treated as an error
	     * because it is not known to be a pointer to a literal.
	     */
	    if((merged_symbol->nlist.n_type & N_TYPE) == N_ABS){
		error_with_cur_obj("r_symbolnum (%lu) field of external "
		    "relocation entry %ld in section (%.16s,%.16s) refers to "
		    "an absolue symbol (%s) and is not known to be in a "
		    "literal section", r_symbolnum, i, s->segname, s->sectname,
		    merged_symbol->nlist.n_un.n_name);
		continue;
	    }
	    /*
	     * For multi module dynamic shared library format files the
	     * merged sections that could have had external relocation
	     * entries must be resolved to private extern symbols.  This is
	     * because for multi module MH_DYLIB files all modules share the
	     * merged sections and the entire section gets relocated when
	     * the library is mapped in. So the above restriction assures
	     * the merged section will get relocated properly and can be
	     * shared amoung library modules.
	     */
	    if(filetype == MH_DYLIB && multi_module_dylib == TRUE){
		/*
		 * If the symbol is undefined or not a private extern it is an
		 * error for in this section for a MH_DYLIB file.
		 */
		if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF)){
		    if(merged_symbol->error_flagged_for_dylib == 0){
			error_with_cur_obj("illegal undefined reference for "
			    "multi module MH_DYLIB output file to symbol: %s "
			    "from a literal pointer section (section (%.16s,"
			    "%.16s) relocation entry: %lu)",
			    merged_symbol->nlist.n_un.n_name, s->segname,
			    s->sectname, i);
			merged_symbol->error_flagged_for_dylib = 1;
		    }
		}
		else if((merged_symbol->nlist.n_type & N_PEXT) != N_PEXT){
		    if(merged_symbol->error_flagged_for_dylib == 0){
			error_with_cur_obj("illegal external reference for "
			    "multi module MH_DYLIB output file to symbol: %s "
			    "(not a private extern symbol) from a literal "
			    "pointer section (section (%.16s,%.16s) relocation "
			    "entry: %lu)", merged_symbol->nlist.n_un.n_name,
			    s->segname, s->sectname, i);
			merged_symbol->error_flagged_for_dylib = 1;
		    }
		}
	    }
	    /*
	     * If the symbol is an undefined symbol then the literal is an
	     * offset to be added to the value of the symbol.
	     */
	    if(merged_symbol->nlist.n_type == (N_EXT | N_UNDF)){
		literal_ms = NULL;
		merged_section_offset = 0;
		offset = get_long((long *)(literals + r_address));
		defined = FALSE;
	    }
	    else {
		/*
		 * All other types of symbol of symbol have been handled so this
		 * symbol must be defined in a section.  The section that the
		 * symbol is defined in must be a literal section or else it
		 * is an error.  Since this is an external relocation entry and
		 * the symbol is defined this means it is defined in some other
		 * object than this one.
		 */
		if((merged_symbol->nlist.n_type & N_TYPE) != N_SECT ||
		   (merged_symbol->nlist.n_type & N_EXT)  != N_EXT){
		    fatal("internal error, in merge_literal_pointers() merged "
			  "symbol %s does not have a type of N_EXT|N_SECT",
			  merged_symbol->nlist.n_un.n_name);
		}
		literal_map = &(merged_symbol->definition_object->
				section_maps[merged_symbol->nlist.n_sect - 1]);
		literal_ms = literal_map->output_section;
		if((literal_ms->s.flags & SECTION_TYPE) != S_CSTRING_LITERALS &&
		   (literal_ms->s.flags & SECTION_TYPE) != S_4BYTE_LITERALS &&
		   (literal_ms->s.flags & SECTION_TYPE) != S_8BYTE_LITERALS){
		    error_with_cur_obj("exteral symbol (%s) for external "
			"relocation entry %ld in section (%.16s,%.16s) refers "
			"a symbol not defined in a literal section",
			merged_symbol->nlist.n_un.n_name, i, s->segname,
			s->sectname);
		    continue;
		}
		section_value = merged_symbol->nlist.n_value;
		literal_s = literal_map->s;
		if(section_value < literal_s->addr ||
		   section_value > literal_s->addr + literal_s->size){
		    error_with_cur_obj("exteral symbol's (%s) address not in "
			"the section (%.16s,%.16s) it is defined in", 
			merged_symbol->nlist.n_un.n_name, literal_s->segname,
			literal_s->sectname);
		    continue;
		}
		input_section_offset = section_value - literal_s->addr;
		/*
		 * At this point it is known that the merged section the
		 * literal is defined in is a literal section.  The checking
		 * for an internal error if the section does not have fine_reloc
		 * entry is left to fine_reloc_output_offset();
		 */
		merged_section_offset = fine_reloc_output_offset(literal_map,
							 input_section_offset);
		/*
		 * since this was an external relocation entry the value of the
		 * literal pointer is symbol+offset and the relocation is done
		 * based on only the symbol's value without the offset added.
		 * That's why offset is NOT added to input_section_offset above.
		 * Also if the offset is not zero that is need to be known so
		 * that a scattered relocation entry can be created on output.
		 */
		offset = get_long((long *)(literals + r_address));
		/*
		 * merged_symbol is set to NULL for the call to
		 * lookup_literal_pointer because this symbol is not undefined.
		 */
		merged_symbol = NULL;

		/* mark the section this symbol is in as referenced */
		literal_map->output_section->referenced = TRUE;
	    }
	}
	else{
	    /*
	     * This is a local relocation entry (the value to which the item
	     * to be relocated is refering to is defined in section number
	     * r_symbolnum in this object file).  Check that r_symbolnum is not
	     * R_ABS so it can be used to directly index the section map.
	     * For scattered relocation entries r_value was previously checked
	     * to be in the section refered to by r_symbolnum.
	     */
	    if(r_symbolnum == R_ABS){
		error_with_cur_obj("r_symbolnum (0x%x) field of relocation "
		    "entry %ld in literal pointer section (%.16s,%.16s) is "
		    "R_ABS (not correct for a literal pointer section)",
		    (unsigned int)r_symbolnum, i, s->segname, s->sectname);
		continue;
	    }
	    merged_symbol = NULL;
	    literal_map = &(cur_obj->section_maps[r_symbolnum - 1]);
	    literal_s = literal_map->s;
	    literal_ms  = literal_map->output_section;
	    if(r_scattered == 0){
		offset = 0;
		section_value = get_long((long *)(literals + r_address));
		if(section_value < literal_s->addr ||
		   section_value > literal_s->addr + literal_s->size){
		    error_with_cur_obj("literal pointer (0x%x) in section "
			"(%.16s,%.16s) at address 0x%x does not point into "
			"its (%.16s,%.16s) section as refered to by its "
			"r_symbolnum (0x%x) field in relocation entry %ld as "
			"it should", (unsigned int)section_value, s->segname,
			s->sectname, (unsigned int)(s->addr + r_address),
			literal_s->segname, literal_s->sectname,
			(unsigned int)r_symbolnum, i);
		    continue;
		}
		if((literal_ms->s.flags & SECTION_TYPE) != S_CSTRING_LITERALS &&
		   (literal_ms->s.flags & SECTION_TYPE) != S_4BYTE_LITERALS &&
		   (literal_ms->s.flags & SECTION_TYPE) != S_8BYTE_LITERALS){
		    error_with_cur_obj("r_symbolnum field (0x%x) in relocation "
			"entry %ld in literal pointer section (%.16s,%.16s) "
			"refers to section (%.16s,%.16s) which is not a "
			"literal section", (unsigned int)r_symbolnum, i,
			s->segname, s->sectname, literal_ms->s.segname,
			literal_ms->s.sectname);
		    continue;
		}
	    }
	    else{
		offset = get_long((long *)(literals + r_address)) - r_value;
		section_value = r_value;
		if((literal_ms->s.flags & SECTION_TYPE) != S_CSTRING_LITERALS &&
		   (literal_ms->s.flags & SECTION_TYPE) != S_4BYTE_LITERALS &&
		   (literal_ms->s.flags & SECTION_TYPE) != S_8BYTE_LITERALS){
		    error_with_cur_obj("r_value field (0x%x) in relocation "
			"entry %ld in literal pointer section (%.16s,%.16s) "
			"refers to section (%.16s,%.16s) which is not a "
			"literal section", (unsigned int)r_value, i, s->segname,
			s->sectname, literal_ms->s.segname,
			literal_ms->s.sectname);
		    continue;
		}
	    }
	    input_section_offset = section_value - literal_s->addr;
	    /*
	     * At this point it is known that the merged section the
	     * literal is defined in is a literal section.  The checking
	     * for an internal error if the section does not have fine_reloc
	     * entry is left to fine_reloc_output_offset();
	     */
	    merged_section_offset = fine_reloc_output_offset(literal_map,
						     input_section_offset);
	    /* mark the section this literal is in as referenced */
	    literal_map->output_section->referenced = TRUE;
	}

	/* 
	 * Since all the output_offset field of all the fine reloc entries were
	 * set to -1 before merging the literals and there must be only one
	 * relocation entry for each literal pointer if the relocation entry
	 * for this literal does not have an output_offset of -1 it is an error
	 * because we have seen it before.
	 */ 
	if((int)(fine_relocs[r_address/4].output_offset) != -1){
	    error_with_cur_obj("more than one relocation entry for literal "
		"pointer at address 0x%x (r_address 0x%x) in section "
		"(%.16s,%.16s)", (unsigned int)(s->addr + r_address),
		(unsigned int)r_address, s->segname, s->sectname);
	    continue;
	}

	/*
	 * Now at long last the literal pointer can be merged and the fine
	 * relocation entries for it can be built.
	 */
	fine_relocs[r_address/4].input_offset = r_address;
	fine_relocs[r_address/4].output_offset =
		lookup_literal_pointer(merged_symbol, literal_ms,
			       merged_section_offset, offset, data, ms, &new);
	count_reloc(ms, new, r_extern, defined);
    }
}
Пример #2
0
/*
 * write_object() writes a Mach-O object file from the built up data structures.
 */
void
write_object(
char *out_file_name)
{
    /* The structures for Mach-O relocatables */
    mach_header_t		header;
    segment_command_t		reloc_segment;
    struct symtab_command	symbol_table;
    struct dysymtab_command	dynamic_symbol_table;
    uint32_t			section_type;
    uint32_t			*indirect_symbols;
    isymbolS			*isymbolP;
    uint32_t			i, j, nsects, nsyms, strsize, nindirectsyms;

    /* locals to fill in section struct fields */
    uint32_t offset, zero;

    /* The GAS data structures */
    struct frchain *frchainP, *p;
    struct symbol *symbolP;
    struct frag *fragP;
    struct fix *fixP;

    uint32_t output_size;
    char *output_addr;
    kern_return_t r;

    enum byte_sex host_byte_sex;
    uint32_t reloff, nrelocs;
    int32_t count;
    char *fill_literal;
    int32_t fill_size;
    int32_t num_bytes;
    char *symbol_name;
    int fd;
    uint32_t local;
    struct stat stat_buf;

#ifdef I860
	I860_tweeks();
#endif
	i = 0; /* to shut up a compiler "may be used uninitialized" warning */

	/*
	 * The first group of things to do is to set all the fields in the
	 * header structures which includes offsets and determining the final
	 * sizes of things.
	 */

	/* 
	 * Fill in the addr and size fields of each section structure and count
	 * the number of sections.
	 */
	nsects = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    frchainP->frch_section.addr = frchainP->frch_root->fr_address;
	    frchainP->frch_section.size = frchainP->frch_last->fr_address -
		   			  frchainP->frch_root->fr_address;
	    nsects++;
	}

	/*
	 * Setup the indirect symbol tables by looking up or creating symbol
	 * from the indirect symbol names and recording the symbol pointers.
	 */
	nindirectsyms = layout_indirect_symbols();

	/*
	 * Setup the symbol table to include only those symbols that will be in
	 * the object file, assign the string table offsets into the symbols
	 * and size the string table.
	 */
	nsyms = 0;
	strsize = 0;
	layout_symbols((int32_t *)&nsyms, (int32_t *)&strsize);

	/* fill in the Mach-O header */
	header.magic = MH_MAGIC_VALUE;
	header.cputype = md_cputype;
	if(archflag_cpusubtype != -1)
	    header.cpusubtype = archflag_cpusubtype;
	else
	    header.cpusubtype = md_cpusubtype;

	header.filetype = MH_OBJECT;
	header.ncmds = 0;
	header.sizeofcmds = 0;
	if(nsects != 0){
	    header.ncmds += 1;
	    header.sizeofcmds += sizeof(segment_command_t) +
				 nsects * sizeof(section_t);
	}
	if(nsyms != 0){
	    header.ncmds += 1;
	    header.sizeofcmds += sizeof(struct symtab_command);
	    if(flagseen['k']){
		header.ncmds += 1;
		header.sizeofcmds += sizeof(struct dysymtab_command);
	    }
	}
	else
	    strsize = 0;
	header.flags = 0;
	if(subsections_via_symbols == TRUE)
	    header.flags |= MH_SUBSECTIONS_VIA_SYMBOLS;
#ifdef ARCH64
	header.reserved = 0;
#endif

	/* fill in the segment command */
	memset(&reloc_segment, '\0', sizeof(segment_command_t));
	reloc_segment.cmd = LC_SEGMENT_VALUE;
	reloc_segment.cmdsize = sizeof(segment_command_t) +
				nsects * sizeof(section_t);
	/* leave reloc_segment.segname full of zeros */
	reloc_segment.vmaddr = 0;
	reloc_segment.vmsize = 0;
	reloc_segment.filesize = 0;
	offset = header.sizeofcmds + sizeof(mach_header_t);
	reloc_segment.fileoff = offset;
	reloc_segment.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
	reloc_segment.initprot= VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
	reloc_segment.nsects = nsects;
	reloc_segment.flags = 0;
	/*
	 * Set the offsets to the contents of the sections (for non-zerofill
	 * sections) and set the filesize and vmsize of the segment.  This is
	 * complicated by the fact that all the zerofill sections have addresses
	 * after the non-zerofill sections and that the alignment of sections
	 * produces gaps that are not in any section.  For the vmsize we rely on
	 * the fact the the sections start at address 0 so it is just the last
	 * zerofill section or the last not-zerofill section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    for(p = frchainP->frch_next; p != NULL; p = p->frch_next)
		if((p->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		    break;
	    if(p != NULL)
		i = p->frch_section.addr - frchainP->frch_section.addr;
	    else
		i = frchainP->frch_section.size;
	    reloc_segment.filesize += i;
	    frchainP->frch_section.offset = offset;
	    offset += i;
	    reloc_segment.vmsize = frchainP->frch_section.addr +
				   frchainP->frch_section.size;
	}
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		continue;
	    reloc_segment.vmsize = frchainP->frch_section.addr +
				   frchainP->frch_section.size;
	}
	offset = round(offset, sizeof(int32_t));

	/*
	 * Count the number of relocation entries for each section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    frchainP->frch_section.nreloc = 0;
	    for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){
		frchainP->frch_section.nreloc += nrelocs_for_fix(fixP);
	    }
	}

	/*
	 * Fill in the offset to the relocation entries of the sections.
	 */
	offset = round(offset, sizeof(int32_t));
	reloff = offset;
	nrelocs = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if(frchainP->frch_section.nreloc == 0)
		frchainP->frch_section.reloff = 0;
	    else
		frchainP->frch_section.reloff = offset;
	    offset += frchainP->frch_section.nreloc *
		      sizeof(struct relocation_info);
	    nrelocs += frchainP->frch_section.nreloc;
	}

	if(flagseen['k']){
	    /* fill in the fields of the dysymtab_command */
	    dynamic_symbol_table.cmd = LC_DYSYMTAB;
	    dynamic_symbol_table.cmdsize = sizeof(struct dysymtab_command);

	    dynamic_symbol_table.ilocalsym = ilocalsym;
	    dynamic_symbol_table.nlocalsym = nlocalsym;
	    dynamic_symbol_table.iextdefsym = iextdefsym;
	    dynamic_symbol_table.nextdefsym = nextdefsym;
	    dynamic_symbol_table.iundefsym = iundefsym;
	    dynamic_symbol_table.nundefsym = nundefsym;

	    if(nindirectsyms == 0){
		dynamic_symbol_table.nindirectsyms = 0;
		dynamic_symbol_table.indirectsymoff = 0;
	    }
	    else{
		dynamic_symbol_table.nindirectsyms = nindirectsyms;
		dynamic_symbol_table.indirectsymoff = offset;
		offset += nindirectsyms * sizeof(uint32_t);
	    }

	    dynamic_symbol_table.tocoff = 0;
	    dynamic_symbol_table.ntoc = 0;
	    dynamic_symbol_table.modtaboff = 0;
	    dynamic_symbol_table.nmodtab = 0;
	    dynamic_symbol_table.extrefsymoff = 0;
	    dynamic_symbol_table.nextrefsyms = 0;
	    dynamic_symbol_table.extreloff = 0;
	    dynamic_symbol_table.nextrel = 0;
	    dynamic_symbol_table.locreloff = 0;
	    dynamic_symbol_table.nlocrel = 0;
	}

	/* fill in the fields of the symtab_command (except the string table) */
	symbol_table.cmd = LC_SYMTAB;
	symbol_table.cmdsize = sizeof(struct symtab_command);
	if(nsyms == 0)
	    symbol_table.symoff = 0;
	else
	    symbol_table.symoff = offset;
	symbol_table.nsyms = nsyms;
	offset += symbol_table.nsyms * sizeof(nlist_t);

	/* fill in the string table fields of the symtab_command */
	if(strsize == 0)
	    symbol_table.stroff = 0;
	else
	    symbol_table.stroff = offset;
	symbol_table.strsize = round(strsize, sizeof(uint32_t));
	offset += round(strsize, sizeof(uint32_t));

	/*
	 * The second group of things to do is now with the size of everything
	 * known the object file and the offsets set in the various structures
	 * the contents of the object file can be created.
	 */

	/*
	 * Create the buffer to copy the parts of the output file into.
	 */
	output_size = offset;
	if((r = vm_allocate(mach_task_self(), (vm_address_t *)&output_addr,
			    output_size, TRUE)) != KERN_SUCCESS)
	    as_fatal("can't vm_allocate() buffer for output file of size %u",
		     output_size);

	/* put the headers in the output file's buffer */
	host_byte_sex = get_host_byte_sex();
	offset = 0;

	/* put the mach_header in the buffer */
	memcpy(output_addr + offset, &header, sizeof(mach_header_t));
	if(host_byte_sex != md_target_byte_sex)
	    swap_mach_header_t((mach_header_t *)(output_addr + offset),
			       md_target_byte_sex);
	offset += sizeof(mach_header_t);

	/* put the segment_command in the buffer */
	if(nsects != 0){
	    memcpy(output_addr + offset, &reloc_segment,
		   sizeof(segment_command_t));
	    if(host_byte_sex != md_target_byte_sex)
		swap_segment_command_t((segment_command_t *)
				       (output_addr + offset),
				       md_target_byte_sex);
	    offset += sizeof(segment_command_t);
	}

	/* put the segment_command's section structures in the buffer */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    memcpy(output_addr + offset, &(frchainP->frch_section),
		   sizeof(section_t));
	    if(host_byte_sex != md_target_byte_sex)
		swap_section_t((section_t *)(output_addr + offset), 1,
			       md_target_byte_sex);
	    offset += sizeof(section_t);
	}

	/* put the symbol_command in the buffer */
	if(nsyms != 0){
	    memcpy(output_addr + offset, &symbol_table,
		   sizeof(struct symtab_command));
	    if(host_byte_sex != md_target_byte_sex)
		swap_symtab_command((struct symtab_command *)
				     (output_addr + offset),
				     md_target_byte_sex);
	    offset += sizeof(struct symtab_command);
	}

	if(flagseen['k']){
	    /* put the dysymbol_command in the buffer */
	    if(nsyms != 0){
		memcpy(output_addr + offset, &dynamic_symbol_table,
		       sizeof(struct dysymtab_command));
		if(host_byte_sex != md_target_byte_sex)
		    swap_dysymtab_command((struct dysymtab_command *)
					  (output_addr + offset),
					  md_target_byte_sex);
		offset += sizeof(struct dysymtab_command);
	    }
	}

	/* put the section contents (frags) in the buffer */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    offset = frchainP->frch_section.offset;
	    for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		know(fragP->fr_type == rs_fill);
		/* put the fixed part of the frag in the buffer */
		memcpy(output_addr + offset, fragP->fr_literal, fragP->fr_fix);
		offset += fragP->fr_fix;

		/* put the variable repeated part of the frag in the buffer */
		fill_literal = fragP->fr_literal + fragP->fr_fix;
		fill_size = fragP->fr_var;
		num_bytes = fragP->fr_offset * fragP->fr_var;
		for(count = 0; count < num_bytes; count += fill_size){
		    memcpy(output_addr + offset, fill_literal, fill_size);
		    offset += fill_size;
		}
	    }
	}


	/* put the symbols in the output file's buffer */
	offset = symbol_table.symoff;
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    if((symbolP->sy_type & N_EXT) == 0){
		symbol_name = symbolP->sy_name;
		symbolP->sy_nlist.n_un.n_strx = symbolP->sy_name_offset;
		if(symbolP->expression != 0) {
		    expressionS *exp;

		    exp = (expressionS *)symbolP->expression;
		    if((exp->X_add_symbol->sy_type & N_TYPE) == N_UNDF)
	    		as_fatal("undefined symbol `%s' in operation setting "
				 "`%s'", exp->X_add_symbol->sy_name,
				 symbol_name);
		    if((exp->X_subtract_symbol->sy_type & N_TYPE) == N_UNDF)
	    		as_fatal("undefined symbol `%s' in operation setting "
				 "`%s'", exp->X_subtract_symbol->sy_name,
				 symbol_name);
		    if(exp->X_add_symbol->sy_other !=
		       exp->X_subtract_symbol->sy_other)
	    		as_fatal("invalid sections for operation on `%s' and "
				 "`%s' setting `%s'",exp->X_add_symbol->sy_name,
				 exp->X_subtract_symbol->sy_name, symbol_name);
		    symbolP->sy_nlist.n_value +=
			exp->X_add_symbol->sy_value -
			exp->X_subtract_symbol->sy_value;
		}
		memcpy(output_addr + offset, (char *)(&symbolP->sy_nlist),
		       sizeof(nlist_t));
		symbolP->sy_name = symbol_name;
		offset += sizeof(nlist_t);
	    }
	}
	for(i = 0; i < nextdefsym; i++){
	    symbol_name = extdefsyms[i]->sy_name;
	    extdefsyms[i]->sy_nlist.n_un.n_strx = extdefsyms[i]->sy_name_offset;
	    memcpy(output_addr + offset, (char *)(&extdefsyms[i]->sy_nlist),
	           sizeof(nlist_t));
	    extdefsyms[i]->sy_name = symbol_name;
	    offset += sizeof(nlist_t);
	}
	for(j = 0; j < nundefsym; j++){
	    symbol_name = undefsyms[j]->sy_name;
	    undefsyms[j]->sy_nlist.n_un.n_strx = undefsyms[j]->sy_name_offset;
	    memcpy(output_addr + offset, (char *)(&undefsyms[j]->sy_nlist),
	           sizeof(nlist_t));
	    undefsyms[j]->sy_name = symbol_name;
	    offset += sizeof(nlist_t);
	}
	if(host_byte_sex != md_target_byte_sex)
	    swap_nlist_t((nlist_t *)(output_addr + symbol_table.symoff),
		         symbol_table.nsyms, md_target_byte_sex);

	/*
	 * Put the relocation entries for each section in the buffer.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    offset = frchainP->frch_section.reloff;
	    for(fixP = frchainP->frch_fix_root; fixP; fixP = fixP->fx_next){
		offset += fix_to_relocation_entries(
					fixP,
					frchainP->frch_section.addr,
					(struct relocation_info *)(output_addr +
								   offset),
				        frchainP->frch_section.flags &
					  S_ATTR_DEBUG);
	    }
	}
	if(host_byte_sex != md_target_byte_sex)
	    swap_relocation_info((struct relocation_info *)
		(output_addr + reloff), nrelocs, md_target_byte_sex);

	if(flagseen['k']){
	    /* put the indirect symbol table in the buffer */
	    offset = dynamic_symbol_table.indirectsymoff;
	    for(frchainP = frchain_root;
		frchainP != NULL;
		frchainP = frchainP->frch_next){
		section_type = frchainP->frch_section.flags & SECTION_TYPE;
		if(section_type == S_NON_LAZY_SYMBOL_POINTERS ||
		   section_type == S_LAZY_SYMBOL_POINTERS ||
		   section_type == S_SYMBOL_STUBS){
		    /*
		     * For each indirect symbol put out the symbol number.
		     */
		    for(isymbolP = frchainP->frch_isym_root;
			isymbolP != NULL;
			isymbolP = isymbolP->isy_next){
			/*
			 * If this is a non-lazy pointer symbol section and
			 * if the symbol is a local symbol then put out
			 * INDIRECT_SYMBOL_LOCAL as the indirect symbol table
			 * entry.  This is used with code gen for fix-n-continue
			 * where the compiler generates indirection for static
			 * data references.  See the comments at the end of
			 * fixup_section() that explains the assembly code used.
			 */
			if(section_type == S_NON_LAZY_SYMBOL_POINTERS &&
			   (isymbolP->isy_symbol->sy_nlist.n_type & N_EXT) !=
			    N_EXT){
    			    local = INDIRECT_SYMBOL_LOCAL;
			    if((isymbolP->isy_symbol->sy_nlist.n_type &
				N_TYPE) == N_ABS)
				local |= INDIRECT_SYMBOL_ABS;
			    memcpy(output_addr + offset, (char *)(&local),
	   			   sizeof(uint32_t));
			}
			else{
			    memcpy(output_addr + offset,
				   (char *)(&isymbolP->isy_symbol->sy_number),
				   sizeof(uint32_t));
			}
			offset += sizeof(uint32_t);
		    }
		}
	    }
	    if(host_byte_sex != md_target_byte_sex){
		indirect_symbols = (uint32_t *)(output_addr +
				    dynamic_symbol_table.indirectsymoff);
		swap_indirect_symbols(indirect_symbols, nindirectsyms, 
				      md_target_byte_sex);
	    }
	}

	/* put the strings in the output file's buffer */
	offset = symbol_table.stroff;
	if(symbol_table.strsize != 0){
	    zero = 0;
	    memcpy(output_addr + offset, (char *)&zero, sizeof(char));
	    offset += sizeof(char);
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    /* Ordinary case: not .stabd. */
	    if(symbolP->sy_name != NULL){
		if((symbolP->sy_type & N_EXT) != 0){
		    memcpy(output_addr + offset, symbolP->sy_name,
			   strlen(symbolP->sy_name) + 1);
		    offset += strlen(symbolP->sy_name) + 1;
		}
	    }
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    /* Ordinary case: not .stabd. */
	    if(symbolP->sy_name != NULL){
		if((symbolP->sy_type & N_EXT) == 0){
		    memcpy(output_addr + offset, symbolP->sy_name,
			   strlen(symbolP->sy_name) + 1);
		    offset += strlen(symbolP->sy_name) + 1;
		}
	    }
	}
	/*
         * Create the output file.  The unlink() is done to handle the problem
         * when the out_file_name is not writable but the directory allows the
         * file to be removed (since the file may not be there the return code
         * of the unlink() is ignored).
         */
	if(bad_error != 0)
	    return;
	/*
	 * Avoid doing the unlink() on special files, just unlink regular files
	 * that exist.
	 */
	if(stat(out_file_name, &stat_buf) != -1){
	    if(stat_buf.st_mode & S_IFREG)
		(void)unlink(out_file_name);
	}
	if((fd = open(out_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1)
	    as_fatal("can't create output file: %s", out_file_name);
	if(write(fd, output_addr, output_size) != (int)output_size)
	    as_fatal("can't write output file");
	if(close(fd) == -1)
	    as_fatal("can't close output file");
}