/* tc-xstormy16.c -- Assembler for the Sanyo XSTORMY16.
- Copyright (C) 2000, 2001, 2002 Free Software Foundation.
+ Copyright 2000, 2001, 2002, 2003 Free Software Foundation.
This file is part of GAS, the GNU Assembler.
cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
}
+static bfd_boolean skipping_fptr = FALSE;
+
void
md_assemble (str)
char * str;
xstormy16_insn insn;
char * errmsg;
+ /* Make sure that if we had an erroneous input line which triggered
+ the skipping_fptr boolean that it does not affect following lines. */
+ skipping_fptr = FALSE;
+
/* Initialize GAS's cgen interface for a new instruction. */
gas_cgen_init_parse ();
if (*input_line_pointer != '@')
return;
- if (strncmp (input_line_pointer+1, "fptr", 4) == 0)
+ if (strncmp (input_line_pointer + 1, "fptr", 4) == 0)
{
input_line_pointer += 5;
SKIP_WHITESPACE ();
goto err;
}
input_line_pointer++;
+ SKIP_WHITESPACE ();
if (e->X_op != O_symbol)
as_bad ("Not a symbolic expression");
+ else if (* input_line_pointer == '-')
+ /* We are computing the difference of two function pointers
+ like this:
+
+ .hword @fptr (foo) - @fptr (bar)
+
+ In this situation we do not want to generate O_fptr_symbol
+ operands because the result is an absolute value, not a
+ function pointer.
+
+ We need to make the check here, rather than when the fixup
+ is generated as the function names (foo & bar in the above
+ example) might be local symbols and we want the expression
+ to be evaluated now. This kind of thing can happen when
+ gcc is generating computed gotos. */
+ skipping_fptr = TRUE;
+ else if (skipping_fptr)
+ skipping_fptr = FALSE;
else
e->X_op = O_fptr_symbol;
}
{
if (fixP->fx_addsy != (symbolS *) NULL
&& (! S_IS_DEFINED (fixP->fx_addsy)
- || S_GET_SEGMENT (fixP->fx_addsy) != sec))
- {
- /* The symbol is undefined (or is defined but not in this section).
- Let the linker figure it out. */
- return 0;
- }
+ || S_GET_SEGMENT (fixP->fx_addsy) != sec)
+ || xstormy16_force_relocation (fixP))
+ /* The symbol is undefined,
+ or it is defined but not in this section,
+ or the relocation will be relative to this symbol not the section symbol.
+ Let the linker figure it out. */
+ return 0;
return fixP->fx_frag->fr_address + fixP->fx_where;
}
case XSTORMY16_OPERAND_IMM3:
case XSTORMY16_OPERAND_IMM3B:
case XSTORMY16_OPERAND_IMM4:
- case XSTORMY16_OPERAND_IMM12:
case XSTORMY16_OPERAND_HMEM8:
return BFD_RELOC_NONE;
+ case XSTORMY16_OPERAND_IMM12:
+ fixP->fx_where += 2;
+ return BFD_RELOC_XSTORMY16_12;
+
case XSTORMY16_OPERAND_IMM8:
case XSTORMY16_OPERAND_LMEM8:
return fixP->fx_pcrel ? BFD_RELOC_8_PCREL : BFD_RELOC_8;
case XSTORMY16_OPERAND_IMM16:
+ /* This might have been processed at parse time. */
fixP->fx_where += 2;
+ if (fixP->fx_cgen.opinfo && fixP->fx_cgen.opinfo != BFD_RELOC_NONE)
+ return fixP->fx_cgen.opinfo;
return fixP->fx_pcrel ? BFD_RELOC_16_PCREL : BFD_RELOC_16;
case XSTORMY16_OPERAND_ABS24:
return BFD_RELOC_XSTORMY16_24;
- case XSTORMY16_OPERAND_REL8_2:
case XSTORMY16_OPERAND_REL8_4:
+ fixP->fx_addnumber -= 2;
+ case XSTORMY16_OPERAND_REL8_2:
+ fixP->fx_addnumber -= 2;
fixP->fx_pcrel = 1;
return BFD_RELOC_8_PCREL;
fixP->fx_where += 2;
/* Fall through... */
case XSTORMY16_OPERAND_REL12A:
+ fixP->fx_addnumber -= 2;
fixP->fx_pcrel = 1;
return BFD_RELOC_XSTORMY16_REL_12;
xstormy16_force_relocation (fix)
fixS * fix;
{
- switch (fix->fx_r_type)
- {
- case BFD_RELOC_XSTORMY16_FPTR16:
- case BFD_RELOC_VTABLE_INHERIT:
- case BFD_RELOC_VTABLE_ENTRY:
- return 1;
+ if (fix->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
+ return 1;
- default:
- break;
- }
-
- return S_FORCE_RELOC (fix->fx_addsy);
+ return generic_force_reloc (fix);
}
/* Return true if a relocation against a symbol may be replaced with
a relocation against section+offset. */
-boolean
+bfd_boolean
xstormy16_fix_adjustable (fixP)
fixS * fixP;
{
/* Canonical name, since used a lot. */
CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
+ /* md_cgen_lookup_reloc() will adjust this to compensate for where
+ in the opcode the relocation happens, for pcrel relocations. We
+ have no other way of keeping track of what this offset needs to
+ be. */
+ fixP->fx_addnumber = 0;
+
/* This port has pc-relative relocs and DIFF_EXPR_OK defined, so
it must deal with turning a BFD_RELOC_{8,16,32,64} into a
BFD_RELOC_*_PCREL for the case of
/* The operand isn't fully resolved. Determine a BFD reloc value
based on the operand information and leave it to
bfd_install_relocation. Note that this doesn't work when
- partial_inplace == false. */
+ !partial_inplace. */
reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
if (reloc_type != BFD_RELOC_NONE)
/* Tuck `value' away for use by tc_gen_reloc.
See the comment describing fx_addnumber in write.h.
This field is misnamed (or misused :-). */
- fixP->fx_addnumber = value;
+ fixP->fx_addnumber += value;
}
\f