/* tc-mn10300.c -- Assembler code for the Matsushita 10300
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1996-2015 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
{ "pc", AM33 },
{ "psw", 0 },
{ "sp", 0 },
+ { "ssp", 0 },
+ { "usp", 0 },
};
#define OTHER_REG_NAME_CNT ARRAY_SIZE (other_registers)
else if (fragP->fr_subtype == 6)
{
int offset = fragP->fr_fix;
+
fragP->fr_literal[offset] = 0xcd;
fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
else if (fragP->fr_subtype == 7)
{
int offset = fragP->fr_fix;
+
fragP->fr_literal[offset] = 0xdd;
fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
+ fragP->fr_literal[offset + 3] = 0;
+ fragP->fr_literal[offset + 4] = 0;
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
else if (fragP->fr_subtype == 8)
{
int offset = fragP->fr_fix;
+
fragP->fr_literal[offset] = 0xfa;
fragP->fr_literal[offset + 1] = 0xff;
fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
else if (fragP->fr_subtype == 9)
{
int offset = fragP->fr_fix;
+
fragP->fr_literal[offset] = 0xfc;
fragP->fr_literal[offset + 1] = 0xff;
else if (fragP->fr_subtype == 11)
{
int offset = fragP->fr_fix;
+
fragP->fr_literal[offset] = 0xcc;
fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
else if (fragP->fr_subtype == 12)
{
int offset = fragP->fr_fix;
+
fragP->fr_literal[offset] = 0xdc;
fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
}
void
-mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
+mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+ bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
{
struct mn10300_fixup fixup;
that they do indeed not match. */
if (opcode->no_match_operands)
{
- int i;
-
/* Look at each operand to see if it's marked. */
for (i = 0; i < MN10300_MAX_OPERANDS; i++)
{
for (i = 0; i < fc; i++)
{
const struct mn10300_operand *operand;
+ int reloc_size;
operand = &mn10300_operands[fixups[i].opindex];
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_TLS_GD
+ && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LD
+ && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LDO
+ && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GOTIE
+ && fixups[i].reloc != BFD_RELOC_MN10300_TLS_IE
+ && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LE
&& fixups[i].reloc != BFD_RELOC_MN10300_GOT32)
{
reloc_howto_type *reloc_howto;
- int size;
int offset;
- fixS *fixP;
reloc_howto = bfd_reloc_type_lookup (stdoutput,
fixups[i].reloc);
if (!reloc_howto)
abort ();
- size = bfd_get_reloc_size (reloc_howto);
+ reloc_size = bfd_get_reloc_size (reloc_howto);
- if (size < 1 || size > 4)
+ if (reloc_size < 1 || reloc_size > 4)
abort ();
offset = 4 - size;
- fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
- size, &fixups[i].exp,
- reloc_howto->pc_relative,
- fixups[i].reloc);
+ fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+ reloc_size, &fixups[i].exp,
+ reloc_howto->pc_relative,
+ fixups[i].reloc);
}
else
{
- int reloc, pcrel, reloc_size, offset;
+ int reloc, pcrel, offset;
fixS *fixP;
reloc = BFD_RELOC_NONE;
if (fixp->fx_addsy && fixp->fx_subsy)
{
- reloc->sym_ptr_ptr = NULL;
+ asection *asec, *ssec;
+
+ asec = S_GET_SEGMENT (fixp->fx_addsy);
+ ssec = S_GET_SEGMENT (fixp->fx_subsy);
/* If we have a difference between two (non-absolute) symbols we must
generate two relocs (one for each symbol) and allow the linker to
resolve them - relaxation may change the distances between symbols,
- even local symbols defined in the same segment. */
- if (S_GET_SEGMENT (fixp->fx_subsy) == seg)
+ even local symbols defined in the same section. */
+ if (ssec != absolute_section || asec != absolute_section)
{
arelent * reloc2 = xmalloc (sizeof * reloc);
*reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
reloc->addend = fixp->fx_offset;
- if (S_GET_SEGMENT (fixp->fx_addsy) == absolute_section)
- reloc->addend += S_GET_VALUE (fixp->fx_addsy);
-
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
- *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ if (asec == absolute_section)
+ {
+ reloc->addend += S_GET_VALUE (fixp->fx_addsy);
+ reloc->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+ }
+ else
+ {
+ reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ }
fixp->fx_pcrel = 0;
fixp->fx_done = 1;
return relocs;
}
-
- if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy))
- || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section)
- {
- as_bad_where (fixp->fx_file, fixp->fx_line,
- "Difference of symbols in different sections is not supported");
- }
else
{
char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
= (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
return relocs;
}
- }
- if (reloc->sym_ptr_ptr)
- free (reloc->sym_ptr_ptr);
- free (reloc);
- return & no_relocs;
+ free (reloc);
+ return & no_relocs;
+ }
}
else
{
return relocs;
}
+/* Returns true iff the symbol attached to the frag is at a known location
+ in the given section, (and hence the relocation to it can be relaxed by
+ the assembler). */
+static inline bfd_boolean
+has_known_symbol_location (fragS * fragp, asection * sec)
+{
+ symbolS * sym = fragp->fr_symbol;
+
+ return sym != NULL
+ && S_IS_DEFINED (sym)
+ && ! S_IS_WEAK (sym)
+ && S_GET_SEGMENT (sym) == sec;
+}
+
int
md_estimate_size_before_relax (fragS *fragp, asection *seg)
{
if (fragp->fr_subtype == 6
- && (!S_IS_DEFINED (fragp->fr_symbol)
- || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+ && ! has_known_symbol_location (fragp, seg))
fragp->fr_subtype = 7;
else if (fragp->fr_subtype == 8
- && (!S_IS_DEFINED (fragp->fr_symbol)
- || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+ && ! has_known_symbol_location (fragp, seg))
fragp->fr_subtype = 9;
else if (fragp->fr_subtype == 10
- && (!S_IS_DEFINED (fragp->fr_symbol)
- || seg != S_GET_SEGMENT (fragp->fr_symbol)))
+ && ! has_known_symbol_location (fragp, seg))
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 ();
long
md_pcrel_from (fixS *fixp)
{
- if (fixp->fx_addsy != NULL && !S_IS_DEFINED (fixp->fx_addsy))
- {
- /* The symbol is undefined. Let the linker figure it out. */
- return 0;
- }
+ if (fixp->fx_addsy != (symbolS *) NULL
+ && (!S_IS_DEFINED (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+ /* The symbol is undefined or weak. Let the linker figure it out. */
+ return 0;
+
return fixp->fx_frag->fr_address + fixp->fx_where;
}
int size = 0;
int value = (int) * valP;
- assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+ gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
/* This should never happen. */
if (seg->flags & SEC_ALLOC)
fixP->fx_done = 0;
return;
+ case BFD_RELOC_MN10300_ALIGN:
+ fixP->fx_done = 1;
+ return;
+
case BFD_RELOC_NONE:
default:
as_bad_where (fixP->fx_file, fixP->fx_line,
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 if ((next_end = mn10300_end_of_match (next + 1, "tlsgd")))
+ reloc_type = BFD_RELOC_MN10300_TLS_GD;
+ else if ((next_end = mn10300_end_of_match (next + 1, "tlsldm")))
+ reloc_type = BFD_RELOC_MN10300_TLS_LD;
+ else if ((next_end = mn10300_end_of_match (next + 1, "dtpoff")))
+ reloc_type = BFD_RELOC_MN10300_TLS_LDO;
+ else if ((next_end = mn10300_end_of_match (next + 1, "gotntpoff")))
+ reloc_type = BFD_RELOC_MN10300_TLS_GOTIE;
+ else if ((next_end = mn10300_end_of_match (next + 1, "indntpoff")))
+ reloc_type = BFD_RELOC_MN10300_TLS_IE;
+ else if ((next_end = mn10300_end_of_match (next + 1, "tpoff")))
+ reloc_type = BFD_RELOC_MN10300_TLS_LE;
else
goto no_suffix;
return result;
}
+
+/* When relaxing, we need to output a reloc for any .align directive
+ that requests alignment to a two byte boundary or larger. */
+
+void
+mn10300_handle_align (fragS *frag)
+{
+ if (linkrelax
+ && (frag->fr_type == rs_align
+ || frag->fr_type == rs_align_code)
+ && frag->fr_address + frag->fr_fix > 0
+ && frag->fr_offset > 1
+ && now_seg != bss_section
+ /* Do not create relocs for the merging sections - such
+ relocs will prevent the contents from being merged. */
+ && (bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE) == 0)
+ /* Create a new fixup to record the alignment request. The symbol is
+ irrelevent but must be present so we use the absolute section symbol.
+ The offset from the symbol is used to record the power-of-two alignment
+ value. The size is set to 0 because the frag may already be aligned,
+ thus causing cvt_frag_to_fill to reduce the size of the frag to zero. */
+ fix_new (frag, frag->fr_fix, 0, & abs_symbol, frag->fr_offset, FALSE,
+ BFD_RELOC_MN10300_ALIGN);
+}
+
+bfd_boolean
+mn10300_force_relocation (struct fix * fixp)
+{
+ if (linkrelax
+ && (fixp->fx_pcrel
+ || fixp->fx_r_type == BFD_RELOC_MN10300_ALIGN))
+ return TRUE;
+
+ return generic_force_reloc (fixp);
+}