/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright (C) 2003-2017 Free Software Foundation, Inc.
+ Copyright (C) 2003-2018 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"
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;
/* Alignment Functions. */
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;
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,
};
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 },
+
{ NULL, no_argument, NULL, 0 }
};
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;
+
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
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;
xtensa_check_frag_count ();
}
+struct trampoline_chain_entry
+{
+ symbolS *sym;
+ addressT offset;
+};
+
+/* Trampoline chain for a given (sym, offset) pair is a sorted array
+ of locations of trampoline jumps leading there. Jumps are represented
+ as pairs (sym, offset): trampoline frag symbol and offset of the jump
+ inside the frag. */
+struct trampoline_chain
+{
+ struct trampoline_chain_entry target;
+ struct trampoline_chain_entry *entry;
+ size_t n_entries;
+ size_t n_max;
+ bfd_boolean needs_sorting;
+};
+
+struct trampoline_chain_index
+{
+ struct trampoline_chain *entry;
+ size_t n_entries;
+ size_t n_max;
+ bfd_boolean needs_sorting;
+};
+
struct trampoline_index
{
fragS **entry;
{
struct trampoline_seg *next;
asection *seg;
+ /* Trampolines ordered by their frag fr_address */
struct trampoline_index index;
+ /* Known trampoline chains ordered by (sym, offset) pair */
+ struct trampoline_chain_index chain_index;
};
static struct trampoline_seg trampoline_seg_list;
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;
return fragP->fr_var < 3;
}
+static int xg_order_trampoline_chain_entry (const void *a, const void *b)
+{
+ 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;
+}
+
+static void xg_sort_trampoline_chain (struct trampoline_chain *tc)
+{
+ qsort (tc->entry, tc->n_entries, sizeof (*tc->entry),
+ xg_order_trampoline_chain_entry);
+ tc->needs_sorting = FALSE;
+}
+
+/* Find entry index in the given chain with maximal address <= source. */
+static size_t xg_find_chain_entry (struct trampoline_chain *tc,
+ addressT source)
+{
+ size_t a = 0;
+ size_t b = tc->n_entries;
+
+ if (tc->needs_sorting)
+ xg_sort_trampoline_chain (tc);
+
+ while (b - a > 1)
+ {
+ size_t c = (a + b) / 2;
+ struct trampoline_chain_entry *e = tc->entry + c;
+
+ if (S_GET_VALUE(e->sym) + e->offset <= source)
+ a = c;
+ else
+ b = c;
+ }
+ return a;
+}
+
+/* Find the best jump target for the source in the given trampoline chain.
+ The best jump target is the one that results in the shortest path to the
+ final target, it's the location of the jump closest to the final target,
+ but within the J_RANGE - J_MARGIN from the source. */
+static struct trampoline_chain_entry *
+xg_get_best_chain_entry (struct trampoline_chain *tc, addressT source)
+{
+ addressT target = S_GET_VALUE(tc->target.sym) + tc->target.offset;
+ size_t i = xg_find_chain_entry (tc, source);
+ struct trampoline_chain_entry *e = tc->entry + i;
+ int step = target < source ? -1 : 1;
+ addressT chained_target;
+ offsetT off;
+
+ if (target > source &&
+ S_GET_VALUE(e->sym) + e->offset <= source &&
+ i + 1 < tc->n_entries)
+ ++i;
+
+ while (i + step < tc->n_entries)
+ {
+ struct trampoline_chain_entry *next = tc->entry + i + step;
+
+ chained_target = S_GET_VALUE(next->sym) + next->offset;
+ off = source - chained_target;
+
+ if (labs (off) >= J_RANGE - J_MARGIN)
+ break;
+
+ i += step;
+ }
+
+ e = tc->entry + i;
+ chained_target = S_GET_VALUE(e->sym) + e->offset;
+ off = source - chained_target;
+
+ if (labs (off) < J_MARGIN ||
+ labs (off) >= J_RANGE - J_MARGIN)
+ return &tc->target;
+ return tc->entry + i;
+}
+
+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_entry *pa = &_pa->target;
+ const struct trampoline_chain_entry *pb = &_pb->target;
+ symbolS *s1 = pa->sym;
+ symbolS *s2 = pb->sym;
+ symbolS *tmp;
+
+ tmp = symbol_symbolS (s1);
+ if (tmp)
+ s1 = tmp;
+
+ tmp = symbol_symbolS (s2);
+ if (tmp)
+ s2 = tmp;
+
+ if (s1 == s2)
+ if (pa->offset == pb->offset)
+ return 0;
+ else
+ return pa->offset < pb->offset ? -1 : 1;
+ else
+ return s1 < s2 ? -1 : 1;
+}
+
+static struct trampoline_chain *
+xg_get_trampoline_chain (struct trampoline_seg *ts,
+ symbolS *sym,
+ addressT offset)
+{
+ struct trampoline_chain_index *idx = &ts->chain_index;
+ struct trampoline_chain c;
+
+ if (idx->needs_sorting)
+ {
+ qsort (idx->entry, idx->n_entries, sizeof (*idx->entry),
+ xg_order_trampoline_chain);
+ idx->needs_sorting = FALSE;
+ }
+ c.target.sym = sym;
+ c.target.offset = offset;
+ return bsearch (&c, idx->entry, idx->n_entries,
+ sizeof (struct trampoline_chain),
+ xg_order_trampoline_chain);
+}
+
+/* Find trampoline chain in the given trampoline segment that is going
+ to the *sym + *offset. If found, replace *sym and *offset with the
+ best jump target in that chain. */
+static struct trampoline_chain *
+xg_find_best_eq_target (struct trampoline_seg *ts,
+ addressT source, symbolS **sym,
+ addressT *offset)
+{
+ struct trampoline_chain *tc = xg_get_trampoline_chain (ts, *sym, *offset);
+
+ if (tc)
+ {
+ struct trampoline_chain_entry *e = xg_get_best_chain_entry (tc, source);
+
+ *sym = e->sym;
+ *offset = e->offset;
+ }
+ return tc;
+}
+
+static void xg_add_location_to_chain (struct trampoline_chain *tc,
+ symbolS *sym, addressT offset)
+{
+ struct trampoline_chain_entry *e;
+
+ if (tc->n_entries == tc->n_max)
+ {
+ tc->n_max = (tc->n_max + 1) * 2;
+ tc->entry = xrealloc (tc->entry, sizeof (*tc->entry) * tc->n_max);
+ }
+ e = tc->entry + tc->n_entries;
+ e->sym = sym;
+ e->offset = offset;
+ ++tc->n_entries;
+ tc->needs_sorting = TRUE;
+}
+
+static struct trampoline_chain *
+xg_create_trampoline_chain (struct trampoline_seg *ts,
+ symbolS *sym, addressT offset)
+{
+ struct trampoline_chain_index *idx = &ts->chain_index;
+ struct trampoline_chain *tc;
+
+ if (idx->n_entries == idx->n_max)
+ {
+ idx->n_max = (idx->n_max + 1) * 2;
+ idx->entry = xrealloc (idx->entry,
+ sizeof (*idx->entry) * idx->n_max);
+ }
+
+ tc = idx->entry + idx->n_entries;
+ tc->target.sym = sym;
+ tc->target.offset = offset;
+ tc->entry = NULL;
+ tc->n_entries = 0;
+ tc->n_max = 0;
+ xg_add_location_to_chain (tc, sym, offset);
+
+ ++idx->n_entries;
+ idx->needs_sorting = TRUE;
+
+ return tc;
+}
+
void dump_trampolines (void);
void
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;
}
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
for (fx = seginfo->fix_root; fx; fx = fx->fx_next)
{
fixS *fixP = fx;
+ struct trampoline_chain *tc = NULL;
+
+ if (xg_is_relaxable_fixup (fixP))
+ {
+ tc = xg_find_best_eq_target (ts, fixP->fx_frag->fr_address,
+ &fixP->fx_addsy, &fixP->fx_offset);
+ if (!tc)
+ tc = xg_create_trampoline_chain (ts, fixP->fx_addsy,
+ fixP->fx_offset);
+ gas_assert (tc);
+ }
while (xg_is_relaxable_fixup (fixP))
- fixP = xg_relax_fixup (idx, fixP);
+ {
+ fixP = xg_relax_fixup (idx, fixP);
+ xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol,
+ fixP->fx_where);
+ }
}
}
static fragS *
-search_trampolines (TInsn *tinsn, fragS *fragP, bfd_boolean unreachable_only)
+xg_find_best_trampoline_for_tinsn (TInsn *tinsn, fragS *fragP)
{
+ symbolS *sym = tinsn->tok[0].X_add_symbol;
+ addressT source = fragP->fr_address;
+ addressT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
struct trampoline_seg *ts = find_trampoline_seg (now_seg);
- fragS *tf = NULL;
size_t i;
- fragS *best_tf = NULL;
- offsetT best_delta = 0;
- offsetT best_addr = 0;
- symbolS *sym = tinsn->tok[0].X_add_symbol;
- offsetT target = S_GET_VALUE (sym) + tinsn->tok[0].X_add_number;
- offsetT addr = fragP->fr_address;
- offsetT lower = (addr < target) ? addr : target;
- offsetT upper = (addr > target) ? addr : target;
- offsetT delta = upper - lower;
- offsetT midpoint = lower + delta / 2;
- offsetT this_delta = -1;
- offsetT this_addr = -1;
-
- if (!ts)
- return NULL;
-
- if (delta > 2 * J_RANGE)
- {
- /* One trampoline won't do; we need multiple.
- Choose the farthest trampoline that's still in range of the original
- and let a later pass finish the job. */
- for (i = 0; i < ts->index.n_entries; ++i)
- {
- tf = ts->index.entry[i];
- this_addr = tf->fr_address + tf->fr_fix;
- if (upper == addr)
- {
- /* Backward jump. */
- if (addr - this_addr < J_RANGE)
- break;
- }
- else if (i + 1 < ts->index.n_entries)
- {
- /* Forward jump. */
- fragS *next = ts->index.entry[i + 1];
- offsetT next_addr = next->fr_address + next->fr_fix;
-
- if (next_addr - addr > J_RANGE)
- break;
- }
- else
- {
- break;
- }
- }
- if (i < ts->index.n_entries &&
- labs (addr - this_addr) < J_RANGE)
- return tf;
- return NULL;
- }
-
- for (i = 0; i < ts->index.n_entries; ++i)
- {
- tf = ts->index.entry[i];
- this_addr = tf->fr_address + tf->fr_fix;
- this_delta = labs (this_addr - midpoint);
- if (unreachable_only && tf->tc_frag_data.needs_jump_around)
- continue;
- if (!best_tf || this_delta < best_delta)
- {
- best_tf = tf;
- best_delta = this_delta;
- best_addr = this_addr;
- }
- }
-
- if (best_tf &&
- best_delta < J_RANGE &&
- labs(best_addr - lower) < J_RANGE &&
- labs(best_addr - upper) < J_RANGE)
- return best_tf;
-
- return NULL; /* No suitable trampoline found. */
-}
-
-
-static fragS *
-get_best_trampoline (TInsn *tinsn, fragS *fragP)
-{
- fragS *tf = NULL;
-
- tf = search_trampolines (tinsn, fragP, TRUE); /* Try unreachable first. */
+ if (!ts || !ts->index.n_entries)
+ return NULL;
- if (tf == NULL)
- tf = search_trampolines (tinsn, fragP, FALSE); /* Try ones needing a jump-around, too. */
+ i = xg_find_best_trampoline (&ts->index, source, target);
- return tf;
+ return ts->index.entry[i];
}
return growth;
}
-
static int
-add_jump_to_trampoline (fragS *tramp, fragS *origfrag)
+xg_get_single_symbol_slot (fragS *fragP)
{
- int i, slot = -1;
+ int i;
+ int slot = -1;
for (i = 0; i < MAX_SLOTS; ++i)
- if (origfrag->tc_frag_data.slot_symbols[i])
+ if (fragP->tc_frag_data.slot_symbols[i])
{
gas_assert (slot == -1);
slot = i;
gas_assert (slot >= 0 && slot < MAX_SLOTS);
+ return slot;
+}
+
+static fixS *
+add_jump_to_trampoline (fragS *tramp, fragS *origfrag)
+{
+ int slot = xg_get_single_symbol_slot (origfrag);
+ fixS *fixP;
+
/* Assemble a jump to the target label in the trampoline frag. */
- xg_append_jump (tramp,
- origfrag->tc_frag_data.slot_symbols[slot],
- origfrag->tc_frag_data.slot_offsets[slot]);
+ fixP = xg_append_jump (tramp,
+ origfrag->tc_frag_data.slot_symbols[slot],
+ origfrag->tc_frag_data.slot_offsets[slot]);
/* Modify the original j to point here. */
origfrag->tc_frag_data.slot_symbols[slot] = tramp->fr_symbol;
xg_remove_trampoline_from_index (&ts->index, tr);
}
- return 3;
+ return fixP;
}
istack.insn[istack.ninsn - 2].opcode == xtensa_j_opcode)
{
TInsn *jinsn = &istack.insn[istack.ninsn - 2];
+ struct trampoline_seg *ts = find_trampoline_seg (segP);
+ struct trampoline_chain *tc = NULL;
+
+ if (ts &&
+ !xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+ total_text_diff))
+ {
+ int s = xg_get_single_symbol_slot (fragP);
+ addressT offset = fragP->tc_frag_data.slot_offsets[s];
+
+ tc = xg_find_best_eq_target (ts, fragP->fr_address,
+ &fragP->tc_frag_data.slot_symbols[s],
+ &offset);
+
+ if (!tc)
+ tc = xg_create_trampoline_chain (ts,
+ fragP->tc_frag_data.slot_symbols[s],
+ offset);
+ fragP->tc_frag_data.slot_offsets[s] = offset;
+ tinsn_immed_from_frag (jinsn, fragP, s);
+ }
- if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset, total_text_diff))
+ if (!xg_symbolic_immeds_fit (jinsn, segP, fragP, fragP->fr_offset,
+ total_text_diff))
{
- fragS *tf = get_best_trampoline (jinsn, fragP);
+ fragS *tf = xg_find_best_trampoline_for_tinsn (jinsn, fragP);
if (tf)
{
- this_text_diff += init_trampoline_frag (tf);
- this_text_diff += add_jump_to_trampoline (tf, fragP);
+ fixS *fixP;
+
+ this_text_diff += init_trampoline_frag (tf) + 3;
+ fixP = add_jump_to_trampoline (tf, fragP);
+ xg_add_location_to_chain (tc, fixP->fx_frag->fr_symbol,
+ fixP->fx_where);
+ fragP->tc_frag_data.relax_seen = FALSE;
}
else
{
/* Rest is done in xtensa_relax_frag. */
}
+static struct litpool_frag *xg_find_litpool (struct litpool_seg *lps,
+ struct litpool_frag *lpf,
+ addressT addr)
+{
+ struct litpool_frag *lp = lpf->prev;
+
+ gas_assert (lp->fragP);
+
+ 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;
+ }
+ }
+ }
+
+ 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_move_literals (void)
{
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;
}
}
}
{
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. */