From 4194268f43623a5f893b9a92b0456d3cb43ab915 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 17 Dec 2012 00:16:49 +0000 Subject: [PATCH] PR ld/14962 * ldexp.h (struct ldexp_control): Add "assign_name". * ldexp.c (fold_name ): Compare and clear assign_name on match. (exp_fold_tree_1): Remove existing code testing for self assignment. Instead set and test expld.assign_name. * ldlang.c (scan_for_self_assignment): Delete. (print_assignment): Instead set and test expld.assign_name. --- ld/ChangeLog | 10 ++++++++++ ld/ldexp.c | 37 +++++++++++++++++-------------------- ld/ldexp.h | 5 +++++ ld/ldlang.c | 59 +++++------------------------------------------------------ 4 files changed, 37 insertions(+), 74 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 705c712..1dd68f0 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2012-12-17 Alan Modra + + PR ld/14962 + * ldexp.h (struct ldexp_control): Add "assign_name". + * ldexp.c (fold_name ): Compare and clear assign_name on match. + (exp_fold_tree_1): Remove existing code testing for self assignment. + Instead set and test expld.assign_name. + * ldlang.c (scan_for_self_assignment): Delete. + (print_assignment): Instead set and test expld.assign_name. + 2012-12-11 Roland McGrath * emulparams/elf_nacl.sh (nacl_rodata_addr): New shell function. diff --git a/ld/ldexp.c b/ld/ldexp.c index cc43b72..5f4e974 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -572,6 +572,9 @@ fold_name (etree_type *tree) break; case NAME: + if (expld.assign_name != NULL + && strcmp (expld.assign_name, tree->name.name) == 0) + expld.assign_name = NULL; if (expld.phase == lang_first_phase_enum) ; else if (tree->name.name[0] == '.' && tree->name.name[1] == 0) @@ -852,8 +855,6 @@ exp_fold_tree_1 (etree_type *tree) } else { - etree_type *name; - struct bfd_link_hash_entry *h = NULL; if (tree->type.node_class == etree_provide) @@ -871,25 +872,20 @@ exp_fold_tree_1 (etree_type *tree) } } - name = tree->assign.src; - if (name->type.node_class == etree_trinary) - { - exp_fold_tree_1 (name->trinary.cond); - if (expld.result.valid_p) - name = (expld.result.value - ? name->trinary.lhs : name->trinary.rhs); - } - - if (name->type.node_class == etree_name - && name->type.node_code == NAME - && strcmp (tree->assign.dst, name->name.name) == 0) - /* Leave it alone. Do not replace a symbol with its own - output address, in case there is another section sizing - pass. Folding does not preserve input sections. */ - break; - + expld.assign_name = tree->assign.dst; exp_fold_tree_1 (tree->assign.src); - if (expld.result.valid_p + /* expld.assign_name remaining equal to tree->assign.dst + below indicates the evaluation of tree->assign.src did + not use the value of tree->assign.dst. We don't allow + self assignment until the final phase for two reasons: + 1) Expressions are evaluated multiple times. With + relaxation, the number of times may vary. + 2) Section relative symbol values cannot be correctly + converted to absolute values, as is required by many + expressions, until final section sizing is complete. */ + if ((expld.result.valid_p + && (expld.phase == lang_final_phase_enum + || expld.assign_name != NULL)) || (expld.phase <= lang_mark_phase_enum && tree->type.node_class == etree_assign && tree->assign.defsym)) @@ -937,6 +933,7 @@ exp_fold_tree_1 (etree_type *tree) && h->type == bfd_link_hash_new) h->type = bfd_link_hash_undefined; } + expld.assign_name = NULL; } break; diff --git a/ld/ldexp.h b/ld/ldexp.h index 187016c..2c726e7 100644 --- a/ld/ldexp.h +++ b/ld/ldexp.h @@ -139,6 +139,11 @@ struct ldexp_control { /* Principally used for diagnostics. */ bfd_boolean assigning_to_dot; + /* If evaluating an assignment, the destination. Cleared if an + etree_name NAME matches this, to signal a self-assignment. + Note that an etree_name DEFINED does not clear this field, nor + does the false branch of a trinary expression. */ + const char *assign_name; /* Working results. */ etree_value_type result; diff --git a/ld/ldlang.c b/ld/ldlang.c index 750711c..01c12df 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -3951,63 +3951,12 @@ print_output_section_statement output_section_statement); } -/* Scan for the use of the destination in the right hand side - of an expression. In such cases we will not compute the - correct expression, since the value of DST that is used on - the right hand side will be its final value, not its value - just before this expression is evaluated. */ - -static bfd_boolean -scan_for_self_assignment (const char * dst, etree_type * rhs) -{ - if (rhs == NULL || dst == NULL) - return FALSE; - - switch (rhs->type.node_class) - { - case etree_binary: - return (scan_for_self_assignment (dst, rhs->binary.lhs) - || scan_for_self_assignment (dst, rhs->binary.rhs)); - - case etree_trinary: - return (scan_for_self_assignment (dst, rhs->trinary.lhs) - || scan_for_self_assignment (dst, rhs->trinary.rhs)); - - case etree_assign: - case etree_provided: - case etree_provide: - if (strcmp (dst, rhs->assign.dst) == 0) - return TRUE; - return scan_for_self_assignment (dst, rhs->assign.src); - - case etree_unary: - return scan_for_self_assignment (dst, rhs->unary.child); - - case etree_value: - if (rhs->value.str) - return strcmp (dst, rhs->value.str) == 0; - return FALSE; - - case etree_name: - if (rhs->name.name) - return strcmp (dst, rhs->name.name) == 0; - return FALSE; - - default: - break; - } - - return FALSE; -} - - static void print_assignment (lang_assignment_statement_type *assignment, lang_output_section_statement_type *output_section) { unsigned int i; bfd_boolean is_dot; - bfd_boolean computation_is_valid = TRUE; etree_type *tree; asection *osec; @@ -4018,15 +3967,14 @@ print_assignment (lang_assignment_statement_type *assignment, { is_dot = FALSE; tree = assignment->exp->assert_s.child; - computation_is_valid = TRUE; } else { const char *dst = assignment->exp->assign.dst; is_dot = (dst[0] == '.' && dst[1] == 0); + expld.assign_name = dst; tree = assignment->exp->assign.src; - computation_is_valid = is_dot || !scan_for_self_assignment (dst, tree); } osec = output_section->bfd_section; @@ -4037,7 +3985,9 @@ print_assignment (lang_assignment_statement_type *assignment, { bfd_vma value; - if (computation_is_valid) + if (assignment->exp->type.node_class == etree_assert + || is_dot + || expld.assign_name != NULL) { value = expld.result.value; @@ -4073,6 +4023,7 @@ print_assignment (lang_assignment_statement_type *assignment, minfo (" "); #endif } + expld.assign_name = NULL; minfo (" "); exp_print_tree (assignment->exp); -- 2.7.4