This is the mail archive of the binutils-cvs@sourceware.org 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]

[binutils-gdb] PR23040, .uleb128 directive doesn't accept some valid expressions


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=38cf168be5816b098cc05abffc482fc905db86a2

commit 38cf168be5816b098cc05abffc482fc905db86a2
Author: Alan Modra <amodra@gmail.com>
Date:   Sat Oct 20 22:22:37 2018 +1030

    PR23040, .uleb128 directive doesn't accept some valid expressions
    
    What a trip down a rabbit hole this bug has been.
    
    First observation: You can't use deferred_expression in s_leb128.
    deferred_expression implements the semantics of .eqv or '==', saving
    an expression with minimal simplification for assignment to a symbol
    so that the expression is evaluated at uses of the symbol.  In
    particular, the value of "dot" is not evaluated at the .eqv symbol
    assignment, but later.  When s_leb128 uses deferred_expression,
    "later" is at the end of assembly, giving entirely the wrong value of
    "dot".  There is no way to fix this for the s_leb128 use without
    breaking .equ (which incidentally was already somewhat broken, see
    commit e4c2619ad1).  So, don't use deferred_expression in s_leb128.
    
    But that leads to the gas test elf/dwarf2-17 failing, because view
    symbols are calculated with a chain of expression symbols.  In the
    dwarf2-17 .L1 case there is a "temp_sym_1 > temp_sym_2" expression,
    with temp_sym_1 and temp_sym_2 on either side of a ".balign".  Since
    ".balign" and many other directives moving "dot" are not calculated on
    the first (and only) pass over source, .L1 cannot be calculated until
    final addresses are assigned to frags.  However, ".uleb128 .L1" *is*
    calculated immediately, resulting in the wrong value.
    
    The reason why .L1 is calculated immediately is that code in
    expr.c:operand after the comment
    	  /* If we have an absolute symbol or a reg, then we know its
    	     value now.  */
    does as it says and fixes the value of .L1, because .L1 is assigned
    to absolute_section in dwarf2dbg.c:set_or_check_view.  So, correct
    that to expr_section.
    
    Unfortunately that fix leads to failure of the elf/dwarf2-5 test with
    ../gas/elf/dwarf2-5.s: Error: attempt to get value of unresolved symbol `.L5'
    ../gas/elf/dwarf2-5.s: Error: attempt to get value of unresolved symbol `.L11'
    ../gas/elf/dwarf2-5.s: Error: attempt to get value of unresolved symbol `.L12'
    So why is that?  Well, it turns out that .L5 is defined in terms of
    .L4, and apparently .L4 is undefined.  But .L4 clearly is defined,
    otherwise we would hit an error when trying to use .L4 a little
    earlier.  There are two copies of .L4!  So, symbols are cloned when
    that should not happen.
    
    Symbol cloning is a technique used by gas to support saving the value
    of symbols that change between uses, but that isn't the case with
    .L4.  Only one value is set and used for .L4, but indeed .L4 was being
    cloned by symbol_clone_if_forward_ref.  This despite no forward refs
    being present.  Also, .L4 is a local symbol and a cursory glance at
    symbol_clone_if_forward_ref "if (symbolP && !LOCAL_SYMBOL_CHECK (symbolP))"
    would seem to prevent cloning of local symbols.  All is not as it
    seems though, a curse of using macros.  LOCAL_SYMBOL_CHECK modifies
    its argument if a "struct local_symbol" is converted to the larger
    "struct symbol", as happens when assigning a view symbol value.
    That fact results in the recursive call to symbol_clone_if_forward_ref
    returning a different address for "add_symbol".  This problem could
    have been fixed by using symbol_same_p rather than comparing symbol
    pointers, but I thought it better to use the real symbol throughout.
    Note that symbol_find_exact also returns the real symbol for a
    converted local symbol.
    
    Finally, this patch does expose lack of support for forward symbol
    definitions in various targets.  For example:
    alpha-linux  +ERROR: ../ld/testsuite/ld-elf/pr11138-2.c: compilation failed
    This is caused by view symbol uses.  On alpha-linux-gcc (GCC) 8.1.1
    20180502 they happen to occur in .byte directives so were silently
    broken in cases like elf/dwarf2-17 anyway.
    /tmp/ccvtsMfU.s: Assembler messages:
    /tmp/ccvtsMfU.s: Fatal error: unhandled relocation type BFD_RELOC_8
    /tmp/ccvtsMfU.s: Fatal error: unhandled relocation type BFD_RELOC_8
    
    md_apply_fix on those targets needs to handle fixups that resolve down
    to a constant.
    
    	PR 23040
    	* symbols.c (get_real_sym): New function.
    	(symbol_same_p): Use get_real_sym.
    	(symbol_clone_if_forward_ref): Save real original add_symbol and
    	op_symbol for comparison against that returned from lookup or
    	recursive calls.
    	* dwarf2dbg.c (set_or_check_view): Use expr_section for
    	expression symbols, not absolute_section.
    	(dwarf2_directive_loc): Check symbol_equated_p and tidy cloning
    	of view symbols.
    	* read.c (s_leb128): Don't use deferred_expression.

Diff:
---
 gas/ChangeLog   | 14 ++++++++++++++
 gas/dwarf2dbg.c | 19 +++++++++++--------
 gas/read.c      |  2 +-
 gas/symbols.c   | 33 ++++++++++++++++++++++-----------
 4 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/gas/ChangeLog b/gas/ChangeLog
index 71dd3b8..240e078 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,17 @@
+2018-10-22  Alan Modra  <amodra@gmail.com>
+
+	PR 23040
+	* symbols.c (get_real_sym): New function.
+	(symbol_same_p): Use get_real_sym.
+	(symbol_clone_if_forward_ref): Save real original add_symbol and
+	op_symbol for comparison against that returned from lookup or
+	recursive calls.
+	* dwarf2dbg.c (set_or_check_view): Use expr_section for
+	expression symbols, not absolute_section.
+	(dwarf2_directive_loc): Check symbol_equated_p and tidy cloning
+	of view symbols.
+	* read.c (s_leb128): Don't use deferred_expression.
+
 2018-10-20  Alan Modra  <amodra@gmail.com>
 
 	PR 23800
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c
index e42c561..57c837b 100644
--- a/gas/dwarf2dbg.c
+++ b/gas/dwarf2dbg.c
@@ -426,7 +426,7 @@ set_or_check_view (struct line_entry *e, struct line_entry *p,
   if (!S_IS_DEFINED (e->loc.view))
     {
       symbol_set_value_expression (e->loc.view, &viewx);
-      S_SET_SEGMENT (e->loc.view, absolute_section);
+      S_SET_SEGMENT (e->loc.view, expr_section);
       symbol_set_frag (e->loc.view, &zero_address_frag);
     }
 
@@ -960,16 +960,19 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED)
 	      if (!name)
 		return;
 	      sym = symbol_find_or_make (name);
-	      if (S_IS_DEFINED (sym))
+	      if (S_IS_DEFINED (sym) || symbol_equated_p (sym))
 		{
-		  if (!S_CAN_BE_REDEFINED (sym))
-		    as_bad (_("symbol `%s' is already defined"), name);
-		  else
+		  if (S_IS_VOLATILE (sym))
 		    sym = symbol_clone (sym, 1);
