Beispiel #1
0
/*
 * layout_addresses() is called after all the assembly code has been read and
 * fragments, symbols and fixups have been created.  This routine sets the
 * address of the fragments and symbols.  Then it does the fixups of the frags
 * and prepares the fixes so relocation entries can be created from them.
 */
void
layout_addresses(
void)
{
    struct frchain *frchainP;
    fragS *fragP;
    relax_addressT slide, tmp;
    symbolS *symbolP;
    uint32_t nbytes, fill_size, repeat_expression, partial_bytes, layout_pass;
    relax_stateT old_fr_type;
    int changed;

	if(frchain_root == NULL)
	    return;

	/*
	 * If there is any current frag close it off.
	 */
	if(frag_now != NULL && frag_now->fr_fix == 0){
	    frag_now->fr_fix = obstack_next_free(&frags) -
			       frag_now->fr_literal;
	    frag_wane(frag_now);
	}

	/*
	 * For every section, add a last ".fill 0" frag that will later be used
	 * as the ending address of that section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * We must do the obstack_finish(), so the next object we put on
	     * obstack frags will not appear to start at the fr_literal of the
	     * current frag.  Also, it ensures that the next object will begin
	     * on a address that is aligned correctly for the engine that runs
	     * the assembler.
	     */
	    (void)obstack_finish(&frags);

	    /*
	     * Make a fresh frag for the last frag.
	     */
	    frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
	    memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
	    frag_now->fr_next = NULL;
	    (void)obstack_finish(&frags);

	    /*
	     * Append the new frag to current frchain.
	     */
	    frchainP->frch_last->fr_next = frag_now;
	    frchainP->frch_last = frag_now;
	    frag_wane(frag_now);

	}

	/*
	 * Now set the relative addresses of frags within the section by
	 * relaxing each section.  That is all sections will start at address
	 * zero and addresses of the frags in that section will increase from
	 * there.
	 *
	 * The debug sections are done last as other section are needed to be
	 * done first becase debug sections may have line numbers with .loc
	 * directives in them and their sizes need to be set before processing
	 * the line number sections.  We also do sections that have rs_leb128s
	 * in them before debug sections but after other sections since they
	 * are used for things like exception tables and they may be refering to
	 * sections such that their sizes too must be known first.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & S_ATTR_DEBUG) == S_ATTR_DEBUG)
		frchainP->layout_pass = 2;
	    else if(frchainP->has_rs_leb128s == TRUE)
		frchainP->layout_pass = 1;
	    else
		frchainP->layout_pass = 0;
	}
	for(layout_pass = 0; layout_pass < 3; layout_pass++){
	    do{
		changed = 0;
		for(frchainP = frchain_root;
		    frchainP;
		    frchainP = frchainP->frch_next){
		    if(frchainP->layout_pass != layout_pass)
			continue;
		    if((frchainP->frch_section.flags & SECTION_TYPE) ==
		       S_ZEROFILL)
			continue;
		    /*
		     * This is done so in case md_estimate_size_before_relax()
		     * (called by relax_section) wants to make fixSs they are
		     * for this section.
		     */
		    frchain_now = frchainP;

		    changed += relax_section(frchainP->frch_root,
					    frchainP->frch_nsect);
		}
	    }
	    while(changed != 0);
	}

	/*
	 * Now set the absolute addresses of all frags by sliding the frags in
	 * each non-zerofill section by the address ranges taken up by the
	 * sections before it.
	 */ 
	slide = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);
	    tmp = frchainP->frch_last->fr_address;
	    if(slide != 0){
		for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		    fragP->fr_address += slide;
		}
	    }
	    slide += tmp;
	}
	/*
	 * Now with the non-zerofill section addresses set set all of the
	 * addresses of the zerofill sections.  Comming in the fr_address is
	 * the size of the section and going out it is the start address.  This
	 * will make layout_symbols() work out naturally.  The only funky thing
	 * is that section numbers do not end up in address order.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);

	    tmp = frchainP->frch_root->fr_address;
	    frchainP->frch_root->fr_address = slide;
	    frchainP->frch_last->fr_address = tmp + slide;
	    slide += tmp;
	}

	/*
	 * Set the symbol addresses based on their frag's address.
	 * First forward references are handled.
	 */
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    if(symbolP->sy_forward != NULL){
		if(symbolP->sy_nlist.n_type & N_STAB)
		    symbolP->sy_other = symbolP->sy_forward->sy_other;
		symbolP->sy_value += symbolP->sy_forward->sy_value +
				     symbolP->sy_forward->sy_frag->fr_address;
		symbolP->sy_forward = 0;
	    }
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    symbolP->sy_value += symbolP->sy_frag->fr_address;
	}

	/*
	 * At this point the addresses of frags now reflect addresses we use in 
	 * the object file and the symbol values are correct.
	 * Scan the frags, converting any ".org"s and ".align"s to ".fill"s.
	 * Also converting any machine-dependent frags using md_convert_frag();
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * This is done so any fixes created by md_convert_frag() are for
	     * this section.
	     */
	    frchain_now = frchainP;

	    for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		switch(fragP->fr_type){
		case rs_align:
		case rs_org:
		    old_fr_type = fragP->fr_type;
		    /* convert this frag to an rs_fill type */
		    fragP->fr_type = rs_fill;
		    /*
		     * Calculate the number of bytes the variable part of the
		     * the rs_fill frag will need to fill.  Then calculate this
		     * as the fill_size * repeat_expression + partial_bytes.
		     */
		    know(fragP->fr_next != NULL);
		    nbytes = fragP->fr_next->fr_address -
			     fragP->fr_address -
			     fragP->fr_fix;
		    if(nbytes < 0){
			as_warn("rs_org invalid, dot past value by %d bytes",
				nbytes);
			nbytes = 0;
		    }
		    fill_size = fragP->fr_var;
		    repeat_expression = nbytes / fill_size;
#ifdef I386
		    /*
		     * For x86 architecures in sections containing only
		     * instuctions being padded with nops that are aligned to 16
		     * bytes or less and are assembled with -dynamic we will
		     * actually end up padding with the optimal nop sequence.
		     * Previously there has been the maximum number of bytes
		     * allocated in the frag to use for this.
		     */
		    if(old_fr_type == rs_align &&
		       (frchain_now->frch_section.flags &
			S_ATTR_PURE_INSTRUCTIONS) != 0 &&
			 fill_size == 1 &&
			 fragP->fr_literal[fragP->fr_fix] == (char)0x90 &&
			 nbytes > 0 && nbytes < 16 &&
			 flagseen['k'] == TRUE){
			i386_align_code(fragP, nbytes);
			/*
			 * The call to i386_align_code() has set the fill_size
			 * in fragP->fr_var to nbytes. So we set the fr_offset
			 * to the fill repeat_expression to 1 to match for this
			 * now an rs_fill type frag.
			 */ 
			fragP->fr_offset = 1;
			break;
		    }
#endif /* I386 */
		    partial_bytes = nbytes - (repeat_expression * fill_size);
		    /*
		     * Now set the fr_offset to the fill repeat_expression
		     * since this is now an rs_fill type.  The fr_var is still
		     * the fill_size.
		     */
		    fragP->fr_offset = repeat_expression;
		    /*
		     * For rs_align frags there may be partial_bytes to fill
		     * with zeros before we can fill with the fill_expression
		     * of fill_size.  When the rs_align frag was created it was
		     * created with fill_size-1 extra bytes in the fixed part.
		     */
		    if(partial_bytes != 0){
			/* moved the fill_expression bytes foward */
			memmove(fragP->fr_literal +fragP->fr_fix +partial_bytes,
				fragP->fr_literal +fragP->fr_fix,
				fragP->fr_var);
    			/* zero out the partial_bytes */
    			memset(fragP->fr_literal + fragP->fr_fix,
			       '\0',
			       partial_bytes);
			/* adjust the fixed part of the frag */
    			fragP->fr_fix += partial_bytes;
		    }
		    break;

		case rs_fill:
		    break;

		case rs_machine_dependent:
		    md_convert_frag(fragP);
		    /*
		     * After md_convert_frag, we make the frag into a ".fill 0"
		     * md_convert_frag() should set up any fixSs and constants
		     * required.
		     */
		    frag_wane(fragP);
		    break;

		case rs_dwarf2dbg:
		    dwarf2dbg_convert_frag(fragP);
		    break;

		case rs_leb128:
		  {
		    int size;
#ifdef OLD
		    valueT value = S_GET_VALUE (fragP->fr_symbol);
#else
		    valueT value;
  		      expressionS *expression;
  		
		      if(fragP->fr_symbol->expression != NULL){
			expression =
			  (expressionS *)fragP->fr_symbol->expression;
			value = 0;
			if(expression->X_add_symbol != NULL)
			    value += expression->X_add_symbol->sy_nlist.n_value;
			if(expression->X_subtract_symbol != NULL)
			   value -= 
			     expression->X_subtract_symbol->sy_nlist.n_value;
			value += expression->X_add_number;
		      }
		      else{
			value = fragP->fr_symbol->sy_nlist.n_value +
				fragP->fr_address;
		      }
#endif

		    size = output_leb128 (fragP->fr_literal + fragP->fr_fix,
					  value,
					  fragP->fr_subtype);
	       
		    fragP->fr_fix += size;
		    fragP->fr_type = rs_fill;
		    fragP->fr_var = 0;
		    fragP->fr_offset = 0;
		    fragP->fr_symbol = NULL; 
		  }
		  break;


		default:
		    BAD_CASE(fragP->fr_type);
		    break;
		}
	    }
	}

	/*
	 * For each section do the fixups for the frags.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    now_seg = frchainP->frch_nsect;
	    fixup_section(frchainP->frch_fix_root, frchainP->frch_nsect);
	}
}
Beispiel #2
0
/*
 * fixup_section() does the fixups of the frags and prepares the fixes so
 * relocation entries can be created from them.  The fixups cause the contents
 * of the frag to have the value for the fixup expression.  A fix structure that
 * ends up with a non-NULL fx_addsy will have a relocation entry created for it.
 */
