summaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorHans-Peter Nilsson <hp@axis.com>2012-08-14 02:29:00 +0000
committerHans-Peter Nilsson <hp@axis.com>2012-08-14 02:29:00 +0000
commit47205d1c411fc6795cb153a2f22d3cc67529321a (patch)
tree29f9728b6a26684550f43e3763a369d48afdba87 /gas/config
parent747b4b71a9e428dd4fbdfba49f99449f7d0ae948 (diff)
downloadbinutils-redhat-47205d1c411fc6795cb153a2f22d3cc67529321a.tar.gz
* config/tc-mmix.c (loc_asserts): New variable.
(mmix_greg_internal): Handle expressions not determinable at first pass. (s_loc): Ditto. Record expressions where the section isn't determinable at the first pass, and assume they don't refer to other sections. (mmix_md_end): Verify that recorded LOC expressions weren't to other sections, else emit error messages.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-mmix.c104
1 files changed, 99 insertions, 5 deletions
diff --git a/gas/config/tc-mmix.c b/gas/config/tc-mmix.c
index 9d423020b0..7052b11664 100644
--- a/gas/config/tc-mmix.c
+++ b/gas/config/tc-mmix.c
@@ -109,6 +109,13 @@ static struct
expressionS exp;
} mmix_raw_gregs[MAX_GREGS];
+static struct loc_assert_s
+ {
+ segT old_seg;
+ symbolS *loc_sym;
+ struct loc_assert_s *next;
+ } *loc_asserts = NULL;
+
/* Fixups for all unique GREG registers. We store the fixups here in
md_convert_frag, then we use the array to convert
BFD_RELOC_MMIX_BASE_PLUS_OFFSET fixups in tc_gen_reloc. The index is
@@ -1994,10 +2001,11 @@ static void
mmix_greg_internal (char *label)
{
expressionS *expP = &mmix_raw_gregs[n_of_raw_gregs].exp;
+ segT section;
/* Don't set the section to register contents section before the
expression has been parsed; it may refer to the current position. */
- expression (expP);
+ section = expression (expP);
/* FIXME: Check that no expression refers to the register contents
section. May need to be done in elf64-mmix.c. */
@@ -2011,6 +2019,24 @@ mmix_greg_internal (char *label)
expP->X_op_symbol = NULL;
}
+ if (section == undefined_section)
+ {
+ /* This is an error or a LOC with an expression involving
+ forward references. For the expression to be correctly
+ evaluated, we need to force a proper symbol; gas loses track
+ of the segment for "local symbols". */
+ if (expP->X_op == O_add)
+ {
+ symbol_get_value_expression (expP->X_op_symbol);
+ symbol_get_value_expression (expP->X_add_symbol);
+ }
+ else
+ {
+ gas_assert (expP->X_op == O_symbol);
+ symbol_get_value_expression (expP->X_add_symbol);
+ }
+ }
+
/* We must handle prefixes here, as we save the labels and expressions
to be output later. */
mmix_raw_gregs[n_of_raw_gregs].label
@@ -3457,6 +3483,7 @@ mmix_md_end (void)
fragS *fragP;
symbolS *mainsym;
asection *regsec;
+ struct loc_assert_s *loc_assert;
int i;
/* The first frag of GREG:s going into the register contents section. */
@@ -3514,6 +3541,29 @@ mmix_md_end (void)
S_SET_EXTERNAL (mainsym);
}
+ /* Check that we didn't LOC into the unknown, or rather that when it
+ was unknown, we actually change sections. */
+ for (loc_assert = loc_asserts;
+ loc_assert != NULL;
+ loc_assert = loc_assert->next)
+ {
+ segT actual_seg;
+
+ resolve_symbol_value (loc_assert->loc_sym);
+ actual_seg = S_GET_SEGMENT (loc_assert->loc_sym);
+ if (actual_seg != loc_assert->old_seg)
+ {
+ char *fnam;
+ unsigned int line;
+ int e_valid = expr_symbol_where (loc_assert->loc_sym, &fnam, &line);
+
+ gas_assert (e_valid == 1);
+ as_bad_where (fnam, line,
+ _("LOC to section unknown or indeterminable "
+ "at first pass"));
+ }
+ }
+
if (n_of_raw_gregs != 0)
{
/* Emit GREGs. They are collected in order of appearance, but must
@@ -3892,13 +3942,30 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
if (exp.X_op == O_illegal
|| exp.X_op == O_absent
- || exp.X_op == O_big
- || section == undefined_section)
+ || exp.X_op == O_big)
{
as_bad (_("invalid LOC expression"));
return;
}
+ if (section == undefined_section)
+ {
+ /* This is an error or a LOC with an expression involving
+ forward references. For the expression to be correctly
+ evaluated, we need to force a proper symbol; gas loses track
+ of the segment for "local symbols". */
+ if (exp.X_op == O_add)
+ {
+ symbol_get_value_expression (exp.X_op_symbol);
+ symbol_get_value_expression (exp.X_add_symbol);
+ }
+ else
+ {
+ gas_assert (exp.X_op == O_symbol);
+ symbol_get_value_expression (exp.X_add_symbol);
+ }
+ }
+
if (section == absolute_section)
{
/* Translate a constant into a suitable section. */
@@ -3970,7 +4037,9 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
}
}
- if (section != now_seg)
+ /* If we can't deduce the section, it must be the current one.
+ Below, we arrange to assert this. */
+ if (section != now_seg && section != undefined_section)
{
obj_elf_section_change_hook ();
subseg_set (section, 0);
@@ -3981,16 +4050,41 @@ s_loc (int ignore ATTRIBUTE_UNUSED)
if (exp.X_op != O_absent)
{
+ symbolS *esym = NULL;
+
if (exp.X_op != O_constant && exp.X_op != O_symbol)
{
/* Handle complex expressions. */
- sym = make_expr_symbol (&exp);
+ esym = sym = make_expr_symbol (&exp);
off = 0;
}
else
{
sym = exp.X_add_symbol;
off = exp.X_add_number;
+
+ if (section == undefined_section)
+ {
+ /* We need an expr_symbol when tracking sections. In
+ order to make this an expr_symbol with file and line
+ tracked, we have to make the exp non-trivial; not an
+ O_symbol with .X_add_number == 0. The constant part
+ is unused. */
+ exp.X_add_number = 1;
+ esym = make_expr_symbol (&exp);
+ }
+ }
+
+ /* Track the LOC's where we couldn't deduce the section: assert
+ that we weren't supposed to change section. */
+ if (section == undefined_section)
+ {
+ struct loc_assert_s *next = loc_asserts;
+ loc_asserts
+ = (struct loc_assert_s *) xmalloc (sizeof (*loc_asserts));
+ loc_asserts->next = next;
+ loc_asserts->old_seg = now_seg;
+ loc_asserts->loc_sym = esym;
}
p = frag_var (rs_org, 1, 1, (relax_substateT) 0, sym, off, (char *) 0);