X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mn10300.c;h=3d159b18561e1517622caa802e1283010025579c;hb=070cb95614a9c50be0d1191d9b9daee178dd4c38;hp=671c0089f7fd0dbfba498f034fed1bb7e324f3d7;hpb=603b72571dd17826efe9843dab8fbb0d5012a1f3;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c index 671c0089f7..3d159b1856 100644 --- a/gas/config/tc-mn10300.c +++ b/gas/config/tc-mn10300.c @@ -1,6 +1,5 @@ /* tc-mn10300.c -- Assembler code for the Matsushita 10300 - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1996-2014 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -281,6 +280,8 @@ static const struct reg_name other_registers[] = { "pc", AM33 }, { "psw", 0 }, { "sp", 0 }, + { "ssp", 0 }, + { "usp", 0 }, }; #define OTHER_REG_NAME_CNT ARRAY_SIZE (other_registers) @@ -675,6 +676,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, else if (fragP->fr_subtype == 6) { int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xcd; fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol, fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL); @@ -684,9 +686,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, else if (fragP->fr_subtype == 7) { int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xdd; fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3]; fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4]; + fragP->fr_literal[offset + 3] = 0; + fragP->fr_literal[offset + 4] = 0; fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol, fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL); @@ -696,6 +701,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, else if (fragP->fr_subtype == 8) { int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xfa; fragP->fr_literal[offset + 1] = 0xff; fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol, @@ -706,6 +712,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, else if (fragP->fr_subtype == 9) { int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xfc; fragP->fr_literal[offset + 1] = 0xff; @@ -725,6 +732,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, else if (fragP->fr_subtype == 11) { int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xcc; fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol, @@ -735,6 +743,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, else if (fragP->fr_subtype == 12) { int offset = fragP->fr_fix; + fragP->fr_literal[offset] = 0xdc; fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol, @@ -1004,7 +1013,8 @@ mn10300_check_fixup (struct mn10300_fixup *fixup) } void -mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp) +mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp, + bfd_reloc_code_real_type r ATTRIBUTE_UNUSED) { struct mn10300_fixup fixup; @@ -1766,8 +1776,6 @@ keep_going: that they do indeed not match. */ if (opcode->no_match_operands) { - int i; - /* Look at each operand to see if it's marked. */ for (i = 0; i < MN10300_MAX_OPERANDS; i++) { @@ -2050,18 +2058,23 @@ keep_going: for (i = 0; i < fc; i++) { const struct mn10300_operand *operand; + int reloc_size; operand = &mn10300_operands[fixups[i].opindex]; if (fixups[i].reloc != BFD_RELOC_UNUSED && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL && fixups[i].reloc != BFD_RELOC_32_GOTOFF && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL + && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GD + && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LD + && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LDO + && fixups[i].reloc != BFD_RELOC_MN10300_TLS_GOTIE + && fixups[i].reloc != BFD_RELOC_MN10300_TLS_IE + && fixups[i].reloc != BFD_RELOC_MN10300_TLS_LE && fixups[i].reloc != BFD_RELOC_MN10300_GOT32) { reloc_howto_type *reloc_howto; - int size; int offset; - fixS *fixP; reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); @@ -2069,20 +2082,20 @@ keep_going: if (!reloc_howto) abort (); - size = bfd_get_reloc_size (reloc_howto); + reloc_size = bfd_get_reloc_size (reloc_howto); - if (size < 1 || size > 4) + if (reloc_size < 1 || reloc_size > 4) abort (); offset = 4 - size; - fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, - size, &fixups[i].exp, - reloc_howto->pc_relative, - fixups[i].reloc); + fix_new_exp (frag_now, f - frag_now->fr_literal + offset, + reloc_size, &fixups[i].exp, + reloc_howto->pc_relative, + fixups[i].reloc); } else { - int reloc, pcrel, reloc_size, offset; + int reloc, pcrel, offset; fixS *fixP; reloc = BFD_RELOC_NONE; @@ -2141,15 +2154,21 @@ keep_going: dwarf2_emit_insn (size); } + + /* Label this frag as one that contains instructions. */ + frag_now->tc_frag_data = TRUE; } /* If while processing a fixup, a reloc really needs to be created then it is done here. */ -arelent * +arelent ** tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { + static arelent * no_relocs = NULL; + static arelent * relocs[MAX_RELOC_EXPANSION + 1]; arelent *reloc; + reloc = xmalloc (sizeof (arelent)); reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); @@ -2158,9 +2177,13 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) as_bad_where (fixp->fx_file, fixp->fx_line, _("reloc %d not supported by object file format"), (int) fixp->fx_r_type); - return NULL; + free (reloc); + return & no_relocs; } + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + relocs[0] = reloc; + relocs[1] = NULL; if (fixp->fx_subsy && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) @@ -2171,53 +2194,43 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) if (fixp->fx_addsy && fixp->fx_subsy) { - reloc->sym_ptr_ptr = NULL; - - /* If we got a difference between two symbols, and the - subtracted symbol is in the current section, use a - PC-relative relocation. If both symbols are in the same - section, the difference would have already been simplified - to a constant. */ - if (S_GET_SEGMENT (fixp->fx_subsy) == seg) - { - reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->addend = (reloc->address - S_GET_VALUE (fixp->fx_subsy) - + fixp->fx_offset); + asection *asec, *ssec; - switch (fixp->fx_r_type) - { - case BFD_RELOC_8: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_8_PCREL); - return reloc; + asec = S_GET_SEGMENT (fixp->fx_addsy); + ssec = S_GET_SEGMENT (fixp->fx_subsy); - case BFD_RELOC_16: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_16_PCREL); - return reloc; + /* If we have a difference between two (non-absolute) symbols we must + generate two relocs (one for each symbol) and allow the linker to + resolve them - relaxation may change the distances between symbols, + even local symbols defined in the same section. */ + if (ssec != absolute_section || asec != absolute_section) + { + arelent * reloc2 = xmalloc (sizeof * reloc); - case BFD_RELOC_24: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_24_PCREL); - return reloc; + relocs[0] = reloc2; + relocs[1] = reloc; - case BFD_RELOC_32: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_32_PCREL); - return reloc; + reloc2->address = reloc->address; + reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_MN10300_SYM_DIFF); + reloc2->addend = - S_GET_VALUE (fixp->fx_subsy); + reloc2->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); - default: - /* Try to compute the absolute value below. */ - break; + reloc->addend = fixp->fx_offset; + if (asec == absolute_section) + { + reloc->addend += S_GET_VALUE (fixp->fx_addsy); + reloc->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + } + else + { + reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); } - } - if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) - || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - "Difference of symbols in different sections is not supported"); + fixp->fx_pcrel = 0; + fixp->fx_done = 1; + return relocs; } else { @@ -2247,14 +2260,12 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) default: reloc->sym_ptr_ptr = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr; - return reloc; + return relocs; } - } - if (reloc->sym_ptr_ptr) - free (reloc->sym_ptr_ptr); - free (reloc); - return NULL; + free (reloc); + return & no_relocs; + } } else { @@ -2262,27 +2273,39 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->addend = fixp->fx_offset; } - return reloc; + return relocs; +} + +/* Returns true iff the symbol attached to the frag is at a known location + in the given section, (and hence the relocation to it can be relaxed by + the assembler). */ +static inline bfd_boolean +has_known_symbol_location (fragS * fragp, asection * sec) +{ + symbolS * sym = fragp->fr_symbol; + + return sym != NULL + && S_IS_DEFINED (sym) + && ! S_IS_WEAK (sym) + && S_GET_SEGMENT (sym) == sec; } int md_estimate_size_before_relax (fragS *fragp, asection *seg) { if (fragp->fr_subtype == 6 - && (!S_IS_DEFINED (fragp->fr_symbol) - || seg != S_GET_SEGMENT (fragp->fr_symbol))) + && ! has_known_symbol_location (fragp, seg)) fragp->fr_subtype = 7; else if (fragp->fr_subtype == 8 - && (!S_IS_DEFINED (fragp->fr_symbol) - || seg != S_GET_SEGMENT (fragp->fr_symbol))) + && ! has_known_symbol_location (fragp, seg)) fragp->fr_subtype = 9; else if (fragp->fr_subtype == 10 - && (!S_IS_DEFINED (fragp->fr_symbol) - || seg != S_GET_SEGMENT (fragp->fr_symbol))) + && ! has_known_symbol_location (fragp, seg)) fragp->fr_subtype = 12; if (fragp->fr_subtype == 13) return 3; + if (fragp->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0])) abort (); @@ -2292,11 +2315,11 @@ md_estimate_size_before_relax (fragS *fragp, asection *seg) long md_pcrel_from (fixS *fixp) { - if (fixp->fx_addsy != NULL && !S_IS_DEFINED (fixp->fx_addsy)) - { - /* The symbol is undefined. Let the linker figure it out. */ - return 0; - } + if (fixp->fx_addsy != (symbolS *) NULL + && (!S_IS_DEFINED (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))) + /* The symbol is undefined or weak. Let the linker figure it out. */ + return 0; + return fixp->fx_frag->fr_address + fixp->fx_where; } @@ -2307,7 +2330,7 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg) int size = 0; int value = (int) * valP; - assert (fixP->fx_r_type < BFD_RELOC_UNUSED); + gas_assert (fixP->fx_r_type < BFD_RELOC_UNUSED); /* This should never happen. */ if (seg->flags & SEC_ALLOC) @@ -2358,6 +2381,10 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg) fixP->fx_done = 0; return; + case BFD_RELOC_MN10300_ALIGN: + fixP->fx_done = 1; + return; + case BFD_RELOC_NONE: default: as_bad_where (fixP->fx_file, fixP->fx_line, @@ -2377,11 +2404,14 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg) bfd_boolean mn10300_fix_adjustable (struct fix *fixp) { - if (TC_FORCE_RELOCATION_LOCAL (fixp)) - return FALSE; - - if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + if (fixp->fx_pcrel) + { + if (TC_FORCE_RELOCATION_LOCAL (fixp)) + return FALSE; + } + /* Non-relative relocs can (and must) be adjusted if they do + not meet the criteria below, or the generic criteria. */ + else if (TC_FORCE_RELOCATION (fixp)) return FALSE; /* Do not adjust relocations involving symbols in code sections, @@ -2395,8 +2425,9 @@ mn10300_fix_adjustable (struct fix *fixp) symbols, because they too break relaxation. We do want to adjust other mergable symbols, like .rodata, because code relaxations need section-relative symbols to properly relax them. */ - if (! (S_GET_SEGMENT(fixp->fx_addsy)->flags & SEC_MERGE)) + if (! (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE)) return FALSE; + if (strncmp (S_GET_SEGMENT (fixp->fx_addsy)->name, ".debug", 6) == 0) return FALSE; @@ -2478,6 +2509,18 @@ mn10300_parse_name (char const *name, reloc_type = BFD_RELOC_MN10300_GOT32; else if ((next_end = mn10300_end_of_match (next + 1, "PLT"))) reloc_type = BFD_RELOC_32_PLT_PCREL; + else if ((next_end = mn10300_end_of_match (next + 1, "tlsgd"))) + reloc_type = BFD_RELOC_MN10300_TLS_GD; + else if ((next_end = mn10300_end_of_match (next + 1, "tlsldm"))) + reloc_type = BFD_RELOC_MN10300_TLS_LD; + else if ((next_end = mn10300_end_of_match (next + 1, "dtpoff"))) + reloc_type = BFD_RELOC_MN10300_TLS_LDO; + else if ((next_end = mn10300_end_of_match (next + 1, "gotntpoff"))) + reloc_type = BFD_RELOC_MN10300_TLS_GOTIE; + else if ((next_end = mn10300_end_of_match (next + 1, "indntpoff"))) + reloc_type = BFD_RELOC_MN10300_TLS_IE; + else if ((next_end = mn10300_end_of_match (next + 1, "tpoff"))) + reloc_type = BFD_RELOC_MN10300_TLS_LE; else goto no_suffix; @@ -2502,3 +2545,95 @@ const pseudo_typeS md_pseudo_table[] = { "mn10300", set_arch_mach, MN103 }, {NULL, 0, 0} }; + +/* Returns FALSE if there is some mn10300 specific reason why the + subtraction of two same-section symbols cannot be computed by + the assembler. */ + +bfd_boolean +mn10300_allow_local_subtract (expressionS * left, expressionS * right, segT section) +{ + bfd_boolean result; + fragS * left_frag; + fragS * right_frag; + fragS * frag; + + /* If we are not performing linker relaxation then we have nothing + to worry about. */ + if (linkrelax == 0) + return TRUE; + + /* If the symbols are not in a code section then they are OK. */ + if ((section->flags & SEC_CODE) == 0) + return TRUE; + + /* Otherwise we have to scan the fragments between the two symbols. + If any instructions are found then we have to assume that linker + relaxation may change their size and so we must delay resolving + the subtraction until the final link. */ + left_frag = symbol_get_frag (left->X_add_symbol); + right_frag = symbol_get_frag (right->X_add_symbol); + + if (left_frag == right_frag) + return ! left_frag->tc_frag_data; + + result = TRUE; + for (frag = left_frag; frag != NULL; frag = frag->fr_next) + { + if (frag->tc_frag_data) + result = FALSE; + if (frag == right_frag) + break; + } + + if (frag == NULL) + for (frag = right_frag; frag != NULL; frag = frag->fr_next) + { + if (frag->tc_frag_data) + result = FALSE; + if (frag == left_frag) + break; + } + + if (frag == NULL) + /* The two symbols are on disjoint fragment chains + - we cannot possibly compute their difference. */ + return FALSE; + + return result; +} + +/* When relaxing, we need to output a reloc for any .align directive + that requests alignment to a two byte boundary or larger. */ + +void +mn10300_handle_align (fragS *frag) +{ + if (linkrelax + && (frag->fr_type == rs_align + || frag->fr_type == rs_align_code) + && frag->fr_address + frag->fr_fix > 0 + && frag->fr_offset > 1 + && now_seg != bss_section + /* Do not create relocs for the merging sections - such + relocs will prevent the contents from being merged. */ + && (bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE) == 0) + /* Create a new fixup to record the alignment request. The symbol is + irrelevent but must be present so we use the absolute section symbol. + The offset from the symbol is used to record the power-of-two alignment + value. The size is set to 0 because the frag may already be aligned, + thus causing cvt_frag_to_fill to reduce the size of the frag to zero. */ + fix_new (frag, frag->fr_fix, 0, & abs_symbol, frag->fr_offset, FALSE, + BFD_RELOC_MN10300_ALIGN); +} + +bfd_boolean +mn10300_force_relocation (struct fix * fixp) +{ + if (linkrelax + && (fixp->fx_pcrel + || fixp->fx_r_type == BFD_RELOC_MN10300_ALIGN)) + return TRUE; + + return generic_force_reloc (fixp); +}