/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright (C) 2003-2015 Free Software Foundation, Inc.
+ Copyright (C) 2003-2016 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
struct suffix_reloc_map
{
- char *suffix;
+ const char *suffix;
int length;
bfd_reloc_code_real_type reloc;
unsigned char operator;
#endif
};
+/* A circular list of all potential and actual literal pool locations
+ in a segment. */
+struct litpool_frag
+{
+ struct litpool_frag *next;
+ struct litpool_frag *prev;
+ fragS *fragP;
+ addressT addr;
+ short priority; /* 1, 2, or 3 -- 1 is highest */
+ short original_priority;
+};
+
+/* Map a segment to its litpool_frag list. */
+struct litpool_seg
+{
+ struct litpool_seg *next;
+ asection *seg;
+ struct litpool_frag frag_list;
+ int frag_count; /* since last litpool location */
+};
+
+static struct litpool_seg litpool_seg_list;
+
/* Directive functions. */
static void xtensa_maybe_create_trampoline_frag (void);
struct trampoline_frag;
static int init_trampoline_frag (struct trampoline_frag *);
+static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
+static bfd_boolean auto_litpools = FALSE;
+static int auto_litpool_limit = 10000;
/* Alignment Functions. */
option_trampolines,
option_no_trampolines,
+
+ option_auto_litpools,
+ option_no_auto_litpools,
+ option_auto_litpool_limit,
};
const char *md_shortopts = "";
{ "trampolines", no_argument, NULL, option_trampolines },
{ "no-trampolines", no_argument, NULL, option_no_trampolines },
+ { "auto-litpools", no_argument, NULL, option_auto_litpools },
+ { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
+ { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
+
{ NULL, no_argument, NULL, 0 }
};
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
switch (c)
{
case option_target_hardware:
{
int earliest, latest = 0;
+ char *end;
if (*arg == 0 || *arg == '-')
as_fatal (_("invalid target hardware version"));
- earliest = strtol (arg, &arg, 0);
+ earliest = strtol (arg, &end, 0);
- if (*arg == 0)
+ if (*end == 0)
latest = earliest;
- else if (*arg == '-')
+ else if (*end == '-')
{
- if (*++arg == 0)
+ if (*++end == 0)
as_fatal (_("invalid target hardware version"));
- latest = strtol (arg, &arg, 0);
+ latest = strtol (end, &end, 0);
}
- if (*arg != 0)
+ if (*end != 0)
as_fatal (_("invalid target hardware version"));
xtensa_setup_hw_workarounds (earliest, latest);
use_trampolines = FALSE;
return 1;
+ case option_auto_litpools:
+ auto_litpools = TRUE;
+ use_literal_section = FALSE;
+ return 1;
+
+ case option_no_auto_litpools:
+ auto_litpools = FALSE;
+ auto_litpool_limit = -1;
+ return 1;
+
+ case option_auto_litpool_limit:
+ {
+ int value = 0;
+ char *end;
+ if (auto_litpool_limit < 0)
+ as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
+ if (*arg == 0 || *arg == '-')
+ as_fatal (_("invalid auto-litpool-limit argument"));
+ value = strtol (arg, &end, 10);
+ if (*end != 0)
+ as_fatal (_("invalid auto-litpool-limit argument"));
+ if (value < 100 || value > 10000)
+ as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
+ auto_litpool_limit = value;
+ auto_litpools = TRUE;
+ use_literal_section = FALSE;
+ return 1;
+ }
+
default:
return 0;
}
flix bundles\n\
--rename-section old=new Rename section 'old' to 'new'\n\
--[no-]trampolines [Do not] generate trampolines (jumps to jumps)\n\
- when jumps do not reach their targets\n", stream);
+ when jumps do not reach their targets\n\
+ --[no-]auto-litpools [Do not] automatically create literal pools\n\
+ --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);
}
\f
static void
directive_push (directiveE directive, bfd_boolean negated, const void *datum)
{
- char *file;
+ const char *file;
unsigned int line;
state_stackS *stack = (state_stackS *) xmalloc (sizeof (state_stackS));
- as_where (&file, &line);
+ file = as_where (&line);
stack->directive = directive;
stack->negated = negated;
{
int len;
unsigned i;
- char *directive_string;
+ const char *directive_string;
if (strncmp (input_line_pointer, "no-", 3) != 0)
*negated = FALSE;
frag_align (2, 0, 0);
record_alignment (now_seg, 2);
- c = get_symbol_end ();
+ c = get_symbol_name (&base_name);
/* Just after name is now '\0'. */
p = input_line_pointer;
*p = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (*input_line_pointer != ',' && *input_line_pointer != ':')
{
xtensa_restore_emit_state (&state);
return;
}
- *p = 0;
+ *p = 0;
colon (base_name);
-
*p = c;
+
input_line_pointer++; /* skip ',' or ':' */
xtensa_elf_cons (4);
{
struct suffix_reloc_map *sfx;
unsigned char operator = (unsigned char) -1;
-
+
for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++)
{
if (sfx->reloc == reloc)
static void
-xg_replace_opname (char **popname, char *newop)
+xg_replace_opname (char **popname, const char *newop)
{
free (*popname);
- *popname = (char *) xmalloc (strlen (newop) + 1);
- strcpy (*popname, newop);
+ *popname = xstrdup (newop);
}
/* Another special case for "WSR.INTSET".... */
if (is_write && !is_user && !strcasecmp ("interrupt", sr_name))
sr_name = "intset";
- new_opname = (char *) xmalloc (strlen (sr_name) + 6);
- sprintf (new_opname, "%s.%s", *popname, sr_name);
+ new_opname = concat (*popname, ".", sr_name, (char *) NULL);
free (*popname);
*popname = new_opname;
static int
-xtensa_translate_zero_immed (char *old_op,
- char *new_op,
+xtensa_translate_zero_immed (const char *old_op,
+ const char *new_op,
char **popname,
int *pnum_args,
char **arg_strings)
if (xg_check_num_args (pnum_args, 2, opname, arg_strings))
return -1;
xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
- arg_strings[2] = (char *) xmalloc (strlen (arg_strings[1]) + 1);
- strcpy (arg_strings[2], arg_strings[1]);
+ arg_strings[2] = xstrdup (arg_strings[1]);
*pnum_args = 3;
}
return 0;
}
/* Don't do anything special with NOPs inside FLIX instructions. They
- are handled elsewhere. Real NOP instructions are always available
+ are handled elsewhere. Real NOP instructions are always available
in configurations with FLIX, so this should never be an issue but
check for it anyway. */
if (!cur_vinsn.inside_bundle && xtensa_nop_opcode == XTENSA_UNDEFINED
if (xg_check_num_args (pnum_args, 0, opname, arg_strings))
return -1;
xg_replace_opname (popname, (has_underbar ? "_or" : "or"));
- arg_strings[0] = (char *) xmalloc (3);
- arg_strings[1] = (char *) xmalloc (3);
- arg_strings[2] = (char *) xmalloc (3);
- strcpy (arg_strings[0], "a1");
- strcpy (arg_strings[1], "a1");
- strcpy (arg_strings[2], "a1");
+ arg_strings[0] = xstrdup ("a1");
+ arg_strings[1] = xstrdup ("a1");
+ arg_strings[2] = xstrdup ("a1");
*pnum_args = 3;
}
return 0;
if (xtensa_operand_is_PCrelative (xtensa_default_isa, opcode, operand)
== 1)
as_bad_where ((char *) file, line,
- _("operand %d of '%s' has out of range value '%u'"),
+ _("operand %d of '%s' has out of range value '%u'"),
operand + 1,
xtensa_opcode_name (xtensa_default_isa, opcode),
value);
pool_location = frag_now;
frag_now->tc_frag_data.lit_frchain = frchain_now;
frag_now->tc_frag_data.literal_frag = frag_now;
+ /* Just record this frag. */
+ xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
frag_variant (rs_machine_dependent, 0, 0,
RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
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)
+ {
+ 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;
}
if (frag->fr_fix == 0)
frag = next_non_empty_frag (frag);
-
+
if (frag)
{
xtensa_insnbuf_from_chars
fmt = xtensa_format_decode (isa, insnbuf);
op_size = xtensa_format_length (isa, fmt);
frag_addr = frag->fr_address % xtensa_fetch_width;
-
+
if (frag_addr + op_size > xtensa_fetch_width)
as_warn_where (frag->fr_file, frag->fr_line,
_("unaligned loop: %d bytes at 0x%lx"),
xtensa_rsr_lcount_opcode = xtensa_opcode_lookup (isa, "rsr.lcount");
xtensa_waiti_opcode = xtensa_opcode_lookup (isa, "waiti");
- for (i = 0; i < xtensa_isa_num_formats (isa); i++)
+ for (i = 0; i < xtensa_isa_num_formats (isa); i++)
{
int format_slots = xtensa_format_num_slots (isa, i);
if (format_slots > config_max_slots)
/* Split off the opcode. */
opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/0123456789.");
- opname = xmalloc (opnamelen + 1);
- memcpy (opname, str, opnamelen);
- opname[opnamelen] = '\0';
+ opname = xstrndup (str, opnamelen);
num_args = tokenize_arguments (arg_strings, str + opnamelen);
if (num_args == -1)
symbolS *expr_symbols = NULL;
-void
+void
xtensa_symbol_new_hook (symbolS *sym)
{
if (is_leb128_expr && S_GET_SEGMENT (sym) == expr_section)
{
case BFD_RELOC_8:
fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF8;
- fixP->fx_signed = 1;
+ fixP->fx_signed = 0;
break;
case BFD_RELOC_16:
fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF16;
- fixP->fx_signed = 1;
+ fixP->fx_signed = 0;
break;
case BFD_RELOC_32:
fixP->fx_r_type = BFD_RELOC_XTENSA_DIFF32;
- fixP->fx_signed = 1;
+ fixP->fx_signed = 0;
break;
default:
break;
{
IStack slotstack;
int i;
- char *file_name;
- unsigned line;
if (find_vinsn_conflicts (vinsn))
{
if (vinsn->format == XTENSA_UNDEFINED)
{
- as_where (&file_name, &line);
- as_bad_where (file_name, line,
- _("couldn't find a valid instruction format"));
+ as_bad (_("couldn't find a valid instruction format"));
fprintf (stderr, _(" ops were: "));
for (i = 0; i < vinsn->num_slots; i++)
fprintf (stderr, _(" %s;"),
if (resources_conflict (vinsn))
{
- as_where (&file_name, &line);
- as_bad_where (file_name, line, _("illegal resource usage in bundle"));
+ as_bad (_("illegal resource usage in bundle"));
fprintf (stderr, " ops were: ");
for (i = 0; i < vinsn->num_slots; i++)
fprintf (stderr, " %s;",
/* Now check resource conflicts on the modified bundle. */
if (resources_conflict (vinsn))
{
- as_where (&file_name, &line);
- as_bad_where (file_name, line, _("illegal resource usage in bundle"));
+ as_bad (_("illegal resource usage in bundle"));
fprintf (stderr, " ops were: ");
for (i = 0; i < vinsn->num_slots; i++)
fprintf (stderr, " %s;",
frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
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;
+ }
if (tinsn->literal_space != 0)
xg_assemble_literal_space (tinsn->literal_space, slot);
frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
frag_now->fr_symbol, frag_now->fr_offset, NULL);
xtensa_set_frag_assembly_state (frag_now);
xtensa_maybe_create_trampoline_frag ();
+ /* Always create one here. */
+ xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
}
else if (is_branch && do_align_targets ())
{
clear_frag_count ();
unreachable_count = 0;
}
+
+ /* We create an area for a possible literal pool every N (default 5000)
+ frags or so. */
+ xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
}
static xtensa_insnbuf trampoline_buf = NULL;
static xtensa_insnbuf trampoline_slotbuf = NULL;
+static xtensa_insnbuf litpool_buf = NULL;
+static xtensa_insnbuf litpool_slotbuf = NULL;
+
#define TRAMPOLINE_FRAG_SIZE 3000
static void
}
}
+static void dump_litpools (void) __attribute__ ((unused));
+
+static void
+dump_litpools (void)
+{
+ struct litpool_seg *lps = litpool_seg_list.next;
+ struct litpool_frag *lpf;
+
+ for ( ; lps ; lps = lps->next )
+ {
+ printf("litpool seg %s\n", lps->seg->name);
+ for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
+ {
+ fragS *litfrag = lpf->fragP->fr_next;
+ int count = 0;
+ while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
+ {
+ if (litfrag->fr_fix == 4)
+ count++;
+ litfrag = litfrag->fr_next;
+ }
+ printf(" %ld <%d:%d> (%d) [%d]: ",
+ lpf->addr, lpf->priority, lpf->original_priority,
+ lpf->fragP->fr_line, count);
+ //dump_frag(lpf->fragP);
+ }
+ }
+}
+
+static void
+xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
+ bfd_boolean only_if_needed)
+{
+ struct litpool_seg *lps = litpool_seg_list.next;
+ fragS *fragP;
+ struct litpool_frag *lpf;
+ bfd_boolean needed = FALSE;
+
+ if (use_literal_section || !auto_litpools)
+ return;
+
+ for ( ; lps ; lps = lps->next )
+ {
+ if (lps->seg == now_seg)
+ break;
+ }
+
+ if (lps == NULL)
+ {
+ lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
+ lps->next = litpool_seg_list.next;
+ litpool_seg_list.next = lps;
+ lps->seg = now_seg;
+ lps->frag_list.next = &lps->frag_list;
+ lps->frag_list.prev = &lps->frag_list;
+ }
+
+ lps->frag_count++;
+
+ if (create)
+ {
+ if (only_if_needed)
+ {
+ if (past_xtensa_end || !use_transform() ||
+ frag_now->tc_frag_data.is_no_transform)
+ {
+ return;
+ }
+ if (auto_litpool_limit <= 0)
+ {
+ /* Don't create a litpool based only on frag count. */
+ return;
+ }
+ else if (lps->frag_count > auto_litpool_limit)
+ {
+ needed = TRUE;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ needed = TRUE;
+ }
+ }
+
+ if (needed)
+ {
+ int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn. */
+ /* Create a potential site for a literal pool. */
+ frag_wane (frag_now);
+ frag_new (0);
+ xtensa_set_frag_assembly_state (frag_now);
+ fragP = frag_now;
+ fragP->tc_frag_data.lit_frchain = frchain_now;
+ fragP->tc_frag_data.literal_frag = fragP;
+ frag_var (rs_machine_dependent, size, size,
+ (only_if_needed) ?
+ RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
+ RELAX_LITERAL_POOL_BEGIN,
+ NULL, 0, NULL);
+ frag_now->tc_frag_data.lit_seg = now_seg;
+ frag_variant (rs_machine_dependent, 0, 0,
+ RELAX_LITERAL_POOL_END, NULL, 0, NULL);
+ xtensa_set_frag_assembly_state (frag_now);
+ }
+ else
+ {
+ /* RELAX_LITERAL_POOL_BEGIN frag is being created;
+ just record it here. */
+ fragP = frag_now;
+ }
+
+ lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag));
+ /* Insert at tail of circular list. */
+ lpf->addr = 0;
+ lps->frag_list.prev->next = lpf;
+ lpf->next = &lps->frag_list;
+ lpf->prev = lps->frag_list.prev;
+ lps->frag_list.prev = lpf;
+ lpf->fragP = fragP;
+ lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
+ lpf->original_priority = lpf->priority;
+
+ lps->frag_count = 0;
+}
+
static void
xtensa_cleanup_align_frags (void)
{
/* Handle a corner case that comes up in hardware
diagnostics. The original assembly looks like this:
-
+
loop aX, LabelA
<empty_frag>--not found by next_non_empty_frag
loop aY, LabelB
{
if (loop_frag->fr_type == rs_machine_dependent
&& (loop_frag->fr_subtype == RELAX_ALIGN_NEXT_OPCODE
- || loop_frag->fr_subtype
+ || loop_frag->fr_subtype
== RELAX_CHECK_ALIGN_NEXT_OPCODE))
targ_frag = loop_frag;
else
sleb128 value, the linker is unable to adjust that value to account for
link-time relaxation. Mark all the code between such symbols so that
its size cannot be changed by linker relaxation. */
-
+
static void
xtensa_mark_difference_of_two_symbols (void)
{
symbolS *expr_sym;
- for (expr_sym = expr_symbols; expr_sym;
+ for (expr_sym = expr_symbols; expr_sym;
expr_sym = symbol_get_tc (expr_sym)->next_expr_symbol)
{
expressionS *exp = symbol_get_value_expression (expr_sym);
{
symbolS *left = exp->X_add_symbol;
symbolS *right = exp->X_op_symbol;
-
+
/* Difference of two symbols not in the same section
are handled with relocations in the linker. */
if (S_GET_SEGMENT (left) == S_GET_SEGMENT (right))
fragS *end;
fragS *walk;
- if (symbol_get_frag (left)->fr_address
+ if (symbol_get_frag (left)->fr_address
<= symbol_get_frag (right)->fr_address)
{
start = symbol_get_frag (left);
walk = start->tc_frag_data.no_transform_end;
else
walk = start;
- do
+ do
{
walk->tc_frag_data.is_no_transform = 1;
walk = walk->fr_next;
static void
xtensa_sanity_check (void)
{
- char *file_name;
+ const char *file_name;
unsigned line;
frchainS *frchP;
asection *s;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
for (s = stdoutput->sections; s; s = s->next)
for (frchP = seg_info (s)->frchainP; frchP; frchP = frchP->frch_next)
{
for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
{
if (fragP->fr_type == rs_machine_dependent
- && fragP->fr_subtype == RELAX_SLOTS
+ && fragP->fr_subtype == RELAX_SLOTS
&& fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED)
{
static xtensa_insnbuf insnbuf = NULL;
xtensa_isa isa = xtensa_default_isa;
int unreported = fragP->tc_frag_data.unreported_expansion;
long new_stretch = 0;
- char *file_name;
+ const char *file_name;
unsigned line;
int lit_size;
static xtensa_insnbuf vbuf = NULL;
int slot, num_slots;
xtensa_format fmt;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
new_logical_line (fragP->fr_file, fragP->fr_line);
fragP->tc_frag_data.unreported_expansion = 0;
break;
case RELAX_LITERAL_POOL_BEGIN:
+ if (fragP->fr_var != 0)
+ {
+ /* We have a converted "candidate" literal pool;
+ assemble a jump around it. */
+ TInsn insn;
+ if (!litpool_slotbuf)
+ {
+ litpool_buf = xtensa_insnbuf_alloc (isa);
+ litpool_slotbuf = xtensa_insnbuf_alloc (isa);
+ }
+ new_stretch += 3;
+ fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
+ fragP->tc_frag_data.is_insn = TRUE;
+ tinsn_init (&insn);
+ insn.insn_type = ITYPE_INSN;
+ insn.opcode = xtensa_j_opcode;
+ insn.ntok = 1;
+ set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
+ fragP->fr_fix);
+ fmt = xg_get_single_format (xtensa_j_opcode);
+ tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
+ xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
+ xtensa_insnbuf_to_chars (isa, litpool_buf,
+ (unsigned char *)fragP->fr_literal +
+ fragP->fr_fix, 3);
+ fragP->fr_fix += 3;
+ fragP->fr_var -= 3;
+ /* Add a fix-up. */
+ fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
+ BFD_RELOC_XTENSA_SLOT0_OP);
+ }
+ break;
+
case RELAX_LITERAL_POOL_END:
+ case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
case RELAX_MAYBE_UNREACHABLE:
case RELAX_MAYBE_DESIRE_ALIGN:
/* No relaxation required. */
int extra_bytes;
int bytes_short = desired_diff - num_widens;
- gas_assert (desired_diff >= 0
+ gas_assert (desired_diff >= 0
&& desired_diff < (signed) xtensa_fetch_width);
if (desired_diff == 0)
return 0;
/* The first instruction in the relaxed sequence will go after
the current wide instruction, and thus its symbolic immediates
might not fit. */
-
+
istack_init (&istack);
- num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP,
+ num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP,
frag_offset + old_size,
min_steps, stretch + old_size);
gas_assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
- fragP->tc_frag_data.slot_subtypes[slot]
+ fragP->tc_frag_data.slot_subtypes[slot]
= (int) RELAX_IMMED + num_steps;
num_literal_bytes = get_num_stack_literal_bytes (&istack);
- literal_diff
+ literal_diff
= num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
-
+
num_text_bytes = get_num_stack_text_bytes (&istack) + old_size;
}
}
int slot;
int num_slots;
xtensa_format fmt;
- char *file_name;
+ const char *file_name;
unsigned line;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
new_logical_line (fragp->fr_file, fragp->fr_line);
switch (fragp->fr_subtype)
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);
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. */
+
+ for (lps = litpool_seg_list.next; lps; lps = lps->next)
+ {
+ frchainS *frchP = seg_info (lps->seg)->frchainP;
+ struct litpool_frag *lpf = lps->frag_list.next;
+ addressT addr = 0;
+
+ for ( ; frchP; frchP = frchP->frch_next)
+ {
+ fragS *fragP;
+ for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
+ {
+ if (lpf && fragP == lpf->fragP)
+ {
+ gas_assert(fragP->fr_type == rs_machine_dependent &&
+ (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
+ fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
+ /* Found a litpool location. */
+ lpf->addr = addr;
+ lpf = lpf->next;
+ }
+ if (fragP->fr_type == rs_machine_dependent &&
+ fragP->fr_subtype == RELAX_SLOTS)
+ {
+ int slot;
+ for (slot = 0; slot < MAX_SLOTS; slot++)
+ {
+ if (fragP->tc_frag_data.literal_frags[slot])
+ {
+ /* 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. */
+ 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. */
+ }
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+ addr += fragP->fr_fix;
+ if (fragP->fr_type == rs_fill)
+ addr += fragP->fr_offset;
+ }
+ }
+ }
+
for (segment = literal_head->next; segment; segment = segment->next)
{
+ const char *seg_name = segment_name (segment->seg);
+
/* Keep the literals for .init and .fini in separate sections. */
- if (!strcmp (segment_name (segment->seg), INIT_SECTION_NAME)
- || !strcmp (segment_name (segment->seg), FINI_SECTION_NAME))
+ if ((!memcmp (seg_name, init_name, init_name_len) &&
+ !strcmp (seg_name + init_name_len, ".literal")) ||
+ (!memcmp (seg_name, fini_name, fini_name_len) &&
+ !strcmp (seg_name + fini_name_len, ".literal")))
continue;
frchain_from = seg_info (segment->seg)->frchainP;
frchain_to = NULL;
frag_splice = &(frchain_from->frch_root);
- while (!search_frag->tc_frag_data.literal_frag)
+ while (search_frag && !search_frag->tc_frag_data.literal_frag)
{
gas_assert (search_frag->fr_fix == 0
|| search_frag->fr_type == rs_align);
search_frag = search_frag->fr_next;
}
+ 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;
+ }
+
gas_assert (search_frag->tc_frag_data.literal_frag->fr_subtype
== RELAX_LITERAL_POOL_BEGIN);
xtensa_switch_section_emit_state (&state, segment->seg, 0);
while (search_frag != frag_now)
{
next_frag = search_frag->fr_next;
-
- /* First, move the frag out of the literal section and
- to the appropriate place. */
if (search_frag->tc_frag_data.literal_frag)
{
literal_pool = search_frag->tc_frag_data.literal_frag;
frchain_to = literal_pool->tc_frag_data.lit_frchain;
gas_assert (frchain_to);
}
+
+ if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
+ {
+ /* Skip empty fill frags. */
+ *frag_splice = next_frag;
+ search_frag = next_frag;
+ continue;
+ }
+
+ if (search_frag->fr_type == rs_align)
+ {
+ /* Skip alignment frags, because the pool as a whole will be
+ aligned if used, and we don't want to force alignment if the
+ pool is unused. */
+ *frag_splice = next_frag;
+ search_frag = next_frag;
+ continue;
+ }
+
+ /* First, move the frag out of the literal section and
+ to the appropriate place. */
+
+ /* Insert an aligmnent 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)
+ {
+ segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
+ emit_state prev_state;
+ fragS *prev_frag;
+ fragS *align_frag;
+ xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
+ prev_frag = frag_now;
+ frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
+ align_frag = frag_now;
+ frag_align (2, 0, 0);
+ /* Splice it into the right place. */
+ prev_frag->fr_next = align_frag->fr_next;
+ align_frag->fr_next = literal_pool->fr_next;
+ literal_pool->fr_next = align_frag;
+ /* Insert after this one. */
+ literal_pool->tc_frag_data.literal_frag = align_frag;
+ xtensa_restore_emit_state (&prev_state);
+ }
insert_after = literal_pool->tc_frag_data.literal_frag;
dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
+ /* Skip align frag. */
+ if (insert_after->fr_next->fr_type == rs_align)
+ {
+ insert_after = insert_after->fr_next;
+ }
*frag_splice = next_frag;
search_frag->fr_next = insert_after->fr_next;
&& !recursive
&& !is_init && ! is_fini)
{
- as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
+ 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
{
const char *gname = inf;
const char *group_name = elf_group_name (sec);
-
+
return (group_name == gname
|| (group_name != NULL
&& gname != NULL
cache_literal_section (bfd_boolean use_abs_literals)
{
const char *text_name, *group_name = 0;
- char *base_name, *name, *suffix;
+ const char *base_name, *suffix;
+ char *name;
segT *pcached;
segT seg, current_section;
int current_subsec;
if (*pcached)
return *pcached;
-
+
text_name = default_lit_sections.lit_prefix;
if (! text_name || ! *text_name)
{
base_name = use_abs_literals ? ".lit4" : ".literal";
if (group_name)
{
- name = xmalloc (strlen (base_name) + strlen (group_name) + 2);
- sprintf (name, "%s.%s", base_name, group_name);
+ name = concat (base_name, ".", group_name, (char *) NULL);
}
else if (strncmp (text_name, ".gnu.linkonce.", linkonce_len) == 0)
{
suffix = strchr (text_name + linkonce_len, '.');
- name = xmalloc (linkonce_len + strlen (base_name) + 1
- + (suffix ? strlen (suffix) : 0));
- strcpy (name, ".gnu.linkonce");
- strcat (name, base_name);
- if (suffix)
- strcat (name, suffix);
+ name = concat (".gnu.linkonce", base_name, suffix ? suffix : "",
+ (char *) NULL);
linkonce = TRUE;
}
else
expressionS *exp = &tinsn->tok[i];
int rc;
unsigned line;
- char *file_name;
+ const char *file_name;
uint32 opnd_value;
switch (exp->X_op)
case O_constant:
if (xtensa_operand_is_visible (isa, opcode, i) == 0)
break;
- as_where (&file_name, &line);
+ file_name = as_where (&line);
/* It is a constant and we called this function
then we have to try to fit it. */
xtensa_insnbuf_set_operand (slotbuf, fmt, slot, opcode, i,
{
int i;
- memset (v, 0, offsetof (vliw_insn, slots)
+ memset (v, 0, offsetof (vliw_insn, slots)
+ sizeof(TInsn) * config_max_slots);
v->format = XTENSA_UNDEFINED;
static void
xg_copy_vinsn (vliw_insn *dst, vliw_insn *src)
{
- memcpy (dst, src,
+ memcpy (dst, src,
offsetof(vliw_insn, slots) + src->num_slots * sizeof(TInsn));
dst->insnbuf = src->insnbuf;
memcpy (dst->slotbuf, src->slotbuf, src->num_slots * sizeof(xtensa_insnbuf));
struct rename_section_struct
{
- char *old_name;
+ const char *old_name;
char *new_name;
struct rename_section_struct *next;
};
char *
-xtensa_section_rename (char *name)
+xtensa_section_rename (const char *name)
{
struct rename_section_struct *r = section_rename;
return r->new_name;
}
- return name;
+ return (char *) name;
}