From: Nick Clifton Date: Tue, 17 May 2005 14:35:21 +0000 (+0000) Subject: * ldlang.c (Scan_for_self_assignment): Check an assignment tree to X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3b83e13a450c5ecc419369bf0e413a895cb52608;p=binutils-gdb.git * ldlang.c (Scan_for_self_assignment): Check an assignment tree to see if the same value is being used on the rhs as on the lhs. (print_assignment): Call scan_for_self_assignment and if it returns true, do no display the result of the computation but instead just the final value of the symbol on the lhs. * ld.texinfo: Document this behaviour and provide an example of when it will happen. --- diff --git a/ld/ChangeLog b/ld/ChangeLog index a7d586592a4..342b9392588 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2005-05-17 Nick Clifton + + * ldlang.c (Scan_for_self_assignment): Check an assignment tree to + see if the same value is being used on the rhs as on the lhs. + (print_assignment): Call scan_for_self_assignment and if it + returns true, do no display the result of the computation but + instead just the final value of the symbol on the lhs. + * ld.texinfo: Document this behaviour and provide an example of + when it will happen. + 2005-05-15 Daniel Jacobowitz * Makefile.am (AM_MAKEINFOFLAGS): Define. diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 7860e250591..e66ec66bef6 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -675,12 +675,40 @@ information about the link, including the following: @itemize @bullet @item -Where object files and symbols are mapped into memory. +Where object files are mapped into memory. @item How common symbols are allocated. @item All archive members included in the link, with a mention of the symbol which caused the archive member to be brought in. +@item +The values assigned to symbols. + +Note - symbols whose values are computed by an expression which +involves a reference to a previous value of the same symbol may not +have correct result displayed in the link map. This is because the +linker discards intermediate results and only retains the final value +of an expression. Under such circumstances the linker will display +the final value enclosed by square brackets. Thus for example a +linker script containing: + +@smallexample + foo = 1 + foo = foo * 4 + foo = foo + 8 +@end smallexample + +will produce the following output in the link map if the @option{-M} +option is used: + +@smallexample + 0x00000001 foo = 0x1 + [0x0000000c] foo = (foo * 0x4) + [0x0000000c] foo = (foo + 0x8) +@end smallexample + +See @ref{Expressions} for more information about expressions in linker +scripts. @end itemize @kindex -n diff --git a/ld/ldlang.c b/ld/ldlang.c index c6c6007dda1..19b986abc79 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 {