Ejemplo n.º 1
0
/*
 * fine_reloc_output_address() returns the output_address for the input_offset
 * in the section with the specified section map.  This can return one of two
 * things depending on the fine relocation entry for the input_offset.  If the
 * section is a symbol stub section and the fine_relocation entry's indirect
 * symbol is defined then the value of the symbol is used.  Otherwise the output
 * offset for the fine relocation entry is added to the specified
 * output_base_address.
 */
extern
unsigned long
fine_reloc_output_address(
struct section_map *map,
unsigned long input_offset,
unsigned long output_base_address)
{
    struct fine_reloc *fine_reloc;
    struct merged_symbol *merged_symbol;
    unsigned long index;
    struct nlist *nlists;
    struct section_map *section_map;

	fine_reloc = fine_reloc_for_input_offset(map, input_offset);
	if(fine_reloc->local_symbol == TRUE){
	    if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS){
		index = fine_reloc->output_offset;
		nlists = (struct nlist *)(cur_obj->obj_addr +
					  cur_obj->symtab->symoff);
		if(nlists[index].n_sect == NO_SECT)
		    return(nlists[index].n_value);
		section_map = &(cur_obj->section_maps[nlists[index].n_sect -1]);
		if(section_map->nfine_relocs == 0)
		    return(nlists[index].n_value - section_map->s->addr +
			   section_map->output_section->s.addr +
			   section_map->offset);
		else
		    return(section_map->output_section->s.addr +
			   fine_reloc_output_offset(section_map,
						    nlists[index].n_value -
						    section_map->s->addr));
	    }
	    else if((map->s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
		    (map->s->flags & SECTION_TYPE) ==
						  S_NON_LAZY_SYMBOL_POINTERS){
		return(output_base_address +
		       fine_reloc->output_offset +
		       input_offset - fine_reloc->input_offset);
	    }
	    else if((map->s->flags & SECTION_TYPE) == S_COALESCED){
		if(fine_reloc->use_contents == TRUE){
		    return(output_base_address +
			   fine_reloc->output_offset +
			   input_offset - fine_reloc->input_offset);
		}
		else{
		    merged_symbol = fine_reloc->merged_symbol;
		    if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
			merged_symbol = (struct merged_symbol *)
					merged_symbol->nlist.n_value;
		    return(merged_symbol->nlist.n_value);
		}
	    }
	    else{
		fatal("internal error, fine_reloc_output_address() called with "
		      "an input_offset which maps to a fine_reloc where "
		      "local_symbol is TRUE but it's not in a S_SYMBOL_STUBS, "
		      "S_LAZY_SYMBOL_POINTERS or S_COALESCED section");
		return(0);
	    }
	}
	else if((map->s->flags & SECTION_TYPE) == S_COALESCED){
	    if(fine_reloc->use_contents == TRUE){
		return(output_base_address +
		       fine_reloc->output_offset +
		       input_offset - fine_reloc->input_offset);
	    }
	    else{
		merged_symbol = fine_reloc->merged_symbol;
		if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
		    merged_symbol = (struct merged_symbol *)
				    merged_symbol->nlist.n_value;
		return(merged_symbol->nlist.n_value);
	    }
	}
	else if((map->s->flags & SECTION_TYPE) == S_SYMBOL_STUBS &&
	        fine_reloc->indirect_defined == TRUE){
	    if(filetype != MH_DYLIB ||
	       (filetype == MH_DYLIB && multi_module_dylib == FALSE) ||
	       (cur_obj == fine_reloc->merged_symbol->definition_object &&
		input_offset - fine_reloc->input_offset == 0)){
		if(cur_obj == fine_reloc->merged_symbol->definition_object)
		    merged_symbol = fine_reloc->merged_symbol;
		else
		    merged_symbol = fine_reloc->merged_symbol;
		if((merged_symbol->nlist.n_type & N_TYPE) == N_INDR)
		    merged_symbol = (struct merged_symbol *)
				    merged_symbol->nlist.n_value;
		return(merged_symbol->nlist.n_value);
	    }
	    else{
		return(output_base_address +
		       fine_reloc->output_offset +
		       input_offset - fine_reloc->input_offset);
	    }
	}
	else{
	    return(output_base_address +
		   fine_reloc->output_offset +
		   input_offset - fine_reloc->input_offset);
	}
}
Ejemplo n.º 2
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);
    }
}