X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-xtensa.c;h=aef6b65e77bff99c6627d2fe34dd5a4e54ece9f4;hb=b81bf389ecc8103ffe23da2f1abbbdda608c132e;hp=f83339acbd946dae62086b276b81ca1be3194d9f;hpb=63a7429b8b4b47f7b2c2caffbdd6d25add3cdce0;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index f83339acbd..aef6b65e77 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -187,7 +187,9 @@ int generating_literals = 0; /* Instruction only properties about code. */ #define XTENSA_PROP_INSN_NO_DENSITY 0x00000040 #define XTENSA_PROP_INSN_NO_REORDER 0x00000080 -#define XTENSA_PROP_INSN_NO_TRANSFORM 0x00000100 +/* Historically, NO_TRANSFORM was a property of instructions, + but it should apply to literals under certain circumstances. */ +#define XTENSA_PROP_NO_TRANSFORM 0x00000100 /* Branch target alignment information. This transmits information to the linker optimization about the priority of aligning a @@ -263,6 +265,9 @@ struct frag_flags_struct unsigned is_data : 1; unsigned is_unreachable : 1; + /* is_specific_opcode implies no_transform. */ + unsigned is_no_transform : 1; + struct { unsigned is_loop_target : 1; @@ -271,8 +276,6 @@ struct frag_flags_struct unsigned is_no_density : 1; /* no_longcalls flag does not need to be placed in the object file. */ - /* is_specific_opcode implies no_transform. */ - unsigned is_no_transform : 1; unsigned is_no_reorder : 1; @@ -352,6 +355,24 @@ op_placement_info_table op_placement_table; #define O_hi16 O_md2 /* use high 16 bits of symbolic value */ #define O_lo16 O_md3 /* use low 16 bits of symbolic value */ +struct suffix_reloc_map +{ + char *suffix; + int length; + bfd_reloc_code_real_type reloc; + unsigned char operator; +}; + +#define SUFFIX_MAP(str, reloc, op) { str, sizeof (str) - 1, reloc, op } + +static struct suffix_reloc_map suffix_relocs[] = +{ + SUFFIX_MAP ("l", BFD_RELOC_LO16, O_lo16), + SUFFIX_MAP ("h", BFD_RELOC_HI16, O_hi16), + SUFFIX_MAP ("plt", BFD_RELOC_XTENSA_PLT, O_pltrel), + { (char *) 0, 0, BFD_RELOC_UNUSED, 0 } +}; + /* Directives. */ @@ -941,43 +962,16 @@ xtensa_clear_insn_labels (void) } -/* The "loops_ok" argument is provided to allow ignoring labels that - define loop ends. This fixes a bug where the NOPs to align a - loop opcode were included in a previous zero-cost loop: - - loop a0, loopend - - loopend: - - loop a2, loopend2 - - - would become: - - loop a0, loopend - - nop.n <===== bad! - loopend: - - loop a2, loopend2 - - - This argument is used to prevent moving the NOP to before the - loop-end label, which is what you want in this special case. */ - static void -xtensa_move_labels (fragS *new_frag, valueT new_offset, bfd_boolean loops_ok) +xtensa_move_labels (fragS *new_frag, valueT new_offset) { sym_list *lit; for (lit = insn_labels; lit; lit = lit->next) { symbolS *lit_sym = lit->sym; - if (loops_ok || ! symbol_get_tc (lit_sym)->is_loop_target) - { - S_SET_VALUE (lit_sym, new_offset); - symbol_set_frag (lit_sym, new_frag); - } + S_SET_VALUE (lit_sym, new_offset); + symbol_set_frag (lit_sym, new_frag); } } @@ -1574,29 +1568,12 @@ xtensa_elf_cons (int nbytes) static bfd_reloc_code_real_type xtensa_elf_suffix (char **str_p, expressionS *exp_p) { - struct map_bfd - { - char *string; - int length; - bfd_reloc_code_real_type reloc; - }; - char ident[20]; char *str = *str_p; char *str2; int ch; int len; - struct map_bfd *ptr; - -#define MAP(str,reloc) { str, sizeof (str) - 1, reloc } - - static struct map_bfd mapping[] = - { - MAP ("l", BFD_RELOC_LO16), - MAP ("h", BFD_RELOC_HI16), - MAP ("plt", BFD_RELOC_XTENSA_PLT), - { (char *) 0, 0, BFD_RELOC_UNUSED } - }; + struct suffix_reloc_map *ptr; if (*str++ != '@') return BFD_RELOC_NONE; @@ -1613,10 +1590,10 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p) len = str2 - ident; ch = ident[0]; - for (ptr = &mapping[0]; ptr->length > 0; ptr++) - if (ch == ptr->string[0] + for (ptr = &suffix_relocs[0]; ptr->length > 0; ptr++) + if (ch == ptr->suffix[0] && len == ptr->length - && memcmp (ident, ptr->string, ptr->length) == 0) + && memcmp (ident, ptr->suffix, ptr->length) == 0) { /* Now check for "identifier@suffix+constant". */ if (*str == '-' || *str == '+') @@ -1644,6 +1621,49 @@ xtensa_elf_suffix (char **str_p, expressionS *exp_p) } +/* Find the matching operator type. */ +static unsigned char +map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc) +{ + struct suffix_reloc_map *sfx; + unsigned char operator = (unsigned char) -1; + + for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++) + { + if (sfx->reloc == reloc) + { + operator = sfx->operator; + break; + } + } + assert (operator != (unsigned char) -1); + return operator; +} + + +/* Find the matching reloc type. */ +static bfd_reloc_code_real_type +map_operator_to_reloc (unsigned char operator) +{ + struct suffix_reloc_map *sfx; + bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; + + for (sfx = &suffix_relocs[0]; sfx->suffix; sfx++) + { + if (sfx->operator == operator) + { + reloc = sfx->reloc; + break; + } + } + + if (reloc == BFD_RELOC_UNUSED) + return BFD_RELOC_32; + + return reloc; +} + + static const char * expression_end (const char *name) { @@ -1744,34 +1764,32 @@ expression_maybe_register (xtensa_opcode opc, int opnd, expressionS *tok) } if ((tok->X_op == O_constant || tok->X_op == O_symbol) - && (reloc = xtensa_elf_suffix (&input_line_pointer, tok)) - && (reloc != BFD_RELOC_NONE)) + && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok)) + != BFD_RELOC_NONE)) { - switch (reloc) + if (reloc == BFD_RELOC_UNUSED) { - default: - case BFD_RELOC_UNUSED: - as_bad (_("unsupported relocation")); - break; - - case BFD_RELOC_XTENSA_PLT: - tok->X_op = O_pltrel; - break; + as_bad (_("unsupported relocation")); + return; + } - case BFD_RELOC_LO16: - if (tok->X_op == O_constant) + if (tok->X_op == O_constant) + { + switch (reloc) + { + case BFD_RELOC_LO16: tok->X_add_number &= 0xffff; - else - tok->X_op = O_lo16; - break; + return; - case BFD_RELOC_HI16: - if (tok->X_op == O_constant) + case BFD_RELOC_HI16: tok->X_add_number = ((unsigned) tok->X_add_number) >> 16; - else - tok->X_op = O_hi16; - break; + return; + + default: + break; + } } + tok->X_op = map_suffix_reloc_to_operator (reloc); } } else @@ -2295,9 +2313,6 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings) char *opname = *popname; bfd_boolean has_underbar = FALSE; - if (cur_vinsn.inside_bundle) - return 0; - if (*opname == '_') { has_underbar = TRUE; @@ -2340,7 +2355,11 @@ xg_translate_idioms (char **popname, int *pnum_args, char **arg_strings) return 0; } - if (xtensa_nop_opcode == XTENSA_UNDEFINED + /* Don't do anything special with NOPs inside FLIX instructions. They + 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 && strcmp (opname, "nop") == 0) { if (use_transform () && !has_underbar && density_supported) @@ -3267,7 +3286,7 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi) BuildOp *op; symbolS *sym; - memset (targ, 0, sizeof (TInsn)); + tinsn_init (targ); targ->linenum = insn->linenum; switch (bi->typ) { @@ -3479,7 +3498,33 @@ xg_expand_to_stack (IStack *istack, TInsn *insn, int lateral_steps) /* Relax the assembly instruction at least "min_steps". - Return the number of steps taken. */ + Return the number of steps taken. + + For relaxation to correctly terminate, every relaxation chain must + terminate in one of two ways: + + 1. If the chain from one instruction to the next consists entirely of + single instructions, then the chain *must* handle all possible + immediates without failing. It must not ever fail because an + immediate is out of range. The MOVI.N -> MOVI -> L32R relaxation + chain is one example. L32R loads 32 bits, and there cannot be an + immediate larger than 32 bits, so it satisfies this condition. + Single instruction relaxation chains are as defined by + xg_is_single_relaxable_instruction. + + 2. Otherwise, the chain must end in a multi-instruction expansion: e.g., + BNEZ.N -> BNEZ -> BNEZ.W15 -> BENZ.N/J + + Strictly speaking, in most cases you can violate condition 1 and be OK + -- in particular when the last two instructions have the same single + size. But nevertheless, you should guarantee the above two conditions. + + We could fix this so that single-instruction expansions correctly + terminate when they can't handle the range, but the error messages are + worse, and it actually turns out that in every case but one (18-bit wide + branches), you need a multi-instruction expansion to get the full range + anyway. And because 18-bit branches are handled identically to 15-bit + branches, there isn't any point in changing it. */ static int xg_assembly_relax (IStack *istack, @@ -3492,12 +3537,9 @@ xg_assembly_relax (IStack *istack, { int steps_taken = 0; - /* assert (has no symbolic operands) - Some of its immeds don't fit. - Try to build a relaxed version. - This may go through a couple of stages - of single instruction transformations before - we get there. */ + /* Some of its immeds don't fit. Try to build a relaxed version. + This may go through a couple of stages of single instruction + transformations before we get there. */ TInsn single_target; TInsn current_insn; @@ -3816,7 +3858,7 @@ xg_expand_assembly_insn (IStack *istack, TInsn *orig_insn) TInsn new_insn; bfd_boolean do_expand; - memset (&new_insn, 0, sizeof (TInsn)); + tinsn_init (&new_insn); /* Narrow it if we can. xg_simplify_insn now does all the appropriate checking (e.g., for the density option). */ @@ -3946,6 +3988,8 @@ xg_assemble_literal (/* const */ TInsn *insn) { emit_state state; symbolS *lit_sym = NULL; + bfd_reloc_code_real_type reloc; + char *p; /* size = 4 for L32R. It could easily be larger when we move to larger constants. Add a parameter later. */ @@ -3981,19 +4025,24 @@ xg_assemble_literal (/* const */ TInsn *insn) frag_align (litalign, 0, 0); record_alignment (now_seg, litalign); - if (emit_val->X_op == O_pltrel) + switch (emit_val->X_op) { - char *p = frag_more (litsize); + case O_pltrel: + p = frag_more (litsize); xtensa_set_frag_assembly_state (frag_now); + reloc = map_operator_to_reloc (emit_val->X_op); if (emit_val->X_add_symbol) emit_val->X_op = O_symbol; else emit_val->X_op = O_constant; fix_new_exp (frag_now, p - frag_now->fr_literal, - litsize, emit_val, 0, BFD_RELOC_XTENSA_PLT); + litsize, emit_val, 0, reloc); + break; + + default: + emit_expr (emit_val, litsize); + break; } - else - emit_expr (emit_val, litsize); assert (frag_now->tc_frag_data.literal_frag == NULL); frag_now->tc_frag_data.literal_frag = get_literal_pool_location (now_seg); @@ -4358,7 +4407,8 @@ frag_format_size (const fragS *fragP) /* If an instruction is about to grow, return the longer size. */ if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP1 - || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2) + || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP2 + || fragP->tc_frag_data.slot_subtypes[0] == RELAX_IMMED_STEP3) return 3; if (fragP->tc_frag_data.slot_subtypes[0] == RELAX_NARROW) @@ -4522,6 +4572,7 @@ xtensa_mark_literal_pool_location (void) fixes into this frchain's fix list. */ pool_location = frag_now; frag_now->tc_frag_data.lit_frchain = frchain_now; + frag_now->tc_frag_data.literal_frag = frag_now; frag_variant (rs_machine_dependent, 0, 0, RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL); xtensa_set_frag_assembly_state (frag_now); @@ -4666,6 +4717,55 @@ relaxable_section (asection *sec) } +static void +xtensa_mark_frags_for_org (void) +{ + segT *seclist; + + /* Walk over each fragment of all of the current segments. If we find + a .org frag in any of the segments, mark all frags prior to it as + "no transform", which will prevent linker optimizations from messing + up the .org distance. This should be done after + xtensa_find_unmarked_state_frags, because we don't want to worry here + about that function trashing the data we save here. */ + + for (seclist = &stdoutput->sections; + seclist && *seclist; + seclist = &(*seclist)->next) + { + segT sec = *seclist; + segment_info_type *seginfo; + fragS *fragP; + flagword flags; + flags = bfd_get_section_flags (stdoutput, sec); + if (flags & SEC_DEBUGGING) + continue; + if (!(flags & SEC_ALLOC)) + continue; + + seginfo = seg_info (sec); + if (seginfo && seginfo->frchainP) + { + fragS *last_fragP = seginfo->frchainP->frch_root; + for (fragP = seginfo->frchainP->frch_root; fragP; + fragP = fragP->fr_next) + { + /* cvt_frag_to_fill has changed the fr_type of org frags to + rs_fill, so use the value as cached in rs_subtype here. */ + if (fragP->fr_subtype == RELAX_ORG) + { + while (last_fragP != fragP->fr_next) + { + last_fragP->tc_frag_data.is_no_transform = TRUE; + last_fragP = last_fragP->fr_next; + } + } + } + } + } +} + + static void xtensa_find_unmarked_state_frags (void) { @@ -4985,7 +5085,7 @@ xtensa_frob_label (symbolS *sym) frag_now->fr_symbol, frag_now->fr_offset, NULL); xtensa_set_frag_assembly_state (frag_now); - xtensa_move_labels (frag_now, 0, TRUE); + xtensa_move_labels (frag_now, 0); } /* No target aligning in the absolute section. */ @@ -5001,7 +5101,7 @@ xtensa_frob_label (symbolS *sym) RELAX_DESIRE_ALIGN_IF_TARGET, frag_now->fr_symbol, frag_now->fr_offset, NULL); xtensa_set_frag_assembly_state (frag_now); - xtensa_move_labels (frag_now, 0, TRUE); + xtensa_move_labels (frag_now, 0); } /* We need to mark the following properties even if we aren't aligning. */ @@ -5070,6 +5170,15 @@ xtensa_unrecognized_line (int ch) void xtensa_flush_pending_output (void) { + /* This line fixes a bug where automatically generated gstabs info + separates a function label from its entry instruction, ending up + with the literal position between the function label and the entry + instruction and crashing code. It only happens with --gstabs and + --text-section-literals, and when several other obscure relaxation + conditions are met. */ + if (outputting_stabs_line_debug) + return; + if (cur_vinsn.inside_bundle) as_bad (_("missing closing brace")); @@ -5266,6 +5375,9 @@ xtensa_handle_align (fragS *fragP) as_bad_where (fragP->fr_file, fragP->fr_line, _("unaligned entry instruction")); } + + if (linkrelax && fragP->fr_type == rs_org) + fragP->fr_subtype = RELAX_ORG; } @@ -6684,15 +6796,13 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn) frag_var (rs_machine_dependent, 0, 0, RELAX_CHECK_ALIGN_NEXT_OPCODE, target_sym, 0, NULL); xtensa_set_frag_assembly_state (frag_now); - - xtensa_move_labels (frag_now, 0, FALSE); } if (vinsn->slots[0].opcode == xtensa_entry_opcode && !vinsn->slots[0].is_specific_opcode) { xtensa_mark_literal_pool_location (); - xtensa_move_labels (frag_now, 0, TRUE); + xtensa_move_labels (frag_now, 0); frag_var (rs_align_test, 1, 1, 0, NULL, 2, NULL); } @@ -8238,6 +8348,7 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p) case RELAX_IMMED: case RELAX_IMMED_STEP1: case RELAX_IMMED_STEP2: + case RELAX_IMMED_STEP3: /* Place the immediate. */ new_stretch += relax_frag_immed (now_seg, fragP, stretch, @@ -8955,6 +9066,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragp) case RELAX_IMMED: case RELAX_IMMED_STEP1: case RELAX_IMMED_STEP2: + case RELAX_IMMED_STEP3: /* Place the immediate. */ convert_frag_immed (sec, fragp, @@ -9302,10 +9414,7 @@ convert_frag_immed (segT segP, /* Add a fixup. */ target_seg = S_GET_SEGMENT (lit_sym); assert (target_seg); - if (tinsn->tok[0].X_op == O_pltrel) - reloc_type = BFD_RELOC_XTENSA_PLT; - else - reloc_type = BFD_RELOC_32; + reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op); fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4, &tinsn->tok[0], FALSE, reloc_type); break; @@ -9486,11 +9595,6 @@ convert_frag_immed_finish_loop (segT segP, fragS *fragP, TInsn *tinsn) target = 0; } - know (symbolP); - know (symbolP->sy_frag); - know (!(S_GET_SEGMENT (symbolP) == absolute_section) - || symbol_get_frag (symbolP) == &zero_address_frag); - loop_length = target - (fragP->fr_address + fragP->fr_fix); loop_length_hi = loop_length & ~0x0ff; loop_length_lo = loop_length & 0x0ff; @@ -9740,17 +9844,14 @@ xtensa_move_literals (void) frchain_to = literal_pool->tc_frag_data.lit_frchain; assert (frchain_to); } - insert_after = literal_pool; - - while (insert_after->fr_next->fr_subtype != RELAX_LITERAL_POOL_END) - insert_after = insert_after->fr_next; - + insert_after = literal_pool->tc_frag_data.literal_frag; dest_seg = insert_after->fr_next->tc_frag_data.lit_seg; *frag_splice = next_frag; search_frag->fr_next = insert_after->fr_next; insert_after->fr_next = search_frag; search_frag->tc_frag_data.lit_seg = dest_seg; + literal_pool->tc_frag_data.literal_frag = search_frag; /* Now move any fixups associated with this frag to the right section. */ @@ -10126,6 +10227,7 @@ xtensa_post_relax_hook (void) xtensa_move_seg_list_to_beginning (literal_head); xtensa_find_unmarked_state_frags (); + xtensa_mark_frags_for_org (); xtensa_create_property_segments (get_frag_is_literal, NULL, @@ -10586,6 +10688,9 @@ get_frag_property_flags (const fragS *fragP, frag_flags *prop_flags) xtensa_frag_flags_init (prop_flags); if (fragP->tc_frag_data.is_literal) 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; if (fragP->tc_frag_data.is_unreachable) prop_flags->is_unreachable = TRUE; else if (fragP->tc_frag_data.is_insn) @@ -10595,9 +10700,6 @@ get_frag_property_flags (const fragS *fragP, frag_flags *prop_flags) prop_flags->insn.is_loop_target = TRUE; if (fragP->tc_frag_data.is_branch_target) prop_flags->insn.is_branch_target = TRUE; - if (fragP->tc_frag_data.is_specific_opcode - || fragP->tc_frag_data.is_no_transform) - prop_flags->insn.is_no_transform = TRUE; if (fragP->tc_frag_data.is_no_density) prop_flags->insn.is_no_density = TRUE; if (fragP->tc_frag_data.use_absolute_literals) @@ -10635,8 +10737,8 @@ frag_flags_to_number (const frag_flags *prop_flags) if (prop_flags->insn.is_no_density) num |= XTENSA_PROP_INSN_NO_DENSITY; - if (prop_flags->insn.is_no_transform) - num |= XTENSA_PROP_INSN_NO_TRANSFORM; + if (prop_flags->is_no_transform) + num |= XTENSA_PROP_NO_TRANSFORM; if (prop_flags->insn.is_no_reorder) num |= XTENSA_PROP_INSN_NO_REORDER; if (prop_flags->insn.is_abslit) @@ -10675,8 +10777,8 @@ xtensa_frag_flags_combinable (const frag_flags *prop_flags_1, if (prop_flags_1->insn.is_no_density != prop_flags_2->insn.is_no_density) return FALSE; - if (prop_flags_1->insn.is_no_transform != - prop_flags_2->insn.is_no_transform) + if (prop_flags_1->is_no_transform != + prop_flags_2->is_no_transform) return FALSE; if (prop_flags_1->insn.is_no_reorder != prop_flags_2->insn.is_no_reorder) @@ -10963,7 +11065,7 @@ istack_push_space (IStack *stack) TInsn *insn; assert (!istack_full (stack)); insn = &stack->insn[rec]; - memset (insn, 0, sizeof (TInsn)); + tinsn_init (insn); stack->ninsn++; return insn; } @@ -10978,7 +11080,7 @@ istack_pop (IStack *stack) int rec = stack->ninsn - 1; assert (!istack_empty (stack)); stack->ninsn--; - memset (&stack->insn[rec], 0, sizeof (TInsn)); + tinsn_init (&stack->insn[rec]); } @@ -10991,17 +11093,6 @@ tinsn_init (TInsn *dst) } -/* Get the ``num''th token of the TInsn. - It is illegal to call this if num > insn->ntoks. */ - -expressionS * -tinsn_get_tok (TInsn *insn, int num) -{ - assert (num < insn->ntok); - return &insn->tok[num]; -} - - /* Return TRUE if ANY of the operands in the insn are symbolic. */ static bfd_boolean