This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: Work around link map generation bug for expressions whichreference the same symbol on the rhs and lhs


Hi Guys,

  I am applying the patch below to work around a problem reported by a
  user on thew gnuarm mailing list.  When a link map is being
  generated incorrect results will be displayed for any expression
  which references the same symbol on both sides of an assignment.
  For example:

     foo = foo + 1

  The problem is that the expression display code resolves the right
  hand side of the assignment using the value that has previously been
  computed for the left hand side of the assignment.  This only
  affects the display of the value of the expression in the link map -
  the correct value is actually used in generating the output binary.

  Since rewriting the expression display code is a large task, I
  decided just to work around the problem by detecting cases where it
  could happen and modifying the displayed output to show only the
  final value of the expression, and not the value that had just been
  computed.  I have also updated the linker's documentation to
  describe this situation.

Cheers
    Nick

ld/ChangeLog
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.
        
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.182
diff -c -3 -p -r1.182 ldlang.c
*** ld/ldlang.c	12 May 2005 07:32:02 -0000	1.182
--- ld/ldlang.c	16 May 2005 16:55:05 -0000
*************** print_output_section_statement
*** 3133,3144 ****
  			output_section_statement);
  }
  
  static void
  print_assignment (lang_assignment_statement_type *assignment,
  		  lang_output_section_statement_type *output_section)
  {
!   int i;
!   int is_dot;
    etree_type *tree;
    etree_value_type result;
  
--- 3133,3195 ----
  			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;
    etree_value_type result;
  
*************** print_assignment (lang_assignment_statem
*** 3147,3160 ****
  
    if (assignment->exp->type.node_class == etree_assert)
      {
!       is_dot = 0;
        tree = assignment->exp->assert_s.child;
      }
    else
      {
        const char *dst = assignment->exp->assign.dst;
!       is_dot = dst[0] == '.' && dst[1] == 0;
        tree = assignment->exp->assign.src;
      }
  
    result = exp_fold_tree (tree, output_section, lang_final_phase_enum,
--- 3198,3214 ----
  
    if (assignment->exp->type.node_class == etree_assert)
      {
!       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);
        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,
*************** print_assignment (lang_assignment_statem
*** 3163,3173 ****
      {
        bfd_vma value;
  
!       value = result.value + result.section->bfd_section->vma;
  
!       minfo ("0x%V", value);
!       if (is_dot)
! 	print_dot = value;
      }
    else
      {
--- 3217,3245 ----
      {
        bfd_vma value;
  
!       if (computation_is_valid)
! 	{
! 	  value = result.value + result.section->bfd_section->vma;
! 
! 	  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 ("          ");
! 	}
      }
    else
      {
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.141
diff -c -3 -p -r1.141 ld.texinfo
*** ld/ld.texinfo	15 Apr 2005 16:37:47 -0000	1.141
--- ld/ld.texinfo	16 May 2005 16:55:02 -0000
*************** information about the link, including th
*** 675,686 ****
  
  @itemize @bullet
  @item
! Where object files and symbols 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.
  @end itemize
  
  @kindex -n
--- 674,713 ----
  
  @itemize @bullet
  @item
! 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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]