diff options
author | Nick Clifton <nickc@redhat.com> | 2007-10-19 17:31:31 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2007-10-19 17:31:31 +0000 |
commit | bfff1642494227904c6c9a6c285cbaa6cf615bbb (patch) | |
tree | 7bf1ece58861b5e9c520e056102994251c0a7504 /gas | |
parent | 97030eea009ba78139fe20eae4585984435ac178 (diff) | |
download | gdb-bfff1642494227904c6c9a6c285cbaa6cf615bbb.zip gdb-bfff1642494227904c6c9a6c285cbaa6cf615bbb.tar.gz gdb-bfff1642494227904c6c9a6c285cbaa6cf615bbb.tar.bz2 |
Add MN10300 linker relaxation support for symbol differences
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 21 | ||||
-rw-r--r-- | gas/config/tc-mn10300.c | 144 | ||||
-rw-r--r-- | gas/config/tc-mn10300.h | 14 | ||||
-rw-r--r-- | gas/doc/internals.texi | 12 | ||||
-rw-r--r-- | gas/expr.c | 3 | ||||
-rw-r--r-- | gas/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gas/testsuite/gas/mn10300/basic.exp | 1 | ||||
-rw-r--r-- | gas/testsuite/gas/mn10300/pr997.l | 20 | ||||
-rw-r--r-- | gas/testsuite/gas/mn10300/pr997.s | 5 |
9 files changed, 181 insertions, 45 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 5911282..f53d2ab 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,24 @@ +2007-10-19 Nick Clifton <nickc@redhat.com> + + * expr.c (expr): Test md_allow_local_subtract (if defined) before + allowing the evaluation of an expression involving two symbols + defined in the same section. + * doc/internals.texi (md_allow_local_subtract): Document the new + macro. + * config/tc-mn10300.h (md_allow_local_subtract): Define. + (RELAX_EXPANSION_POSSIBLE): Define. + (MAX_RELOC_EXPANSION): Define. + (TC_FRAG_TYPE): Define. + * config/tc-mn10300.c (md_assemble): Mark fragments as containing code. + (tc_gen_reloc): Return an array of relocs. If necessary generate + two relocs to handle an expressions involving the difference of + two symbols. + (mn10300_fix_adjustable): Do not test TC_FORCE_RELOCATION_LOCAL + when then fixup is not pc-relative. + (mn10300_allow_local_subtract): New function. Determine when it + is safe to compute the difference between two symbols at assemble + time. + 2007-10-19 Alan Modra <amodra@bigpond.net.au> * config/tc-ppc.c (ppc_parse_name): Skip leading '%'. diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c index 671c008..5ec58bb 100644 --- a/gas/config/tc-mn10300.c +++ b/gas/config/tc-mn10300.c @@ -2141,15 +2141,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 +2164,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) @@ -2173,44 +2183,33 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { 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 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 segment. */ 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); + arelent * reloc2 = xmalloc (sizeof * reloc); - switch (fixp->fx_r_type) - { - case BFD_RELOC_8: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_8_PCREL); - return reloc; + relocs[0] = reloc2; + relocs[1] = reloc; - case BFD_RELOC_16: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_16_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); - case BFD_RELOC_24: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_24_PCREL); - return reloc; + reloc->addend = fixp->fx_offset; + if (S_GET_SEGMENT (fixp->fx_addsy) == absolute_section) + reloc->addend += S_GET_VALUE (fixp->fx_addsy); - case BFD_RELOC_32: - reloc->howto = bfd_reloc_type_lookup (stdoutput, - BFD_RELOC_32_PCREL); - return reloc; + reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - default: - /* Try to compute the absolute value below. */ - break; - } + fixp->fx_pcrel = 0; + fixp->fx_done = 1; + return relocs; } if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) @@ -2247,14 +2246,14 @@ 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; + return & no_relocs; } else { @@ -2262,7 +2261,7 @@ 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; } int @@ -2377,11 +2376,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 +2397,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; @@ -2502,3 +2505,60 @@ 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; +} diff --git a/gas/config/tc-mn10300.h b/gas/config/tc-mn10300.h index 20de21c..af7a6e6 100644 --- a/gas/config/tc-mn10300.h +++ b/gas/config/tc-mn10300.h @@ -98,13 +98,21 @@ void mn10300_cons_fix_new PARAMS ((fragS *, int, int, expressionS *)); #define md_number_to_chars number_to_chars_littleendian -/* Don't bother to adjust relocs. */ -/* #define tc_fix_adjustable(FIX) 0 */ #define tc_fix_adjustable(FIX) mn10300_fix_adjustable (FIX) -extern bfd_boolean mn10300_fix_adjustable PARAMS ((struct fix *)); +extern bfd_boolean mn10300_fix_adjustable (struct fix *); /* We do relaxing in the assembler as well as the linker. */ extern const struct relax_type md_relax_table[]; #define TC_GENERIC_RELAX_TABLE md_relax_table #define DWARF2_LINE_MIN_INSN_LENGTH 1 + +/* The difference between same-section symbols may be affected by linker + relaxation, so do not resolve such expressions in the assembler. */ +#define md_allow_local_subtract(l,r,s) mn10300_allow_local_subtract (l, r, s) +extern bfd_boolean mn10300_allow_local_subtract (expressionS *, expressionS *, segT); + +#define RELOC_EXPANSION_POSSIBLE +#define MAX_RELOC_EXPANSION 2 + +#define TC_FRAG_TYPE bfd_boolean diff --git a/gas/doc/internals.texi b/gas/doc/internals.texi index ff1df98..62f16f7 100644 --- a/gas/doc/internals.texi +++ b/gas/doc/internals.texi @@ -1535,6 +1535,18 @@ The function should return the debug format that is preferred by the CPU backend. This format will be used when generating assembler specific debug information. +@item md_allow_local_subtract (@var{left}, @var{right}, @var{section}) +If defined, GAS will call this macro when evaluating an expression which is the +difference of two symbols defined in the same section. It takes three +arguments: @code{expressioS * @var{left}} which is the symbolic expression on +the left hand side of the subtraction operation, @code{expressionS * +@var{right}} which is the symbolic expression on the right hand side of the +subtraction, and @code{segT @var{section}} which is the section containing the two +symbols. The macro should return a non-zero value if the expression should be +evaluated. Targets which implement link time relaxation which may change the +position of the two symbols relative to each other should ensure that this +macro returns zero in situations where this can occur. + @end table @node Object format backend @@ -1738,6 +1738,9 @@ expr (int rankarg, /* Larger # is higher rank. */ && right.X_op == O_symbol && resultP->X_op == O_symbol && retval == rightseg +#ifdef md_allow_local_subtract + && md_allow_local_subtract (resultP, & right, rightseg) +#endif && (SEG_NORMAL (rightseg) || right.X_add_symbol == resultP->X_add_symbol) && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol), diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index c180bea..953f096 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2007-10-19 Nick Clifton <nickc@redhat.com> + + * gas/mn10300/basic.exp: Run pr997 test. + * gas/mn10300/pr997.s: New test. + * gas/mn10300/pr887.l: Expected output. + 2007-10-17 Nathan Sidwell <nathan@codesourcery.com> * gas/m68k/mcf-movsr.s: New. diff --git a/gas/testsuite/gas/mn10300/basic.exp b/gas/testsuite/gas/mn10300/basic.exp index 9b1b53b..c74fcf6 100644 --- a/gas/testsuite/gas/mn10300/basic.exp +++ b/gas/testsuite/gas/mn10300/basic.exp @@ -1801,6 +1801,7 @@ if [istarget mn10300*-*-*] then { do_am33_8 run_list_test "movpc" "" + run_list_test "pr997" "-a" run_dump_test "am33-2" run_dump_test "relax" diff --git a/gas/testsuite/gas/mn10300/pr997.l b/gas/testsuite/gas/mn10300/pr997.l new file mode 100644 index 0000000..b122095 --- /dev/null +++ b/gas/testsuite/gas/mn10300/pr997.l @@ -0,0 +1,20 @@ +GAS LISTING .*/pr997.s.*page 1 + + + 1.*.data + 2.* + 3 0000 68656C6C.*msg:.*.asciz "hello world.\\n" + 3 6F20776F + 3 726C642E + 3 0A00 + 4.*msglen = .-msg-1 + 5.*msglen=msglen & 0xff + +.*GAS LISTING.*/pr997.s.*page 2 + + +DEFINED SYMBOLS +.*/pr997.s:3.*.data:0+00 msg +.*/pr997.s:4.*\*ABS\*:0+0d msglen + +NO UNDEFINED SYMBOLS diff --git a/gas/testsuite/gas/mn10300/pr997.s b/gas/testsuite/gas/mn10300/pr997.s new file mode 100644 index 0000000..4a54bbc --- /dev/null +++ b/gas/testsuite/gas/mn10300/pr997.s @@ -0,0 +1,5 @@ + .data + +msg: .asciz "hello world.\n" +msglen = .-msg-1 +msglen=msglen & 0xff |