/* tc-xtensa.c -- Assemble Xtensa instructions.
- Copyright 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
static vliw_insn cur_vinsn;
+unsigned xtensa_num_pipe_stages;
unsigned xtensa_fetch_width = XCHAL_INST_FETCH_WIDTH;
static enum debug_info_type xt_saved_debug_type = DEBUG_NONE;
static void xtensa_literal_pseudo (int);
static void xtensa_frequency_pseudo (int);
static void xtensa_elf_cons (int);
+static void xtensa_leb128 (int);
/* Parsing and Idiom Translation. */
{ "4byte", xtensa_elf_cons, 4 },
{ "short", xtensa_elf_cons, 2 },
{ "2byte", xtensa_elf_cons, 2 },
+ { "sleb128", xtensa_leb128, 1},
+ { "uleb128", xtensa_leb128, 0},
{ "begin", xtensa_begin_directive, 0 },
{ "end", xtensa_end_directive, 0 },
{ "literal", xtensa_literal_pseudo, 0 },
}
}
else
- emit_expr (&exp, (unsigned int) nbytes);
+ {
+ xtensa_set_frag_assembly_state (frag_now);
+ emit_expr (&exp, (unsigned int) nbytes);
+ }
}
while (*input_line_pointer++ == ',');
demand_empty_rest_of_line ();
}
+static bfd_boolean is_leb128_expr;
+
+static void
+xtensa_leb128 (int sign)
+{
+ is_leb128_expr = TRUE;
+ s_leb128 (sign);
+ is_leb128_expr = FALSE;
+}
+
\f
/* Parsing and Idiom Translation. */
|| S_GET_SEGMENT (expr->X_add_symbol) != pc_seg)
{
/* For a direct call with --no-longcalls, be optimistic and
- assume it will be in range. */
+ assume it will be in range. If the symbol is weak and
+ undefined, it may remain undefined at link-time, in which
+ case it will have a zero value and almost certainly be out
+ of range for a direct call; thus, relax for undefined weak
+ symbols even if longcalls is not enabled. */
if (is_direct_call_opcode (insn->opcode)
- && ! pc_frag->tc_frag_data.use_longcalls)
+ && ! pc_frag->tc_frag_data.use_longcalls
+ && (! S_IS_WEAK (expr->X_add_symbol)
+ || S_IS_DEFINED (expr->X_add_symbol)))
return TRUE;
return FALSE;
xtensa_rsr_lcount_opcode = xtensa_opcode_lookup (isa, "rsr.lcount");
xtensa_waiti_opcode = xtensa_opcode_lookup (isa, "waiti");
+ xtensa_num_pipe_stages = xtensa_isa_num_pipe_stages (isa);
+
init_op_placement_info_table ();
/* Set up the assembly state. */
void
xtensa_symbol_new_hook (symbolS *sym)
{
- if (S_GET_SEGMENT (sym) == expr_section)
+ if (is_leb128_expr && S_GET_SEGMENT (sym) == expr_section)
{
symbol_get_tc (sym)->next_expr_symbol = expr_symbols;
expr_symbols = sym;
{
xtensa_isa isa = xtensa_default_isa;
rt = new_resource_table
- (isa, xtensa_isa_num_pipe_stages (isa),
+ (isa, xtensa_num_pipe_stages,
xtensa_isa_num_funcUnits (isa),
(unit_num_copies_func) xtensa_funcUnit_num_copies,
(opcode_num_units_func) xtensa_opcode_num_funcUnit_uses,
}
-/* Some difference-of-symbols expressions make it out to the linker. Some
- don't. If one does, then the linker can optimize between the two labels.
- If it doesn't, then the linker shouldn't. */
-
+/* When a difference-of-symbols expression is encoded as a uleb128 or
+ 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)
{
IStack istack;
offsetT frag_offset;
int num_steps;
- fragS *lit_fragP;
int num_text_bytes, num_literal_bytes;
- int literal_diff, total_text_diff, this_text_diff, first;
+ int literal_diff, total_text_diff, this_text_diff;
assert (fragP->fr_opcode != NULL);
istack_init (&istack);
num_steps = xg_assembly_relax (&istack, &tinsn, segP, fragP, frag_offset,
min_steps, stretch);
- if (num_steps < min_steps)
- {
- as_fatal (_("internal error: relaxation failed"));
- return 0;
- }
-
- if (num_steps > RELAX_IMMED_MAXSTEPS)
- {
- as_fatal (_("internal error: relaxation requires too many steps"));
- return 0;
- }
+ assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
fragP->tc_frag_data.slot_subtypes[slot] = (int) RELAX_IMMED + num_steps;
/* Figure out the number of bytes needed. */
- lit_fragP = 0;
num_literal_bytes = get_num_stack_literal_bytes (&istack);
- literal_diff =
- num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
- first = 0;
- while (istack.insn[first].opcode == XTENSA_UNDEFINED)
- first++;
-
+ literal_diff
+ = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
num_text_bytes = get_num_stack_text_bytes (&istack);
if (from_wide_insn)
{
+ int first = 0;
+ while (istack.insn[first].opcode == XTENSA_UNDEFINED)
+ first++;
+
num_text_bytes += old_size;
if (opcode_fits_format_slot (istack.insn[first].opcode, fmt, slot))
num_text_bytes -= xg_get_single_size (istack.insn[first].opcode);
+ else
+ {
+ /* 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,
+ frag_offset + old_size,
+ min_steps, stretch + old_size);
+ assert (num_steps >= min_steps && num_steps <= RELAX_IMMED_MAXSTEPS);
+
+ fragP->tc_frag_data.slot_subtypes[slot]
+ = (int) RELAX_IMMED + num_steps;
+
+ num_literal_bytes = get_num_stack_literal_bytes (&istack);
+ literal_diff
+ = num_literal_bytes - fragP->tc_frag_data.literal_expansion[slot];
+
+ num_text_bytes = get_num_stack_text_bytes (&istack) + old_size;
+ }
}
total_text_diff = num_text_bytes - old_size;
/* Find the associated expandable literal for this. */
if (literal_diff != 0)
{
- lit_fragP = fragP->tc_frag_data.literal_frags[slot];
+ fragS *lit_fragP = fragP->tc_frag_data.literal_frags[slot];
if (lit_fragP)
{
assert (literal_diff == 4);
prop_flags->is_literal = TRUE;
if (fragP->tc_frag_data.is_specific_opcode
|| fragP->tc_frag_data.is_no_transform)
- prop_flags->is_no_transform = TRUE;
+ {
+ prop_flags->is_no_transform = TRUE;
+ if (xtensa_frag_flags_is_empty (prop_flags))
+ prop_flags->is_data = TRUE;
+ }
if (fragP->tc_frag_data.is_unreachable)
prop_flags->is_unreachable = TRUE;
else if (fragP->tc_frag_data.is_insn)