static
void
fixup_section(
fixS *fixP,
int nsect)
{
    symbolS *add_symbolP;
    symbolS *sub_symbolP;
    signed_expr_t value;
    int size;
    char *place;
    int32_t where;
    char pcrel;
    fragS *fragP;
    int	add_symbol_N_TYPE;
    int	add_symbol_nsect;
#ifndef SPARC
    int sub_symbol_nsect;
#endif

	/*
	 * The general fix expression is "fx_addsy - fx_subsy + fx_offset".
	 * The goal is to put the result of this expression into the frag at
	 * "place" for size "size".  The value of the expression is calculated
	 * in the variable "value" and starts with just the fx_offset.
	 */
	for( ; fixP != NULL; fixP = fixP->fx_next){
	    fragP       = fixP->fx_frag;
	    know(fragP);
	    where	= fixP->fx_where;
	    place       = fragP->fr_literal + where;
	    size	= fixP->fx_size;
#ifdef TC_FIXUP_SYMBOL
		fixP->fx_offset += TC_FIXUP_SYMBOL(fixP, nsect, &fixP->fx_addsy);
		fixP->fx_offset -= TC_FIXUP_SYMBOL(fixP, nsect, &fixP->fx_subsy);
#endif
#if defined(I386) && defined(ARCH64)
		if(fixP->fx_addsy == fixP->fx_subsy){
			/*
			 * If we've fixed up both symbols to the same location,
			 * we don't need a relocation entry.
			 */
			fixP->fx_addsy = NULL;
			fixP->fx_subsy = NULL;
		}
#endif
	    add_symbolP = fixP->fx_addsy;
	    sub_symbolP = fixP->fx_subsy;
	    value  	= fixP->fx_offset;
	    pcrel       = fixP->fx_pcrel;

#if ARM
	    /* If the symbol is defined in this file, the linker won't set the
	       low-order bit for a Thumb symbol, so we have to do it here.  */
	    if(add_symbolP != NULL && add_symbolP->sy_desc & N_ARM_THUMB_DEF &&
	       !(sub_symbolP != NULL && sub_symbolP->sy_desc & N_ARM_THUMB_DEF) &&
	       !pcrel){
	        value |= 1;
	    }
#endif

	    add_symbol_N_TYPE = 0;
	    add_symbol_nsect = 0;

	    if(add_symbolP != NULL){
		add_symbol_N_TYPE = add_symbolP->sy_type & N_TYPE;
		if(add_symbol_N_TYPE == N_SECT)
		    add_symbol_nsect = add_symbolP->sy_other;
	    }

	    /*
	     * Is there a subtract symbol?
	     */
	    if(sub_symbolP){
		/* is it just -sym ? */
		if(add_symbolP == NULL){
		    if(sub_symbolP->sy_type != N_ABS)
			as_warn("Negative of non-absolute symbol %s",
				sub_symbolP->sy_name);
#if !(defined(I386) && defined(ARCH64))
			/* Symbol offsets are not part of fixups for x86_64. */
		    value -= sub_symbolP->sy_value;
#endif
		    fixP->fx_subsy = NULL;
		}
		/*
		 * There are both an add symbol and a subtract symbol at this
		 * point.
		 *
		 * If both symbols are absolute then just calculate the
		 * value of the fix expression and no relocation entry will be
		 * needed.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_ABS &&
		        (add_symbolP->sy_type & N_TYPE) == N_ABS){
		    value += add_symbolP->sy_value - sub_symbolP->sy_value;
		    add_symbolP = NULL;
		    fixP->fx_addsy = NULL; /* no relocation entry */
		    fixP->fx_subsy = NULL;
		}
		/*
		 * If both symbols are defined in a section then calculate the
		 * value of the fix expression and let a section difference
		 * relocation entry be created.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_SECT &&
		        (add_symbolP->sy_type & N_TYPE) == N_SECT){
		    /*
		     * We are use the new features that are incompatible with
		     * 3.2 then just calculate the value and let this create a
		     * SECTDIFF relocation type.
		     */
#ifdef SPARC
		    /*
		     * Special case dealing with assembler internal relocation
		     * entries SPARC_RELOC_13 and RELOC_22. The can not be
		     * output and must be resolved.
		     */
		    if((fixP->fx_r_type == SPARC_RELOC_13) ||
		       (fixP->fx_r_type == SPARC_RELOC_22)){
			if(sub_symbolP->sy_other == add_symbolP->sy_other){
			    value += add_symbolP->sy_value -
			    sub_symbolP->sy_value;
			    add_symbolP = NULL;
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    fixP->fx_subsy = NULL;
			}
			else{
			    as_warn("Can't emit reloc type %u {-symbol \"%s\"} "
			            "@ file address %llu (mode?).",
				    fixP->fx_r_type, sub_symbolP->sy_name,
				    fragP->fr_address + where);
			}
		    }
		    else
			value += add_symbolP->sy_value - sub_symbolP->sy_value;
#else
#if !(defined(I386) && defined(ARCH64))
			/*
			 * Special case for x86_64.  'value' doesn't include
			 * the difference between the two symbols because
			 * that's handled by the subtractor/vanilla reloc pair.
			 */
		    value += add_symbolP->sy_value;
		    value -= sub_symbolP->sy_value;
#else
		    /*
		     * But for x86_64 expressions in the debug section must
		     * be the actual value of the expression.
		     */
		    if(is_section_debug(nsect)){
			value += add_symbolP->sy_value;
			value -= sub_symbolP->sy_value;
		    }
#endif
		    sub_symbol_nsect = sub_symbolP->sy_other;
		    /*
		     * If we have the special assembly time constant expression
		     * of the difference of two symbols defined in the same
		     * section then divided by exactly 2 adjust the value and
		     * make sure these symbols will produce an assembly time
		     * constant.
		     */
		    if(fixP->fx_sectdiff_divide_by_two == 1){
			value = value / 2;
			if(is_assembly_time_constant_subtraction_expression(
				add_symbolP, add_symbol_nsect,
				sub_symbolP, sub_symbol_nsect) == TRUE){
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    goto down;
			}
			else{
			    layout_line = fixP->line;
			    layout_file = fixP->file;
			    as_warn("section difference divide by two "
				    "expression, \"%s\" minus \"%s\" divide by "
				    "2 will not produce an assembly time "
				    "constant", add_symbolP->sy_name,
				    sub_symbolP->sy_name);
			}
		    }
		    if(is_end_section_address(add_symbol_nsect,
					      add_symbolP->sy_value) ||
		       is_end_section_address(sub_symbol_nsect,
					      sub_symbolP->sy_value)){
			if(is_assembly_time_constant_subtraction_expression(
				add_symbolP, add_symbol_nsect,
				sub_symbolP, sub_symbol_nsect) == TRUE){
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    goto down;
			}
			if(is_section_debug(nsect) &&
	   		   strcmp(add_symbolP->sy_name, FAKE_LABEL_NAME) == 0 &&
	   		   strcmp(sub_symbolP->sy_name, FAKE_LABEL_NAME) == 0){
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    goto down;
			}
			layout_line = fixP->line;
			layout_file = fixP->file;
			as_warn("section difference relocatable subtraction "
				"expression, \"%s\" minus \"%s\" using a "
				"symbol at the end of section will not "
				"produce an assembly time constant",
				add_symbolP->sy_name, sub_symbolP->sy_name);
			as_warn("use a symbol with a constant value created "
				"with an assignment instead of the expression, "
				"L_const_sym = %s - %s", add_symbolP->sy_name,
				sub_symbolP->sy_name);
			layout_line = 0;
			layout_file = NULL;
		    }
#endif
		    goto down;
		}
		/*
		 * If the subtract symbol is absolute subtract it's value from
		 * the fix expression and let a relocation entry get created
		 * that is not a section difference type.
		 */
		else if(sub_symbolP->sy_type == N_ABS){
		    value -= sub_symbolP->sy_value;
		    fixP->fx_subsy = NULL; /* no SECTDIFF relocation entry */
		}
		/*
		 * At this point we have something we can't generate a
		 * relocation entry for (two undefined symbols, etc.).
		 */
	        else{
		     layout_line = fixP->line;
		     layout_file = fixP->file;
		     as_bad("non-relocatable subtraction expression, \"%s\" "
			     "minus \"%s\"", add_symbolP->sy_name,
			     sub_symbolP->sy_name);
		     if((add_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_bad("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", add_symbolP->sy_name);
		     if((sub_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_bad("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", sub_symbolP->sy_name);
		     layout_line = 0;
		     layout_file = NULL;
		}
	    }

	    /*
	     * If a there is an add symbol in the fixup expression then add
	     * the symbol value into the fixup expression's value.
	     */
	    if(add_symbolP){
		/*
		 * If this symbol is in this section and is pc-relative and we
		 * do not want to force a pc-relative relocation entry (to
		 * support scattered loading) then just calculate the value.
		 */
		if(add_symbol_nsect == nsect
		   /* FROM write.c line 2659 */
#ifdef ARM
		   && !TC_FORCE_RELOCATION_LOCAL (fixP)
#else
		   && pcrel
#endif
		   && !(fixP->fx_pcrel_reloc)){
		    /*
		     * This fixup was made when the symbol's section was
		     * unknown, but it is now in this section. So we know how
		     * to do the address without relocation.
		     */
		    value += add_symbolP->sy_value;
#ifdef ARM
		    /* FROM write.c line 2667 */
		    value -= MD_PCREL_FROM_SECTION (fixP, nsect);
#else
		    value -= size + where + fragP->fr_address;
#endif
		    pcrel = 0;	/* Lie. Don't want further pcrel processing. */
		    fixP->fx_addsy = NULL; /* No relocations please. */
		    /*
		     * It would be nice to check that the address does not
		     * overflow.
		     * I didn't do this check because:
		     * +  It is machine dependent in the general case (eg 32032)
		     * +  Compiler output will never need this checking, so why
		     *    slow down the usual case?
		     */
		}
		else{
		    switch(add_symbol_N_TYPE){
		    case N_ABS:
			/*
			 * If the value of the symbol was an expression then
			 * now evaluate the expression now.  This can happen
			 * when symbols like:
			 *	.set x,a-b
			 * are used and the value of x is not known till all
			 * of the symbols are seen and had their values set.
			 */
			if(add_symbolP->expression != NULL){
			    expressionS *exp;

			    exp = (expressionS *)add_symbolP->expression;
			    value +=
				exp->X_add_symbol->sy_value +
				exp->X_add_number -
				exp->X_subtract_symbol->sy_value;
			}
			else
			{
			    value += add_symbolP->sy_value;
			}
			fixP->fx_addsy = NULL; /* no relocation entry */
			add_symbolP = NULL;
			break;
			
		    case N_SECT:
#if (defined(I386) && defined(ARCH64))
			/*
			 * Symbol offsets are not part of fixups for external
			 * symbols for x86_64.
			 */
			if((is_section_debug(nsect) &&
			    add_symbol_N_TYPE != N_UNDF) ||
			   (add_symbol_N_TYPE == N_SECT &&
			    is_local_symbol(add_symbolP) &&
			    !is_section_cstring_literals(add_symbol_nsect)) )
#else
			if(((add_symbolP->sy_type & N_EXT) != N_EXT ||
			    add_symbol_N_TYPE != N_SECT ||
			    !is_section_coalesced(add_symbol_nsect)) &&
			   (add_symbolP->sy_desc & N_WEAK_DEF) != N_WEAK_DEF)
#endif
			    value += add_symbolP->sy_value;
			break;
			
		    case N_UNDF:
			break;
			
		    default:
			BAD_CASE(add_symbol_N_TYPE);
			break;
		    }
		}
	    }
down:
	    /*
	     * If the fixup expression is pc-relative then the value of the pc
	     * will be added to the expression when the machine executes the
	     * the instruction so we adjust the fixup expression's value by
	     * subtracting off the pc value (where) and adjust for insn size.
	     */
	    if(pcrel){
#ifdef ARM
	        /* This should work for both */
	        /* FROM write.c line 2688 */
		value -= MD_PCREL_FROM_SECTION (fixP, nsect);
#elif !(defined(I386) && defined(ARCH64))
		/* Symbol offsets are not part of fixups for x86_64. */
		value -= size + where + fragP->fr_address;
#endif
		if(add_symbolP == NULL){
		    fixP->fx_addsy = &abs_symbol; /* force relocation entry */
		}
	    }

	    if((size == 1 && (value & 0xffffff00) &&
			    ((value & 0xffffff80) != 0xffffff80)) ||
	       (size == 2 && (value & 0xffff0000) &&
			    ((value & 0xffff8000) != 0xffff8000))){
		layout_line = fixP->line;
		layout_file = fixP->file;
		as_bad("Fixup of %lld too large for field width of %d",
			value, size);
		layout_line = 0;
		layout_file = NULL;
	    }

	    /*
	     * Now place the fix expression's value in the place for the size.
	     * And save the fix expression's value to be used when creating
	     * a relocation entry if required.
	     */
	    md_number_to_imm((unsigned char *)place, value, size, fixP, nsect);
	    fixP->fx_value = value;

	    /*
	     * If this is a non-lazy pointer section and this fix is for a
	     * local symbol without an subtract symbol then cause this not to
	     * generate a relocation entry.  This is used with code gen for
	     * fix-n-continue where the compiler generates indirection for
	     * static data references.  So the assembly looks like this:
	     *
	     * 	.non_lazy_symbol_pointer
	     * 	L_i$non_lazy_ptr:
       	     * 	.indirect_symbol _i
       	     * 	.long   _i
	     *
	     * this allows the value of the symbol to be set into the pointer
	     * but not cause the relocation entry to be created.  The code in
	     * write_object() then changes the indirect symbol table entry to
	     * INDIRECT_SYMBOL_LOCAL when the symbol is local.  This is what
	     * the static and dynamic linkers expect and will then cause the
	     * pointer to be correctly relocated.
	     */
	    if(is_section_non_lazy_symbol_pointers(nsect) &&
	       (add_symbolP->sy_type & N_EXT) != N_EXT &&
	       sub_symbolP == NULL){
		fixP->fx_addsy = NULL; /* no relocation entry */
	    }
	}
}
Beispiel #3
0
Datei: app.c Projekt: 0mp/freebsd
int
do_scrub_chars (int (*get) (char *, int), char *tostart, int tolen)
{
  char *to = tostart;
  char *toend = tostart + tolen;
  char *from;
  char *fromend;
  int fromlen;
  register int ch, ch2 = 0;
  /* Character that started the string we're working on.  */
  static char quotechar;

  /*State 0: beginning of normal line
	  1: After first whitespace on line (flush more white)
	  2: After first non-white (opcode) on line (keep 1white)
	  3: after second white on line (into operands) (flush white)
	  4: after putting out a .linefile, put out digits
	  5: parsing a string, then go to old-state
	  6: putting out \ escape in a "d string.
	  7: no longer used
	  8: no longer used
	  9: After seeing symbol char in state 3 (keep 1white after symchar)
	 10: After seeing whitespace in state 9 (keep white before symchar)
	 11: After seeing a symbol character in state 0 (eg a label definition)
	 -1: output string in out_string and go to the state in old_state
	 -2: flush text until a '*' '/' is seen, then go to state old_state
#ifdef TC_V850
	 12: After seeing a dash, looking for a second dash as a start
	     of comment.
#endif
#ifdef DOUBLEBAR_PARALLEL
	 13: After seeing a vertical bar, looking for a second
	     vertical bar as a parallel expression separator.
#endif
#ifdef TC_IA64
	 14: After seeing a `(' at state 0, looking for a `)' as
	     predicate.
	 15: After seeing a `(' at state 1, looking for a `)' as
	     predicate.
#endif
#ifdef TC_Z80
	 16: After seeing an 'a' or an 'A' at the start of a symbol
	 17: After seeing an 'f' or an 'F' in state 16
#endif
	  */

  /* I added states 9 and 10 because the MIPS ECOFF assembler uses
     constructs like ``.loc 1 20''.  This was turning into ``.loc
     120''.  States 9 and 10 ensure that a space is never dropped in
     between characters which could appear in an identifier.  Ian
     Taylor, [email protected].

     I added state 11 so that something like "Lfoo add %r25,%r26,%r27" works
     correctly on the PA (and any other target where colons are optional).
     Jeff Law, [email protected].

     I added state 13 so that something like "cmp r1, r2 || trap #1" does not
     get squashed into "cmp r1,r2||trap#1", with the all important space
     between the 'trap' and the '#1' being eliminated.  [email protected]  */

  /* This macro gets the next input character.  */

#define GET()							\
  (from < fromend						\
   ? * (unsigned char *) (from++)				\
   : (saved_input = NULL,					\
      fromlen = (*get) (input_buffer, sizeof input_buffer),	\
      from = input_buffer,					\
      fromend = from + fromlen,					\
      (fromlen == 0						\
       ? EOF							\
       : * (unsigned char *) (from++))))

  /* This macro pushes a character back on the input stream.  */

#define UNGET(uch) (*--from = (uch))

  /* This macro puts a character into the output buffer.  If this
     character fills the output buffer, this macro jumps to the label
     TOFULL.  We use this rather ugly approach because we need to
     handle two different termination conditions: EOF on the input
     stream, and a full output buffer.  It would be simpler if we
     always read in the entire input stream before processing it, but
     I don't want to make such a significant change to the assembler's
     memory usage.  */

#define PUT(pch)				\
  do						\
    {						\
      *to++ = (pch);				\
      if (to >= toend)				\
	goto tofull;				\
    }						\
  while (0)

  if (saved_input != NULL)
    {
      from = saved_input;
      fromend = from + saved_input_len;
    }
  else
    {
      fromlen = (*get) (input_buffer, sizeof input_buffer);
      if (fromlen == 0)
	return 0;
      from = input_buffer;
      fromend = from + fromlen;
    }

  while (1)
    {
      /* The cases in this switch end with continue, in order to
	 branch back to the top of this while loop and generate the
	 next output character in the appropriate state.  */
      switch (state)
	{
	case -1:
	  ch = *out_string++;
	  if (*out_string == '\0')
	    {
	      state = old_state;
	      old_state = 3;
	    }
	  PUT (ch);
	  continue;

	case -2:
	  for (;;)
	    {
	      do
		{
		  ch = GET ();

		  if (ch == EOF)
		    {
		      as_warn (_("end of file in comment"));
		      goto fromeof;
		    }

		  if (ch == '\n')
		    PUT ('\n');
		}
	      while (ch != '*');

	      while ((ch = GET ()) == '*')
		;

	      if (ch == EOF)
		{
		  as_warn (_("end of file in comment"));
		  goto fromeof;
		}

	      if (ch == '/')
		break;

	      UNGET (ch);
	    }

	  state = old_state;
	  UNGET (' ');
	  continue;

	case 4:
	  ch = GET ();
	  if (ch == EOF)
	    goto fromeof;
	  else if (ch >= '0' && ch <= '9')
	    PUT (ch);
	  else
	    {
	      while (ch != EOF && IS_WHITESPACE (ch))
		ch = GET ();
	      if (ch == '"')
		{
		  quotechar = ch;
		  state = 5;
		  old_state = 3;
		  PUT (ch);
		}
	      else
		{
		  while (ch != EOF && ch != '\n')
		    ch = GET ();
		  state = 0;
		  PUT (ch);
		}
	    }
	  continue;

	case 5:
	  /* We are going to copy everything up to a quote character,
	     with special handling for a backslash.  We try to
	     optimize the copying in the simple case without using the
	     GET and PUT macros.  */
	  {
	    char *s;
	    int len;

	    for (s = from; s < fromend; s++)
	      {
		ch = *s;
		if (ch == '\\'
		    || ch == quotechar
		    || ch == '\n')
		  break;
	      }
	    len = s - from;
	    if (len > toend - to)
	      len = toend - to;
	    if (len > 0)
	      {
		memcpy (to, from, len);
		to += len;
		from += len;
		if (to >= toend)
		  goto tofull;
	      }
	  }

	  ch = GET ();
	  if (ch == EOF)
	    {
	      as_warn (_("end of file in string; '%c' inserted"), quotechar);
	      state = old_state;
	      UNGET ('\n');
	      PUT (quotechar);
	    }
	  else if (ch == quotechar)
	    {
	      state = old_state;
	      PUT (ch);
	    }
#ifndef NO_STRING_ESCAPES
	  else if (ch == '\\')
	    {
	      state = 6;
	      PUT (ch);
	    }
#endif
	  else if (scrub_m68k_mri && ch == '\n')
	    {
	      /* Just quietly terminate the string.  This permits lines like
		   bne	label	loop if we haven't reach end yet.  */
	      state = old_state;
	      UNGET (ch);
	      PUT ('\'');
	    }
	  else
	    {
	      PUT (ch);
	    }
	  continue;

	case 6:
	  state = 5;
	  ch = GET ();
	  switch (ch)
	    {
	      /* Handle strings broken across lines, by turning '\n' into
		 '\\' and 'n'.  */
	    case '\n':
	      UNGET ('n');
	      add_newlines++;
	      PUT ('\\');
	      continue;

	    case EOF:
	      as_warn (_("end of file in string; '%c' inserted"), quotechar);
	      PUT (quotechar);
	      continue;

	    case '"':
	    case '\\':
	    case 'b':
	    case 'f':
	    case 'n':
	    case 'r':
	    case 't':
	    case 'v':
	    case 'x':
	    case 'X':
	    case '0':
	    case '1':
	    case '2':
	    case '3':
	    case '4':
	    case '5':
	    case '6':
	    case '7':
	      break;

	    default:
#ifdef ONLY_STANDARD_ESCAPES
	      as_warn (_("unknown escape '\\%c' in string; ignored"), ch);
#endif
	      break;
	    }
	  PUT (ch);
	  continue;

#ifdef DOUBLEBAR_PARALLEL
	case 13:
	  ch = GET ();
	  if (ch != '|')
	    abort ();

	  /* Reset back to state 1 and pretend that we are parsing a
	     line from just after the first white space.  */
	  state = 1;
	  PUT ('|');
	  continue;
#endif
#ifdef TC_Z80
	case 16:
	  /* We have seen an 'a' at the start of a symbol, look for an 'f'.  */
	  ch = GET ();
	  if (ch == 'f' || ch == 'F') 
	    {
	      state = 17;
	      PUT (ch);
	    }
	  else
	    {
	      state = 9;
	      break;
	    }
	case 17:
	  /* We have seen "af" at the start of a symbol,
	     a ' here is a part of that symbol.  */
	  ch = GET ();
	  state = 9;
	  if (ch == '\'')
	    /* Change to avoid warning about unclosed string.  */
	    PUT ('`');
	  else
	    UNGET (ch);
	  break;
#endif
	}

      /* OK, we are somewhere in states 0 through 4 or 9 through 11.  */

      /* flushchar: */
      ch = GET ();

#ifdef TC_IA64
      if (ch == '(' && (state == 0 || state == 1))
	{
	  state += 14;
	  PUT (ch);
	  continue;
	}
      else if (state == 14 || state == 15)
	{
	  if (ch == ')')
	    {
	      state -= 14;
	      PUT (ch);
	      ch = GET ();
	    }
	  else
	    {
	      PUT (ch);
	      continue;
	    }
	}
#endif

    recycle:

#if defined TC_ARM && defined OBJ_ELF
      /* We need to watch out for .symver directives.  See the comment later
	 in this function.  */
      if (symver_state == NULL)
	{
	  if ((state == 0 || state == 1) && ch == symver_pseudo[0])
	    symver_state = symver_pseudo + 1;
	}
      else
	{
	  /* We advance to the next state if we find the right
	     character.  */
	  if (ch != '\0' && (*symver_state == ch))
	    ++symver_state;
	  else if (*symver_state != '\0')
	    /* We did not get the expected character, or we didn't
	       get a valid terminating character after seeing the
	       entire pseudo-op, so we must go back to the beginning.  */
	    symver_state = NULL;
	  else
	    {
	      /* We've read the entire pseudo-op.  If this is the end
		 of the line, go back to the beginning.  */
	      if (IS_NEWLINE (ch))
		symver_state = NULL;
	    }
	}
#endif /* TC_ARM && OBJ_ELF */

#ifdef TC_M68K
      /* We want to have pseudo-ops which control whether we are in
	 MRI mode or not.  Unfortunately, since m68k MRI mode affects
	 the scrubber, that means that we need a special purpose
	 recognizer here.  */
      if (mri_state == NULL)
	{
	  if ((state == 0 || state == 1)
	      && ch == mri_pseudo[0])
	    mri_state = mri_pseudo + 1;
	}
      else
	{
	  /* We advance to the next state if we find the right
	     character, or if we need a space character and we get any
	     whitespace character, or if we need a '0' and we get a
	     '1' (this is so that we only need one state to handle
	     ``.mri 0'' and ``.mri 1'').  */
	  if (ch != '\0'
	      && (*mri_state == ch
		  || (*mri_state == ' '
		      && lex[ch] == LEX_IS_WHITESPACE)
		  || (*mri_state == '0'
		      && ch == '1')))
	    {
	      mri_last_ch = ch;
	      ++mri_state;
	    }
	  else if (*mri_state != '\0'
		   || (lex[ch] != LEX_IS_WHITESPACE
		       && lex[ch] != LEX_IS_NEWLINE))
	    {
	      /* We did not get the expected character, or we didn't
		 get a valid terminating character after seeing the
		 entire pseudo-op, so we must go back to the
		 beginning.  */
	      mri_state = NULL;
	    }
	  else
	    {
	      /* We've read the entire pseudo-op.  mips_last_ch is
		 either '0' or '1' indicating whether to enter or
		 leave MRI mode.  */
	      do_scrub_begin (mri_last_ch == '1');
	      mri_state = NULL;

	      /* We continue handling the character as usual.  The
		 main gas reader must also handle the .mri pseudo-op
		 to control expression parsing and the like.  */
	    }
	}
#endif

      if (ch == EOF)
	{
	  if (state != 0)
	    {
	      as_warn (_("end of file not at end of a line; newline inserted"));
	      state = 0;
	      PUT ('\n');
	    }
	  goto fromeof;
	}

      switch (lex[ch])
	{
	case LEX_IS_WHITESPACE:
	  do
	    {
	      ch = GET ();
	    }
	  while (ch != EOF && IS_WHITESPACE (ch));
	  if (ch == EOF)
	    goto fromeof;

	  if (state == 0)
	    {
	      /* Preserve a single whitespace character at the
		 beginning of a line.  */
	      state = 1;
	      UNGET (ch);
	      PUT (' ');
	      break;
	    }

#ifdef KEEP_WHITE_AROUND_COLON
	  if (lex[ch] == LEX_IS_COLON)
	    {
	      /* Only keep this white if there's no white *after* the
		 colon.  */
	      ch2 = GET ();
	      UNGET (ch2);
	      if (!IS_WHITESPACE (ch2))
		{
		  state = 9;
		  UNGET (ch);
		  PUT (' ');
		  break;
		}
	    }
#endif
	  if (IS_COMMENT (ch)
	      || ch == '/'
	      || IS_LINE_SEPARATOR (ch)
	      || IS_PARALLEL_SEPARATOR (ch))
	    {
	      if (scrub_m68k_mri)
		{
		  /* In MRI mode, we keep these spaces.  */
		  UNGET (ch);
		  PUT (' ');
		  break;
		}
	      goto recycle;
	    }

	  /* If we're in state 2 or 11, we've seen a non-white
	     character followed by whitespace.  If the next character
	     is ':', this is whitespace after a label name which we
	     normally must ignore.  In MRI mode, though, spaces are
	     not permitted between the label and the colon.  */
	  if ((state == 2 || state == 11)
	      && lex[ch] == LEX_IS_COLON
	      && ! scrub_m68k_mri)
	    {
	      state = 1;
	      PUT (ch);
	      break;
	    }

	  switch (state)
	    {
	    case 1:
	      /* We can arrive here if we leave a leading whitespace
		 character at the beginning of a line.  */
	      goto recycle;
	    case 2:
	      state = 3;
	      if (to + 1 < toend)
		{
		  /* Optimize common case by skipping UNGET/GET.  */
		  PUT (' ');	/* Sp after opco */
		  goto recycle;
		}
	      UNGET (ch);
	      PUT (' ');
	      break;
	    case 3:
	      if (scrub_m68k_mri)
		{
		  /* In MRI mode, we keep these spaces.  */
		  UNGET (ch);
		  PUT (' ');
		  break;
		}
	      goto recycle;	/* Sp in operands */
	    case 9:
	    case 10:
	      if (scrub_m68k_mri)
		{
		  /* In MRI mode, we keep these spaces.  */
		  state = 3;
		  UNGET (ch);
		  PUT (' ');
		  break;
		}
	      state = 10;	/* Sp after symbol char */
	      goto recycle;
	    case 11:
	      if (LABELS_WITHOUT_COLONS || flag_m68k_mri)
		state = 1;
	      else
		{
		  /* We know that ch is not ':', since we tested that
		     case above.  Therefore this is not a label, so it
		     must be the opcode, and we've just seen the
		     whitespace after it.  */
		  state = 3;
		}
	      UNGET (ch);
	      PUT (' ');	/* Sp after label definition.  */
	      break;
	    default:
	      BAD_CASE (state);
	    }
	  break;

	case LEX_IS_TWOCHAR_COMMENT_1ST:
	  ch2 = GET ();
	  if (ch2 == '*')
	    {
	      for (;;)
		{
		  do
		    {
		      ch2 = GET ();
		      if (ch2 != EOF && IS_NEWLINE (ch2))
			add_newlines++;
		    }
		  while (ch2 != EOF && ch2 != '*');

		  while (ch2 == '*')
		    ch2 = GET ();

		  if (ch2 == EOF || ch2 == '/')
		    break;

		  /* This UNGET will ensure that we count newlines
		     correctly.  */
		  UNGET (ch2);
		}

	      if (ch2 == EOF)
		as_warn (_("end of file in multiline comment"));

	      ch = ' ';
	      goto recycle;
	    }
#ifdef DOUBLESLASH_LINE_COMMENTS
	  else if (ch2 == '/')
	    {
	      do
		{
		  ch = GET ();
		}
	      while (ch != EOF && !IS_NEWLINE (ch));
	      if (ch == EOF)
		as_warn ("end of file in comment; newline inserted");
	      state = 0;
	      PUT ('\n');
	      break;
	    }
#endif
	  else
	    {
	      if (ch2 != EOF)
		UNGET (ch2);
	      if (state == 9 || state == 10)
		state = 3;
	      PUT (ch);
	    }
	  break;

	case LEX_IS_STRINGQUOTE:
	  quotechar = ch;
	  if (state == 10)
	    {
	      /* Preserve the whitespace in foo "bar".  */
	      UNGET (ch);
	      state = 3;
	      PUT (' ');

	      /* PUT didn't jump out.  We could just break, but we
		 know what will happen, so optimize a bit.  */
	      ch = GET ();
	      old_state = 3;
	    }
	  else if (state == 9)
	    old_state = 3;
	  else
	    old_state = state;
	  state = 5;
	  PUT (ch);
	  break;

#ifndef IEEE_STYLE
	case LEX_IS_ONECHAR_QUOTE:
	  if (state == 10)
	    {
	      /* Preserve the whitespace in foo 'b'.  */
	      UNGET (ch);
	      state = 3;
	      PUT (' ');
	      break;
	    }
	  ch = GET ();
	  if (ch == EOF)
	    {
	      as_warn (_("end of file after a one-character quote; \\0 inserted"));
	      ch = 0;
	    }
	  if (ch == '\\')
	    {
	      ch = GET ();
	      if (ch == EOF)
		{
		  as_warn (_("end of file in escape character"));
		  ch = '\\';
		}
	      else
		ch = process_escape (ch);
	    }
	  sprintf (out_buf, "%d", (int) (unsigned char) ch);

	  /* None of these 'x constants for us.  We want 'x'.  */
	  if ((ch = GET ()) != '\'')
	    {
#ifdef REQUIRE_CHAR_CLOSE_QUOTE
	      as_warn (_("missing close quote; (assumed)"));
#else
	      if (ch != EOF)
		UNGET (ch);
#endif
	    }
	  if (strlen (out_buf) == 1)
	    {
	      PUT (out_buf[0]);
	      break;
	    }
	  if (state == 9)
	    old_state = 3;
	  else
	    old_state = state;
	  state = -1;
	  out_string = out_buf;
	  PUT (*out_string++);
	  break;
#endif

	case LEX_IS_COLON:
#ifdef KEEP_WHITE_AROUND_COLON
	  state = 9;
#else
	  if (state == 9 || state == 10)
	    state = 3;
	  else if (state != 3)
	    state = 1;
#endif
	  PUT (ch);
	  break;

	case LEX_IS_NEWLINE:
	  /* Roll out a bunch of newlines from inside comments, etc.  */
	  if (add_newlines)
	    {
	      --add_newlines;
	      UNGET (ch);
	    }
	  /* Fall through.  */

	case LEX_IS_LINE_SEPARATOR:
	  state = 0;
	  PUT (ch);
	  break;

	case LEX_IS_PARALLEL_SEPARATOR:
	  state = 1;
	  PUT (ch);
	  break;

#ifdef TC_V850
	case LEX_IS_DOUBLEDASH_1ST:
	  ch2 = GET ();
	  if (ch2 != '-')
	    {
	      UNGET (ch2);
	      goto de_fault;
	    }
	  /* Read and skip to end of line.  */
	  do
	    {
	      ch = GET ();
	    }
	  while (ch != EOF && ch != '\n');

	  if (ch == EOF)
	    as_warn (_("end of file in comment; newline inserted"));

	  state = 0;
	  PUT ('\n');
	  break;
#endif
#ifdef DOUBLEBAR_PARALLEL
	case LEX_IS_DOUBLEBAR_1ST:
	  ch2 = GET ();
	  UNGET (ch2);
	  if (ch2 != '|')
	    goto de_fault;

	  /* Handle '||' in two states as invoking PUT twice might
	     result in the first one jumping out of this loop.  We'd
	     then lose track of the state and one '|' char.  */
	  state = 13;
	  PUT ('|');
	  break;
#endif
	case LEX_IS_LINE_COMMENT_START:
	  /* FIXME-someday: The two character comment stuff was badly
	     thought out.  On i386, we want '/' as line comment start
	     AND we want C style comments.  hence this hack.  The
	     whole lexical process should be reworked.  xoxorich.  */
	  if (ch == '/')
	    {
	      ch2 = GET ();
	      if (ch2 == '*')
		{
		  old_state = 3;
		  state = -2;
		  break;
		}
	      else
		{
		  UNGET (ch2);
		}
	    }

	  if (state == 0 || state == 1)	/* Only comment at start of line.  */
	    {
	      int startch;

	      startch = ch;

	      do
		{
		  ch = GET ();
		}
	      while (ch != EOF && IS_WHITESPACE (ch));

	      if (ch == EOF)
		{
		  as_warn (_("end of file in comment; newline inserted"));
		  PUT ('\n');
		  break;
		}

	      if (ch < '0' || ch > '9' || state != 0 || startch != '#')
		{
		  /* Not a cpp line.  */
		  while (ch != EOF && !IS_NEWLINE (ch))
		    ch = GET ();
		  if (ch == EOF)
		    as_warn (_("end of file in comment; newline inserted"));
		  state = 0;
		  PUT ('\n');
		  break;
		}
	      /* Looks like `# 123 "filename"' from cpp.  */
	      UNGET (ch);
	      old_state = 4;
	      state = -1;
	      if (scrub_m68k_mri)
		out_string = "\tlinefile ";
	      else
		out_string = "\t.linefile ";
	      PUT (*out_string++);
	      break;
	    }

#ifdef TC_D10V
	  /* All insns end in a char for which LEX_IS_SYMBOL_COMPONENT is true.
	     Trap is the only short insn that has a first operand that is
	     neither register nor label.
	     We must prevent exef0f ||trap #1 to degenerate to exef0f ||trap#1 .
	     We can't make '#' LEX_IS_SYMBOL_COMPONENT because it is
	     already LEX_IS_LINE_COMMENT_START.  However, it is the
	     only character in line_comment_chars for d10v, hence we
	     can recognize it as such.  */
	  /* An alternative approach would be to reset the state to 1 when
	     we see '||', '<'- or '->', but that seems to be overkill.  */
	  if (state == 10)
	    PUT (' ');
#endif
	  /* We have a line comment character which is not at the
	     start of a line.  If this is also a normal comment
	     character, fall through.  Otherwise treat it as a default
	     character.  */
	  if (strchr (tc_comment_chars, ch) == NULL
	      && (! scrub_m68k_mri
		  || (ch != '!' && ch != '*')))
	    goto de_fault;
	  if (scrub_m68k_mri
	      && (ch == '!' || ch == '*' || ch == '#')
	      && state != 1
	      && state != 10)
	    goto de_fault;
	  /* Fall through.  */
	case LEX_IS_COMMENT_START:
#if defined TC_ARM && defined OBJ_ELF
	  /* On the ARM, `@' is the comment character.
	     Unfortunately this is also a special character in ELF .symver
	     directives (and .type, though we deal with those another way).
	     So we check if this line is such a directive, and treat
	     the character as default if so.  This is a hack.  */
	  if ((symver_state != NULL) && (*symver_state == 0))
	    goto de_fault;
#endif

#ifdef TC_ARM
	  /* For the ARM, care is needed not to damage occurrences of \@
	     by stripping the @ onwards.  Yuck.  */
	  if (to > tostart && *(to - 1) == '\\')
	    /* Do not treat the @ as a start-of-comment.  */
	    goto de_fault;
#endif

#ifdef WARN_COMMENTS
	  if (!found_comment)
	    as_where (&found_comment_file, &found_comment);
#endif
	  do
	    {
	      ch = GET ();
	    }
	  while (ch != EOF && !IS_NEWLINE (ch));
	  if (ch == EOF)
	    as_warn (_("end of file in comment; newline inserted"));
	  state = 0;
	  PUT ('\n');
	  break;

	case LEX_IS_SYMBOL_COMPONENT:
	  if (state == 10)
	    {
	      /* This is a symbol character following another symbol
		 character, with whitespace in between.  We skipped
		 the whitespace earlier, so output it now.  */
	      UNGET (ch);
	      state = 3;
	      PUT (' ');
	      break;
	    }

#ifdef TC_Z80
	  /* "af'" is a symbol containing '\''.  */
	  if (state == 3 && (ch == 'a' || ch == 'A')) 
	    {
	      state = 16;
	      PUT (ch);
	      ch = GET ();
	      if (ch == 'f' || ch == 'F') 
		{
		  state = 17;
		  PUT (ch);
		  break;
		}
	      else
		{
		  state = 9;
		  if (!IS_SYMBOL_COMPONENT (ch)) 
		    {
		      UNGET (ch);
		      break;
		    }
		}
	    }
#endif
	  if (state == 3)
	    state = 9;

	  /* This is a common case.  Quickly copy CH and all the
	     following symbol component or normal characters.  */
	  if (to + 1 < toend
	      && mri_state == NULL
#if defined TC_ARM && defined OBJ_ELF
	      && symver_state == NULL
#endif
	      )
	    {
	      char *s;
	      int len;

	      for (s = from; s < fromend; s++)
		{
		  int type;

		  ch2 = *(unsigned char *) s;
		  type = lex[ch2];
		  if (type != 0
		      && type != LEX_IS_SYMBOL_COMPONENT)
		    break;
		}

	      if (s > from)
		/* Handle the last character normally, for
		   simplicity.  */
		--s;

	      len = s - from;

	      if (len > (toend - to) - 1)
		len = (toend - to) - 1;

	      if (len > 0)
		{
		  PUT (ch);
		  memcpy (to, from, len);
		  to += len;
		  from += len;
		  if (to >= toend)
		    goto tofull;
		  ch = GET ();
		}
	    }

	  /* Fall through.  */
	default:
	de_fault:
	  /* Some relatively `normal' character.  */
	  if (state == 0)
	    {
	      state = 11;	/* Now seeing label definition.  */
	    }
	  else if (state == 1)
	    {
	      state = 2;	/* Ditto.  */
	    }
	  else if (state == 9)
	    {
	      if (!IS_SYMBOL_COMPONENT (ch))
		state = 3;
	    }
	  else if (state == 10)
	    {
	      if (ch == '\\')
		{
		  /* Special handling for backslash: a backslash may
		     be the beginning of a formal parameter (of a
		     macro) following another symbol character, with
		     whitespace in between.  If that is the case, we
		     output a space before the parameter.  Strictly
		     speaking, correct handling depends upon what the
		     macro parameter expands into; if the parameter
		     expands into something which does not start with
		     an operand character, then we don't want to keep
		     the space.  We don't have enough information to
		     make the right choice, so here we are making the
		     choice which is more likely to be correct.  */
		  if (to + 1 >= toend)
		    {
		      /* If we're near the end of the buffer, save the
		         character for the next time round.  Otherwise
		         we'll lose our state.  */
		      UNGET (ch);
		      goto tofull;
		    }
		  *to++ = ' ';
		}

	      state = 3;
	    }
	  PUT (ch);
	  break;
	}
    }

  /*NOTREACHED*/

 fromeof:
  /* We have reached the end of the input.  */
  return to - tostart;

 tofull:
  /* The output buffer is full.  Save any input we have not yet
     processed.  */
  if (fromend > from)
    {
      saved_input = from;
      saved_input_len = fromend - from;
    }
  else
    saved_input = NULL;

  return to - tostart;
}
Beispiel #4
0
/*
 * relax_section() here we set the fr_address values in the frags.
 * After this, all frags in this segment have addresses that are correct
 * relative to the section (that is the section starts at address zero).
 * After all of the sections have been processed by this call and their sizes
 * are know then they can be slid to their final address.
 */
static
int
relax_section(
struct frag *frag_root,
int nsect)
{
    struct frag *fragP;
    relax_addressT address;

    int32_t stretch; /* May be any size, 0 or negative. */
		     /* Cumulative number of addresses we have */
		     /* relaxed this pass. */
		     /* We may have relaxed more than one address. */
    int32_t stretched;  /* Have we stretched on this pass? */
		    /* This is 'cuz stretch may be zero, when,
		       in fact some piece of code grew, and
		       another shrank.  If a branch instruction
		       doesn't fit anymore, we need another pass */

#ifndef ARM
    const relax_typeS *this_type;
    const relax_typeS *start_type;
    relax_substateT next_state;
    relax_substateT this_state;
    int32_t aim;
#endif /* !defined(ARM) */

    int32_t growth;
    uint32_t was_address;
    int32_t offset;
    symbolS *symbolP;
    int32_t target;
    int32_t after;
    uint32_t oldoff, newoff;
    int ret;

	ret = 0;
	growth = 0;

	/*
	 * For each frag in segment count and store (a 1st guess of) fr_address.
	 */
	address = 0;
	for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
#ifdef ARM
            fragP->relax_marker = 0;
#endif /* ARM */
	    fragP->fr_address = address;
	    address += fragP->fr_fix;
	    switch(fragP->fr_type){
	    case rs_fill:
		address += fragP->fr_offset * fragP->fr_var;
		break;

	    case rs_align:
		offset = relax_align (address, (int) fragP->fr_offset);
		/*
		 * If a maximum number of bytes to fill was specified for this
		 * align (stored in fr_subtype) then check to see if this align
		 * can be done.  If not ignore it.  If so and this alignment is
		 * larger than any previous alignment then this becomes the
		 * section's alignment.
		 */
		if(fragP->fr_subtype != 0){
		    if(offset > (int32_t)fragP->fr_subtype){
			offset = 0;
		    }
		    else{
			if(frchain_now->frch_section.align <
			   (uint32_t)fragP->fr_offset)
			    frchain_now->frch_section.align = fragP->fr_offset;
		    }
		}
		address += offset;
		break;

	    case rs_org:
		/*
		 * Assume .org is nugatory. It will grow with 1st relax.
		 */
		break;

	    case rs_machine_dependent:
		address += md_estimate_size_before_relax(fragP, nsect);
		break;

	    case rs_dwarf2dbg:
		address += dwarf2dbg_estimate_size_before_relax(fragP);
		break;

	    case rs_leb128:
	      /* Initial guess is always 1; doing otherwise can result in
		 stable solutions that are larger than the minimum.  */
	      address += fragP->fr_offset = 1;
	      break;

	    default:
		BAD_CASE(fragP->fr_type);
		break;
	    }
	}

	/*
	 * Do relax().
	 * Make repeated passes over the chain of frags allowing each frag to
	 * grow if needed.  On each pass each frag's address is incremented by
	 * the accumulated growth, kept in stretched.  Passes are continued 
	 * until there is no stretch on the previous pass.
	 */
	do{
	    stretch = 0;
	    stretched = 0;
	    for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
#ifdef ARM
                fragP->relax_marker ^= 1;
#endif /* ARM */
		was_address = fragP->fr_address;
		fragP->fr_address += stretch;
		address = fragP->fr_address;
		symbolP = fragP->fr_symbol;
		offset = fragP->fr_offset;
		switch(fragP->fr_type){
		case rs_fill:	/* .fill never relaxes. */
		    growth = 0;
		    break;

		case rs_align:
		    oldoff = relax_align(was_address + fragP->fr_fix, offset);
		    newoff = relax_align(address + fragP->fr_fix, offset);
		    /*
		     * Check if a maximum number of bytes to fill was specified
		     * for this align (stored in fr_subtype).
		     */
		    if(fragP->fr_subtype != 0){
			if(oldoff > fragP->fr_subtype)
			    oldoff = 0;
			if(newoff > fragP->fr_subtype)
			    newoff = 0;
		    }
		    growth = newoff - oldoff;
		    break;

		case rs_org:
		    target = offset;
		    if(symbolP != NULL){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag );
			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
		    }
		    know(fragP->fr_next);
		    after = fragP->fr_next->fr_address;
		    /*
		     * Growth may be negative, but variable part of frag cannot
		     * have < 0 chars. That is, we can't .org backwards.
		     */
		    growth = ((target - after ) > 0) ? (target - after) : 0;

		    growth -= stretch;	/* This is an absolute growth factor */
		    break;

		case rs_machine_dependent:
#ifdef ARM
		    growth = arm_relax_frag(nsect, fragP, stretch);
#else /* !defined(ARM) */
		    this_state = fragP->fr_subtype;
		    this_type = md_relax_table + this_state;
		    start_type = this_type;

		    target = offset;
		    if(symbolP){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag);

			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
			/*
			 * If frag has yet to be reached on this pass,
			 * assume it will move by STRETCH just as we did.
			 * If this is not so, it will be because some frag
			 * between grows, and that will force another pass.
			 */
			if(symbolP->sy_frag->fr_address >= was_address &&
			   is_down_range(fragP, symbolP->sy_frag))
			    target += stretch;
		    }
		    aim = target - address - fragP->fr_fix;
		    if(aim < 0){
			/* Look backwards. */
			for(next_state = this_type->rlx_more; next_state; ){
			    if(aim >= this_type->rlx_backward)
				next_state = 0;
			    else{	/* Grow to next state. */
				this_state = next_state;
				this_type = md_relax_table + this_state;
				next_state = this_type->rlx_more;
			    }
			}
		    }
		    else{
			/* Look forwards. */
			for(next_state = this_type->rlx_more; next_state; ){
			    if(aim <= this_type->rlx_forward)
				next_state = 0;
			    else{	/* Grow to next state. */
				this_state = next_state;
				this_type = md_relax_table + this_state;
				next_state = this_type->rlx_more;
			    }
			}
		    }
		    if((growth = this_type->rlx_length -start_type->rlx_length))
			  fragP->fr_subtype = this_state;
#endif /* !defined(ARM) */
		    break;
		  case rs_dwarf2dbg:
		      growth = dwarf2dbg_relax_frag(fragP);
		      break;

		  case rs_leb128:
		    {
		      valueT value;
		      offsetT size;
#ifdef OLD
		      value = resolve_symbol_value (fragP->fr_symbol);
#else
  		      expressionS *expression;
  		
		      if(fragP->fr_symbol->expression != NULL){
			expression =
			  (expressionS *)fragP->fr_symbol->expression;
			value = 0;
			if(expression->X_add_symbol != NULL)
			    value +=
			     (expression->X_add_symbol->sy_nlist.n_value +
			      expression->X_add_symbol->sy_frag->fr_address);
			if(expression->X_subtract_symbol != NULL)
			   value -= 
			     (expression->X_subtract_symbol->sy_nlist.n_value +
			      expression->X_subtract_symbol->
							   sy_frag->fr_address);
			value += expression->X_add_number;
		      }
		      else{
			value = fragP->fr_symbol->sy_nlist.n_value +
				fragP->fr_address;
		      }
#endif
		      size = sizeof_leb128 (value, fragP->fr_subtype);
		      growth = size - fragP->fr_offset;
		      fragP->fr_offset = size;
		    }
		    break;

		  default:
		      BAD_CASE(fragP->fr_type);
		      break;
		}
		if(growth) {
		    stretch += growth;
		    stretched++;
		}
	    }			/* For each frag in the segment. */
	}while(stretched);	/* Until nothing further to relax. */

	/*
	 * We now have valid fr_address'es for each frag.  All fr_address's
	 * are correct, relative to their own section.  We have made all the
	 * fixS for this section that will be made.
	 */

	for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
	    if(fragP->last_fr_address != fragP->fr_address){
		fragP->last_fr_address = fragP->fr_address;
		ret = 1;
	    }
	}
	return(ret);
}
static int
i386_intel_operand (char *operand_string, int got_a_float)
{
  char *saved_input_line_pointer, *buf;
  segT exp_seg;
  expressionS exp, *expP;
  char suffix = 0;
  int ret;

  /* Initialize state structure.  */
  intel_state.op_modifier = O_absent;
  intel_state.is_mem = 0;
  intel_state.base = NULL;
  intel_state.index = NULL;
  intel_state.seg = NULL;
  operand_type_set (&intel_state.reloc_types, ~0);
  gas_assert (!intel_state.in_offset);
  gas_assert (!intel_state.in_bracket);
  gas_assert (!intel_state.in_scale);

  saved_input_line_pointer = input_line_pointer;
  input_line_pointer = buf = xstrdup (operand_string);

  /* A '$' followed by an identifier char is an identifier.  Otherwise,
     it's operator '.' followed by an expression.  */
  if (*buf == '$' && !is_identifier_char (buf[1]))
    *buf = '.';

  intel_syntax = -1;
  memset (&exp, 0, sizeof(exp));
  exp_seg = expression (&exp);
  ret = i386_intel_simplify (&exp);
  intel_syntax = 1;

  SKIP_WHITESPACE ();
  if (!is_end_of_line[(unsigned char) *input_line_pointer])
    {
      as_bad (_("junk `%s' after expression"), input_line_pointer);
      ret = 0;
    }
  else if (exp.X_op == O_illegal || exp.X_op == O_absent)
    {
      as_bad (_("invalid expression"));
      ret = 0;
    }

  input_line_pointer = saved_input_line_pointer;
  free (buf);

  gas_assert (!intel_state.in_offset);
  gas_assert (!intel_state.in_bracket);
  gas_assert (!intel_state.in_scale);

  if (!ret)
    return 0;

  if (intel_state.op_modifier != O_absent
      && current_templates->start->base_opcode != 0x8d /* lea */)
    {
      i.types[this_operand].bitfield.unspecified = 0;

      switch (intel_state.op_modifier)
	{
	case O_byte_ptr:
	  i.types[this_operand].bitfield.byte = 1;
	  suffix = BYTE_MNEM_SUFFIX;
	  break;

	case O_word_ptr:
	  i.types[this_operand].bitfield.word = 1;
	  if ((current_templates->start->name[0] == 'l'
	       && current_templates->start->name[2] == 's'
	       && current_templates->start->name[3] == 0)
	      || current_templates->start->base_opcode == 0x62 /* bound */)
	    suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
	  else if (got_a_float == 2)	/* "fi..." */
	    suffix = SHORT_MNEM_SUFFIX;
	  else
	    suffix = WORD_MNEM_SUFFIX;
	  break;

	case O_dword_ptr:
	  i.types[this_operand].bitfield.dword = 1;
	  if ((current_templates->start->name[0] == 'l'
	       && current_templates->start->name[2] == 's'
	       && current_templates->start->name[3] == 0)
	      || current_templates->start->base_opcode == 0x62 /* bound */)
	    suffix = WORD_MNEM_SUFFIX;
	  else if (flag_code == CODE_16BIT
		   && (current_templates->start->opcode_modifier.jump
		       || current_templates->start->opcode_modifier.jumpdword))
	    suffix = LONG_DOUBLE_MNEM_SUFFIX;
	  else if (got_a_float == 1)	/* "f..." */
	    suffix = SHORT_MNEM_SUFFIX;
	  else
	    suffix = LONG_MNEM_SUFFIX;
	  break;

	case O_fword_ptr:
	  i.types[this_operand].bitfield.fword = 1;
	  if (current_templates->start->name[0] == 'l'
	      && current_templates->start->name[2] == 's'
	      && current_templates->start->name[3] == 0)
	    suffix = LONG_MNEM_SUFFIX;
	  else if (!got_a_float)
	    {
	      if (flag_code == CODE_16BIT)
		add_prefix (DATA_PREFIX_OPCODE);
	      suffix = LONG_DOUBLE_MNEM_SUFFIX;
	    }
	  else
	    suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
	  break;

	case O_qword_ptr:
	  i.types[this_operand].bitfield.qword = 1;
	  if (current_templates->start->base_opcode == 0x62 /* bound */
	      || got_a_float == 1)	/* "f..." */
	    suffix = LONG_MNEM_SUFFIX;
	  else
	    suffix = QWORD_MNEM_SUFFIX;
	  break;

	case O_tbyte_ptr:
	  i.types[this_operand].bitfield.tbyte = 1;
	  if (got_a_float == 1)
	    suffix = LONG_DOUBLE_MNEM_SUFFIX;
	  else
	    suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
	  break;

	case O_oword_ptr:
	case O_xmmword_ptr:
	  i.types[this_operand].bitfield.xmmword = 1;
	  suffix = XMMWORD_MNEM_SUFFIX;
	  break;

	case O_ymmword_ptr:
	  i.types[this_operand].bitfield.ymmword = 1;
	  suffix = YMMWORD_MNEM_SUFFIX;
	  break;

	case O_far_ptr:
	  suffix = LONG_DOUBLE_MNEM_SUFFIX;
	  /* FALLTHROUGH */
	case O_near_ptr:
	  if (!current_templates->start->opcode_modifier.jump
	      && !current_templates->start->opcode_modifier.jumpdword)
	    suffix = got_a_float /* so it will cause an error */
		     ? BYTE_MNEM_SUFFIX
		     : LONG_DOUBLE_MNEM_SUFFIX;
	  break;

	default:
	  BAD_CASE (intel_state.op_modifier);
	  break;
	}

      if (!i.suffix)
	i.suffix = suffix;
      else if (i.suffix != suffix)
	{
	  as_bad (_("conflicting operand size modifiers"));
	  return 0;
	}
    }

  /* Operands for jump/call need special consideration.  */
  if (current_templates->start->opcode_modifier.jump
      || current_templates->start->opcode_modifier.jumpdword
      || current_templates->start->opcode_modifier.jumpintersegment)
    {
      if (i.op[this_operand].regs || intel_state.base || intel_state.index
	  || intel_state.is_mem > 1)
	i.types[this_operand].bitfield.jumpabsolute = 1;
      else
	switch (intel_state.op_modifier)
	  {
	  case O_near_ptr:
	    if (intel_state.seg)
	      i.types[this_operand].bitfield.jumpabsolute = 1;
	    else
	      intel_state.is_mem = 1;
	    break;
	  case O_far_ptr:
	  case O_absent:
	    if (!intel_state.seg)
	      {
		intel_state.is_mem = 1;
		if (intel_state.op_modifier == O_absent)
		  break;
		as_bad (_("cannot infer the segment part of the operand"));
		return 0;
	      }
	    else if (S_GET_SEGMENT (intel_state.seg) == reg_section)
	      i.types[this_operand].bitfield.jumpabsolute = 1;
	    else
	      {
		i386_operand_type types;

		if (i.imm_operands >= MAX_IMMEDIATE_OPERANDS)
		  {
		    as_bad (_("at most %d immediate operands are allowed"),
			    MAX_IMMEDIATE_OPERANDS);
		    return 0;
		  }
		expP = &im_expressions[i.imm_operands++];
		memset (expP, 0, sizeof(*expP));
		expP->X_op = O_symbol;
		expP->X_add_symbol = intel_state.seg;
		i.op[this_operand].imms = expP;

		resolve_expression (expP);
		operand_type_set (&types, ~0);
		if (!i386_finalize_immediate (S_GET_SEGMENT (intel_state.seg),
					      expP, types, operand_string))
		  return 0;
		if (i.operands < MAX_OPERANDS)
		  {
		    this_operand = i.operands++;
		    i.types[this_operand].bitfield.unspecified = 1;
		  }
		if (suffix == LONG_DOUBLE_MNEM_SUFFIX)
		  i.suffix = 0;
		intel_state.seg = NULL;
		intel_state.is_mem = 0;
	      }
	    break;
	  default:
	    i.types[this_operand].bitfield.jumpabsolute = 1;
	    break;
	  }
      if (i.types[this_operand].bitfield.jumpabsolute)
	intel_state.is_mem |= 1;
    }
  else if (intel_state.seg)
    intel_state.is_mem |= 1;

  if (i.op[this_operand].regs)
    {
      i386_operand_type temp;

      /* Register operand.  */
      if (intel_state.base || intel_state.index || intel_state.seg)
	{
	  as_bad (_("invalid operand"));
	  return 0;
	}

      temp = i.op[this_operand].regs->reg_type;
      temp.bitfield.baseindex = 0;
      i.types[this_operand] = operand_type_or (i.types[this_operand], temp);
      i.types[this_operand].bitfield.unspecified = 0;
      ++i.reg_operands;
    }
  else if (intel_state.base || intel_state.index || intel_state.seg
	   || intel_state.is_mem)
    {
      /* Memory operand.  */
      if (i.mem_operands
	  >= 2 - !current_templates->start->opcode_modifier.isstring)
	{
	  as_bad (_("too many memory references for `%s'"),
		  current_templates->start->name);
	  return 0;
	}

      expP = &disp_expressions[i.disp_operands];
      memcpy (expP, &exp, sizeof(exp));
      resolve_expression (expP);

      if (expP->X_op != O_constant || expP->X_add_number
	  || (!intel_state.base && !intel_state.index))
	{
	  i.op[this_operand].disps = expP;
	  i.disp_operands++;

	  if (flag_code == CODE_64BIT)
	    {
	      i.types[this_operand].bitfield.disp32 = 1;
	      if (!i.prefix[ADDR_PREFIX])
		{
		  i.types[this_operand].bitfield.disp64 = 1;
		  i.types[this_operand].bitfield.disp32s = 1;
		}
	    }
	  else if (!i.prefix[ADDR_PREFIX] ^ (flag_code == CODE_16BIT))
	    i.types[this_operand].bitfield.disp32 = 1;
	  else
	    i.types[this_operand].bitfield.disp16 = 1;

#if defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)
	  /*
	   * exp_seg is used only for verification in
	   * i386_finalize_displacement, and we can end up seeing reg_section
	   * here - but we know we removed all registers from the expression
	   * (or error-ed on any remaining ones) in i386_intel_simplify.  I
	   * consider the check in i386_finalize_displacement bogus anyway, in
	   * particular because it doesn't allow for expr_section, so I'd
	   * rather see that check (and the similar one in
	   * i386_finalize_immediate) use SEG_NORMAL(), but not being an a.out
	   * expert I can't really say whether that would have other bad side
	   * effects.
	   */
	  if (OUTPUT_FLAVOR == bfd_target_aout_flavour
	      && exp_seg == reg_section)
	    exp_seg = expP->X_op != O_constant ? undefined_section
					       : absolute_section;
#endif

	  if (!i386_finalize_displacement (exp_seg, expP,
					   intel_state.reloc_types,
					   operand_string))
	    return 0;
	}

      if (intel_state.base || intel_state.index)
	i.types[this_operand].bitfield.baseindex = 1;

      if (intel_state.seg)
	{
	  for (;;)
	    {
	      expP = symbol_get_value_expression (intel_state.seg);
	      if (expP->X_op != O_full_ptr)
		break;
	      intel_state.seg = expP->X_add_symbol;
	    }
	  if (expP->X_op != O_register)
	    {
	      as_bad (_("segment register name expected"));
	      return 0;
	    }
	  if (!i386_regtab[expP->X_add_number].reg_type.bitfield.sreg2
	      && !i386_regtab[expP->X_add_number].reg_type.bitfield.sreg3)
	    {
	      as_bad (_("invalid use of register"));
	      return 0;
	    }
	  switch (i386_regtab[expP->X_add_number].reg_num)
	    {
	    case 0: i.seg[i.mem_operands] = &es; break;
	    case 1: i.seg[i.mem_operands] = &cs; break;
	    case 2: i.seg[i.mem_operands] = &ss; break;
	    case 3: i.seg[i.mem_operands] = &ds; break;
	    case 4: i.seg[i.mem_operands] = &fs; break;
	    case 5: i.seg[i.mem_operands] = &gs; break;
	    case RegFlat: i.seg[i.mem_operands] = NULL; break;
	    }
	}

      /* Swap base and index in 16-bit memory operands like
	 [si+bx]. Since i386_index_check is also used in AT&T
	 mode we have to do that here.  */
      if (intel_state.base
	  && intel_state.index
	  && intel_state.base->reg_type.bitfield.reg16
	  && intel_state.index->reg_type.bitfield.reg16
	  && intel_state.base->reg_num >= 6
	  && intel_state.index->reg_num < 6)
	{
	  i.base_reg = intel_state.index;
	  i.index_reg = intel_state.base;
	}
      else
	{
	  i.base_reg = intel_state.base;
	  i.index_reg = intel_state.index;
	}

      if (!i386_index_check (operand_string))
	return 0;

      i.types[this_operand].bitfield.mem = 1;
      ++i.mem_operands;
    }
  else
    {
      /* Immediate.  */
      if (i.imm_operands >= MAX_IMMEDIATE_OPERANDS)
	{
	  as_bad (_("at most %d immediate operands are allowed"),
		  MAX_IMMEDIATE_OPERANDS);
	  return 0;
	}

      expP = &im_expressions[i.imm_operands++];
      i.op[this_operand].imms = expP;
      *expP = exp;

      return i386_finalize_immediate (exp_seg, expP, intel_state.reloc_types,
				      operand_string);
    }

  return 1;
}
/*
 * We allow an empty expression, and just assume (absolute,0) silently.
 * Unary operators and parenthetical expressions are treated as operands.
 * As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
 *
 * Most expressions are either register (which does not even reach here)
 * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common.
 *
 * After expr(RANK,resultP) input_line_pointer -> operator of rank <= RANK.
 * Also, we have consumed any leading or trailing spaces (operand does that)
 * and done all intervening operators.
 */
