diff options
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 88 |
1 files changed, 80 insertions, 8 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index c6c6007..19b986a 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -3133,12 +3133,63 @@ 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) { - int i; - int is_dot; + unsigned int i; + bfd_boolean is_dot; + bfd_boolean computation_is_valid = TRUE; etree_type *tree; etree_value_type result; @@ -3147,14 +3198,17 @@ print_assignment (lang_assignment_statement_type *assignment, if (assignment->exp->type.node_class == etree_assert) { - is_dot = 0; + 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; + + is_dot = (dst[0] == '.' && dst[1] == 0); tree = assignment->exp->assign.src; + computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE); } result = exp_fold_tree (tree, output_section, lang_final_phase_enum, @@ -3163,11 +3217,29 @@ print_assignment (lang_assignment_statement_type *assignment, { bfd_vma value; - value = result.value + result.section->bfd_section->vma; + if (computation_is_valid) + { + value = result.value + result.section->bfd_section->vma; - minfo ("0x%V", value); - if (is_dot) - print_dot = value; + minfo ("0x%V", value); + if (is_dot) + print_dot = value; + } + else + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst, + FALSE, FALSE, TRUE); + if (h) + { + value = h->u.def.value + result.section->bfd_section->vma; + + minfo ("[0x%V]", value); + } + else + minfo ("[unresolved]"); + } } else { |