Пример #1
0
/*
 * print_load_fvmlibs_list() prints the fvmlib segments table.  For debugging.
 */
__private_extern__
void
print_load_fvmlibs_list(void)
{
    struct merged_fvmlib **p, *mfl;

	print("Load fvmlibs list\n");
	p = &merged_fvmlibs;
	while(*p){
	    mfl = *p;
	    if(mfl->fl->cmd == LC_LOADFVMLIB)
		print("    LC_LOADFVMLIB\n");
	    else
		print("    LC_IDFVMLIB\n");
	    print("\tcmdsize %u\n", mfl->fl->cmdsize);
	    if(mfl->fl->fvmlib.name.offset < mfl->fl->cmdsize)
		print("\tname %s (offset %u)\n",
		       (char *)(mfl->fl) + mfl->fl->fvmlib.name.offset,
		       mfl->fl->fvmlib.name.offset);
	    else
		print("\tname ?(bad offset %u)\n",mfl->fl->fvmlib.name.offset);
	    print("\tminor version %u\n", mfl->fl->fvmlib.minor_version);
	    print("\theader addr 0x%08x\n",
		  (unsigned int)(mfl->fl->fvmlib.header_addr));
	    print("    fvmlib_name %s\n", mfl->fvmlib_name);
	    print("    definition_object ");
	    print_obj_name(mfl->definition_object);
	    print("\n");
	    print("    multiple %s\n", mfl->multiple == TRUE ? "TRUE" :
		   "FALSE");
	    p = &(mfl->next);
	}
}
Пример #2
0
/*
 * lookup_merged_fvmlib() adds the LC_LOADFVMLIB structure passed to it to the
 * merged list of fixed VM libraries.  It warns if it see the same library
 * twice.
 */
static
struct merged_fvmlib *
lookup_merged_fvmlib(
struct fvmlib_command *fl)
{
    char *fvmlib_name;
    struct merged_fvmlib **p, *mfl;

	fvmlib_name = (char *)fl + fl->fvmlib.name.offset;
	p = &merged_fvmlibs;
	while(*p){
	    mfl = *p;
	    if(strcmp(mfl->fvmlib_name, fvmlib_name) == 0){
		if(mfl->multiple == FALSE){
		    if(mfl->fl->cmd == LC_IDFVMLIB)
			error("multiple object files identify fixed VM library "
			      "%s", fvmlib_name);
		    else
			warning("multiple object files load fixed VM library "
				"%s", fvmlib_name);
		    print_obj_name(mfl->definition_object);
		    print("%s fixed VM library %s\n",
			  mfl->fl->cmd == LC_LOADFVMLIB ? "loads" :"identifies",
			  fvmlib_name);
		    mfl->multiple = TRUE;
		}
		print_obj_name(cur_obj);
		print("%s fixed VM library %s\n",
		      mfl->fl->cmd == LC_LOADFVMLIB ? "loads" : "identifies",
		      fvmlib_name);
		return(mfl);
	    }
	    p = &(mfl->next);
	}
	*p = allocate(sizeof(struct merged_fvmlib));
	memset(*p, '\0', sizeof(struct merged_fvmlib));
	mfl = *p;
	mfl->fl = fl;
	mfl->fvmlib_name = fvmlib_name;
	mfl->definition_object = cur_obj;
	mfl->multiple = FALSE;
	return(mfl);
}
Пример #3
0
/*
 * pass2() creates the output file and the memory buffer to create the file
 * into.  It drives the process to get everything copied into the buffer for
 * the output file.  It then writes the output file and deallocates the buffer.
 */ 