static
segT	/* Return resultP -> X_seg */
expr(
operator_rankT	rank, /* larger # is higher rank */
expressionS *resultP) /* deliver result here */
{
    expressionS	right;
    operatorT	op_left;
    char	c_left;	/* 1st operator character. */
    operatorT	op_right;
    char	c_right;

	know(rank >= 0);

	(void)operand(resultP);
	know(*input_line_pointer != ' '); /* Operand() gobbles spaces. */

	c_left = *input_line_pointer; /* Potential operator character. */
	op_left = (operatorT)op_encoding[(int)c_left];
	if(op_left == two_char_operator)
	    op_left = two_char_op_encoding(c_left);

	while(op_left != O_illegal && op_rank[op_left] > rank){

	    input_line_pointer += op_size[op_left];
	    /* -> after 1st character of operator. */

	    if(SEG_NONE == expr(op_rank[op_left], &right)){
		as_warn("Missing operand value assumed absolute 0.");
		resultP->X_add_number		= 0;
		resultP->X_subtract_symbol	= NULL;
		resultP->X_add_symbol		= NULL;
		resultP->X_seg			= SEG_ABSOLUTE;
	    }
	    know(*input_line_pointer != ' ');

	    c_right = *input_line_pointer;
	    op_right = (operatorT)op_encoding[(int)c_right];
	    if(op_right == two_char_operator)
		op_right = two_char_op_encoding(c_right);

	    /* -> after 1st character of operator. */
	    know(op_right == 0 || op_rank [op_right] <= op_rank[op_left]);

	    /* input_line_pointer -> after right-hand quantity. */
	    /* left-hand quantity in resultP */
	    /* right-hand quantity in right. */
	    /* operator in op_left. */

	    /*
	     * Operations are not supported on bignums or floating-point
	     * operands.
	     */
	    if(resultP->X_seg == SEG_BIG){
		as_warn("Left operand of %c is a %s integer 0 assumed",
			c_left, resultP->X_add_number > 0 ? "bignum" :
			"float");
		resultP->X_seg = SEG_ABSOLUTE;
		resultP->X_add_symbol = 0;
		resultP->X_subtract_symbol = 0;
		resultP->X_add_number = 0;
	    }
	    if(right.X_seg == SEG_BIG){
		as_warn("Right operand of %c is a %s integer 0 assumed",
			c_left, right.X_add_number > 0 ? "bignum" :
			"float");
		right.X_seg = SEG_ABSOLUTE;
		right.X_add_symbol = 0;
		right.X_subtract_symbol = 0;
		right.X_add_number = 0;
	    }
	    if(op_left == O_subtract){
		/*
		 * Convert - into + by exchanging symbols and negating
		 * number. I know -infinity can't be negated in 2's
		 * complement: but then it can't be subtracted either.
		 * This trick does not cause any further inaccuracy.
		 */
		struct symbol *symbolP;

		right.X_add_number      = - right.X_add_number;
		symbolP                 = right.X_add_symbol;
		right.X_add_symbol	    = right.X_subtract_symbol;
		right.X_subtract_symbol = symbolP;
		if(symbolP){
/* This is not used, as it drops in to the next if */
		    right.X_seg	    = SEG_DIFFSECT;
		}
		op_left = O_add;
	    }
	    if(op_left == O_add){
		segT seg1;
		segT seg2;
		
/* not SEG_NONE and not SEG_BIG */
		know(resultP->X_seg == SEG_SECT ||
		     resultP->X_seg == SEG_UNKNOWN ||
		     resultP->X_seg == SEG_DIFFSECT ||
		     resultP->X_seg == SEG_ABSOLUTE);
/* not SEG_NONE and not SEG_BIG */
		know(right.X_seg == SEG_SECT ||
		     right.X_seg == SEG_UNKNOWN ||
		     right.X_seg == SEG_DIFFSECT ||
		     right.X_seg == SEG_ABSOLUTE);
		
		clean_up_expression(&right);
		clean_up_expression(resultP);

/* could this just return -1 instead of SEG_PASS1? and tested in the below if
statement */
		seg1 = expr_part(&resultP->X_add_symbol,
				 right.X_add_symbol);
		seg2 = expr_part(&resultP->X_subtract_symbol,
				 right.X_subtract_symbol);
		if((int)seg1 == -1 || (int)seg2 == -1){
		    as_warn("Can't relocate expression. Absolute 0 assumed.");
		    resultP->X_seg        = SEG_ABSOLUTE;
		    resultP->X_add_number = 0;
		}
		else{
		    if(seg2 == SEG_ABSOLUTE){
			resultP->X_seg = seg1;
		    }
		    else{
/* also know seg2 != -1 (SEG_PASS1) */
			know(seg2 != SEG_ABSOLUTE);
/* seg2 is for the subtract symbols, since seg2 != SEG_ABSOLUTE as would be
returned when there is no subtract symbols then expr_part() must have
combined a symbol into resultP->X_subtract_symbol that is either undefined
or defined in a section. */
			know(resultP->X_subtract_symbol);
			/*
			 * If we are not to use the new incompatible features
			 * then "symbol1 - symbol2" must both be in the same
			 * section and will turn out as absolute.
			 */
			if(!flagseen['k']){
			    if(seg1 != SEG_UNKNOWN &&
			       seg1 != SEG_ABSOLUTE &&
			       seg2 != SEG_UNKNOWN &&
			       seg1 != seg2 &&
			       resultP->X_add_symbol->sy_other !=
			       resultP->X_subtract_symbol->sy_other){
				know(seg1 == SEG_SECT);
				know(seg2 == SEG_SECT);
				know(resultP->X_add_symbol);
				know(resultP->X_subtract_symbol);
				as_warn("Expression too complex: "
				       "forgetting %s - %s",
				       resultP->X_add_symbol->sy_name,
				       resultP->X_subtract_symbol->sy_name);
				resultP->X_seg = SEG_ABSOLUTE;
				/* Clean_up_expression() will do the rest */
			    }
			    else{
/* this can result in returning an expression that is NULL - symbol and the
caller must deal with this being illegal.  maybe this should be put in
expression() routine (not a macro).  Note the code in cons() */
				resultP->X_seg = SEG_DIFFSECT;
			    }	/* If relocation too complex. */
			}
			else{
			    resultP->X_seg = SEG_DIFFSECT;
			}

		    }		/* If seg2 == SEG_ABSOLUTE. */
		}		/* If need pass 2. */
		resultP->X_add_number += right.X_add_number;
		clean_up_expression(resultP);
	    }
	    else{	/* Not +. */
		if(resultP->X_seg == SEG_UNKNOWN ||
		   right.X_seg == SEG_UNKNOWN){
		    as_warn("Can't relocate expression. Absolute 0 assumed.");
		    resultP->X_seg        = SEG_ABSOLUTE;
		    resultP->X_add_number = 0;
		}
		else{
		    /*
		     * Will be SEG_ABSOLUTE. (or error)
		     */
		    try_to_make_absolute(resultP);
		    try_to_make_absolute(&right);
		    resultP->X_subtract_symbol = NULL;
		    resultP->X_add_symbol = NULL;
		    if(resultP->X_seg != SEG_ABSOLUTE ||
		       right.X_seg != SEG_ABSOLUTE){
			as_warn("Relocation error. Absolute 0 assumed");
			resultP->X_seg        = SEG_ABSOLUTE;
			resultP->X_add_number = 0;
		    }
		    else{
			/*
			 * Both are absolute so perform the operation
			 * on the constants.
			 */
			switch(op_left){
			case O_bit_inclusive_or:
			    resultP->X_add_number |= right.X_add_number;
			    break;
			  
			case O_modulus:
			    if(right.X_add_number){
				resultP->X_add_number %=
					right.X_add_number;
			    }
			    else{
				as_warn("Division by 0. 0 assumed.");
				resultP->X_add_number = 0;
			    }
			    break;
			  
			case O_bit_and:
			    resultP->X_add_number &= right.X_add_number;
			    break;
			  
			case O_multiply:
			    resultP->X_add_number *= right.X_add_number;
			    break;
			  
			case O_divide:
			    if(right.X_add_number){
				resultP->X_add_number /=
					right.X_add_number;
			    }
			    else{
				as_warn("Division by 0. 0 assumed.");
				resultP->X_add_number = 0;
			    }
			    break;
			  
			case O_left_shift:
			    resultP->X_add_number <<=
				right.X_add_number;
			    break;
			  
			case O_right_shift:
			    resultP->X_add_number >>=
				right.X_add_number;
			    break;
			  
			case O_bit_exclusive_or:
			    resultP->X_add_number ^= right.X_add_number;
			    break;
			  
			case O_bit_or_not:
			    resultP->X_add_number |=
				~right.X_add_number;
			    break;

			case O_less_than:
			    resultP->X_add_number =
			       (resultP->X_add_number <
				  right.X_add_number);
			    break;
		      
			case O_greater_than:
			    resultP->X_add_number =
			       (resultP->X_add_number >
				  right.X_add_number);
			    break;
		      
			case O_less_than_or_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number <=
				  right.X_add_number);
			    break;
		      
			case O_greater_than_or_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number >=
				  right.X_add_number);
			    break;
		      
			case O_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number ==
				  right.X_add_number);
			    break;
		      
			case O_not_equal:
			    resultP->X_add_number =
			       (resultP->X_add_number !=
				  right.X_add_number);
			    break;
			  
			default:
			    BAD_CASE( op_left );
			    break;
			}	/* switch(op_left) */
		    }
		}		/* If we have to force need_pass_2 */
	    } 		/* If operator was + */
	    op_left = op_right;
	}			/* While next operator is >= this rank */
	return(resultP->X_seg);
}
Beispiel #7
0
/*
 * layout_addresses() is called after all the assembly code has been read and
 * fragments, symbols and fixups have been created.  This routine sets the
 * address of the fragments and symbols.  Then it does the fixups of the frags
 * and prepares the fixes so relocation entries can be created from them.
 */
