aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog21
-rw-r--r--gas/config/tc-mn10300.c144
-rw-r--r--gas/config/tc-mn10300.h14
-rw-r--r--gas/doc/internals.texi12
-rw-r--r--gas/expr.c3
-rw-r--r--gas/testsuite/ChangeLog6
-rw-r--r--gas/testsuite/gas/mn10300/basic.exp1
-rw-r--r--gas/testsuite/gas/mn10300/pr997.l20
-rw-r--r--gas/testsuite/gas/mn10300/pr997.s5
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
diff --git a/gas/expr.c b/gas/expr.c
index 4f4d380..285b438 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -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