} emit_state;
-/* A map that keeps information on a per-subsegment basis. This is
- maintained during initial assembly, but is invalid once the
- subsegments are smashed together. I.E., it cannot be used during
- the relaxation. */
-
-typedef struct subseg_map_struct
-{
- /* the key */
- segT seg;
- subsegT subseg;
-
- /* the data */
- unsigned flags;
- /* the fall-through frequency + the branch target frequency
- typically used for the instruction after a call */
- float cur_total_freq;
- /* the branch target frequency alone */
- float cur_target_freq;
-
- struct subseg_map_struct *next;
-} subseg_map;
-
-
/* Opcode placement information */
typedef unsigned long long bitfield;
static void xtensa_set_frag_assembly_state (fragS *);
static void finish_vinsn (vliw_insn *);
static bfd_boolean emit_single_op (TInsn *);
+static int total_frag_text_expansion (fragS *);
/* Alignment Functions. */
static long relax_frag_add_nop (fragS *);
-/* Flags for the Last Instruction in Each Subsegment. */
+/* Accessors for additional per-subsegment information. */
-static subseg_map *get_subseg_info (segT, subsegT);
static unsigned get_last_insn_flags (segT, subsegT);
static void set_last_insn_flags (segT, subsegT, unsigned, bfd_boolean);
+static float get_subseg_total_freq (segT, subsegT);
+static float get_subseg_target_freq (segT, subsegT);
+static void set_subseg_freq (segT, subsegT, float, float);
/* Segment list functions. */
static void cache_literal_section
(seg_list *, const char *, segT *, bfd_boolean);
-/* Property flags on fragments and conversion to object file flags. */
-
-static bfd_boolean get_frag_is_literal (const fragS *);
-static bfd_boolean get_frag_is_insn (const fragS *);
-static bfd_boolean get_frag_is_no_transform (fragS *);
-static void set_frag_is_specific_opcode (fragS *, bfd_boolean);
-static void set_frag_is_no_transform (fragS *, bfd_boolean);
-
/* Import from elf32-xtensa.c in BFD library. */
extern char *xtensa_get_property_section_name (asection *, const char *);
bfd_boolean expr_is_equal (expressionS *, expressionS *);
static void copy_expr (expressionS *, const expressionS *);
-#ifdef XTENSA_SECTION_RENAME
+/* Section renaming. */
+
static void build_section_rename (const char *);
-static void add_section_rename (char *, char *);
-#endif
/* ISA imported from bfd. */
option_no_workarounds,
-#ifdef XTENSA_SECTION_RENAME
option_rename_section_name,
-#endif
option_prefer_l32r,
option_prefer_const16,
{ "workaround-close-loop-end", no_argument, NULL,
option_workaround_close_loop_end },
-#ifdef XTENSA_SECTION_RENAME
{ "rename-section", required_argument, NULL, option_rename_section_name },
-#endif /* XTENSA_SECTION_RENAME */
{ "link-relax", no_argument, NULL, option_link_relax },
{ "no-link-relax", no_argument, NULL, option_no_link_relax },
warn_unaligned_branch_targets = TRUE;
return 1;
-#ifdef XTENSA_SECTION_RENAME
case option_rename_section_name:
build_section_rename (arg);
return 1;
-#endif /* XTENSA_SECTION_RENAME */
case 'Q':
/* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
{
fputs ("\n\
Xtensa options:\n\
---[no-]text-section-literals\n\
- [Do not] put literals in the text section\n\
---[no-]absolute-literals\n\
- [Do not] default to use non-PC-relative literals\n\
---[no-]target-align [Do not] try to align branch targets\n\
---[no-]longcalls [Do not] emit 32-bit call sequences\n\
---[no-]transform [Do not] transform instructions\n"
-#ifdef XTENSA_SECTION_RENAME
-"--rename-section old=new(:old1=new1)*\n\
- Rename section 'old' to 'new'\n"
-#endif /* XTENSA_SECTION_RENAME */
- , stream);
+ --[no-]text-section-literals\n\
+ [Do not] put literals in the text section\n\
+ --[no-]absolute-literals\n\
+ [Do not] default to use non-PC-relative literals\n\
+ --[no-]target-align [Do not] try to align branch targets\n\
+ --[no-]longcalls [Do not] emit 32-bit call sequences\n\
+ --[no-]transform [Do not] transform instructions\n\
+ --rename-section old=new Rename section 'old' to 'new'\n", stream);
}
\f
strcpy (newname4 + suffix_pos, ".lit4");
}
- /* Note that retrieve_literal_seg does not create a segment if
+ /* Note that cache_literal_section does not create a segment if
it already exists. */
default_lit_sections.lit_seg = NULL;
default_lit_sections.lit4_seg = NULL;
xtensa_frequency_pseudo (int ignored ATTRIBUTE_UNUSED)
{
float fall_through_f, target_f;
- subseg_map *seginfo;
fall_through_f = (float) strtod (input_line_pointer, &input_line_pointer);
if (fall_through_f < 0)
return;
}
- seginfo = get_subseg_info (now_seg, now_subseg);
- seginfo->cur_target_freq = target_f;
- seginfo->cur_total_freq = target_f + fall_through_f;
+ set_subseg_freq (now_seg, now_subseg, target_f + fall_through_f, target_f);
demand_empty_rest_of_line ();
}
}
-/* Return TRUE if the opcode is an entry opcode. This is used because
- "entry" adds an implicit ".align 4" and also the entry instruction
- has an extra check for an operand value. */
-
-static bfd_boolean
-is_entry_opcode (xtensa_opcode opcode)
-{
- if (opcode == XTENSA_UNDEFINED)
- return FALSE;
-
- return (opcode == xtensa_entry_opcode);
-}
-
-
-/* Return TRUE if the opcode is a movi or movi.n opcode. This is
- so we can relax "movi aX, foo" in the front end. */
-
-static bfd_boolean
-is_movi_opcode (xtensa_opcode opcode)
-{
- if (opcode == XTENSA_UNDEFINED)
- return FALSE;
-
- return (opcode == xtensa_movi_opcode)
- || (opcode == xtensa_movi_n_opcode);
-}
-
-
-static bfd_boolean
-is_the_loop_opcode (xtensa_opcode opcode)
-{
- if (opcode == XTENSA_UNDEFINED)
- return FALSE;
-
- return (opcode == xtensa_loop_opcode);
-}
-
-
-static bfd_boolean
-is_jx_opcode (xtensa_opcode opcode)
-{
- if (opcode == XTENSA_UNDEFINED)
- return FALSE;
-
- return (opcode == xtensa_jx_opcode);
-}
-
-
-/* Return TRUE if the opcode is a retw or retw.n.
- Needed to add nops to avoid a hardware interlock issue. */
-
-static bfd_boolean
-is_windowed_return_opcode (xtensa_opcode opcode)
-{
- if (opcode == XTENSA_UNDEFINED)
- return FALSE;
-
- return (opcode == xtensa_retw_opcode || opcode == xtensa_retw_n_opcode);
-}
-
-
/* Convert from BFD relocation type code to slot and operand number.
Returns non-zero on failure. */
fmt_length = xtensa_format_length (xtensa_default_isa, fmt);
the_fix = fix_new_exp (fragP, offset, fmt_length, expr,
howto->pc_relative, reloc);
+ the_fix->fx_no_overflow = 1;
if (expr->X_add_symbol
&& (S_IS_EXTERNAL (expr->X_add_symbol)
switch its state so it will instantiate a NOP. */
static void
-update_next_frag_state (fragS *fragP, bfd_boolean unreachable)
+update_next_frag_state (fragS *fragP)
{
fragS *next_fragP = fragP->fr_next;
fragS *new_target = NULL;
&& (new_target->fr_subtype == RELAX_MAYBE_DESIRE_ALIGN
|| new_target->fr_subtype == RELAX_DESIRE_ALIGN));
}
- if (unreachable)
- {
- if (align_targets)
- {
- next_fragP->fr_subtype = RELAX_UNREACHABLE;
- next_fragP->tc_frag_data.is_unreachable = TRUE;
- new_target->fr_subtype = RELAX_DESIRE_ALIGN;
- new_target->tc_frag_data.is_branch_target = TRUE;
- }
- while (next_fragP && next_fragP->fr_fix == 0)
- {
- if (next_fragP->fr_type == rs_machine_dependent
- && next_fragP->fr_subtype == RELAX_LOOP_END)
- {
- next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP;
- return;
- }
- next_fragP = next_fragP->fr_next;
- }
- }
- else
+ while (next_fragP && next_fragP->fr_fix == 0)
{
- if (align_targets)
+ if (next_fragP->fr_type == rs_machine_dependent
+ && next_fragP->fr_subtype == RELAX_LOOP_END)
{
- next_fragP->fr_subtype = RELAX_MAYBE_UNREACHABLE;
- next_fragP->tc_frag_data.is_unreachable = FALSE;
- new_target->fr_subtype = RELAX_MAYBE_DESIRE_ALIGN;
- new_target->tc_frag_data.is_branch_target = FALSE;
+ next_fragP->fr_subtype = RELAX_LOOP_END_ADD_NOP;
+ return;
}
+
+ next_fragP = next_fragP->fr_next;
}
}
&& !is_unaligned_label (sym)
&& !generating_literals)
{
- float freq = get_subseg_info (now_seg, now_subseg)->cur_target_freq;
+ float freq = get_subseg_target_freq (now_seg, now_subseg);
xtensa_set_frag_assembly_state (frag_now);
/* The only time this type of frag grows is when there is a
xg_add_branch_and_loop_targets (&orig_insn);
/* Special-case for "entry" instruction. */
- if (is_entry_opcode (orig_insn.opcode))
+ if (orig_insn.opcode == xtensa_entry_opcode)
{
/* Check that the third opcode (#2) is >= 16. */
if (orig_insn.ntok >= 3)
xtensa_handle_align (fragS *fragP)
{
if (linkrelax
- && !get_frag_is_literal (fragP)
+ && ! fragP->tc_frag_data.is_literal
&& (fragP->fr_type == rs_align
|| fragP->fr_type == rs_align_code)
&& fragP->fr_address + fragP->fr_fix > 0
int
md_estimate_size_before_relax (fragS *fragP, segT seg ATTRIBUTE_UNUSED)
{
- return fragP->tc_frag_data.text_expansion[0];
+ return total_frag_text_expansion (fragP);
}
solely whether the hardware is available to execute the given
instructions together. It also doesn't check if the tinsns
write the same state, or access the same tieports. That is
- checked by check_t1_t2_read_write. */
+ checked by check_t1_t2_reads_and_writes. */
static bfd_boolean
resources_conflict (vliw_insn *vinsn)
int line;
if (find_vinsn_conflicts (vinsn))
- return;
+ {
+ xg_clear_vinsn (vinsn);
+ return;
+ }
/* First, find a format that works. */
if (vinsn->format == XTENSA_UNDEFINED)
}
-/* Check how the result registers of t1 and t2 relate.
+/* Check how the state used by t1 and t2 relate.
Cases found are:
case A: t1 reads a register t2 writes (an antidependency within a bundle)
bundle)
case D: t1 writes a state that t2 also writes
case E: t1 writes a tie queue that t2 also writes
- case F: two volatile queue writes
+ case F: two volatile queue accesses
*/
static char
{
xtensa_interface t2_int
= xtensa_interfaceOperand_interface (isa, t2->opcode, j);
+ int t2_class = xtensa_interface_class_id (isa, t2_int);
+
t2_inout = xtensa_interface_inout (isa, j);
- if (xtensa_interface_has_side_effect (isa, t2_int) == 1
- && t2_inout != 'i')
+ if (xtensa_interface_has_side_effect (isa, t2_int) == 1)
t2_volatile = TRUE;
+
for (i = 0; i < t1_interfaces; i++)
{
xtensa_interface t1_int
= xtensa_interfaceOperand_interface (isa, t1->opcode, j);
+ int t1_class = xtensa_interface_class_id (isa, t2_int);
+
t1_inout = xtensa_interface_inout (isa, i);
- if (xtensa_interface_has_side_effect (isa, t1_int) == 1
- && t1_inout != 'i')
+ if (xtensa_interface_has_side_effect (isa, t1_int) == 1)
t1_volatile = TRUE;
+
+ if (t1_volatile && t2_volatile && (t1_class == t2_class))
+ return 'f';
if (t1_int != t2_int)
continue;
return 'e';
}
}
-
- if (t1_volatile && t2_volatile)
- return 'f';
return conflict;
}
}
else
{
- if (workaround_b_j_loop_end && is_jx_opcode (tinsn->opcode)
+ if (workaround_b_j_loop_end
+ && tinsn->opcode == xtensa_jx_opcode
&& use_transform ())
{
/* Add 2 of these. */
Because the scheduling and bundling characteristics of movi and
l32r or const16 are so different, we can do much better if we relax
it prior to scheduling and bundling, rather than after. */
- if (is_movi_opcode (orig_insn->opcode) && !cur_vinsn.inside_bundle
+ if ((orig_insn->opcode == xtensa_movi_opcode
+ || orig_insn->opcode == xtensa_movi_n_opcode)
+ && !cur_vinsn.inside_bundle
&& (orig_insn->tok[1].X_op == O_symbol
|| orig_insn->tok[1].X_op == O_pltrel))
xg_assembly_relax (&istack, orig_insn, now_seg, frag_now, 0, 1, 0);
}
+static int
+total_frag_text_expansion (fragS *fragP)
+{
+ int slot;
+ int total_expansion = 0;
+
+ for (slot = 0; slot < MAX_SLOTS; slot++)
+ total_expansion += fragP->tc_frag_data.text_expansion[slot];
+
+ return total_expansion;
+}
+
+
/* Emit a vliw instruction to the current fragment. */
static void
}
if (frag_now_fix () != 0
- && (!get_frag_is_insn (frag_now)
+ && (! frag_now->tc_frag_data.is_insn
|| (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- || !use_transform () != get_frag_is_no_transform (frag_now)
+ || !use_transform () != frag_now->tc_frag_data.is_no_transform
|| (directive_state[directive_absolute_literals]
!= frag_now->tc_frag_data.use_absolute_literals)))
{
xtensa_move_labels (frag_now, 0, FALSE);
}
- if (is_entry_opcode (vinsn->slots[0].opcode)
+ if (vinsn->slots[0].opcode == xtensa_entry_opcode
&& !vinsn->slots[0].is_specific_opcode)
{
xtensa_mark_literal_pool_location ();
}
if (vinsn_has_specific_opcodes (vinsn) && use_transform ())
- set_frag_is_specific_opcode (frag_now, TRUE);
+ frag_now->tc_frag_data.is_specific_opcode = TRUE;
if (finish_frag)
{
if (do_align_targets ()
&& xtensa_opcode_is_call (isa, vinsn->slots[0].opcode) == 1)
{
- float freq = get_subseg_info (now_seg, now_subseg)->cur_total_freq;
+ float freq = get_subseg_total_freq (now_seg, now_subseg);
frag_now->tc_frag_data.is_insn = TRUE;
frag_var (rs_machine_dependent, 4, (int) freq, RELAX_DESIRE_ALIGN,
frag_now->fr_symbol, frag_now->fr_offset, NULL);
use for alignment narrow branches that definitely will not expand to a
jump and a branch. These functions find and mark these cases. */
-/* the range in bytes of a bnez.n and beqz.n */
-#define MAX_IMMED6 68
+/* The range in bytes of BNEZ.N and BEQZ.N. The target operand is encoded
+ as PC + 4 + imm6, where imm6 is a 6-bit immediate ranging from 0 to 63.
+ We start counting beginning with the frag after the 2-byte branch, so the
+ maximum offset is (4 - 2) + 63 = 65. */
+#define MAX_IMMED6 65
static size_t unrelaxed_frag_max_size (fragS *);
{
if (next_instrs_are_b_retw (fragP))
{
- if (get_frag_is_no_transform (fragP))
+ if (fragP->tc_frag_data.is_no_transform)
as_bad (_("instruction sequence (write a0, branch, retw) may trigger hardware errata"));
else
relax_frag_add_nop (fragP);
xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf);
opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf);
- if (is_windowed_return_opcode (opcode))
+ if (opcode == xtensa_retw_opcode || opcode == xtensa_retw_n_opcode)
return TRUE;
return FALSE;
{
if (next_instr_is_loop_end (fragP))
{
- if (get_frag_is_no_transform (fragP))
+ if (fragP->tc_frag_data.is_no_transform)
as_bad (_("branching or jumping to a loop end may trigger hardware errata"));
else
relax_frag_add_nop (fragP);
if (min_bytes < REQUIRED_LOOP_DIVIDING_BYTES)
{
- if (get_frag_is_no_transform (fragP))
+ if (fragP->tc_frag_data.is_no_transform)
as_bad (_("loop end too close to another loop end may trigger hardware errata"));
else
{
&& (branch_before_loop_end (fragP->fr_next)
|| (workaround_all_short_loops
&& current_opcode != XTENSA_UNDEFINED
- && !is_the_loop_opcode (current_opcode))))
+ && current_opcode != xtensa_loop_opcode)))
{
- if (get_frag_is_no_transform (fragP))
+ if (fragP->tc_frag_data.is_no_transform)
as_bad (_("loop containing less than three instructions may trigger hardware errata"));
else
relax_frag_add_nop (fragP);
(*widens)++;
break;
}
- /* FIXME: shouldn't this add the expansion of all slots? */
- address += fragP->tc_frag_data.text_expansion[0];
+ address += total_frag_text_expansion (fragP);;
break;
case RELAX_IMMED:
if (estimate_only && xtensa_opcode_is_loop (isa, tinsn.opcode))
return 0;
- if (workaround_b_j_loop_end && !get_frag_is_no_transform (fragP))
+ if (workaround_b_j_loop_end && ! fragP->tc_frag_data.is_no_transform)
branch_jmp_to_next = is_branch_jmp_to_next (&tinsn, fragP);
negatable_branch = (xtensa_opcode_is_branch (isa, tinsn.opcode) == 1);
}
}
- /* FIXME: When a negatable branch expands and then contracts in a
- subsequent pass, update_next_frag_state correctly updates the
- type of the frag to RELAX_MAYBE_UNREACHABLE, but it doesn't undo
- any expansion relax_frag_for_align may have expected it to. For
- now, change back to only call it when the branch expands. */
if (negatable_branch && istack.ninsn > 1)
- update_next_frag_state (fragP, FALSE /* istack.ninsn > 1 */);
+ update_next_frag_state (fragP);
return this_text_diff;
}
is_loop = xtensa_opcode_is_loop (xtensa_default_isa, orig_tinsn.opcode) == 1;
- if (workaround_b_j_loop_end && !get_frag_is_no_transform (fragP))
+ if (workaround_b_j_loop_end && ! fragP->tc_frag_data.is_no_transform)
branch_jmp_to_next = is_branch_jmp_to_next (&orig_tinsn, fragP);
if (branch_jmp_to_next && !next_frag_is_loop_target (fragP))
label:
*/
-static offsetT get_expression_value (segT, expressionS *);
-
static void
convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn)
{
addmi_offset += loop_offset;
assert (tinsn->ntok == 2);
- target = get_expression_value (segP, &tinsn->tok[1]);
+ 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;
+ 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;
+ }
know (symbolP);
know (symbolP->sy_frag);
for (next_fragP = fragP; next_fragP != NULL;
next_fragP = next_fragP->fr_next)
{
- set_frag_is_no_transform (next_fragP, TRUE);
+ next_fragP->tc_frag_data.is_no_transform = TRUE;
if (next_fragP->tc_frag_data.is_loop_target)
target_count++;
if (target_count == 2)
}
}
+\f
+/* A map that keeps information on a per-subsegment basis. This is
+ maintained during initial assembly, but is invalid once the
+ subsegments are smashed together. I.E., it cannot be used during
+ the relaxation. */
-static offsetT
-get_expression_value (segT segP, expressionS *exp)
+typedef struct subseg_map_struct
{
- if (exp->X_op == O_constant)
- return exp->X_add_number;
- if (exp->X_op == O_symbol)
- {
- /* Find the fragment. */
- symbolS *sym = exp->X_add_symbol;
+ /* the key */
+ segT seg;
+ subsegT subseg;
- assert (S_GET_SEGMENT (sym) == segP
- || S_GET_SEGMENT (sym) == absolute_section);
+ /* the data */
+ unsigned flags;
+ float total_freq; /* fall-through + branch target frequency */
+ float target_freq; /* branch target frequency alone */
+
+ struct subseg_map_struct *next;
+} subseg_map;
- return (S_GET_VALUE (sym) + exp->X_add_number);
- }
- as_bad (_("invalid expression evaluation type %d"), exp->X_op);
- return 0;
-}
-\f
static subseg_map *sseg_map = NULL;
static subseg_map *
for (subseg_e = sseg_map; subseg_e; subseg_e = subseg_e->next)
{
if (seg == subseg_e->seg && subseg == subseg_e->subseg)
- return subseg_e;
+ break;
}
-
- subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map));
+ return subseg_e;
+}
+
+
+static subseg_map *
+add_subseg_info (segT seg, subsegT subseg)
+{
+ subseg_map *subseg_e = (subseg_map *) xmalloc (sizeof (subseg_map));
memset (subseg_e, 0, sizeof (subseg_map));
subseg_e->seg = seg;
subseg_e->subseg = subseg;
subseg_e->flags = 0;
/* Start off considering every branch target very important. */
- subseg_e->cur_target_freq = 1.0;
- subseg_e->cur_total_freq = 1.0;
+ subseg_e->target_freq = 1.0;
+ subseg_e->total_freq = 1.0;
subseg_e->next = sseg_map;
sseg_map = subseg_e;
-
return subseg_e;
}
get_last_insn_flags (segT seg, subsegT subseg)
{
subseg_map *subseg_e = get_subseg_info (seg, subseg);
- return subseg_e->flags;
+ if (subseg_e)
+ return subseg_e->flags;
+ return 0;
}
bfd_boolean val)
{
subseg_map *subseg_e = get_subseg_info (seg, subseg);
+ if (! subseg_e)
+ subseg_e = add_subseg_info (seg, subseg);
if (val)
subseg_e->flags |= fl;
else
subseg_e->flags &= ~fl;
}
+
+static float
+get_subseg_total_freq (segT seg, subsegT subseg)
+{
+ subseg_map *subseg_e = get_subseg_info (seg, subseg);
+ if (subseg_e)
+ return subseg_e->total_freq;
+ return 1.0;
+}
+
+
+static float
+get_subseg_target_freq (segT seg, subsegT subseg)
+{
+ subseg_map *subseg_e = get_subseg_info (seg, subseg);
+ if (subseg_e)
+ return subseg_e->target_freq;
+ return 1.0;
+}
+
+
+static void
+set_subseg_freq (segT seg, subsegT subseg, float total_f, float target_f)
+{
+ subseg_map *subseg_e = get_subseg_info (seg, subseg);
+ if (! subseg_e)
+ subseg_e = add_subseg_info (seg, subseg);
+ subseg_e->total_freq = total_f;
+ subseg_e->target_freq = target_f;
+}
+
\f
/* Segment Lists and emit_state Stuff. */
/* Push all the literal segments to the end of the gnu list. */
-static segT get_last_sec (void);
-
static void
xtensa_reorder_segments (void)
{
segT sec;
- segT last_sec;
+ segT last_sec = 0;
int old_count = 0;
int new_count = 0;
for (sec = stdoutput->sections; sec != NULL; sec = sec->next)
- old_count++;
+ {
+ last_sec = sec;
+ old_count++;
+ }
/* Now that we have the last section, push all the literal
sections to the end. */
- last_sec = get_last_sec ();
xtensa_reorder_seg_list (literal_head, last_sec);
xtensa_reorder_seg_list (init_literal_head, last_sec);
xtensa_reorder_seg_list (fini_literal_head, last_sec);
}
-static segT
-get_last_sec (void)
-{
- segT last_sec = stdoutput->sections;
- while (last_sec->next != NULL)
- last_sec = last_sec->next;
-
- return last_sec;
-}
-
-
/* Change the emit state (seg, subseg, and frag related stuff) to the
correct location. Return a emit_state which can be passed to
xtensa_restore_emit_state to return to current fragment. */
state->now_subseg = now_subseg;
state->generating_literals = generating_literals;
generating_literals++;
- subseg_new (segment_name (new_now_seg), new_now_subseg);
+ subseg_set (new_now_seg, new_now_subseg);
}
xtensa_restore_emit_state (emit_state *state)
{
generating_literals = state->generating_literals;
- subseg_new (state->name, state->now_subseg);
+ subseg_set (state->now_seg, state->now_subseg);
}
/* Get a segment of a given name. If the segment is already
present, return it; otherwise, create a new one. */
-static segT retrieve_literal_seg (seg_list *, const char *, bfd_boolean);
-
static void
cache_literal_section (seg_list *head,
const char *name,
- segT *seg,
+ segT *pseg,
bfd_boolean is_code)
{
segT current_section = now_seg;
int current_subsec = now_subseg;
+ segT seg;
- if (*seg != 0)
+ if (*pseg != 0)
return;
- *seg = retrieve_literal_seg (head, name, is_code);
- subseg_set (current_section, current_subsec);
-}
-
-
-/* Get a segment of a given name. If the segment is already
- present, return it; otherwise, create a new one. */
-static segT seg_present (const char *);
-static void add_seg_list (seg_list *, segT);
-
-static segT
-retrieve_literal_seg (seg_list *head, const char *name, bfd_boolean is_code)
-{
- segT ret = 0;
+ /* Check if the named section exists. */
+ for (seg = stdoutput->sections; seg; seg = seg->next)
+ {
+ if (!strcmp (segment_name (seg), name))
+ break;
+ }
- ret = seg_present (name);
- if (!ret)
+ if (!seg)
{
- ret = subseg_new (name, (subsegT) 0);
+ /* Create a new literal section. */
+ seg = subseg_new (name, (subsegT) 0);
if (head)
- add_seg_list (head, ret);
- bfd_set_section_flags (stdoutput, ret, SEC_HAS_CONTENTS |
+ {
+ /* Add the newly created literal segment to the specified list. */
+ seg_list *n = (seg_list *) xmalloc (sizeof (seg_list));
+ n->seg = seg;
+ n->next = head->next;
+ head->next = n;
+ }
+ bfd_set_section_flags (stdoutput, seg, SEC_HAS_CONTENTS |
SEC_READONLY | SEC_ALLOC | SEC_LOAD
| (is_code ? SEC_CODE : SEC_DATA));
- bfd_set_section_alignment (stdoutput, ret, 2);
+ bfd_set_section_alignment (stdoutput, seg, 2);
}
- return ret;
-}
-
-
-/* Return a segment of a given name if it is present. */
-
-static segT
-seg_present (const char *name)
-{
- segT seg;
- seg = stdoutput->sections;
-
- while (seg)
- {
- if (!strcmp (segment_name (seg), name))
- return seg;
- seg = seg->next;
- }
-
- return 0;
-}
-
-
-/* Add a segment to a segment list. */
-
-static void
-add_seg_list (seg_list *head, segT seg)
-{
- seg_list *n;
- n = (seg_list *) xmalloc (sizeof (seg_list));
- assert (n);
-
- n->seg = seg;
- n->next = head->next;
- head->next = n;
+ *pseg = seg;
+ subseg_set (current_section, current_subsec);
}
\f
typedef bfd_boolean (*frag_predicate) (const fragS *);
typedef void (*frag_flags_fn) (const fragS *, frag_flags *);
+static bfd_boolean get_frag_is_literal (const fragS *);
static void xtensa_create_property_segments
(frag_predicate, frag_predicate, const char *, xt_section_type);
static void xtensa_create_xproperty_segments
}
-static bfd_boolean
-get_frag_is_insn (const fragS *fragP)
-{
- assert (fragP != NULL);
- return fragP->tc_frag_data.is_insn;
-}
-
-
-static bfd_boolean
-get_frag_is_no_transform (fragS *fragP)
-{
- return fragP->tc_frag_data.is_no_transform;
-}
-
-
-static void
-set_frag_is_specific_opcode (fragS *fragP, bfd_boolean is_specific_opcode)
-{
- fragP->tc_frag_data.is_specific_opcode = is_specific_opcode;
-}
-
-
-static void
-set_frag_is_no_transform (fragS *fragP, bfd_boolean is_no_transform)
-{
- fragP->tc_frag_data.is_no_transform = is_no_transform;
-}
-
-
static void
xtensa_create_property_segments (frag_predicate property_function,
frag_predicate end_property_function,
}
\f
-/* Support for Tensilica's "--rename-section" option. */
-
-#ifdef XTENSA_SECTION_RENAME
+/* Support for the "--rename-section" option. */
struct rename_section_struct
{
static struct rename_section_struct *section_rename;
-/* Parse the string oldname=new_name:oldname2=new_name2
- and call add_section_rename. */
+/* Parse the string "oldname=new_name(:oldname2=new_name2)*" and add
+ entries to the section_rename list. Note: Specifying multiple
+ renamings separated by colons is not documented and is retained only
+ for backward compatibility. */
static void
build_section_rename (const char *arg)
{
+ struct rename_section_struct *r;
char *this_arg = NULL;
char *next_arg = NULL;
- for (this_arg = strdup (arg); this_arg != NULL; this_arg = next_arg)
+ for (this_arg = xstrdup (arg); this_arg != NULL; this_arg = next_arg)
{
+ char *old_name, *new_name;
+
if (this_arg)
{
next_arg = strchr (this_arg, ':');
next_arg++;
}
}
- {
- char *old_name = this_arg;
- char *new_name = strchr (this_arg, '=');
- if (*old_name == '\0')
- {
- as_warn (_("ignoring extra '-rename-section' delimiter ':'"));
- continue;
- }
- if (!new_name || new_name[1] == '\0')
- {
- as_warn (_("ignoring invalid '-rename-section' "
- "specification: '%s'"), old_name);
- continue;
- }
- *new_name = '\0';
- new_name++;
- add_section_rename (old_name, new_name);
- }
- }
-}
+ old_name = this_arg;
+ new_name = strchr (this_arg, '=');
+ if (*old_name == '\0')
+ {
+ as_warn (_("ignoring extra '-rename-section' delimiter ':'"));
+ continue;
+ }
+ if (!new_name || new_name[1] == '\0')
+ {
+ as_warn (_("ignoring invalid '-rename-section' specification: '%s'"),
+ old_name);
+ continue;
+ }
+ *new_name = '\0';
+ new_name++;
-static void
-add_section_rename (char *old_name, char *new_name)
-{
- struct rename_section_struct *r = section_rename;
+ /* Check for invalid section renaming. */
+ for (r = section_rename; r != NULL; r = r->next)
+ {
+ if (strcmp (r->old_name, old_name) == 0)
+ as_bad (_("section %s renamed multiple times"), old_name);
+ if (strcmp (r->new_name, new_name) == 0)
+ as_bad (_("multiple sections remapped to output section %s"),
+ new_name);
+ }
- /* Check for invalid section renaming. */
- for (r = section_rename; r != NULL; r = r->next)
- {
- if (strcmp (r->old_name, old_name) == 0)
- as_bad (_("section %s renamed multiple times"), old_name);
- if (strcmp (r->new_name, new_name) == 0)
- as_bad (_("multiple sections remapped to output section %s"),
- new_name);
+ /* Now add it. */
+ r = (struct rename_section_struct *)
+ xmalloc (sizeof (struct rename_section_struct));
+ r->old_name = xstrdup (old_name);
+ r->new_name = xstrdup (new_name);
+ r->next = section_rename;
+ section_rename = r;
}
-
- /* Now add it. */
- r = (struct rename_section_struct *)
- xmalloc (sizeof (struct rename_section_struct));
- r->old_name = strdup (old_name);
- r->new_name = strdup (new_name);
- r->next = section_rename;
- section_rename = r;
}
-const char *
-xtensa_section_rename (const char *name)
+char *
+xtensa_section_rename (char *name)
{
struct rename_section_struct *r = section_rename;
return name;
}
-
-#endif /* XTENSA_SECTION_RENAME */