void
layout_addresses(
void)
{
    struct frchain *frchainP;
    fragS *fragP;
    relax_addressT slide, tmp;
    symbolS *symbolP;
    unsigned long nbytes, fill_size, repeat_expression, partial_bytes;

	if(frchain_root == NULL)
	    return;

	/*
	 * If there is any current frag close it off.
	 */
	if(frag_now != NULL && frag_now->fr_fix == 0){
	    frag_now->fr_fix = obstack_next_free(&frags) -
			       frag_now->fr_literal;
	    frag_wane(frag_now);
	}

	/*
	 * For every section, add a last ".fill 0" frag that will later be used
	 * as the ending address of that section.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * We must do the obstack_finish(), so the next object we put on
	     * obstack frags will not appear to start at the fr_literal of the
	     * current frag.  Also, it ensures that the next object will begin
	     * on a address that is aligned correctly for the engine that runs
	     * the assembler.
	     */
	    obstack_finish(&frags);

	    /*
	     * Make a fresh frag for the last frag.
	     */
	    frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
	    memset(frag_now, '\0', SIZEOF_STRUCT_FRAG);
	    frag_now->fr_next = NULL;
	    obstack_finish(&frags);

	    /*
	     * Append the new frag to current frchain.
	     */
	    frchainP->frch_last->fr_next = frag_now;
	    frchainP->frch_last = frag_now;
	    frag_wane(frag_now);

	}

	/*
	 * Now set the relitive addresses of frags within the section by
	 * relaxing each section.  That is all sections will start at address
	 * zero and addresses of the frags in that section will increase from
	 * there.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    /*
	     * This is done so in case md_estimate_size_before_relax() (called
	     * by relax_section) wants to make fixSs they are for this
	     * section.
	     */
	    frchain_now = frchainP;

	    relax_section(frchainP->frch_root, frchainP->frch_nsect);
	}

	/*
	 * Now set the absolute addresses of all frags by sliding the frags in
	 * each non-zerofill section by the address ranges taken up by the
	 * sections before it.
	 */ 
	slide = 0;
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);
	    tmp = frchainP->frch_last->fr_address;
	    if(slide != 0){
		for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		    fragP->fr_address += slide;
		}
	    }
	    slide += tmp;
	}
	/*
	 * Now with the non-zerofill section addresses set set all of the
	 * addresses of the zerofill sections.  Comming in the fr_address is
	 * the size of the section and going out it is the start address.  This
	 * will make layout_symbols() work out naturally.  The only funky thing
	 * is that section numbers do not end up in address order.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL)
		continue;
	    slide = round(slide, 1 << frchainP->frch_section.align);

	    tmp = frchainP->frch_root->fr_address;
	    frchainP->frch_root->fr_address = slide;
	    frchainP->frch_last->fr_address = tmp + slide;
	    slide += tmp;
	}

	/*
	 * Set the symbol addresses based on there frag's address.
	 * First forward references are handled.
	 */
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    if(symbolP->sy_forward != NULL){
		if(symbolP->sy_nlist.n_type & N_STAB)
		    symbolP->sy_other = symbolP->sy_forward->sy_other;
		symbolP->sy_value += symbolP->sy_forward->sy_value +
				     symbolP->sy_forward->sy_frag->fr_address;
		symbolP->sy_forward = 0;
	    }
	}
	for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){
	    symbolP->sy_value += symbolP->sy_frag->fr_address;
	}

	/*
	 * At this point the addresses of frags now reflect addresses we use in 
	 * the object file and the symbol values are correct.
	 * Scan the frags, converting any ".org"s and ".align"s to ".fill"s.
	 * Also converting any machine-dependent frags using md_convert_frag();
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    /*
	     * This is done so any fixes created by md_convert_frag() are for
	     * this section.
	     */
	    frchain_now = frchainP;

	    for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){
		switch(fragP->fr_type){
		case rs_align:
		case rs_org:
		    /* convert this frag to an rs_fill type */
		    fragP->fr_type = rs_fill;
		    /*
		     * Calculate the number of bytes the variable part of the
		     * the rs_fill frag will need to fill.  Then calculate this
		     * as the fill_size * repeat_expression + partial_bytes.
		     */
		    know(fragP->fr_next != NULL);
		    nbytes = fragP->fr_next->fr_address -
			     fragP->fr_address -
			     fragP->fr_fix;
		    if(nbytes < 0){
			as_warn("rs_org invalid, dot past value by %ld bytes",
				nbytes);
			nbytes = 0;
		    }
		    fill_size = fragP->fr_var;
		    repeat_expression = nbytes / fill_size;
		    partial_bytes = nbytes - (repeat_expression * fill_size);
		    /*
		     * Now set the fr_offset to the fill repeat_expression
		     * since this is now an rs_fill type.  The fr_var is still
		     * the fill_size.
		     */
		    fragP->fr_offset = repeat_expression;
		    /*
		     * For rs_align frags there may be partial_bytes to fill
		     * with zeros before we can fill with the fill_expression
		     * of fill_size.  When the rs_align frag was created it was
		     * created with fill_size-1 extra bytes in the fixed part.
		     */
		    if(partial_bytes != 0){
			/* moved the fill_expression bytes foward */
			memmove(fragP->fr_literal +fragP->fr_fix +partial_bytes,
				fragP->fr_literal +fragP->fr_fix,
				fragP->fr_var);
    			/* zero out the partial_bytes */
    			memset(fragP->fr_literal + fragP->fr_fix,
			       '\0',
			       partial_bytes);
			/* adjust the fixed part of the frag */
    			fragP->fr_fix += partial_bytes;
		    }
		    break;

		case rs_fill:
		    break;

		case rs_machine_dependent:
		    md_convert_frag(fragP);
		    /*
		     * After md_convert_frag, we make the frag into a ".fill 0"
		     * md_convert_frag() should set up any fixSs and constants
		     * required.
		     */
		    frag_wane(fragP);
		    break;

		default:
		    BAD_CASE(fragP->fr_type);
		    break;
		}
	    }
	}

	/*
	 * For each section do the fixups for the frags.
	 */
	for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){
	    fixup_section(frchainP->frch_fix_root, frchainP->frch_nsect);
	}
}
Beispiel #8
0
/*
 * relax_section() here we set the fr_address values in the frags.
 * After this, all frags in this segment have addresses that are correct
 * relative to the section (that is the section starts at address zero).
 * After all of the sections have been processed by this call and their sizes
 * are know then they can be slid to their final address.
 */
