* ldlang.c (Scan_for_self_assignment): Check an assignment tree to
authorNick Clifton <nickc@redhat.com>
Tue, 17 May 2005 14:35:21 +0000 (14:35 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 17 May 2005 14:35:21 +0000 (14:35 +0000)
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.

ld/ChangeLog
ld/ld.texinfo
ld/ldlang.c

index a7d5865..342b939 100644 (file)
@@ -1,3 +1,13 @@
+2005-05-17  Nick Clifton  <nickc@redhat.com>
+
+       * 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  <dan@codesourcery.com>
 
        * Makefile.am (AM_MAKEINFOFLAGS): Define.
index 7860e25..e66ec66 100644 (file)
@@ -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
index c6c6007..19b986a 100644 (file)
@@ -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
     {