/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ Copyright (C) 2003-2021 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "xtensa-relax.h"
#include "dwarf2dbg.h"
#include "xtensa-istack.h"
-#include "struc-symbol.h"
#include "xtensa-config.h"
#include "elf/xtensa.h"
/* Provide default values for new configuration settings. */
-#ifndef XSHAL_ABI
-#define XSHAL_ABI 0
+#ifndef XTHAL_ABI_WINDOWED
+#define XTHAL_ABI_WINDOWED 0
+#endif
+
+#ifndef XTHAL_ABI_CALL0
+#define XTHAL_ABI_CALL0 1
+#endif
+
+#ifndef XTENSA_MARCH_EARLIEST
+#define XTENSA_MARCH_EARLIEST 0
#endif
#ifndef uint32
bfd_boolean density_supported;
bfd_boolean absolute_literals_supported;
+static unsigned microarch_earliest;
+
static vliw_insn cur_vinsn;
unsigned xtensa_num_pipe_stages;
addressT addr;
short priority; /* 1, 2, or 3 -- 1 is highest */
short original_priority;
+ int literal_count;
};
/* Map a segment to its litpool_frag list. */
static struct litpool_seg litpool_seg_list;
+/* Limit maximal size of auto litpool by half of the j range. */
+#define MAX_AUTO_POOL_LITERALS 16384
+
+/* Limit maximal size of explicit literal pool by l32r range. */
+#define MAX_EXPLICIT_POOL_LITERALS 65536
+
+#define MAX_POOL_LITERALS \
+ (auto_litpools ? MAX_AUTO_POOL_LITERALS : MAX_EXPLICIT_POOL_LITERALS)
/* Directive functions. */
static fixS *xg_append_jump (fragS *fragP, symbolS *sym, offsetT offset);
static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
static bfd_boolean auto_litpools = FALSE;
-static int auto_litpool_limit = 10000;
+static int auto_litpool_limit = 0;
+static bfd_boolean xtensa_is_init_fini (segT seg);
/* Alignment Functions. */
static bfd_boolean workaround_close_loop_end = FALSE;
static bfd_boolean maybe_has_close_loop_end = FALSE;
static bfd_boolean enforce_three_byte_loop_align = FALSE;
+static bfd_boolean opt_linkrelax = TRUE;
/* When workaround_short_loops is TRUE, all loops with early exits must
have at least 3 instructions. workaround_all_short_loops is a modifier
static bfd_boolean workaround_all_short_loops = FALSE;
+/* Generate individual property section for every section.
+ This option is defined in BDF library. */
+extern bfd_boolean elf32xtensa_separate_props;
+
+/* Xtensa ABI.
+ This option is defined in BDF library. */
+extern int elf32xtensa_abi;
static void
xtensa_setup_hw_workarounds (int earliest, int latest)
option_auto_litpools,
option_no_auto_litpools,
option_auto_litpool_limit,
+
+ option_separate_props,
+ option_no_separate_props,
+
+ option_abi_windowed,
+ option_abi_call0,
};
const char *md_shortopts = "";
{ "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
{ "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
+ { "separate-prop-tables", no_argument, NULL, option_separate_props },
+
+ { "abi-windowed", no_argument, NULL, option_abi_windowed },
+ { "abi-call0", no_argument, NULL, option_abi_call0 },
+
{ NULL, no_argument, NULL, 0 }
};
as_warn (_("--no-density option is ignored"));
return 1;
case option_link_relax:
- linkrelax = 1;
+ opt_linkrelax = TRUE;
return 1;
case option_no_link_relax:
- linkrelax = 0;
+ opt_linkrelax = FALSE;
return 1;
case option_flix:
produce_flix = FLIX_ALL;
case option_auto_litpools:
auto_litpools = TRUE;
use_literal_section = FALSE;
+ if (auto_litpool_limit <= 0)
+ auto_litpool_limit = MAX_AUTO_POOL_LITERALS / 2;
return 1;
case option_no_auto_litpools:
return 1;
}
+ case option_separate_props:
+ elf32xtensa_separate_props = TRUE;
+ return 1;
+
+ case option_no_separate_props:
+ elf32xtensa_separate_props = FALSE;
+ return 1;
+
+ case option_abi_windowed:
+ elf32xtensa_abi = XTHAL_ABI_WINDOWED;
+ return 1;
+
+ case option_abi_call0:
+ elf32xtensa_abi = XTHAL_ABI_CALL0;
+ return 1;
+
default:
return 0;
}
--auto-litpool-limit=<value>\n\
(range 100-10000) Maximum number of blocks of\n\
instructions to emit between literal pool\n\
- locations; implies --auto-litpools flag\n", stream);
+ locations; implies --auto-litpools flag\n\
+ --[no-]separate-prop-tables\n\
+ [Do not] place Xtensa property records into\n\
+ individual property sections for each section.\n\
+ Default is to generate single property section.\n", stream);
}
\f
emit_state state;
char *p, *base_name;
char c;
- segT dest_seg;
if (inside_directive (directive_literal))
{
saved_insn_labels = insn_labels;
insn_labels = NULL;
- /* If we are using text-section literals, then this is the right value... */
- dest_seg = now_seg;
-
base_name = input_line_pointer;
xtensa_switch_to_literal_fragment (&state);
- /* ...but if we aren't using text-section-literals, then we
- need to put them in the section we just switched to. */
- if (use_literal_section || directive_state[directive_absolute_literals])
- dest_seg = now_seg;
-
- /* FIXME, despite the previous comments, dest_seg is unused... */
- (void) dest_seg;
-
/* All literals are aligned to four-byte boundaries. */
frag_align (2, 0, 0);
record_alignment (now_seg, 2);
}
}
-fini:
+ fini:
if (saw_comma || saw_colon)
goto err;
input_line_pointer = old_input_line_pointer;
return num_args;
-err:
+ err:
if (saw_comma)
as_bad (_("extra comma"));
else if (saw_colon)
return 0;
}
+ /* Without an operand, this is given a default immediate operand of 0. */
+ if ((strcmp (opname, "simcall") == 0 && microarch_earliest >= 280000))
+ {
+ if (*pnum_args == 0)
+ {
+ arg_strings[0] = (char *) xmalloc (2);
+ strcpy (arg_strings[0], "0");
+ *pnum_args = 1;
+ }
+ return 0;
+ }
+
if (strcmp (opname, "bbsi.l") == 0)
{
if (xg_check_num_args (pnum_args, 3, opname, arg_strings))
{
flagword flags, link_once_flags;
- flags = bfd_get_section_flags (abfd, sec);
+ flags = bfd_section_flags (sec);
link_once_flags = (flags & SEC_LINK_ONCE);
/* Flags might not be set yet. */
symbol will be in the output file. */
if (get_is_linkonce_section (stdoutput, sec))
{
- symbolP = symbol_new (name, sec, 0, frag);
+ symbolP = symbol_new (name, sec, frag, 0);
S_CLEAR_EXTERNAL (symbolP);
/* symbolP->local = 1; */
}
else
- symbolP = symbol_new (name, sec, 0, frag);
+ symbolP = symbol_new (name, sec, frag, 0);
xtensa_add_literal_sym (symbolP);
{
/* Any labels pointing to the current location need
to be adjusted to after the literal pool. */
- emit_state s;
fragS *pool_location;
if (use_literal_section)
RELAX_LITERAL_POOL_END, NULL, 0, NULL);
xtensa_set_frag_assembly_state (frag_now);
- /* Now put a frag into the literal pool that points to this location. */
set_literal_pool_location (now_seg, pool_location);
- xtensa_switch_to_non_abs_literal_fragment (&s);
- frag_align (2, 0, 0);
- record_alignment (now_seg, 2);
-
- /* Close whatever frag is there. */
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_set_frag_assembly_state (frag_now);
- frag_now->tc_frag_data.literal_frag = pool_location;
- frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
- xtensa_restore_emit_state (&s);
- xtensa_set_frag_assembly_state (frag_now);
}
static fragS *
get_literal_pool_location (segT seg)
{
- struct litpool_seg *lps = litpool_seg_list.next;
- struct litpool_frag *lpf;
- for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
- ;
- if (lps)
+ if (auto_litpools)
{
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- { /* Skip "candidates" for now. */
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
- lpf->priority == 1)
- return lpf->fragP;
- }
- /* Must convert a lower-priority pool. */
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
- {
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
- return lpf->fragP;
- }
- /* Still no match -- try for a low priority pool. */
- for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ struct litpool_seg *lps = litpool_seg_list.next;
+ struct litpool_frag *lpf;
+ for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
+ ;
+ if (lps)
{
- if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
- return lpf->fragP;
+ for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ { /* Skip "candidates" for now. */
+ if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
+ lpf->priority == 1)
+ return lpf->fragP;
+ }
+ /* Must convert a lower-priority pool. */
+ for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ {
+ if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
+ return lpf->fragP;
+ }
+ /* Still no match -- try for a low priority pool. */
+ for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
+ {
+ if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ return lpf->fragP;
+ }
}
}
return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
segment_info_type *seginfo;
fragS *fragP;
flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
+ flags = bfd_section_flags (sec);
if (flags & SEC_DEBUGGING)
continue;
if (!(flags & SEC_ALLOC))
segment_info_type *seginfo;
fragS *fragP;
flagword flags;
- flags = bfd_get_section_flags (stdoutput, sec);
+ flags = bfd_section_flags (sec);
if (flags & SEC_DEBUGGING)
continue;
if (!(flags & SEC_ALLOC))
asection *sec,
void *unused ATTRIBUTE_UNUSED)
{
- flagword flags = bfd_get_section_flags (abfd, sec);
+ flagword flags = bfd_section_flags (sec);
segment_info_type *seginfo = seg_info (sec);
fragS *frag = seginfo->frchainP->frch_root;
asection *sec,
void *unused ATTRIBUTE_UNUSED)
{
- flagword flags = bfd_get_section_flags (abfd, sec);
+ flagword flags = bfd_section_flags (sec);
segment_info_type *seginfo = seg_info (sec);
fragS *frag = seginfo->frchainP->frch_root;
xtensa_isa isa = xtensa_default_isa;
directive_state[directive_density] = XCHAL_HAVE_DENSITY;
directive_state[directive_absolute_literals] = XSHAL_USE_ABSOLUTE_LITERALS;
+
+ microarch_earliest = XTENSA_MARCH_EARLIEST;
}
void
xtensa_default_isa = xtensa_isa_init (0, 0);
isa = xtensa_default_isa;
- linkrelax = 1;
+ linkrelax = opt_linkrelax;
/* Set up the literal sections. */
memset (&default_lit_sections, 0, sizeof (default_lit_sections));
/* Set up the assembly state. */
if (!frag_now->tc_frag_data.is_assembly_state_set)
xtensa_set_frag_assembly_state (frag_now);
+
+ if (!use_literal_section)
+ xtensa_mark_literal_pool_location ();
}
/* Set up the assembly state. */
if (!frag_now->tc_frag_data.is_assembly_state_set)
xtensa_set_frag_assembly_state (frag_now);
+
+ if (!use_literal_section
+ && seg_info (now_seg)->tc_segment_info_data.literal_pool_loc == NULL
+ && !xtensa_is_init_fini (now_seg))
+ xtensa_mark_literal_pool_location ();
}
case BFD_RELOC_8:
if (fixP->fx_subsy)
{
+ bfd_boolean neg = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+ < S_GET_VALUE (fixP->fx_subsy);
+
switch (fixP->fx_r_type)
{
case BFD_RELOC_8:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
+ fixP->fx_r_type = neg
+ ? BFD_RELOC_XTENSA_NDIFF8 : BFD_RELOC_XTENSA_PDIFF8;
fixP->fx_signed = 0;
break;
case BFD_RELOC_16:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
+ fixP->fx_r_type = neg
+ ? BFD_RELOC_XTENSA_NDIFF16 : BFD_RELOC_XTENSA_PDIFF16;
fixP->fx_signed = 0;
break;
case BFD_RELOC_32:
- fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
+ fixP->fx_r_type = neg
+ ? BFD_RELOC_XTENSA_NDIFF32 : BFD_RELOC_XTENSA_PDIFF32;
fixP->fx_signed = 0;
break;
default:
val = *valP;
fixP->fx_done = 1;
}
+ else if (S_GET_SEGMENT (fixP->fx_addsy) == absolute_section)
+ {
+ val = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset;
+ *valP = val;
+ fixP->fx_done = 1;
+ }
/* fall through */
case BFD_RELOC_XTENSA_PLT:
frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
if (tinsn->opcode == xtensa_l32r_opcode)
- {
- frag_now->tc_frag_data.literal_frags[slot] =
- tinsn->tok[1].X_add_symbol->sy_frag;
- }
+ frag_now->tc_frag_data.literal_frags[slot]
+ = symbol_get_frag (tinsn->tok[1].X_add_symbol);
if (tinsn->literal_space != 0)
xg_assemble_literal_space (tinsn->literal_space, slot);
frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
find_trampoline_seg (asection *seg)
{
struct trampoline_seg *ts = trampoline_seg_list.next;
+ static struct trampoline_seg *mr;
+
+ if (mr && mr->seg == seg)
+ return mr;
for ( ; ts; ts = ts->next)
{
if (ts->seg == seg)
- return ts;
+ {
+ mr = ts;
+ return ts;
+ }
}
return NULL;
const struct trampoline_chain_entry *pa = a;
const struct trampoline_chain_entry *pb = b;
- if (pa->sym == pb->sym ||
- S_GET_VALUE (pa->sym) == S_GET_VALUE (pb->sym))
- if (pa->offset == pb->offset)
- return 0;
- else
- return pa->offset < pb->offset ? -1 : 1;
- else
- return S_GET_VALUE (pa->sym) < S_GET_VALUE (pb->sym) ? -1 : 1;
+ if (pa->sym != pb->sym)
+ {
+ valueT aval = S_GET_VALUE (pa->sym);
+ valueT bval = S_GET_VALUE (pb->sym);
+
+ if (aval != bval)
+ return aval < bval ? -1 : 1;
+ }
+ if (pa->offset != pb->offset)
+ return pa->offset < pb->offset ? -1 : 1;
+ return 0;
}
static void xg_sort_trampoline_chain (struct trampoline_chain *tc)
static int xg_order_trampoline_chain (const void *a, const void *b)
{
- const struct trampoline_chain *pa = a;
- const struct trampoline_chain *pb = b;
+ const struct trampoline_chain *_pa = a;
+ const struct trampoline_chain *_pb = b;
+ const struct trampoline_chain_entry *pa = &_pa->target;
+ const struct trampoline_chain_entry *pb = &_pb->target;
+ symbolS *s1 = pa->sym;
+ symbolS *s2 = pb->sym;
+
+ if (s1 != s2)
+ {
+ symbolS *tmp = symbol_symbolS (s1);
+ if (tmp)
+ s1 = tmp;
+
+ tmp = symbol_symbolS (s2);
+ if (tmp)
+ s2 = tmp;
- return xg_order_trampoline_chain_entry (&pa->target, &pb->target);
+ if (s1 != s2)
+ return s1 < s2 ? -1 : 1;
+ }
+
+ if (pa->offset != pb->offset)
+ return pa->offset < pb->offset ? -1 : 1;
+ return 0;
}
static struct trampoline_chain *
struct trampoline_chain_index *idx = &ts->chain_index;
struct trampoline_chain c;
+ if (idx->n_entries == 0)
+ return NULL;
+
if (idx->needs_sorting)
{
qsort (idx->entry, idx->n_entries, sizeof (*idx->entry),
printf(" %ld <%d:%d> (%d) [%d]: ",
lpf->addr, lpf->priority, lpf->original_priority,
lpf->fragP->fr_line, count);
- //dump_frag(lpf->fragP);
+ /* dump_frag(lpf->fragP); */
}
}
}
lpf->fragP = fragP;
lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
lpf->original_priority = lpf->priority;
+ lpf->literal_count = 0;
lps->frag_count = 0;
}
static xtensa_insnbuf insnbuf = NULL;
static xtensa_insnbuf slotbuf = NULL;
xtensa_isa isa = xtensa_default_isa;
- int offset = 0;
+ unsigned int offset = 0;
int slot;
bfd_boolean branch_seen = FALSE;
xtensa_isa isa = xtensa_default_isa;
static xtensa_insnbuf insnbuf = NULL;
int insn_count = 0;
- int offset = 0;
+ unsigned int offset = 0;
if (!fragP->tc_frag_data.is_insn)
return insn_count;
{
static xtensa_insnbuf insnbuf = NULL;
xtensa_isa isa = xtensa_default_isa;
- int offset = 0;
+ unsigned int offset = 0;
if (!fragP->tc_frag_data.is_insn)
return FALSE;
return FALSE;
}
-
#define XTINFO_NAME "Xtensa_Info"
#define XTINFO_NAMESZ 12
#define XTINFO_TYPE 1
int sz;
info_sec = subseg_new (".xtensa.info", 0);
- bfd_set_section_flags (stdoutput, info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
+ bfd_set_section_flags (info_sec, SEC_HAS_CONTENTS | SEC_READONLY);
data = XNEWVEC (char, 100);
sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
- XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
+ XSHAL_USE_ABSOLUTE_LITERALS, xtensa_abi_choice ());
sz = strlen (data) + 1;
/* Add enough null terminators to pad to a word boundary. */
trampoline_frag->fr_address > target))
continue;
+ /* Don't choose trampoline that contains the source. */
+ if (source >= trampoline_frag->fr_address
+ && source <= trampoline_frag->fr_address +
+ trampoline_frag->fr_fix)
+ continue;
+
off = trampoline_frag->fr_address - fulcrum;
/* Stop if some trampoline is found and the search is more than
J_RANGE / 4 from the projected fulcrum. A trampoline w/o jump
char label[10 + 2 * sizeof(fp)];
sprintf (label, ".L0_TR_%p", fp);
- lsym = (symbolS *)local_symbol_make (label, now_seg, 0, fp);
+ lsym = (symbolS *) local_symbol_make (label, now_seg, fp, 0);
fp->fr_symbol = lsym;
if (fp->tc_frag_data.needs_jump_around)
{
static fixS *fix_new_exp_in_seg
(segT, subsegT, fragS *, int, int, expressionS *, int,
bfd_reloc_code_real_type);
-static void convert_frag_immed_finish_loop (segT, fragS *, TInsn *);
static void
convert_frag_immed (segT segP,
target_offset += unreach->tc_frag_data.text_expansion[0];
}
gas_assert (gen_label == NULL);
- gen_label = symbol_new (FAKE_LABEL_NAME, now_seg,
+ gen_label = symbol_new (FAKE_LABEL_NAME, now_seg, fragP,
fr_opcode - fragP->fr_literal
- + target_offset, fragP);
+ + target_offset);
break;
case ITYPE_INSN:
}
}
- if (expanded && xtensa_opcode_is_loop (isa, orig_tinsn.opcode) == 1)
- convert_frag_immed_finish_loop (segP, fragP, &orig_tinsn);
-
if (expanded && is_direct_call_opcode (orig_tinsn.opcode))
{
/* Add an expansion note on the expanded instruction. */
}
-/* Relax a loop instruction so that it can span loop >256 bytes.
-
- loop as, .L1
- .L0:
- rsr as, LEND
- wsr as, LBEG
- addi as, as, lo8 (label-.L1)
- addmi as, as, mid8 (label-.L1)
- wsr as, LEND
- isync
- rsr as, LCOUNT
- addi as, as, 1
- .L1:
- <<body>>
- label:
-*/
-
-static void
-convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
-{
- TInsn loop_insn;
- TInsn addi_insn;
- TInsn addmi_insn;
- unsigned long target;
- static xtensa_insnbuf insnbuf = NULL;
- unsigned int loop_length, loop_length_hi, loop_length_lo;
- xtensa_isa isa = xtensa_default_isa;
- addressT loop_offset;
- addressT addi_offset = 9;
- addressT addmi_offset = 12;
- fragS *next_fragP;
- int target_count;
-
- if (!insnbuf)
- insnbuf = xtensa_insnbuf_alloc (isa);
-
- /* Get the loop offset. */
- loop_offset = get_expanded_loop_offset (tinsn->opcode);
-
- /* Validate that there really is a LOOP at the loop_offset. Because
- loops are not bundleable, we can assume that the instruction will be
- in slot 0. */
- tinsn_from_chars (&loop_insn, fragP->fr_opcode + loop_offset, 0);
- tinsn_immed_from_frag (&loop_insn, fragP, 0);
-
- gas_assert (xtensa_opcode_is_loop (isa, loop_insn.opcode) == 1);
- addi_offset += loop_offset;
- addmi_offset += loop_offset;
-
- gas_assert (tinsn->ntok == 2);
- if (tinsn->tok[1].X_op == O_constant)
- target = tinsn->tok[1].X_add_number;
- else if (tinsn->tok[1].X_op == O_symbol)
- {
- /* Find the fragment. */
- symbolS *sym = tinsn->tok[1].X_add_symbol;
- gas_assert (S_GET_SEGMENT (sym) == segP
- || S_GET_SEGMENT (sym) == absolute_section);
- target = (S_GET_VALUE (sym) + tinsn->tok[1].X_add_number);
- }
- else
- {
- as_bad (_("invalid expression evaluation type %d"), tinsn->tok[1].X_op);
- target = 0;
- }
-
- loop_length = target - (fragP->fr_address + fragP->fr_fix);
- loop_length_hi = loop_length & ~0x0ff;
- loop_length_lo = loop_length & 0x0ff;
- if (loop_length_lo >= 128)
- {
- loop_length_lo -= 256;
- loop_length_hi += 256;
- }
-
- /* Because addmi sign-extends the immediate, 'loop_length_hi' can be at most
- 32512. If the loop is larger than that, then we just fail. */
- if (loop_length_hi > 32512)
- as_bad_where (fragP->fr_file, fragP->fr_line,
- _("loop too long for LOOP instruction"));
-
- tinsn_from_chars (&addi_insn, fragP->fr_opcode + addi_offset, 0);
- gas_assert (addi_insn.opcode == xtensa_addi_opcode);
-
- tinsn_from_chars (&addmi_insn, fragP->fr_opcode + addmi_offset, 0);
- gas_assert (addmi_insn.opcode == xtensa_addmi_opcode);
-
- set_expr_const (&addi_insn.tok[2], loop_length_lo);
- tinsn_to_insnbuf (&addi_insn, insnbuf);
-
- fragP->tc_frag_data.is_insn = TRUE;
- xtensa_insnbuf_to_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addi_offset, 0);
-
- set_expr_const (&addmi_insn.tok[2], loop_length_hi);
- tinsn_to_insnbuf (&addmi_insn, insnbuf);
- xtensa_insnbuf_to_chars
- (isa, insnbuf, (unsigned char *) fragP->fr_opcode + addmi_offset, 0);
-
- /* Walk through all of the frags from here to the loop end
- and mark them as no_transform to keep them from being modified
- by the linker. If we ever have a relocation for the
- addi/addmi of the difference of two symbols we can remove this. */
-
- target_count = 0;
- for (next_fragP = fragP; next_fragP != NULL;
- next_fragP = next_fragP->fr_next)
- {
- next_fragP->tc_frag_data.is_no_transform = TRUE;
- if (next_fragP->tc_frag_data.is_loop_target)
- target_count++;
- if (target_count == 2)
- break;
- }
-}
-
\f
/* A map that keeps information on a per-subsegment basis. This is
maintained during initial assembly, but is invalid once the
/* 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);
+ lsym = (symbolS *) local_symbol_make (label, lps->seg, poolend, 0);
poolbeg->fr_symbol = lsym;
/* Rest is done in xtensa_relax_frag. */
}
-static void
-xtensa_move_literals (void)
+static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lpf,
+ addressT addr)
{
- seg_list *segment;
- frchainS *frchain_from, *frchain_to;
- fragS *search_frag, *next_frag, *literal_pool, *insert_after;
- fragS **frag_splice;
- emit_state state;
- segT dest_seg;
- fixS *fix, *next_fix, **fix_splice;
- sym_list *lit;
- struct litpool_seg *lps;
- const char *init_name = INIT_SECTION_NAME;
- const char *fini_name = FINI_SECTION_NAME;
- int init_name_len = strlen(init_name);
- int fini_name_len = strlen(fini_name);
+ struct litpool_frag *lp = lpf->prev;
- mark_literal_frags (literal_head->next);
+ gas_assert (lp->fragP);
- if (use_literal_section)
- return;
+ while (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ {
+ lp = lp->prev;
+ if (lp->fragP == NULL)
+ {
+ /* End of list; have to bite the bullet.
+ Take the nearest. */
+ lp = lpf->prev;
+ break;
+ }
+ /* Does it (conservatively) reach? */
+ if (addr - lp->addr <= 128 * 1024)
+ {
+ if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
+ lp->literal_count < MAX_POOL_LITERALS)
+ {
+ /* Found a good one. */
+ break;
+ }
+ else if (lp->prev->fragP &&
+ addr - lp->prev->addr > 128 * 1024 &&
+ lp->prev->literal_count < MAX_POOL_LITERALS)
+ {
+ /* 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. */
+ lp = lpf->prev;
+ break;
+ }
+ }
+ }
- /* Assign addresses (rough estimates) to the potential literal pool locations
- and create new ones if the gaps are too large. */
+ if (lp->literal_count >= MAX_POOL_LITERALS)
+ {
+ lp = lpf->prev;
+ while (lp && lp->fragP && lp->literal_count >= MAX_POOL_LITERALS)
+ {
+ lp = lp->prev;
+ }
+ gas_assert (lp);
+ }
+
+ gas_assert (lp && lp->fragP && lp->literal_count < MAX_POOL_LITERALS);
+ ++lp->literal_count;
+
+ /* Convert candidate and add the jump around. */
+ if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
+ xg_promote_candidate_litpool (lps, lp);
+
+ return lp;
+}
+
+static bfd_boolean xtensa_is_init_fini (segT seg)
+{
+ if (!seg)
+ return 0;
+ return strcmp (segment_name (seg), INIT_SECTION_NAME) == 0
+ || strcmp (segment_name (seg), FINI_SECTION_NAME) == 0;
+}
+
+static void
+xtensa_assign_litpool_addresses (void)
+{
+ struct litpool_seg *lps;
for (lps = litpool_seg_list.next; lps; lps = lps->next)
{
struct litpool_frag *lpf = lps->frag_list.next;
addressT addr = 0;
+ if (xtensa_is_init_fini (lps->seg))
+ continue;
+
for ( ; frchP; frchP = frchP->frch_next)
{
fragS *fragP;
int slot;
for (slot = 0; slot < MAX_SLOTS; slot++)
{
- if (fragP->tc_frag_data.literal_frags[slot])
+ fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
+
+ if (litfrag
+ && litfrag->tc_frag_data.is_literal
+ && !litfrag->tc_frag_data.literal_frag)
{
- /* L32R; point its literal to the nearest litpool
- preferring non-"candidate" positions to avoid
- the jump-around. */
- fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
- struct litpool_frag *lp = lpf->prev;
- if (!lp->fragP)
- {
- break;
- }
- while (lp->fragP->fr_subtype ==
- RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
- {
- lp = lp->prev;
- if (lp->fragP == NULL)
- {
- /* End of list; have to bite the bullet.
- Take the nearest. */
- lp = lpf->prev;
- break;
- }
- /* Does it (conservatively) reach? */
- if (addr - lp->addr <= 128 * 1024)
- {
- if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
- {
- /* Found a good one. */
- break;
- }
- else if (lp->prev->fragP &&
- addr - lp->prev->addr > 128 * 1024)
- {
- /* 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. */
- lp = lpf->prev;
- 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
- forward refs. */
- litfrag->tc_frag_data.literal_frag = lp->fragP;
- }
+ /* L32R referring .literal or generated as a result
+ of relaxation. Point its literal to the nearest
+ litpool preferring non-"candidate" positions to
+ avoid the jump-around. */
+
+ struct litpool_frag *lp;
+
+ lp = xg_find_litpool (lps, lpf, addr);
+ /* Take earliest use of this literal to avoid
+ forward refs. */
+ litfrag->tc_frag_data.literal_frag = lp->fragP;
}
}
}
}
}
}
+}
+
+static void
+xtensa_move_literals (void)
+{
+ seg_list *segment;
+ frchainS *frchain_from, *frchain_to;
+ fragS *search_frag, *next_frag, *literal_pool, *insert_after;
+ fragS **frag_splice;
+ emit_state state;
+ segT dest_seg;
+ fixS *fix, *next_fix, **fix_splice;
+ sym_list *lit;
+ const char *init_name = INIT_SECTION_NAME;
+ const char *fini_name = FINI_SECTION_NAME;
+ int init_name_len = strlen(init_name);
+ int fini_name_len = strlen(fini_name);
+ mark_literal_frags (literal_head->next);
+
+ if (use_literal_section)
+ return;
+
+ /* Assign addresses (rough estimates) to the potential literal pool locations
+ and create new ones if the gaps are too large. */
+
+ xtensa_assign_litpool_addresses ();
+
+ /* Walk through the literal segments. */
for (segment = literal_head->next; segment; segment = segment->next)
{
const char *seg_name = segment_name (segment->seg);
}
if (!search_frag)
- {
- search_frag = frchain_from->frch_root;
- as_bad_where (search_frag->fr_file, search_frag->fr_line,
- _("literal pool location required for text-section-literals; specify with .literal_position"));
- continue;
- }
+ continue;
gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
== RELAX_LITERAL_POOL_BEGIN);
{
fragS *pool_location = get_literal_pool_location (now_seg);
segT lit_seg;
- bfd_boolean is_init =
- (now_seg && !strcmp (segment_name (now_seg), INIT_SECTION_NAME));
- bfd_boolean is_fini =
- (now_seg && !strcmp (segment_name (now_seg), FINI_SECTION_NAME));
+ bfd_boolean is_init_fini = xtensa_is_init_fini (now_seg);
if (pool_location == NULL
&& !use_literal_section
- && !is_init && ! is_fini)
+ && !is_init_fini)
{
if (!auto_litpools)
{
xtensa_switch_section_emit_state (result, lit_seg, 0);
if (!use_literal_section
- && !is_init && !is_fini
+ && !is_init_fini
&& get_literal_pool_location (now_seg) != pool_location)
{
/* Close whatever frag is there. */
elf_group_name (seg) = group_name;
- bfd_set_section_flags (stdoutput, seg, flags);
- bfd_set_section_alignment (stdoutput, seg, 2);
+ bfd_set_section_flags (seg, flags);
+ bfd_set_section_alignment (seg, 2);
}
*pcached = seg;
num_recs++;
rec_size = num_recs * 8;
- bfd_set_section_size (stdoutput, sec, rec_size);
+ bfd_set_section_size (sec, rec_size);
if (num_recs)
{
num_recs++;
rec_size = num_recs * (8 + 4);
- bfd_set_section_size (stdoutput, sec, rec_size);
+ bfd_set_section_size (sec, rec_size);
/* elf_section_data (sec)->this_hdr.sh_entsize = 12; */
if (num_recs)
static bfd_boolean
exclude_section_from_property_tables (segT sec)
{
- flagword flags = bfd_get_section_flags (stdoutput, sec);
+ flagword flags = bfd_section_flags (sec);
/* Sections that don't contribute to the memory footprint are excluded. */
if ((flags & SEC_DEBUGGING)