From 17ae5ed8b9f453404f41598a7d4cfcb23f028e7b Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Thu, 18 May 2017 20:31:52 -0300 Subject: [PATCH] LVU: defer reset-view checks that depend on late-resolved addresses --- gas/dwarf2dbg.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++--- gas/dwarf2dbg.h | 2 ++ gas/write.c | 2 ++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index 29346c9cea0..5f49e387644 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -227,6 +227,10 @@ static struct dwarf2_line_info current = { lists. */ static symbolS *force_reset_view; +/* This symbol evaluates to an expression that, if nonzero, indicates + some view assert check failed. */ +static symbolS *view_assert_failed; + /* The size of an address on the target. */ static unsigned int sizeof_address; @@ -349,15 +353,36 @@ set_or_check_view (struct line_entry *e, struct line_entry *p, } } - if (S_IS_DEFINED (e->loc.view) && symbol_constant_p (e->loc.view) - && viewx.X_op == O_constant) + if (S_IS_DEFINED (e->loc.view) && symbol_constant_p (e->loc.view)) { expressionS *value = symbol_get_value_expression (e->loc.view); /* We can't compare the view numbers at this point, because in VIEWX we've only determined whether we're to reset it so far. */ - if (!value->X_add_number != !viewx.X_add_number) - as_bad (_("view number mismatch")); + if (viewx.X_op == O_constant) + { + if (!value->X_add_number != !viewx.X_add_number) + as_bad (_("view number mismatch")); + } + /* Record the expression to check it later. It is the result of + a logical not, thus 0 or 1. We just add up all such deferred + expressions, and resolve it at the end. */ + else if (!value->X_add_number) + { + symbolS *deferred = make_expr_symbol (&viewx); + if (view_assert_failed) + { + expressionS chk; + memset (&chk, 0, sizeof (chk)); + chk.X_unsigned = 1; + chk.X_op = O_add; + chk.X_add_number = 0; + chk.X_add_symbol = view_assert_failed; + chk.X_op_symbol = deferred; + deferred = make_expr_symbol (&chk); + } + view_assert_failed = deferred; + } } if (viewx.X_op != O_constant || viewx.X_add_number) @@ -2156,3 +2181,38 @@ dwarf2_finish (void) out_debug_info (info_seg, abbrev_seg, line_seg, ranges_seg); } } + +/* Perform any deferred checks pertaining to debug information. */ + +void +dwarf2dbg_final_check (void) +{ + /* Perform reset-view checks. Don't evaluate view_assert_failed + recursively: it could be very deep. It's a chain of adds, with + each chain element pointing to the next in X_add_symbol, and + holding the check value in X_op_symbol. */ + while (view_assert_failed) + { + gas_assert (!symbol_resolved_p (view_assert_failed)); + + expressionS *expr = symbol_get_value_expression (view_assert_failed); + symbolS *sym = view_assert_failed; + + /* If view_assert_failed looks like a compound check in the + chain, break it up. */ + if (expr->X_op == O_add && expr->X_add_number == 0 && expr->X_unsigned) + { + view_assert_failed = expr->X_add_symbol; + sym = expr->X_op_symbol; + } + else + view_assert_failed = NULL; + + offsetT failed = resolve_symbol_value (sym); + if (!symbol_resolved_p (sym) || failed) + { + as_bad (_("view number mismatch")); + break; + } + } +} diff --git a/gas/dwarf2dbg.h b/gas/dwarf2dbg.h index 7b5fcd1f90f..49826fd054a 100644 --- a/gas/dwarf2dbg.h +++ b/gas/dwarf2dbg.h @@ -100,6 +100,8 @@ extern int dwarf2dbg_estimate_size_before_relax (fragS *); extern int dwarf2dbg_relax_frag (fragS *); extern void dwarf2dbg_convert_frag (fragS *); +extern void dwarf2dbg_final_check (void); + /* An enumeration which describes the sizes of offsets (to DWARF sections) and the mechanism by which the size is indicated. */ enum dwarf2_format { diff --git a/gas/write.c b/gas/write.c index dd9e4af727b..09f6f0b6787 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1902,6 +1902,8 @@ write_object_file (void) /* Relaxation has completed. Freeze all syms. */ finalize_syms = 1; + dwarf2dbg_final_check (); + #ifdef md_post_relax_hook md_post_relax_hook; #endif -- 2.47.2