/* tc-mn10300.c -- Assembler code for the Matsushita 10300
- Copyright 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
{0x7fff, -0x8000, 3, 12},
{0x7fffffff, -0x80000000, 5, 0},
+ /* fbCC relaxing */
+ {0x7f, -0x80, 3, 14},
+ {0x7fff, -0x8000, 6, 15},
+ {0x7fffffff, -0x80000000, 8, 0},
+
};
/* Local functions. */
const struct mn10300_operand *,
offsetT));
static int reg_name_search PARAMS ((const struct reg_name *, int, const char *));
-static boolean data_register_name PARAMS ((expressionS *expressionP));
-static boolean address_register_name PARAMS ((expressionS *expressionP));
-static boolean other_register_name PARAMS ((expressionS *expressionP));
-static void set_arch_mach PARAMS ((unsigned int));
+static bfd_boolean data_register_name PARAMS ((expressionS *expressionP));
+static bfd_boolean address_register_name PARAMS ((expressionS *expressionP));
+static bfd_boolean other_register_name PARAMS ((expressionS *expressionP));
+static bfd_boolean r_register_name PARAMS ((expressionS *expressionP));
+static bfd_boolean xr_register_name PARAMS ((expressionS *expressionP));
+static void set_arch_mach PARAMS ((int));
/* Set linkrelax here to avoid fixups in most sections. */
int linkrelax = 1;
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
- { "file", dwarf2_directive_file, 0 },
- { "loc", dwarf2_directive_loc, 0 },
{ "am30", set_arch_mach, AM30 },
{ "am33", set_arch_mach, AM33 },
+ { "am33_2", (void (*) PARAMS ((int))) set_arch_mach, AM33_2 },
{ "mn10300", set_arch_mach, MN103 },
{NULL, 0, 0}
};
-#define HAVE_AM33 (current_machine == AM33)
+#define HAVE_AM33_2 (current_machine == AM33_2)
+#define HAVE_AM33 (current_machine == AM33 || HAVE_AM33_2)
#define HAVE_AM30 (current_machine == AM30)
/* Opcode hash table. */
{ "mcrl", 3 },
{ "mcvf", 4 },
{ "mdrq", 1 },
- { "pc", 0 },
{ "sp", 0 },
{ "xr0", 0 },
{ "xr1", 1 },
#define XR_REG_NAME_CNT \
(sizeof (xr_registers) / sizeof (struct reg_name))
+/* We abuse the `value' field, that would be otherwise unused, to
+ encode the architecture on which (access to) the register was
+ introduced. FIXME: we should probably warn when we encounter a
+ register name when assembling for an architecture that doesn't
+ support it, before parsing it as a symbol name. */
static const struct reg_name other_registers[] =
{
+ { "epsw", AM33 },
{ "mdr", 0 },
+ { "pc", AM33 },
{ "psw", 0 },
{ "sp", 0 },
};
#define OTHER_REG_NAME_CNT \
(sizeof (other_registers) / sizeof (struct reg_name))
+static const struct reg_name float_registers[] =
+{
+ { "fs0", 0 },
+ { "fs1", 1 },
+ { "fs10", 10 },
+ { "fs11", 11 },
+ { "fs12", 12 },
+ { "fs13", 13 },
+ { "fs14", 14 },
+ { "fs15", 15 },
+ { "fs16", 16 },
+ { "fs17", 17 },
+ { "fs18", 18 },
+ { "fs19", 19 },
+ { "fs2", 2 },
+ { "fs20", 20 },
+ { "fs21", 21 },
+ { "fs22", 22 },
+ { "fs23", 23 },
+ { "fs24", 24 },
+ { "fs25", 25 },
+ { "fs26", 26 },
+ { "fs27", 27 },
+ { "fs28", 28 },
+ { "fs29", 29 },
+ { "fs3", 3 },
+ { "fs30", 30 },
+ { "fs31", 31 },
+ { "fs4", 4 },
+ { "fs5", 5 },
+ { "fs6", 6 },
+ { "fs7", 7 },
+ { "fs8", 8 },
+ { "fs9", 9 },
+};
+
+#define FLOAT_REG_NAME_CNT \
+ (sizeof (float_registers) / sizeof (struct reg_name))
+
+static const struct reg_name double_registers[] =
+{
+ { "fd0", 0 },
+ { "fd10", 10 },
+ { "fd12", 12 },
+ { "fd14", 14 },
+ { "fd16", 16 },
+ { "fd18", 18 },
+ { "fd2", 2 },
+ { "fd20", 20 },
+ { "fd22", 22 },
+ { "fd24", 24 },
+ { "fd26", 26 },
+ { "fd28", 28 },
+ { "fd30", 30 },
+ { "fd4", 4 },
+ { "fd6", 6 },
+ { "fd8", 8 },
+};
+
+#define DOUBLE_REG_NAME_CNT \
+ (sizeof (double_registers) / sizeof (struct reg_name))
+
+
/* reg_name_search does a binary search of the given register table
to see if "name" is a valid regiter name. Returns the register
number from the array on success, or -1 on failure. */
* its original state.
*/
-static boolean
+static bfd_boolean
r_register_name (expressionP)
expressionS *expressionP;
{
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
- return true;
+ return TRUE;
}
/* Reset the line as if we had not done anything. */
input_line_pointer = start;
- return false;
+ return FALSE;
}
/* Summary of register_name().
* its original state.
*/
-static boolean
+static bfd_boolean
xr_register_name (expressionP)
expressionS *expressionP;
{
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
- return true;
+ return TRUE;
}
/* Reset the line as if we had not done anything. */
input_line_pointer = start;
- return false;
+ return FALSE;
}
/* Summary of register_name().
* its original state.
*/
-static boolean
+static bfd_boolean
data_register_name (expressionP)
expressionS *expressionP;
{
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
- return true;
+ return TRUE;
}
/* Reset the line as if we had not done anything. */
input_line_pointer = start;
- return false;
+ return FALSE;
}
/* Summary of register_name().
* its original state.
*/
-static boolean
+static bfd_boolean
address_register_name (expressionP)
expressionS *expressionP;
{
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
- return true;
+ return TRUE;
}
/* Reset the line as if we had not done anything. */
input_line_pointer = start;
- return false;
+ return FALSE;
}
/* Summary of register_name().
* its original state.
*/
-static boolean
+static bfd_boolean
other_register_name (expressionP)
expressionS *expressionP;
{
/* Put back the delimiting char. */
*input_line_pointer = c;
+ /* Look to see if it's in the register table. */
+ if (reg_number == 0
+ || (reg_number == AM33 && HAVE_AM33))
+ {
+ expressionP->X_op = O_register;
+ expressionP->X_add_number = 0;
+
+ /* Make the rest nice. */
+ expressionP->X_add_symbol = NULL;
+ expressionP->X_op_symbol = NULL;
+
+ return TRUE;
+ }
+
+ /* Reset the line as if we had not done anything. */
+ input_line_pointer = start;
+ return FALSE;
+}
+
+static bfd_boolean double_register_name PARAMS ((expressionS *));
+static bfd_boolean float_register_name PARAMS ((expressionS *));
+
+/* Summary of float_register_name:
+
+ in: Input_line_pointer points to 1st char of operand.
+
+ out: A expressionS.
+ The operand may have been a register: in this case, X_op == O_register,
+ X_add_number is set to the register number, and truth is returned.
+ Input_line_pointer->(next non-blank) char after operand, or is in
+ its original state. */
+
+static bfd_boolean
+float_register_name (expressionP)
+ expressionS *expressionP;
+{
+ int reg_number;
+ char *name;
+ char *start;
+ char c;
+
+ /* Find the spelling of the operand. */
+ start = name = input_line_pointer;
+
+ c = get_symbol_end ();
+ reg_number = reg_name_search (float_registers, FLOAT_REG_NAME_CNT, name);
+
+ /* Put back the delimiting char. */
+ * input_line_pointer = c;
+
+ /* Look to see if it's in the register table. */
+ if (reg_number >= 0)
+ {
+ expressionP->X_op = O_register;
+ expressionP->X_add_number = reg_number;
+
+ /* Make the rest nice. */
+ expressionP->X_add_symbol = NULL;
+ expressionP->X_op_symbol = NULL;
+
+ return TRUE;
+ }
+
+ /* Reset the line as if we had not done anything. */
+ input_line_pointer = start;
+ return FALSE;
+}
+
+/* Summary of double_register_name:
+
+ in: Input_line_pointer points to 1st char of operand.
+
+ out: A expressionS.
+ The operand may have been a register: in this case, X_op == O_register,
+ X_add_number is set to the register number, and truth is returned.
+ Input_line_pointer->(next non-blank) char after operand, or is in
+ its original state. */
+
+static bfd_boolean
+double_register_name (expressionP)
+ expressionS *expressionP;
+{
+ int reg_number;
+ char *name;
+ char *start;
+ char c;
+
+ /* Find the spelling of the operand. */
+ start = name = input_line_pointer;
+
+ c = get_symbol_end ();
+ reg_number = reg_name_search (double_registers, DOUBLE_REG_NAME_CNT, name);
+
+ /* Put back the delimiting char. */
+ * input_line_pointer = c;
+
/* Look to see if it's in the register table. */
if (reg_number >= 0)
{
expressionP->X_add_symbol = NULL;
expressionP->X_op_symbol = NULL;
- return true;
+ return TRUE;
}
/* Reset the line as if we had not done anything. */
input_line_pointer = start;
- return false;
+ return FALSE;
}
void
fragP->fr_var = 0;
fragP->fr_fix += 5;
}
+ else if (fragP->fr_subtype == 13)
+ {
+ fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
+ fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 3;
+ }
+ else if (fragP->fr_subtype == 14)
+ {
+ /* Reverse the condition of the first branch. */
+ int offset = fragP->fr_fix;
+ int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+ switch (opcode)
+ {
+ case 0xd0:
+ opcode = 0xd1;
+ break;
+ case 0xd1:
+ opcode = 0xd0;
+ break;
+ case 0xd2:
+ opcode = 0xdc;
+ break;
+ case 0xd3:
+ opcode = 0xdb;
+ break;
+ case 0xd4:
+ opcode = 0xda;
+ break;
+ case 0xd5:
+ opcode = 0xd9;
+ break;
+ case 0xd6:
+ opcode = 0xd8;
+ break;
+ case 0xd7:
+ opcode = 0xdd;
+ break;
+ case 0xd8:
+ opcode = 0xd6;
+ break;
+ case 0xd9:
+ opcode = 0xd5;
+ break;
+ case 0xda:
+ opcode = 0xd4;
+ break;
+ case 0xdb:
+ opcode = 0xd3;
+ break;
+ case 0xdc:
+ opcode = 0xd2;
+ break;
+ case 0xdd:
+ opcode = 0xd7;
+ break;
+ default:
+ abort ();
+ }
+ fragP->fr_literal[offset + 1] = opcode;
+
+ /* Create a fixup for the reversed conditional branch. */
+ sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+ fix_new (fragP, fragP->fr_fix + 2, 1,
+ symbol_new (buf, sec, 0, fragP->fr_next),
+ fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+ /* Now create the unconditional branch + fixup to the
+ final target. */
+ fragP->fr_literal[offset + 3] = 0xcc;
+ fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 6;
+ }
+ else if (fragP->fr_subtype == 15)
+ {
+ /* Reverse the condition of the first branch. */
+ int offset = fragP->fr_fix;
+ int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+ switch (opcode)
+ {
+ case 0xd0:
+ opcode = 0xd1;
+ break;
+ case 0xd1:
+ opcode = 0xd0;
+ break;
+ case 0xd2:
+ opcode = 0xdc;
+ break;
+ case 0xd3:
+ opcode = 0xdb;
+ break;
+ case 0xd4:
+ opcode = 0xda;
+ break;
+ case 0xd5:
+ opcode = 0xd9;
+ break;
+ case 0xd6:
+ opcode = 0xd8;
+ break;
+ case 0xd7:
+ opcode = 0xdd;
+ break;
+ case 0xd8:
+ opcode = 0xd6;
+ break;
+ case 0xd9:
+ opcode = 0xd5;
+ break;
+ case 0xda:
+ opcode = 0xd4;
+ break;
+ case 0xdb:
+ opcode = 0xd3;
+ break;
+ case 0xdc:
+ opcode = 0xd2;
+ break;
+ case 0xdd:
+ opcode = 0xd7;
+ break;
+ default:
+ abort ();
+ }
+ fragP->fr_literal[offset + 1] = opcode;
+
+ /* Create a fixup for the reversed conditional branch. */
+ sprintf (buf, ".%s_%ld", FAKE_LABEL_NAME, label_count++);
+ fix_new (fragP, fragP->fr_fix + 2, 1,
+ symbol_new (buf, sec, 0, fragP->fr_next),
+ fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+ /* Now create the unconditional branch + fixup to the
+ final target. */
+ fragP->fr_literal[offset + 3] = 0xdc;
+ fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
+ fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+ fragP->fr_var = 0;
+ fragP->fr_fix += 8;
+ }
else
abort ();
}
}
/* Set the default machine type. */
+#ifdef TE_LINUX
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, AM33_2))
+ as_warn (_("could not set architecture and machine"));
+
+ current_machine = AM33_2;
+#else
if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, MN103))
as_warn (_("could not set architecture and machine"));
current_machine = MN103;
+#endif
+}
+
+static symbolS *GOT_symbol;
+
+static inline int mn10300_check_fixup PARAMS ((struct mn10300_fixup *));
+static inline int mn10300_PIC_related_p PARAMS ((symbolS *));
+
+static inline int
+mn10300_PIC_related_p (sym)
+ symbolS *sym;
+{
+ expressionS *exp;
+
+ if (! sym)
+ return 0;
+
+ if (sym == GOT_symbol)
+ return 1;
+
+ exp = symbol_get_value_expression (sym);
+
+ return (exp->X_op == O_PIC_reloc
+ || mn10300_PIC_related_p (exp->X_add_symbol)
+ || mn10300_PIC_related_p (exp->X_op_symbol));
+}
+
+static inline int
+mn10300_check_fixup (fixup)
+ struct mn10300_fixup *fixup;
+{
+ expressionS *exp = &fixup->exp;
+
+ repeat:
+ switch (exp->X_op)
+ {
+ case O_add:
+ case O_subtract: /* If we're sufficiently unlucky that the label
+ and the expression that references it happen
+ to end up in different frags, the subtract
+ won't be simplified within expression(). */
+ /* The PIC-related operand must be the first operand of a sum. */
+ if (exp != &fixup->exp || mn10300_PIC_related_p (exp->X_op_symbol))
+ return 1;
+
+ if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
+ fixup->reloc = BFD_RELOC_32_GOT_PCREL;
+
+ exp = symbol_get_value_expression (exp->X_add_symbol);
+ goto repeat;
+
+ case O_symbol:
+ if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol)
+ fixup->reloc = BFD_RELOC_32_GOT_PCREL;
+ break;
+
+ case O_PIC_reloc:
+ fixup->reloc = exp->X_md;
+ exp->X_op = O_symbol;
+ if (fixup->reloc == BFD_RELOC_32_PLT_PCREL
+ && fixup->opindex >= 0
+ && (mn10300_operands[fixup->opindex].flags
+ & MN10300_OPERAND_RELAX))
+ return 1;
+ break;
+
+ default:
+ return (mn10300_PIC_related_p (exp->X_add_symbol)
+ || mn10300_PIC_related_p (exp->X_op_symbol));
+ }
+
+ return 0;
+}
+
+void
+mn10300_cons_fix_new (frag, off, size, exp)
+ fragS *frag;
+ int off, size;
+ expressionS *exp;
+{
+ struct mn10300_fixup fixup;
+
+ fixup.opindex = -1;
+ fixup.exp = *exp;
+ fixup.reloc = BFD_RELOC_UNUSED;
+
+ mn10300_check_fixup (&fixup);
+
+ if (fixup.reloc == BFD_RELOC_MN10300_GOT32)
+ switch (size)
+ {
+ case 2:
+ fixup.reloc = BFD_RELOC_MN10300_GOT16;
+ break;
+
+ case 3:
+ fixup.reloc = BFD_RELOC_MN10300_GOT24;
+ break;
+
+ case 4:
+ break;
+
+ default:
+ goto error;
+ }
+ else if (fixup.reloc == BFD_RELOC_UNUSED)
+ switch (size)
+ {
+ case 1:
+ fixup.reloc = BFD_RELOC_8;
+ break;
+
+ case 2:
+ fixup.reloc = BFD_RELOC_16;
+ break;
+
+ case 3:
+ fixup.reloc = BFD_RELOC_24;
+ break;
+
+ case 4:
+ fixup.reloc = BFD_RELOC_32;
+ break;
+
+ default:
+ goto error;
+ }
+ else if (size != 4)
+ {
+ error:
+ as_bad (_("unsupported BFD relocation size %u"), size);
+ fixup.reloc = BFD_RELOC_UNUSED;
+ }
+
+ fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc);
}
void
/* If the instruction is not available on the current machine
then it can not possibly match. */
if (opcode->machine
+ && !(opcode->machine == AM33_2 && HAVE_AM33_2)
&& !(opcode->machine == AM33 && HAVE_AM33)
&& !(opcode->machine == AM30 && HAVE_AM30))
goto error;
goto error;
}
}
+ else if (operand->flags & MN10300_OPERAND_FSREG)
+ {
+ if (!float_register_name (&ex))
+ {
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
+ }
+ else if (operand->flags & MN10300_OPERAND_FDREG)
+ {
+ if (!double_register_name (&ex))
+ {
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
+ }
+ else if (operand->flags & MN10300_OPERAND_FPCR)
+ {
+ char *start = input_line_pointer;
+ char c = get_symbol_end ();
+
+ if (strcasecmp (start, "fpcr") != 0)
+ {
+ *input_line_pointer = c;
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
+ *input_line_pointer = c;
+ goto keep_going;
+ }
else if (operand->flags & MN10300_OPERAND_USP)
{
char *start = input_line_pointer;
str = hold;
goto error;
}
+ else if (HAVE_AM33_2 && float_register_name (&ex))
+ {
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
+ else if (HAVE_AM33_2 && double_register_name (&ex))
+ {
+ input_line_pointer = hold;
+ str = hold;
+ goto error;
+ }
else if (*str == ')' || *str == '(')
{
input_line_pointer = hold;
mask = MN10300_OPERAND_DREG | MN10300_OPERAND_AREG;
if (HAVE_AM33)
mask |= MN10300_OPERAND_RREG | MN10300_OPERAND_XRREG;
+ if (HAVE_AM33_2)
+ mask |= MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG;
if ((operand->flags & mask) == 0)
{
input_line_pointer = hold;
fixups[fc].exp = ex;
fixups[fc].opindex = *opindex_ptr;
fixups[fc].reloc = BFD_RELOC_UNUSED;
+ if (mn10300_check_fixup (& fixups[fc]))
+ goto error;
++fc;
break;
}
if (opcode->format == FMT_D2)
size = 4;
+ if (opcode->format == FMT_D3)
+ size = 5;
+
if (opcode->format == FMT_D4)
size = 6;
/* jmp */
else if (size == 3 && opcode->opcode == 0xcc0000)
type = 10;
+ else if (size == 3 && (opcode->opcode & 0xfff000) == 0xf8d000)
+ type = 13;
/* bCC (uncommon cases) */
else
type = 3;
is really two 8bit immediates. */
number_to_chars_bigendian (f, insn, 4);
}
+ else if (opcode->format == FMT_D3)
+ {
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+ number_to_chars_bigendian (f + 4, extension & 0xff, 1);
+ }
else if (opcode->format == FMT_D4)
{
unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
const struct mn10300_operand *operand;
operand = &mn10300_operands[fixups[i].opindex];
- if (fixups[i].reloc != BFD_RELOC_UNUSED)
+ if (fixups[i].reloc != BFD_RELOC_UNUSED
+ && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL
+ && fixups[i].reloc != BFD_RELOC_32_GOTOFF
+ && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL
+ && fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
{
reloc_howto_type *reloc_howto;
int size;
fixS *fixP;
reloc = BFD_RELOC_NONE;
+ if (fixups[i].reloc != BFD_RELOC_UNUSED)
+ reloc = fixups[i].reloc;
/* How big is the reloc? Remember SPLIT relocs are
implicitly 32bits. */
if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
/* Is the reloc pc-relative? */
pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
+ if (reloc != BFD_RELOC_NONE)
+ pcrel = bfd_reloc_type_lookup (stdoutput, reloc)->pc_relative;
offset = size - (reloc_size + operand->shift) / 8;
/* Choose a proper BFD relocation type. */
- if (pcrel)
+ if (reloc != BFD_RELOC_NONE)
+ ;
+ else if (pcrel)
{
if (reloc_size == 32)
reloc = BFD_RELOC_32_PCREL;
}
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ if (fixp->fx_subsy
+ && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
+ {
+ fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
+ fixp->fx_subsy = 0;
+ }
+
if (fixp->fx_addsy && fixp->fx_subsy)
{
reloc->sym_ptr_ptr = NULL;
reloc->howto = bfd_reloc_type_lookup (stdoutput,
BFD_RELOC_8_PCREL);
return reloc;
-
+
case BFD_RELOC_16:
reloc->howto = bfd_reloc_type_lookup (stdoutput,
BFD_RELOC_16_PCREL);
case BFD_RELOC_8:
md_number_to_chars (fixpos, reloc->addend, 1);
break;
-
+
case BFD_RELOC_16:
md_number_to_chars (fixpos, reloc->addend, 2);
break;
|| seg != S_GET_SEGMENT (fragp->fr_symbol)))
fragp->fr_subtype = 12;
+ if (fragp->fr_subtype == 13)
+ return 3;
if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
abort ();
fixP->fx_done = 1;
}
-/* Return nonzero if the fixup in FIXP will require a relocation,
- even it if appears that the fixup could be completely handled
- within GAS. */
-
-int
-mn10300_force_relocation (fixp)
- struct fix *fixp;
-{
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- return 1;
-
- /* Do not adjust relocations involving symbols in code sections,
- because it breaks linker relaxations. This could be fixed in the
- linker, but this fix is simpler, and it pretty much only affects
- object size a little bit. */
- if ((S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE)
- && fixp->fx_subsy
- && S_GET_SEGMENT (fixp->fx_addsy) == S_GET_SEGMENT (fixp->fx_subsy))
- return 1;
-
- return 0;
-}
-
/* Return zero if the fixup in fixp should be left alone and not
adjusted. */
-boolean
+bfd_boolean
mn10300_fix_adjustable (fixp)
struct fix *fixp;
{
- /* Prevent all adjustments to global symbols. */
- if (S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
+ if (! TC_RELOC_RTSYM_LOC_FIXUP (fixp))
return 0;
if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
*extensionp |= ((val & ((1 << (24 - operand->bits)) - 1))
<< operand->shift);
}
+ else if ((operand->flags & (MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG)))
+ {
+ /* See devo/opcodes/m10300-opc.c just before #define FSM0 for an
+ explanation of these variables. Note that FMT-implied shifts
+ are not taken into account for FP registers. */
+ unsigned long mask_low, mask_high;
+ int shl_low, shr_high, shl_high;
+
+ switch (operand->bits)
+ {
+ case 5:
+ /* Handle regular FP registers. */
+ if (operand->shift >= 0)
+ {
+ /* This is an `m' register. */
+ shl_low = operand->shift;
+ shl_high = 8 + (8 & shl_low) + (shl_low & 4) / 4;
+ }
+ else
+ {
+ /* This is an `n' register. */
+ shl_low = -operand->shift;
+ shl_high = shl_low / 4;
+ }
+
+ mask_low = 0x0f;
+ mask_high = 0x10;
+ shr_high = 4;
+ break;
+
+ case 3:
+ /* Handle accumulators. */
+ shl_low = -operand->shift;
+ shl_high = 0;
+ mask_low = 0x03;
+ mask_high = 0x04;
+ shr_high = 2;
+ break;
+
+ default:
+ abort ();
+ }
+ *insnp |= ((((val & mask_high) >> shr_high) << shl_high)
+ | ((val & mask_low) << shl_low));
+ }
else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
{
*insnp |= (((long) val & ((1 << operand->bits) - 1))
static void
set_arch_mach (mach)
- unsigned int mach;
+ int mach;
{
if (!bfd_set_arch_mach (stdoutput, bfd_arch_mn10300, mach))
as_warn (_("could not set architecture and machine"));
current_machine = mach;
}
+
+static inline char * mn10300_end_of_match PARAMS ((char *, char *));
+
+static inline char *
+mn10300_end_of_match (cont, what)
+ char *cont, *what;
+{
+ int len = strlen (what);
+
+ if (strncmp (cont, what, strlen (what)) == 0
+ && ! is_part_of_name (cont[len]))
+ return cont + len;
+
+ return NULL;
+}
+
+int
+mn10300_parse_name (name, exprP, nextcharP)
+ char const *name;
+ expressionS *exprP;
+ char *nextcharP;
+{
+ char *next = input_line_pointer;
+ char *next_end;
+ int reloc_type;
+ segT segment;
+
+ exprP->X_op_symbol = NULL;
+
+ if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
+ {
+ if (! GOT_symbol)
+ GOT_symbol = symbol_find_or_make (name);
+
+ exprP->X_add_symbol = GOT_symbol;
+ no_suffix:
+ /* If we have an absolute symbol or a reg,
+ then we know its value now. */
+ segment = S_GET_SEGMENT (exprP->X_add_symbol);
+ if (segment == absolute_section)
+ {
+ exprP->X_op = O_constant;
+ exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
+ exprP->X_add_symbol = NULL;
+ }
+ else if (segment == reg_section)
+ {
+ exprP->X_op = O_register;
+ exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
+ exprP->X_add_symbol = NULL;
+ }
+ else
+ {
+ exprP->X_op = O_symbol;
+ exprP->X_add_number = 0;
+ }
+
+ return 1;
+ }
+
+ exprP->X_add_symbol = symbol_find_or_make (name);
+
+ if (*nextcharP != '@')
+ goto no_suffix;
+ else if ((next_end = mn10300_end_of_match (next + 1, "GOTOFF")))
+ reloc_type = BFD_RELOC_32_GOTOFF;
+ else if ((next_end = mn10300_end_of_match (next + 1, "GOT")))
+ reloc_type = BFD_RELOC_MN10300_GOT32;
+ else if ((next_end = mn10300_end_of_match (next + 1, "PLT")))
+ reloc_type = BFD_RELOC_32_PLT_PCREL;
+ else
+ goto no_suffix;
+
+ *input_line_pointer = *nextcharP;
+ input_line_pointer = next_end;
+ *nextcharP = *input_line_pointer;
+ *input_line_pointer = '\0';
+
+ exprP->X_op = O_PIC_reloc;
+ exprP->X_add_number = 0;
+ exprP->X_md = reloc_type;
+
+ return 1;
+}