static
void
relax_section(
struct frag *frag_root,
int nsect)
{
    struct frag *fragP;
    relax_addressT address;

    long stretch; /* May be any size, 0 or negative. */
		  /* Cumulative number of addresses we have */
		  /* relaxed this pass. */
		  /* We may have relaxed more than one address. */
    long stretched;  /* Have we stretched on this pass? */
		    /* This is 'cuz stretch may be zero, when,
		       in fact some piece of code grew, and
		       another shrank.  If a branch instruction
		       doesn't fit anymore, we need another pass */

    const relax_typeS *this_type;
    const relax_typeS *start_type;
    relax_substateT next_state;
    relax_substateT this_state;

    long growth;
    unsigned long was_address;
    long offset;
    symbolS *symbolP;
    long target;
    long after;
    long aim;
    unsigned long oldoff, newoff;

	growth = 0;

	/*
	 * For each frag in segment count and store (a 1st guess of) fr_address.
	 */
	address = 0;
	for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
	    fragP->fr_address = address;
	    address += fragP->fr_fix;
	    switch(fragP->fr_type){
	    case rs_fill:
		address += fragP->fr_offset * fragP->fr_var;
		break;

	    case rs_align:
		offset = relax_align (address, (int) fragP->fr_offset);
		/*
		 * If a maximum number of bytes to fill was specified for this
		 * align (stored in fr_subtype) then check to see if this align
		 * can be done.  If not ignore it.  If so and this alignment is
		 * larger than any previous alignment then this becomes the
		 * section's alignment.
		 */
		if(fragP->fr_subtype != 0){
		    if(offset > (long)fragP->fr_subtype){
			offset = 0;
		    }
		    else{
			if(frchain_now->frch_section.align <
			   (unsigned long)fragP->fr_offset)
			    frchain_now->frch_section.align = fragP->fr_offset;
		    }
		}
		address += offset;
		break;

	    case rs_org:
		/*
		 * Assume .org is nugatory. It will grow with 1st relax.
		 */
		break;

	    case rs_machine_dependent:
		address += md_estimate_size_before_relax(fragP, nsect);
		break;

	    default:
		BAD_CASE(fragP->fr_type);
		break;
	    }
	}

	/*
	 * Do relax().
	 * Make repeated passes over the chain of frags allowing each frag to
	 * grow if needed.  On each pass each frag's address is incremented by
	 * the accumulated growth, kept in stretched.  Passes are continued 
	 * until there is no stretch on the previous pass.
	 */
	do{
	    stretch = 0;
	    stretched = 0;
	    for(fragP = frag_root; fragP != NULL; fragP = fragP->fr_next){
		was_address = fragP->fr_address;
		fragP->fr_address += stretch;
		address = fragP->fr_address;
		symbolP = fragP->fr_symbol;
		offset = fragP->fr_offset;
		switch(fragP->fr_type){
		case rs_fill:	/* .fill never relaxes. */
		    growth = 0;
		    break;

		case rs_align:
		    oldoff = relax_align(was_address + fragP->fr_fix, offset);
		    newoff = relax_align(address + fragP->fr_fix, offset);
		    /*
		     * Check if a maximum number of bytes to fill was specified
		     * for this align (stored in fr_subtype).
		     */
		    if(fragP->fr_subtype != 0){
			if(oldoff > fragP->fr_subtype)
			    oldoff = 0;
			if(newoff > fragP->fr_subtype)
			    newoff = 0;
		    }
		    growth = newoff - oldoff;
		    break;

		case rs_org:
		    target = offset;
		    if(symbolP != NULL){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag );
			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
		    }
		    know(fragP->fr_next);
		    after = fragP->fr_next->fr_address;
		    /*
		     * Growth may be negative, but variable part of frag cannot
		     * have < 0 chars. That is, we can't .org backwards.
		     */
		    growth = ((target - after ) > 0) ? (target - after) : 0;

		    growth -= stretch;	/* This is an absolute growth factor */
		    break;

		case rs_machine_dependent:
		    this_state = fragP->fr_subtype;
		    this_type = md_relax_table + this_state;
		    start_type = this_type;

		    target = offset;
		    if(symbolP){
			know(((symbolP->sy_type & N_TYPE) == N_ABS) ||
			     ((symbolP->sy_type & N_TYPE) == N_SECT));
			know(symbolP->sy_frag);
			know((symbolP->sy_type & N_TYPE) != N_ABS ||
			     symbolP->sy_frag == &zero_address_frag);

			target += symbolP->sy_value +
				  symbolP->sy_frag->fr_address;
			/*
			 * If frag has yet to be reached on this pass,
			 * assume it will move by STRETCH just as we did.
			 * If this is not so, it will be because some frag
			 * between grows, and that will force another pass.
			 */
			if(symbolP->sy_frag->fr_address >= was_address &&
			   is_down_range(fragP, symbolP->sy_frag))
			    target += stretch;
		    }
		    aim = target - address - fragP->fr_fix;
		    if(aim < 0){
			/* Look backwards. */
			for(next_state = this_type->rlx_more; next_state; ){
			    if(aim >= this_type->rlx_backward)
				next_state = 0;
			    else{	/* Grow to next state. */
				this_state = next_state;
				this_type = md_relax_table + this_state;
				next_state = this_type->rlx_more;
			    }
			}
		    }
		    else{
			/* Look forwards. */
			for(next_state = this_type->rlx_more; next_state; ){
			    if(aim <= this_type->rlx_forward)
				next_state = 0;
			    else{	/* Grow to next state. */
				this_state = next_state;
				this_type = md_relax_table + this_state;
				next_state = this_type->rlx_more;
			    }
			}
		    }
		    if((growth = this_type->rlx_length -start_type->rlx_length))
			  fragP->fr_subtype = this_state;
		    break;

		  default:
		      BAD_CASE(fragP->fr_type);
		      break;
		}
		if(growth) {
		    stretch += growth;
		    stretched++;
		}
	    }			/* For each frag in the segment. */
	}while(stretched);	/* Until nothing further to relax. */

	/*
	 * We now have valid fr_address'es for each frag.  All fr_address's
	 * are correct, relative to their own section.  We have made all the
	 * fixS for this section that will be made.
	 */
}
Beispiel #9
0
/*
 * fixup_section() does the fixups of the frags and prepares the fixes so
 * relocation entries can be created from them.  The fixups cause the contents
 * of the frag to have the value for the fixup expression.  A fix structure that
 * ends up with a non NULL fx_addsy will have a relocation entry created for it.
 */
