This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Committed: MMIX: fix FAIL: gas/mmix/fb-2
- From: Hans-Peter Nilsson <hp at bitrange dot com>
- To: binutils at sourceware dot org
- Date: Mon, 13 Aug 2012 22:33:40 -0400 (EDT)
- Subject: Committed: MMIX: fix FAIL: gas/mmix/fb-2
Somewhat non-trivial: the test-case contains a LOC (kind-of like
.org) with an expression complex enough that the section is
indeterminable at the first pass, but not actually changing.
Changing sections using LOC, at least to a section not trivially
determinable seems useless, as mmixal has no actual notion of
sections: the handling of sections is just a mapping of constant
values. Thus, for such expressions I settled for not changing
sections and verifying that there was no intended section
change, matching the failing test-case. Which in turn required
actually checking for section changes and emitting appropriate
errors; covered by a new test-case.
Thanks to Alan's fixes in the ld-mmix test-suite earlier, the
MMIX test-results are clean (though only in absence of a target
compiler), so I'll add mmix-knuth-mmixware to my binutils
autotester; tagging along with arm-unknown-eabi,
mipsisa32r2el-unknown-linux-gnu, cris-axis-linux-gnu and
cris-axis-elf. Yay.
gas:
* 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.
gas/testsuite:
* gas/mmix/err-fb-2.s: New test.
Index: config/tc-mmix.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mmix.c,v
retrieving revision 1.36
diff -p -u -r1.36 tc-mmix.c
--- config/tc-mmix.c 17 May 2012 15:13:16 -0000 1.36
+++ config/tc-mmix.c 14 Aug 2012 02:21:55 -0000
@@ -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);
Index: gas/mmix/err-fb-2.s
===================================================================
RCS file: gas/mmix/err-fb-2.s
diff -N gas/mmix/err-fb-2.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gas/mmix/err-fb-2.s 14 Aug 2012 02:09:11 -0000
@@ -0,0 +1,26 @@
+# { dg-do assemble { target mmix-*-* } }
+# Mostly like fb-2.s, but with LOCs to indeterminable sections
+# *different* to the one LOC'd from. Two cases are tested: an
+# undefined symbol and a section just indeterminable at the first pass
+# (at the point of the LOC).
+
+1H IS 5
+0H LOC #10
+1H BYTE 1B
+0H LOC 2F+#20+0F # { dg-error "indeterminable" "" }
+0H IS 4
+ .section .text.unknown
+2H SWYM
+1H IS 50
+1H GREG 1B+1F
+ SWYM
+1H LDA $30,1B
+1H OCTA 1B,1F
+ LOC undefd # { dg-error "unknown" "" }
+1H SWYM
+
+9H IS 42
+ WYDE 9B,9F
+9H IS 9B+1
+ WYDE 9B,9F
+9H IS 9B+1
brgds, H-P