/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ Copyright (C) 2003-2017 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
/* Flags to indicate whether the hardware supports the density and
absolute literals options. */
-bfd_boolean density_supported = XCHAL_HAVE_DENSITY;
-bfd_boolean absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
+bfd_boolean density_supported;
+bfd_boolean absolute_literals_supported;
static vliw_insn cur_vinsn;
unsigned xtensa_num_pipe_stages;
-unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+unsigned xtensa_fetch_width;
static enum debug_info_type xt_saved_debug_type = DEBUG_NONE;
SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL, O_tlscall),
SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF, O_tpoff),
SUFFIX_MAP ("dtpoff", BFD_RELOC_XTENSA_TLS_DTPOFF, O_dtpoff),
- { (char *) 0, 0, BFD_RELOC_UNUSED, 0 }
};
{
FALSE, /* none */
FALSE, /* literal */
-#if !XCHAL_HAVE_DENSITY
FALSE, /* density */
-#else
- TRUE, /* density */
-#endif
TRUE, /* transform */
FALSE, /* freeregs */
FALSE, /* longcalls */
FALSE, /* literal_prefix */
FALSE, /* schedule */
-#if XSHAL_USE_ABSOLUTE_LITERALS
- TRUE /* absolute_literals */
-#else
FALSE /* absolute_literals */
-#endif
};
/* A circular list of all potential and actual literal pool locations
static void xtensa_restore_emit_state (emit_state *);
static segT cache_literal_section (bfd_boolean);
-/* Import from elf32-xtensa.c in BFD library. */
-
-extern asection *xtensa_make_property_section (asection *, const char *);
-
/* op_placement_info functions. */
static void init_op_placement_info_table (void);
if (!directive_state_stack)
{
- as_bad (_("unmatched end directive"));
+ as_bad (_("unmatched .end directive"));
*directive = directive_none;
return;
}
char *str2;
int ch;
int len;
- struct suffix_reloc_map *ptr;
+ unsigned int i;
if (*str++ != '@')
return BFD_RELOC_NONE;
len = str2 - ident;
ch = ident[0];
- for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++)
- if (ch == ptr->suffix[0]
- && len == ptr->length
- && memcmp (ident, ptr->suffix, ptr->length) == 0)
+ for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
+ if (ch == suffix_relocs[i].suffix[0]
+ && len == suffix_relocs[i].length
+ && memcmp (ident, suffix_relocs[i].suffix, suffix_relocs[i].length) == 0)
{
/* Now check for "identifier@suffix+constant". */
if (*str == '-' || *str == '+')
}
*str_p = str;
- return ptr->reloc;
+ return suffix_relocs[i].reloc;
}
return BFD_RELOC_UNUSED;
static operatorT
map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
{
- struct suffix_reloc_map *sfx;
operatorT operator = O_illegal;
+ unsigned int i;
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+ for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
{
- if (sfx->reloc == reloc)
+ if (suffix_relocs[i].reloc == reloc)
{
- operator = sfx->operator;
+ operator = suffix_relocs[i].operator;
break;
}
}
static bfd_reloc_code_real_type
map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal)
{
- struct suffix_reloc_map *sfx;
+ unsigned int i;
bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
- for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
+ for (i = 0; i < ARRAY_SIZE (suffix_relocs); i++)
{
- if (sfx->operator == operator)
+ if (suffix_relocs[i].operator == operator)
{
- reloc = sfx->reloc;
+ reloc = suffix_relocs[i].reloc;
break;
}
}
cnt_arg = *cnt_argp;
/* replace the argument with "31-(argument)" */
- new_arg = concat ("31-(", cnt_argp, ")", (char *) NULL);
+ new_arg = concat ("31-(", cnt_arg, ")", (char *) NULL);
free (cnt_arg);
*cnt_argp = new_arg;
number_to_chars_littleendian (buf, val, n);
}
+static void
+xg_init_global_config (void)
+{
+ target_big_endian = XCHAL_HAVE_BE;
+
+ density_supported = XCHAL_HAVE_DENSITY;
+ absolute_literals_supported = XSHAL_USE_ABSOLUTE_LITERALS;
+ xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
+
+ directive_state[directive_density] = XCHAL_HAVE_DENSITY;
+ directive_state[directive_absolute_literals] = XSHAL_USE_ABSOLUTE_LITERALS;
+}
+
+void
+xtensa_init (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+{
+ xg_init_global_config ();
+}
/* This function is called once, at assembler startup time. It should
set up all the tables, etc. that the MD part of the assembler will
orig_insn.is_specific_opcode = (has_underbar || !use_transform ());
orig_insn.opcode = xtensa_opcode_lookup (isa, opname);
- /* Special case: Check for "CALLXn.TLS" psuedo op. If found, grab its
+ /* Special case: Check for "CALLXn.TLS" pseudo op. If found, grab its
extra argument and set the opcode to "CALLXn". */
if (orig_insn.opcode == XTENSA_UNDEFINED
&& strncasecmp (opname, "callx", 5) == 0)
}
}
- /* Special case: Check for "j.l" psuedo op. */
+ /* Special case: Check for "j.l" pseudo op. */
if (orig_insn.opcode == XTENSA_UNDEFINED
&& strncasecmp (opname, "j.l", 3) == 0)
{
lps->seg = now_seg;
lps->frag_list.next = &lps->frag_list;
lps->frag_list.prev = &lps->frag_list;
+ /* Put candidate literal pool at the beginning of every section,
+ so that even when section starts with literal load there's a
+ literal pool available. */
+ lps->frag_count = auto_litpool_limit;
}
lps->frag_count++;
/* Move the fix-up from the original j insn to this one. */
fixP->fx_frag = fragP;
fixP->fx_where = fragP->fr_fix - 3;
+ fixP->fx_size = 3;
fixP->tc_fix_data.slot = 0;
+ fixP->fx_r_type = BFD_RELOC_XTENSA_SLOT0_OP;
xtensa_add_cached_fixup (&fixup_cache, fixP);
xtensa_format fmt;
xtensa_isa isa = xtensa_default_isa;
int growth = 0;
+ int i, slot = -1;
+
+ for (i = 0; i < MAX_SLOTS; ++i)
+ if (origfrag->tc_frag_data.slot_symbols[i])
+ {
+ gas_assert (slot == -1);
+ slot = i;
+ }
+
+ gas_assert (slot >= 0 && slot < MAX_SLOTS);
lsym = tramp->fr_symbol;
/* Assemble a jump to the target label in the trampoline frag. */
- tsym = origfrag->tc_frag_data.slot_symbols[0];
- toffset = origfrag-> tc_frag_data.slot_offsets[0];
+ tsym = origfrag->tc_frag_data.slot_symbols[slot];
+ toffset = origfrag-> tc_frag_data.slot_offsets[slot];
tinsn_init (&insn);
insn.insn_type = ITYPE_INSN;
insn.opcode = xtensa_j_opcode;
if (fixP)
fixP->fx_offset += 3;
/* Modify the original j to point here. */
- origfrag->tc_frag_data.slot_symbols[0] = lsym;
- origfrag->tc_frag_data.slot_offsets[0] = tramp->fr_fix - 3;
+ origfrag->tc_frag_data.slot_symbols[slot] = lsym;
+ origfrag->tc_frag_data.slot_offsets[slot] = tramp->fr_fix - 3;
/* If trampoline is full, remove it from the list. */
check_and_update_trampolines ();
static void mark_literal_frags (seg_list *);
+static void
+xg_promote_candidate_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lp)
+{
+ fragS *poolbeg;
+ fragS *poolend;
+ symbolS *lsym;
+ char label[10 + 2 * sizeof (fragS *)];
+
+ poolbeg = lp->fragP;
+ lp->priority = 1;
+ poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
+ poolend = poolbeg->fr_next;
+ gas_assert (poolend->fr_type == rs_machine_dependent &&
+ poolend->fr_subtype == RELAX_LITERAL_POOL_END);
+ /* Create a local symbol pointing to the
+ end of the pool. */
+ sprintf (label, ".L0_LT_%p", poolbeg);
+ lsym = (symbolS *)local_symbol_make (label, lps->seg,
+ 0, poolend);
+ poolbeg->fr_symbol = lsym;
+ /* Rest is done in xtensa_relax_frag. */
+}
+
static void
xtensa_move_literals (void)
{
/* This is still a "candidate" but the next one
will be too far away, so revert to the nearest
one, convert it and add the jump around. */
- fragS *poolbeg;
- fragS *poolend;
- symbolS *lsym;
- char label[10 + 2 * sizeof (fragS *)];
lp = lpf->prev;
- poolbeg = lp->fragP;
- lp->priority = 1;
- poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
- poolend = poolbeg->fr_next;
- gas_assert (poolend->fr_type == rs_machine_dependent &&
- poolend->fr_subtype == RELAX_LITERAL_POOL_END);
- /* Create a local symbol pointing to the
- end of the pool. */
- sprintf (label, ".L0_LT_%p", poolbeg);
- lsym = (symbolS *)local_symbol_make (label, lps->seg,
- 0, poolend);
- poolbeg->fr_symbol = lsym;
- /* Rest is done in xtensa_relax_frag. */
+ break;
}
}
}
+
+ /* Convert candidate and add the jump around. */
+ if (lp->fragP->fr_subtype ==
+ RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ xg_promote_candidate_litpool (lps, lp);
+
if (! litfrag->tc_frag_data.literal_frag)
{
/* Take earliest use of this literal to avoid
/* First, move the frag out of the literal section and
to the appropriate place. */
- /* Insert an aligmnent frag at start of pool. */
+ /* Insert an alignment frag at start of pool. */
if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
{
static void
xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
{
- static bfd_boolean recursive = FALSE;
fragS *pool_location = get_literal_pool_location (now_seg);
segT lit_seg;
bfd_boolean is_init =
if (pool_location == NULL
&& !use_literal_section
- && !recursive
&& !is_init && ! is_fini)
{
if (!auto_litpools)
{
as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
}
-
- /* When we mark a literal pool location, we want to put a frag in
- the literal pool that points to it. But to do that, we want to
- switch_to_literal_fragment. But literal sections don't have
- literal pools, so their location is always null, so we would
- recurse forever. This is kind of hacky, but it works. */
-
- recursive = TRUE;
- xtensa_mark_literal_pool_location ();
- recursive = FALSE;
+ xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
+ pool_location = get_literal_pool_location (now_seg);
}
lit_seg = cache_literal_section (FALSE);