extern
void
pass2(void)
{
    unsigned long i, j, section_type;
    struct object_list *object_list, **p;
#ifndef RLD
    int mode;
    struct stat stat_buf;
    kern_return_t r;

	/*
	 * In UNIX standard conformance mode we are not allowed to replace
	 * a file that is not writeable.
	 */
	if(get_unix_standard_mode() == TRUE && 
	   access(outputfile, F_OK) == 0 &&
	   access(outputfile, W_OK) == -1)
	    system_fatal("can't write output file: %s", outputfile);

	/*
	 * Create the output file.  The unlink() is done to handle the problem
	 * when the outputfile 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).
	 */
	(void)unlink(outputfile);
	if((fd = open(outputfile, O_WRONLY | O_CREAT | O_TRUNC, 0777)) == -1)
	    system_fatal("can't create output file: %s", outputfile);
#ifdef F_NOCACHE
        /* tell filesystem to NOT cache the file when reading or writing */
	(void)fcntl(fd, F_NOCACHE, 1);
#endif
	if(fstat(fd, &stat_buf) == -1)
	    system_fatal("can't stat file: %s", outputfile);
	/*
	 * Turn the execute bits on or off depending if there are any undefined
	 * symbols in the output file.  If the file existed before the above
	 * open() call the creation mode in that call would have been ignored
	 * so it has to be set explicitly in any case.
	 */
	if(output_mach_header.flags & MH_NOUNDEFS ||
	   (has_dynamic_linker_command && output_for_dyld))
	    mode = (stat_buf.st_mode & 0777) | (0111 & ~umask(0));
	else
	    mode = (stat_buf.st_mode & 0777) & ~0111;
	if(fchmod(fd, mode) == -1)
	    system_fatal("can't set execution permissions output file: %s",
			 outputfile);

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

	/*
	 * Set up for flushing pages to the output file as they fill up.
	 */
	if(flush)
	    setup_output_flush();

	/*
	 * Make sure pure_instruction sections are padded with nop's.
	 */
	nop_pure_instruction_scattered_sections();

#endif /* !defined(RLD) */

	/*
	 * The strings indexes for the merged string blocks need to be set
	 * before the dylib tables are output because the module names are in
	 * them as well as the merged symbol names.
	 */
	set_merged_string_block_indexes();

#ifndef RLD
	/*
	 * Copy the dylib tables into the output file.  This is done before the
	 * sections are outputted so that the indexes to the local and external
	 * relocation entries for each object can be used as running indexes as
	 * each section in the object is outputted.
	 */
	if(filetype == MH_DYLIB)
	    output_dylib_tables();
#endif /* !defined(RLD) */

	/*
	 * Create the array of pointers to merged sections in the output file
	 * so the relocation routines can use it to set the 'referenced' fields
	 * in the merged section structures.
	 */
	create_output_sections_array();

	/*
	 * Copy the merged literal sections and the sections created from files
	 * into the output object file.
	 */
	output_literal_sections();
#ifndef RLD
	output_sections_from_files();
#endif /* !defined(RLD) */

	/*
	 * For each non-literal content section in each object file loaded 
	 * relocate it into the output file (along with the relocation entries).
	 * Then relocate local symbols into the output file for the loaded
	 * objects.
	 */
	for(p = &objects; *p; p = &(object_list->next)){
	    object_list = *p;
	    for(i = 0; i < object_list->used; i++){
		cur_obj = &(object_list->object_files[i]);
		/* print the object file name if tracing */
		if(trace){
		    print_obj_name(cur_obj);
		    print("\n");
		}
		if(cur_obj->dylib)
		    continue;
		if(cur_obj->bundle_loader)
		    continue;
		if(cur_obj->dylinker)
		    continue;
		if(cur_obj != base_obj){
		    for(j = 0; j < cur_obj->nsection_maps; j++){
			if(cur_obj->section_maps[j].s->flags & S_ATTR_DEBUG)
			    continue;
#ifdef RLD
			if(cur_obj->set_num == cur_set)
#endif /* RLD */
			{
			    section_type = (cur_obj->section_maps[j].s->flags &
                                                   SECTION_TYPE);
			    if(section_type == S_REGULAR ||
			       section_type == S_SYMBOL_STUBS ||
			       section_type == S_NON_LAZY_SYMBOL_POINTERS ||
			       section_type == S_LAZY_SYMBOL_POINTERS ||
			       section_type == S_COALESCED ||
			       section_type == S_MOD_INIT_FUNC_POINTERS ||
			       section_type == S_MOD_TERM_FUNC_POINTERS){
				output_section(&(cur_obj->section_maps[j]));
			    }
			}
		    }
		}
		output_local_symbols();
#if defined(VM_SYNC_DEACTIVATE) && !defined(_POSIX_C_SOURCE) && !defined(__CYGWIN__)
		vm_msync(mach_task_self(), (vm_address_t)cur_obj->obj_addr,
			 (vm_size_t)cur_obj->obj_size, VM_SYNC_DEACTIVATE);
#endif /* VM_SYNC_DEACTIVATE */
	    }
	}
	/*
	 * If there were errors in output_section() then return as so not
	 * to cause later internal errors.
	 */
	if(errors != 0)
	    return;

#ifdef RLD
	/*
	 * For each content section clean up the data structures not needed
	 * after rld is run.  This must be done after ALL the sections are
	 * output'ed because the fine relocation entries could be used by any
	 * of the sections.
	 */
	for(p = &objects; *p; p = &(object_list->next)){
	    object_list = *p;
	    for(i = 0; i < object_list->used; i++){
		cur_obj = &(object_list->object_files[i]);
		for(j = 0; j < cur_obj->nsection_maps; j++){
		    if(cur_obj->section_maps[j].nfine_relocs != 0){
			free(cur_obj->section_maps[j].fine_relocs);
			cur_obj->section_maps[j].fine_relocs = NULL;
			cur_obj->section_maps[j].nfine_relocs = 0;
		    }
		}
		if(cur_obj->nundefineds != 0){
		    free(cur_obj->undefined_maps);
		    cur_obj->undefined_maps = NULL;
		    cur_obj->nundefineds = 0;
		}
	    }
	}
#endif /* RLD */

	/*
	 * Set the SG_NORELOC flag in the segments that had no relocation to
	 * or for them.
	 */
	set_SG_NORELOC_flags();

#ifndef SA_RLD
	/*
	 * Copy the indirect symbol table into the output file.
	 */
	output_indirect_symbols();
#endif /* SA_RLD */

	/*
	 * Copy the merged symbol table into the output file.
	 */
	output_merged_symbols();

	/*
	 * Copy the headers into the output file.
	 */
	output_headers();

#ifndef RLD
	if(flush){
	    /*
	     * Flush the sections that have been scatter loaded.
	     */
	    flush_scatter_copied_sections();
	    /*
	     * flush the remaining part of the object file that is not a full
	     * page.
	     */
	    final_output_flush();
	}
	else{
	    /*
	     * Write the entire object file.
	     */
	    if(write(fd, output_addr, output_size) != (int)output_size)
		system_fatal("can't write output file");

	    if((r = vm_deallocate(mach_task_self(), (vm_address_t)output_addr,
				  output_size)) != KERN_SUCCESS)
		mach_fatal(r, "can't vm_deallocate() buffer for output file");
	}
#ifdef F_NOCACHE
	/* re-enable caching of file reads/writes */
	(void)fcntl(fd, F_NOCACHE, 0);
#endif
	if(close(fd) == -1)
	    system_fatal("can't close output file");
#endif /* RLD */
}
Пример #4
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);
    }
}