-		  S_SET_SEGMENT (sym, undefined_section);
-		  S_SET_VALUE (sym, 0);
-		  symbol_set_frag (sym, &zero_address_frag);
+		  else if (!S_CAN_BE_REDEFINED (sym))
+		    {
+		      as_bad (_("symbol `%s' is already defined"), name);
+		      return;
+		    }
 		}
+	      S_SET_SEGMENT (sym, undefined_section);
+	      S_SET_VALUE (sym, 0);
+	      symbol_set_frag (sym, &zero_address_frag);
 	    }
 	  current.view = sym;
 	}
diff --git a/gas/read.c b/gas/read.c
index f011149..4a8b15a 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -5252,7 +5252,7 @@ s_leb128 (int sign)
 
   do
     {
-      deferred_expression (&exp);
+      expression (&exp);
       emit_leb128_expr (&exp, sign);
     }
   while (*input_line_pointer++ == ',');
diff --git a/gas/symbols.c b/gas/symbols.c
index 4088837..2056981 100644
--- a/gas/symbols.c
+++ b/gas/symbols.c
@@ -619,9 +619,22 @@ symbol_clone (symbolS *orgsymP, int replace)
   return newsymP;
 }
 
+/* If S is a local symbol that has been converted, return the
+   converted symbol.  Otherwise return S.  */
+
+static inline symbolS *
+get_real_sym (symbolS *s)
+{
+  if (s != NULL
+      && s->sy_flags.sy_local_symbol
+      && local_symbol_converted_p ((struct local_symbol *) s))
+    s = local_symbol_get_real_symbol ((struct local_symbol *) s);
+  return s;
+}
+
 /* Referenced symbols, if they are forward references, need to be cloned
    (without replacing the original) so that the value of the referenced
-   symbols at the point of use .  */
+   symbols at the point of use is saved by the clone.  */
 
 #undef symbol_clone_if_forward_ref
 symbolS *
@@ -629,8 +642,10 @@ symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward)
 {
   if (symbolP && !LOCAL_SYMBOL_CHECK (symbolP))
     {
-      symbolS *add_symbol = symbolP->sy_value.X_add_symbol;
-      symbolS *op_symbol = symbolP->sy_value.X_op_symbol;
+      symbolS *orig_add_symbol = get_real_sym (symbolP->sy_value.X_add_symbol);
+      symbolS *orig_op_symbol = get_real_sym (symbolP->sy_value.X_op_symbol);
+      symbolS *add_symbol = orig_add_symbol;
+      symbolS *op_symbol = orig_op_symbol;
 
       if (symbolP->sy_flags.sy_forward_ref)
 	is_forward = 1;
@@ -659,8 +674,8 @@ symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward)
 	}
 
       if (symbolP->sy_flags.sy_forward_ref
-	  || add_symbol != symbolP->sy_value.X_add_symbol
-	  || op_symbol != symbolP->sy_value.X_op_symbol)
+	  || add_symbol != orig_add_symbol
+	  || op_symbol != orig_op_symbol)
 	{
 	  if (symbolP != &dot_symbol)
 	    {
@@ -2462,12 +2477,8 @@ symbol_set_value_expression (symbolS *s, const expressionS *exp)
 int
 symbol_same_p (symbolS *s1, symbolS *s2)
 {
-  if (s1->sy_flags.sy_local_symbol
-      && local_symbol_converted_p ((struct local_symbol *) s1))
-    s1 = local_symbol_get_real_symbol ((struct local_symbol *) s1);
-  if (s2->sy_flags.sy_local_symbol
-      && local_symbol_converted_p ((struct local_symbol *) s2))
-    s2 = local_symbol_get_real_symbol ((struct local_symbol *) s2);
+  s1 = get_real_sym (s1);
+  s2 = get_real_sym (s2);
   return s1 == s2;
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]