* 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.
This commit is contained in:
Hans-Peter Nilsson 2012-08-14 02:29:01 +00:00
parent 6ce7895693
commit c3330fbecc
2 changed files with 110 additions and 5 deletions

View File

@ -1,3 +1,14 @@
2012-08-14 Hans-Peter Nilsson <hp@bitrange.com>
* 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.
2012-08-13 Ian Bolton <ian.bolton@arm.com>
Laurent Desnogues <laurent.desnogues@arm.com>
Jim MacArthur <jim.macarthur@arm.com>

View File

@ -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);