static
void
fixup_section(
fixS *fixP,
int nsect)
{
    symbolS *add_symbolP;
    symbolS *sub_symbolP;
    long value;
    int size;
    char *place;
    long where;
    char pcrel;
    fragS *fragP;
    int	add_symbol_N_TYPE;
    int	add_symbol_nsect;
#ifndef SPARC
    int sub_symbol_nsect;
#endif

	/*
	 * The general fix expression is "fx_addsy - fx_subsy + fx_offset".
	 * The goal is to put the result of this expression into the frag at
	 * "place" for size "size".  The value of the expression is calculated
	 * in the variable "value" and starts with just the fx_offset.
	 */
	for( ; fixP != NULL; fixP = fixP->fx_next){
	    fragP       = fixP->fx_frag;
	    know(fragP);
	    where	= fixP->fx_where;
	    place       = fragP->fr_literal + where;
	    size	= fixP->fx_size;
	    add_symbolP = fixP->fx_addsy;
	    sub_symbolP = fixP->fx_subsy;
	    value  	= fixP->fx_offset;
	    pcrel       = fixP->fx_pcrel;

	    add_symbol_N_TYPE = 0;
	    add_symbol_nsect = 0;

	    if(add_symbolP != NULL){
		add_symbol_N_TYPE = add_symbolP->sy_type & N_TYPE;
		if(add_symbol_N_TYPE == N_SECT)
		    add_symbol_nsect = add_symbolP->sy_other;
	    }

	    /*
	     * Is there a subtract symbol?
	     */
	    if(sub_symbolP){
		/* is it just -sym ? */
		if(add_symbolP == NULL){
		    if(sub_symbolP->sy_type != N_ABS)
			as_warn("Negative of non-absolute symbol %s",
				sub_symbolP->sy_name);
		    value -= sub_symbolP->sy_value;
		    fixP->fx_subsy = NULL;
		}
		/*
		 * There are both an add symbol and a subtract symbol at this
		 * point.
		 *
		 * If both symbols are absolute then just calculate the
		 * value of the fix expression and no relocation entry will be
		 * needed.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_ABS &&
		        (add_symbolP->sy_type & N_TYPE) == N_ABS){
		    value += add_symbolP->sy_value - sub_symbolP->sy_value;
		    add_symbolP = NULL;
		    fixP->fx_addsy = NULL; /* no relocation entry */
		    fixP->fx_subsy = NULL;
		}
		/*
		 * If both symbols are defined in a section then calculate the
		 * value of the fix expression and let a section difference
		 * relocation entry be created.
		 */
		else if((sub_symbolP->sy_type & N_TYPE) == N_SECT &&
		        (add_symbolP->sy_type & N_TYPE) == N_SECT){
		    /*
		     * We are use the new features that are incompatible with
		     * 3.2 then just calculate the value and let this create a
		     * SECTDIFF relocation type.
		     */
#ifdef SPARC
		    /*
		     * Special case dealing with assembler internal relocation
		     * entries SPARC_RELOC_13 and RELOC_22. The can not be
		     * output and must be resolved.
		     */
		    if((fixP->fx_r_type == SPARC_RELOC_13) ||
		       (fixP->fx_r_type == SPARC_RELOC_22)){
			if(sub_symbolP->sy_other == add_symbolP->sy_other){
			    value += add_symbolP->sy_value -
			    sub_symbolP->sy_value;
			    add_symbolP = NULL;
			    fixP->fx_addsy = NULL; /* no relocation entry */
			    fixP->fx_subsy = NULL;
			}
			else{
			    as_warn("Can't emit reloc type %u {-symbol \"%s\"} "
			            "@ file address %ld (mode?).",
				    fixP->fx_r_type, sub_symbolP->sy_name,
				    fragP->fr_address + where);
			}
		    }
		    else
			value += add_symbolP->sy_value - sub_symbolP->sy_value;
#else
		    value += add_symbolP->sy_value - sub_symbolP->sy_value;
		    sub_symbol_nsect = sub_symbolP->sy_other;
		    if(is_end_section_address(add_symbol_nsect,
					      add_symbolP->sy_value) ||
		       is_end_section_address(sub_symbol_nsect,
					      sub_symbolP->sy_value)){
			layout_line = fixP->line;
			layout_file = fixP->file;
			as_warn("section difference relocatable subtraction "
				"expression, \"%s\" minus \"%s\" using a "
				"symbol at the end of section will not "
				"produce an assembly time constant",
				add_symbolP->sy_name, sub_symbolP->sy_name);
			as_warn("use a symbol with a constant value created "
				"with an assignment instead of the expression, "
				"L_const_sym = %s - %s", add_symbolP->sy_name,
				sub_symbolP->sy_name);
			layout_line = 0;
			layout_file = NULL;
		    }
#endif
		    goto down;
		}
		/*
		 * If the subtract symbol is absolute subtract it's value from
		 * the fix expression and let a relocation entry get created
		 * that is not a section difference type.
		 */
		else if(sub_symbolP->sy_type == N_ABS){
		    value -= sub_symbolP->sy_value;
		    fixP->fx_subsy = NULL; /* no SECTDIFF relocation entry */
		}
		/*
		 * At this point we have something we can't generate a
		 * relocation entry for (two undefined symbols, etc.).
		 */
	        else{
		     layout_line = fixP->line;
		     layout_file = fixP->file;
		     as_warn("non-relocatable subtraction expression, \"%s\" "
			     "minus \"%s\"", add_symbolP->sy_name,
			     sub_symbolP->sy_name);
		     if((add_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_warn("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", add_symbolP->sy_name);
		     if((sub_symbolP->sy_type & N_TYPE) == N_UNDF)
			as_warn("symbol: \"%s\" can't be undefined in a "
				"subtraction expression", sub_symbolP->sy_name);
		     layout_line = 0;
		     layout_file = NULL;
		}
	    }

	    /*
	     * If a there is an add symbol in the fixup expression then add
	     * the symbol value into the fixup expression's value.
	     */
	    if(add_symbolP){
		/*
		 * If this symbol is in this section and is pc-relative and we
		 * do not want to force a pc-relative relocation entry (to
		 * support scattered loading) then just calculate the value.
		 */
		if(add_symbol_nsect == nsect &&
		   pcrel && !(fixP->fx_pcrel_reloc)){
		    /*
		     * This fixup was made when the symbol's section was
		     * unknown, but it is now in this section. So we know how
		     * to do the address without relocation.
		     */
		    value += add_symbolP->sy_value;
		    value -= size + where + fragP->fr_address;
		    pcrel = 0;	/* Lie. Don't want further pcrel processing. */
		    fixP->fx_addsy = NULL; /* No relocations please. */
		    /*
		     * It would be nice to check that the address does not
		     * overflow.
		     * I didn't do this check because:
		     * +  It is machine dependent in the general case (eg 32032)
		     * +  Compiler output will never need this checking, so why
		     *    slow down the usual case?
		     */
		}
		else{
		    switch(add_symbol_N_TYPE){
		    case N_ABS:
			/*
			 * If the value of the symbol was an expression then
			 * now evaluate the expression now.  This can happen
			 * when symbols like:
			 *	.set x,a-b
			 * are used and the value of x is not known till all
			 * of the symbols are seen and had their values set.
			 */
			if(add_symbolP->expression != NULL){
			    expressionS *exp;

			    exp = (expressionS *)add_symbolP->expression;
			    value +=
				exp->X_add_symbol->sy_value -
				exp->X_subtract_symbol->sy_value;
			}
			else
			    value += add_symbolP->sy_value;
			fixP->fx_addsy = NULL; /* no relocation entry */
			add_symbolP = NULL;
			break;
			
		    case N_SECT:
			if((add_symbolP->sy_type & N_EXT) != N_EXT ||
			   add_symbol_N_TYPE != N_SECT ||
			   !is_section_coalesced(add_symbol_nsect))
			    value += add_symbolP->sy_value;
			break;
			
		    case N_UNDF:
			break;
			
		    default:
			BAD_CASE(add_symbol_N_TYPE);
			break;
		    }
		}
	    }
down:
	    /*
	     * If the fixup expression is pc-relative then the value of the pc
	     * will be added to the expression when the machine executes the
	     * the instruction so we adjust the fixup expression's value by
	     * subtracting off the pc value (where) and adjust for insn size.
	     */
	    if(pcrel){
		value -= size + where + fragP->fr_address;
		if(add_symbolP == NULL){
		    fixP->fx_addsy = &abs_symbol; /* force relocation entry */
		}
	    }

	    if((size == 1 && (value & 0xffffff00) &&
			    ((value & 0xffffff80) != 0xffffff80)) ||
	       (size == 2 && (value & 0xffff8000) &&
			    ((value & 0xffff8000) != 0xffff8000)))
		as_warn("Fixup of %ld too large for field width of %d",
			value, size);

	    /*
	     * Now place the fix expression's value in the place for the size.
	     * And save the fix expression's value to be used when creating
	     * a relocation entry if required.
	     */
	    md_number_to_imm((unsigned char *)place, value, size, fixP, nsect);
	    fixP->fx_value = value;

	    /*
	     * If this is a non-lazy pointer section and this fix is for a
	     * local symbol without an subtract symbol then cause this not to
	     * generate a relocation entry.  This is used with code gen for
	     * fix-n-continue where the compiler generates indirection for
	     * static data references.  So the assembly looks like this:
	     *
	     * 	.non_lazy_symbol_pointer
	     * 	L_i$non_lazy_ptr:
       	     * 	.indirect_symbol _i
       	     * 	.long   _i
	     *
	     * this allows the value of the symbol to be set into the pointer
	     * but not cause the relocation entry to be created.  The code in
	     * write_object() then changes the indirect symbol table entry to
	     * INDIRECT_SYMBOL_LOCAL when the symbol is local.  This is what
	     * the static and dynamic linkers expect and will then cause the
	     * pointer to be correctly relocated.
	     */
	    if(is_section_non_lazy_symbol_pointers(nsect) &&
	       (add_symbolP->sy_type & N_EXT) != N_EXT &&
	       sub_symbolP == NULL){
		fixP->fx_addsy = NULL; /* no relocation entry */
	    }
	}
}