* target-descriptions.c (tdesc_named_type): Move code_ptr and data_ptr
[deliverable/binutils-gdb.git] / gas / symbols.c
index 49d546d8332fb00712279150a9352dc4b8bfb193..8943af3c11701de7c5e8ddc6f91a4a10ccd353da 100644 (file)
@@ -1,6 +1,6 @@
 /* symbols.c -symbol table-
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -144,8 +144,7 @@ symbol_create (const char *name, /* It is copied, the caller can destroy/modify.
 
   symbolP->bsym = bfd_make_empty_symbol (stdoutput);
   if (symbolP->bsym == NULL)
-    as_perror ("%s", "bfd_make_empty_symbol");
-  symbolP->bsym->udata.p = (PTR) symbolP;
+    as_fatal ("bfd_make_empty_symbol: %s", bfd_errmsg (bfd_get_error ()));
   S_SET_NAME (symbolP, preserved_copy_of_name);
 
   S_SET_SEGMENT (symbolP, segment);
@@ -309,6 +308,7 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
 
   if ((symbolP = symbol_find (sym_name)) != 0)
     {
+      S_CLEAR_WEAKREFR (symbolP);
 #ifdef RESOLVE_SYMBOL_REDEFINITION
       if (RESOLVE_SYMBOL_REDEFINITION (symbolP))
        return symbolP;
@@ -331,8 +331,16 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
          local_symbol_set_frag (locsym, frag_now);
          locsym->lsy_value = frag_now_fix ();
        }
-      else if (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))
+      else if (!(S_IS_DEFINED (symbolP) || symbol_equated_p (symbolP))
+              || S_IS_COMMON (symbolP)
+              || S_IS_VOLATILE (symbolP))
        {
+         if (S_IS_VOLATILE (symbolP))
+           {
+             symbolP = symbol_clone (symbolP, 1);
+             S_SET_VALUE (symbolP, 0);
+             S_CLEAR_VOLATILE (symbolP);
+           }
          if (S_GET_VALUE (symbolP) == 0)
            {
              symbolP->sy_frag = frag_now;
@@ -364,6 +372,7 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
                    && S_IS_EXTERNAL (symbolP))
                   || S_GET_SEGMENT (symbolP) == bss_section)
                  && (now_seg == data_section
+                     || now_seg == bss_section
                      || now_seg == S_GET_SEGMENT (symbolP)))
                {
                  /* Select which of the 2 cases this is.  */
@@ -419,7 +428,10 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
          if (!(frag_now == symbolP->sy_frag
                && S_GET_VALUE (symbolP) == frag_now_fix ()
                && S_GET_SEGMENT (symbolP) == now_seg))
-           as_bad (_("symbol `%s' is already defined"), sym_name);
+           {
+             as_bad (_("symbol `%s' is already defined"), sym_name);
+             symbolP = symbol_clone (symbolP, 0);
+           }
        }
 
     }
@@ -537,6 +549,115 @@ symbol_make (const char *name)
   return (symbolP);
 }
 
+symbolS *
+symbol_clone (symbolS *orgsymP, int replace)
+{
+  symbolS *newsymP;
+  asymbol *bsymorg, *bsymnew;
+
+  /* Running local_symbol_convert on a clone that's not the one currently
+     in local_hash would incorrectly replace the hash entry.  Thus the
+     symbol must be converted here.  Note that the rest of the function
+     depends on not encountering an unconverted symbol.  */
+  if (LOCAL_SYMBOL_CHECK (orgsymP))
+    orgsymP = local_symbol_convert ((struct local_symbol *) orgsymP);
+  bsymorg = orgsymP->bsym;
+
+  know (S_IS_DEFINED (orgsymP));
+
+  newsymP = obstack_alloc (&notes, sizeof (*newsymP));
+  *newsymP = *orgsymP;
+  bsymnew = bfd_make_empty_symbol (bfd_asymbol_bfd (bsymorg));
+  if (bsymnew == NULL)
+    as_fatal ("bfd_make_empty_symbol: %s", bfd_errmsg (bfd_get_error ()));
+  newsymP->bsym = bsymnew;
+  bsymnew->name = bsymorg->name;
+  bsymnew->flags =  bsymorg->flags;
+  bsymnew->section =  bsymorg->section;
+  bfd_copy_private_symbol_data (bfd_asymbol_bfd (bsymorg), bsymorg,
+                               bfd_asymbol_bfd (bsymnew), bsymnew);
+
+#ifdef obj_symbol_clone_hook
+  obj_symbol_clone_hook (newsymP, orgsymP);
+#endif
+
+#ifdef tc_symbol_clone_hook
+  tc_symbol_clone_hook (newsymP, orgsymP);
+#endif
+
+  if (replace)
+    {
+      if (symbol_rootP == orgsymP)
+       symbol_rootP = newsymP;
+      else if (orgsymP->sy_previous)
+       {
+         orgsymP->sy_previous->sy_next = newsymP;
+         orgsymP->sy_previous = NULL;
+       }
+      if (symbol_lastP == orgsymP)
+       symbol_lastP = newsymP;
+      else if (orgsymP->sy_next)
+       orgsymP->sy_next->sy_previous = newsymP;
+      orgsymP->sy_previous = orgsymP->sy_next = orgsymP;
+      debug_verify_symchain (symbol_rootP, symbol_lastP);
+
+      symbol_table_insert (newsymP);
+    }
+  else
+    newsymP->sy_previous = newsymP->sy_next = newsymP;
+
+  return newsymP;
+}
+
+/* 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 .  */
+
+#undef symbol_clone_if_forward_ref
+symbolS *
+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;
+
+      if (symbolP->sy_forward_ref)
+       is_forward = 1;
+
+      if (is_forward)
+       {
+         /* assign_symbol() clones volatile symbols; pre-existing expressions
+            hold references to the original instance, but want the current
+            value.  Just repeat the lookup.  */
+         if (add_symbol && S_IS_VOLATILE (add_symbol))
+           add_symbol = symbol_find_exact (S_GET_NAME (add_symbol));
+         if (op_symbol && S_IS_VOLATILE (op_symbol))
+           op_symbol = symbol_find_exact (S_GET_NAME (op_symbol));
+       }
+
+      /* Re-using sy_resolving here, as this routine cannot get called from
+        symbol resolution code.  */
+      if (symbolP->bsym->section == expr_section && !symbolP->sy_resolving)
+       {
+         symbolP->sy_resolving = 1;
+         add_symbol = symbol_clone_if_forward_ref (add_symbol, is_forward);
+         op_symbol = symbol_clone_if_forward_ref (op_symbol, is_forward);
+         symbolP->sy_resolving = 0;
+       }
+
+      if (symbolP->sy_forward_ref
+         || add_symbol != symbolP->sy_value.X_add_symbol
+         || op_symbol != symbolP->sy_value.X_op_symbol)
+       symbolP = symbol_clone (symbolP, 0);
+
+      symbolP->sy_value.X_add_symbol = add_symbol;
+      symbolP->sy_value.X_op_symbol = op_symbol;
+    }
+
+  return symbolP;
+}
+
 symbolS *
 symbol_temp_new (segT seg, valueT ofs, fragS *frag)
 {
@@ -562,18 +683,41 @@ symbol_temp_make (void)
 
 symbolS *
 symbol_find_exact (const char *name)
+{
+  return symbol_find_exact_noref (name, 0);
+}
+
+symbolS *
+symbol_find_exact_noref (const char *name, int noref)
 {
   struct local_symbol *locsym;
+  symbolS* sym;
 
   locsym = (struct local_symbol *) hash_find (local_hash, name);
   if (locsym != NULL)
     return (symbolS *) locsym;
 
-  return ((symbolS *) hash_find (sy_hash, name));
+  sym = ((symbolS *) hash_find (sy_hash, name));
+
+  /* Any references to the symbol, except for the reference in
+     .weakref, must clear this flag, such that the symbol does not
+     turn into a weak symbol.  Note that we don't have to handle the
+     local_symbol case, since a weakrefd is always promoted out of the
+     local_symbol table when it is turned into a weak symbol.  */
+  if (sym && ! noref)
+    S_CLEAR_WEAKREFD (sym);
+
+  return sym;
 }
 
 symbolS *
 symbol_find (const char *name)
+{
+  return symbol_find_noref (name, 0);
+}
+
+symbolS *
+symbol_find_noref (const char *name, int noref)
 {
 #ifdef tc_canonicalize_symbol_name
   {
@@ -602,7 +746,7 @@ symbol_find (const char *name)
       *copy = '\0';
     }
 
-  return symbol_find_exact (name);
+  return symbol_find_exact_noref (name, noref);
 }
 
 /* Once upon a time, symbols were kept in a singly linked list.  At
@@ -737,6 +881,69 @@ verify_symbol_chain (symbolS *rootP, symbolS *lastP)
   assert (lastP == symbolP);
 }
 
+#ifdef OBJ_COMPLEX_RELC
+
+static int
+use_complex_relocs_for (symbolS * symp)
+{
+  switch (symp->sy_value.X_op)
+    {
+    case O_constant:
+      return 0;
+
+    case O_symbol:
+    case O_symbol_rva:
+    case O_uminus:
+    case O_bit_not:
+    case O_logical_not:
+      if (  (S_IS_COMMON (symp->sy_value.X_add_symbol)
+          || S_IS_LOCAL (symp->sy_value.X_add_symbol))
+         &&
+             (S_IS_DEFINED (symp->sy_value.X_add_symbol)
+          && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section))
+       return 0;
+      break;
+
+    case O_multiply:
+    case O_divide:
+    case O_modulus:
+    case O_left_shift:
+    case O_right_shift:
+    case O_bit_inclusive_or:
+    case O_bit_or_not:
+    case O_bit_exclusive_or:
+    case O_bit_and:
+    case O_add:
+    case O_subtract:
+    case O_eq:
+    case O_ne:
+    case O_lt:
+    case O_le:
+    case O_ge:
+    case O_gt:
+    case O_logical_and:
+    case O_logical_or:
+
+      if (  (S_IS_COMMON (symp->sy_value.X_add_symbol)
+          || S_IS_LOCAL (symp->sy_value.X_add_symbol))
+         && 
+           (S_IS_COMMON (symp->sy_value.X_op_symbol)
+          || S_IS_LOCAL (symp->sy_value.X_op_symbol))
+
+         && S_IS_DEFINED (symp->sy_value.X_add_symbol)
+         && S_IS_DEFINED (symp->sy_value.X_op_symbol)
+         && S_GET_SEGMENT (symp->sy_value.X_add_symbol) != expr_section
+         && S_GET_SEGMENT (symp->sy_value.X_op_symbol) != expr_section)
+       return 0;
+      break;
+      
+    default:
+      break;
+    }
+  return 1;
+}
+#endif
+
 static void
 report_op_error (symbolS *symp, symbolS *left, symbolS *right)
 {
@@ -781,13 +988,11 @@ report_op_error (symbolS *symp, symbolS *left, symbolS *right)
          && seg_right != undefined_section)
        {
          if (right)
-           as_bad_where (file, line,
-                         _("invalid sections for operation on `%s' and `%s' setting `%s'"),
-                         S_GET_NAME (left), S_GET_NAME (right), S_GET_NAME (symp));
+           as_bad (_("invalid sections for operation on `%s' and `%s' setting `%s'"),
+                   S_GET_NAME (left), S_GET_NAME (right), S_GET_NAME (symp));
          else
-           as_bad_where (file, line,
-                         _("invalid section for operation on `%s' setting `%s'"),
-                         S_GET_NAME (left), S_GET_NAME (symp));
+           as_bad (_("invalid section for operation on `%s' setting `%s'"),
+                   S_GET_NAME (left), S_GET_NAME (symp));
        }
     }
 }
@@ -841,6 +1046,53 @@ resolve_symbol_value (symbolS *symp)
       final_val = 0;
       resolved = 1;
     }
+#ifdef OBJ_COMPLEX_RELC
+  else if (final_seg == expr_section
+          && use_complex_relocs_for (symp))
+    {
+      symbolS * relc_symbol = NULL;
+      char * relc_symbol_name = NULL;
+
+      relc_symbol_name = symbol_relc_make_expr (& symp->sy_value);
+
+      /* For debugging, print out conversion input & output.  */
+#ifdef DEBUG_SYMS
+      print_expr (& symp->sy_value);
+      if (relc_symbol_name)
+       fprintf (stderr, "-> relc symbol: %s\n", relc_symbol_name);
+#endif
+
+      if (relc_symbol_name != NULL)
+       relc_symbol = symbol_new (relc_symbol_name, undefined_section,
+                                 0, & zero_address_frag);
+
+      if (relc_symbol == NULL)
+       {
+         as_bad (_("cannot convert expression symbol %s to complex relocation"),
+                 S_GET_NAME (symp));
+         resolved = 0;
+       }
+      else
+       {
+         symbol_table_insert (relc_symbol);
+
+         /* S_CLEAR_EXTERNAL (relc_symbol); */
+         if (symp->bsym->flags & BSF_SRELC)
+           relc_symbol->bsym->flags |= BSF_SRELC;
+         else
+           relc_symbol->bsym->flags |= BSF_RELC;         
+         /* symp->bsym->flags |= BSF_RELC; */
+         copy_symbol_attributes (symp, relc_symbol);
+         symp->sy_value.X_op = O_symbol;
+         symp->sy_value.X_add_symbol = relc_symbol;
+         symp->sy_value.X_add_number = 0;
+         resolved = 1;
+       }
+
+      final_seg = undefined_section;
+      goto exit_dont_set_value;
+    }
+#endif
   else
     {
       symbolS *add_symbol, *op_symbol;
@@ -882,6 +1134,19 @@ resolve_symbol_value (symbolS *symp)
            symp->sy_value.X_op_symbol = NULL;
 
        do_symbol:
+         if (S_IS_WEAKREFR (symp))
+           {
+             assert (final_val == 0);
+             if (S_IS_WEAKREFR (add_symbol))
+               {
+                 assert (add_symbol->sy_value.X_op == O_symbol
+                         && add_symbol->sy_value.X_add_number == 0);
+                 add_symbol = add_symbol->sy_value.X_add_symbol;
+                 assert (! S_IS_WEAKREFR (add_symbol));
+                 symp->sy_value.X_add_symbol = add_symbol;
+               }
+           }
+
          if (symp->sy_mri_common)
            {
              /* This is a symbol inside an MRI common section.  The
@@ -925,8 +1190,9 @@ resolve_symbol_value (symbolS *symp)
              symp->sy_resolving = 0;
              goto exit_dont_set_value;
            }
-         else if (finalize_syms && final_seg == expr_section
-                  && seg_left != expr_section)
+         else if (finalize_syms
+                  && ((final_seg == expr_section && seg_left != expr_section)
+                      || symbol_shadow_p (symp)))
            {
              /* If the symbol is an expression symbol, do similarly
                 as for undefined and common syms above.  Handles
@@ -951,6 +1217,8 @@ resolve_symbol_value (symbolS *symp)
            }
 
          resolved = symbol_resolved_p (add_symbol);
+         if (S_IS_WEAKREFR (symp))
+           goto exit_dont_set_value;
          break;
 
        case O_uminus:
@@ -1189,6 +1457,74 @@ resolve_local_symbol_values (void)
   hash_traverse (local_hash, resolve_local_symbol);
 }
 
+/* Obtain the current value of a symbol without changing any
+   sub-expressions used.  */
+
+int
+snapshot_symbol (symbolS **symbolPP, valueT *valueP, segT *segP, fragS **fragPP)
+{
+  symbolS *symbolP = *symbolPP;
+
+  if (LOCAL_SYMBOL_CHECK (symbolP))
+    {
+      struct local_symbol *locsym = (struct local_symbol *) symbolP;
+
+      *valueP = locsym->lsy_value;
+      *segP = locsym->lsy_section;
+      *fragPP = local_symbol_get_frag (locsym);
+    }
+  else
+    {
+      expressionS expr = symbolP->sy_value;
+
+      if (!symbolP->sy_resolved && expr.X_op != O_illegal)
+       {
+         int resolved;
+
+         if (symbolP->sy_resolving)
+           return 0;
+         symbolP->sy_resolving = 1;
+         resolved = resolve_expression (&expr);
+         symbolP->sy_resolving = 0;
+         if (!resolved)
+           return 0;
+
+         switch (expr.X_op)
+           {
+           case O_constant:
+           case O_register:
+             if (!symbol_equated_p (symbolP))
+               break;
+             /* Fall thru.  */
+           case O_symbol:
+           case O_symbol_rva:
+             symbolP = expr.X_add_symbol;
+             break;
+           default:
+             return 0;
+           }
+       }
+
+      /* Never change a defined symbol.  */
+      if (symbolP->bsym->section == undefined_section
+         || symbolP->bsym->section == expr_section)
+       *symbolPP = symbolP;
+      *valueP = expr.X_add_number;
+      *segP = symbolP->bsym->section;
+      *fragPP = symbolP->sy_frag;
+
+      if (*segP == expr_section)
+       switch (expr.X_op)
+         {
+         case O_constant: *segP = absolute_section; break;
+         case O_register: *segP = reg_section; break;
+         default: break;
+         }
+    }
+
+  return 1;
+}
+
 /* Dollar labels look like a number followed by a dollar sign.  Eg, "42$".
    They are *really* local.  That is, they go out of scope whenever we see a
    label that isn't local.  Also, like fb labels, there can be multiple
@@ -1564,22 +1900,16 @@ S_GET_VALUE (symbolS *s)
       if (!finalize_syms)
        return val;
     }
+  if (S_IS_WEAKREFR (s))
+    return S_GET_VALUE (s->sy_value.X_add_symbol);
+
   if (s->sy_value.X_op != O_constant)
     {
-      static symbolS *recur;
-
-      /* FIXME: In non BFD assemblers, S_IS_DEFINED and S_IS_COMMON
-        may call S_GET_VALUE.  We use a static symbol to avoid the
-        immediate recursion.  */
-      if (recur == s)
-       return (valueT) s->sy_value.X_add_number;
-      recur = s;
       if (! s->sy_resolved
          || s->sy_value.X_op != O_symbol
          || (S_IS_DEFINED (s) && ! S_IS_COMMON (s)))
        as_bad (_("attempt to get value of unresolved symbol `%s'"),
                S_GET_NAME (s));
-      recur = NULL;
     }
   return (valueT) s->sy_value.X_add_number;
 }
@@ -1598,6 +1928,7 @@ S_SET_VALUE (symbolS *s, valueT val)
   s->sy_value.X_op = O_constant;
   s->sy_value.X_add_number = (offsetT) val;
   s->sy_value.X_unsigned = 0;
+  S_CLEAR_WEAKREFR (s);
 }
 
 void
@@ -1653,9 +1984,31 @@ S_IS_WEAK (symbolS *s)
 {
   if (LOCAL_SYMBOL_CHECK (s))
     return 0;
+  /* Conceptually, a weakrefr is weak if the referenced symbol is.  We
+     could probably handle a WEAKREFR as always weak though.  E.g., if
+     the referenced symbol has lost its weak status, there's no reason
+     to keep handling the weakrefr as if it was weak.  */
+  if (S_IS_WEAKREFR (s))
+    return S_IS_WEAK (s->sy_value.X_add_symbol);
   return (s->bsym->flags & BSF_WEAK) != 0;
 }
 
+int
+S_IS_WEAKREFR (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return 0;
+  return s->sy_weakrefr != 0;
+}
+
+int
+S_IS_WEAKREFD (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return 0;
+  return s->sy_weakrefd != 0;
+}
+
 int
 S_IS_COMMON (symbolS *s)
 {
@@ -1747,6 +2100,22 @@ S_IS_STABD (symbolS *s)
   return S_GET_NAME (s) == 0;
 }
 
+int
+S_IS_VOLATILE (const symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return 0;
+  return s->sy_volatile;
+}
+
+int
+S_IS_FORWARD_REF (const symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return 0;
+  return s->sy_forward_ref;
+}
+
 const char *
 S_GET_NAME (symbolS *s)
 {
@@ -1839,10 +2208,70 @@ S_SET_WEAK (symbolS *s)
 {
   if (LOCAL_SYMBOL_CHECK (s))
     s = local_symbol_convert ((struct local_symbol *) s);
+#ifdef obj_set_weak_hook
+  obj_set_weak_hook (s);
+#endif
   s->bsym->flags |= BSF_WEAK;
   s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL);
 }
 
+void
+S_SET_WEAKREFR (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    s = local_symbol_convert ((struct local_symbol *) s);
+  s->sy_weakrefr = 1;
+  /* If the alias was already used, make sure we mark the target as
+     used as well, otherwise it might be dropped from the symbol
+     table.  This may have unintended side effects if the alias is
+     later redirected to another symbol, such as keeping the unused
+     previous target in the symbol table.  Since it will be weak, it's
+     not a big deal.  */
+  if (s->sy_used)
+    symbol_mark_used (s->sy_value.X_add_symbol);
+}
+
+void
+S_CLEAR_WEAKREFR (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return;
+  s->sy_weakrefr = 0;
+}
+
+void
+S_SET_WEAKREFD (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    s = local_symbol_convert ((struct local_symbol *) s);
+  s->sy_weakrefd = 1;
+  S_SET_WEAK (s);
+}
+
+void
+S_CLEAR_WEAKREFD (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return;
+  if (s->sy_weakrefd)
+    {
+      s->sy_weakrefd = 0;
+      /* If a weakref target symbol is weak, then it was never
+        referenced directly before, not even in a .global directive,
+        so decay it to local.  If it remains undefined, it will be
+        later turned into a global, like any other undefined
+        symbol.  */
+      if (s->bsym->flags & BSF_WEAK)
+       {
+#ifdef obj_clear_weak_hook
+         obj_clear_weak_hook (s);
+#endif
+         s->bsym->flags &= ~BSF_WEAK;
+         s->bsym->flags |= BSF_LOCAL;
+       }
+    }
+}
+
 void
 S_SET_THREAD_LOCAL (symbolS *s)
 {
@@ -1872,6 +2301,29 @@ S_SET_NAME (symbolS *s, const char *name)
   s->bsym->name = name;
 }
 
+void
+S_SET_VOLATILE (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    s = local_symbol_convert ((struct local_symbol *) s);
+  s->sy_volatile = 1;
+}
+
+void
+S_CLEAR_VOLATILE (symbolS *s)
+{
+  if (!LOCAL_SYMBOL_CHECK (s))
+    s->sy_volatile = 0;
+}
+
+void
+S_SET_FORWARD_REF (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    s = local_symbol_convert ((struct local_symbol *) s);
+  s->sy_forward_ref = 1;
+}
+
 /* Return the previous symbol in a chain.  */
 
 symbolS *
@@ -1910,6 +2362,7 @@ symbol_set_value_expression (symbolS *s, const expressionS *exp)
   if (LOCAL_SYMBOL_CHECK (s))
     s = local_symbol_convert ((struct local_symbol *) s);
   s->sy_value = *exp;
+  S_CLEAR_WEAKREFR (s);
 }
 
 /* Return a pointer to the X_add_number component of a symbol.  */
@@ -1944,6 +2397,7 @@ symbol_set_frag (symbolS *s, fragS *f)
       return;
     }
   s->sy_frag = f;
+  S_CLEAR_WEAKREFR (s);
 }
 
 /* Return the frag of a symbol.  */
@@ -1964,6 +2418,8 @@ symbol_mark_used (symbolS *s)
   if (LOCAL_SYMBOL_CHECK (s))
     return;
   s->sy_used = 1;
+  if (S_IS_WEAKREFR (s))
+    symbol_mark_used (s->sy_value.X_add_symbol);
 }
 
 /* Clear the mark of whether a symbol has been used.  */
@@ -2149,6 +2605,17 @@ symbol_constant_p (symbolS *s)
   return s->sy_value.X_op == O_constant;
 }
 
+/* Return whether a symbol was cloned and thus removed from the global
+   symbol list.  */
+
+int
+symbol_shadow_p (symbolS *s)
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return 0;
+  return s->sy_next == s;
+}
+
 /* Return the BFD symbol for a symbol.  */
 
 asymbol *
@@ -2287,11 +2754,17 @@ print_symbol_value_1 (FILE *file, symbolS *sym)
        fprintf (file, " local");
       if (S_IS_EXTERNAL (sym))
        fprintf (file, " extern");
+      if (S_IS_WEAK (sym))
+       fprintf (file, " weak");
       if (S_IS_DEBUG (sym))
        fprintf (file, " debug");
       if (S_IS_DEFINED (sym))
        fprintf (file, " defined");
     }
+  if (S_IS_WEAKREFR (sym))
+    fprintf (file, " weakrefr");
+  if (S_IS_WEAKREFD (sym))
+    fprintf (file, " weakrefd");
   fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym)));
   if (symbol_resolved_p (sym))
     {
@@ -2464,3 +2937,219 @@ symbol_print_statistics (FILE *file)
   fprintf (file, "%lu mini local symbols created, %lu converted\n",
           local_symbol_count, local_symbol_conversion_count);
 }
+
+#ifdef OBJ_COMPLEX_RELC
+
+/* Convert given symbol to a new complex-relocation symbol name.  This
+   may bee a recursive function, since it might be called for non-leaf
+   nodes (plain symbols) in the expression tree.  The caller owns the
+   returning string, so should free() it eventually.  Errors are
+   indicated via as_bad() and a NULL return value.  The given symbol
+   is marked with sy_used_in_reloc.  */
+
+char *
+symbol_relc_make_sym (symbolS * sym)
+{
+  char * terminal = NULL;
+  const char * sname;
+  char typetag;
+  int sname_len;
+
+  assert (sym != NULL);
+
+  /* Recurse to symbol_relc_make_expr if this symbol
+     is defined as an expression or a plain value.  */
+  if (   S_GET_SEGMENT (sym) == expr_section
+      || S_GET_SEGMENT (sym) == absolute_section)
+    return symbol_relc_make_expr (& sym->sy_value);
+
+  /* This may be a "fake symbol" L0\001, referring to ".".
+     Write out a special null symbol to refer to this position.  */
+  if (! strcmp (S_GET_NAME (sym), FAKE_LABEL_NAME))
+    return xstrdup (".");
+
+  /* We hope this is a plain leaf symbol.  Construct the encoding
+     as {S,s}II...:CCCCCCC....
+     where 'S'/'s' means section symbol / plain symbol
+     III is decimal for the symbol name length
+     CCC is the symbol name itself.  */
+  symbol_mark_used_in_reloc (sym);
+
+  sname = S_GET_NAME (sym);
+  sname_len = strlen (sname);
+  typetag = symbol_section_p (sym) ? 'S' : 's';
+
+  terminal = xmalloc (1 /* S or s */
+                     + 8 /* sname_len in decimal */
+                     + 1 /* _ spacer */
+                     + sname_len /* name itself */
+                     + 1 /* \0 */ );
+
+  sprintf (terminal, "%c%d:%s", typetag, sname_len, sname);
+  return terminal;
+}
+
+/* Convert given value to a new complex-relocation symbol name.  This
+   is a non-recursive function, since it is be called for leaf nodes
+   (plain values) in the expression tree.  The caller owns the
+   returning string, so should free() it eventually.  No errors.  */
+
+char *
+symbol_relc_make_value (offsetT val)
+{
+  char * terminal = xmalloc (28);  /* Enough for long long.  */
+
+  terminal[0] = '#';
+  sprintf_vma (& terminal[1], val);
+  return terminal;
+}
+
+/* Convert given expression to a new complex-relocation symbol name.
+   This is a recursive function, since it traverses the entire given
+   expression tree.  The caller owns the returning string, so should
+   free() it eventually.  Errors are indicated via as_bad() and a NULL
+   return value.  */
+
+char *
+symbol_relc_make_expr (expressionS * exp)
+{
+  char * opstr = NULL; /* Operator prefix string.  */
+  int    arity = 0;    /* Arity of this operator.  */
+  char * operands[3];  /* Up to three operands.  */
+  char * concat_string = NULL;
+
+  operands[0] = operands[1] = operands[2] = NULL;
+
+  assert (exp != NULL);
+
+  /* Match known operators -> fill in opstr, arity, operands[] and fall
+     through to construct subexpression fragments; may instead return 
+     string directly for leaf nodes.  */
+
+  /* See expr.h for the meaning of all these enums.  Many operators 
+     have an unnatural arity (X_add_number implicitly added).  The
+     conversion logic expands them to explicit "+" subexpressions.   */
+
+  switch (exp->X_op)
+    {
+    default:
+      as_bad ("Unknown expression operator (enum %d)", exp->X_op);
+      break;
+
+      /* Leaf nodes.  */
+    case O_constant:
+      return symbol_relc_make_value (exp->X_add_number);
+
+    case O_symbol:
+      if (exp->X_add_number) 
+       { 
+         arity = 2; 
+         opstr = "+"; 
+         operands[0] = symbol_relc_make_sym (exp->X_add_symbol);
+         operands[1] = symbol_relc_make_value (exp->X_add_number);
+         break;
+       }
+      else
+       return symbol_relc_make_sym (exp->X_add_symbol);
+
+      /* Helper macros for nesting nodes.  */
+
+#define HANDLE_XADD_OPT1(str_)                                                 \
+      if (exp->X_add_number)                                           \
+        {                                                              \
+          arity = 2;                                                   \
+          opstr = "+:" str_;                                           \
+          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);      \
+          operands[1] = symbol_relc_make_value (exp->X_add_number);    \
+          break;                                                       \
+        }                                                              \
+      else                                                             \
+        {                                                              \
+          arity = 1;                                                   \
+          opstr = str_;                                                        \
+          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);      \
+        }                                                              \
+      break
+      
+#define HANDLE_XADD_OPT2(str_)                                                 \
+      if (exp->X_add_number)                                           \
+        {                                                              \
+          arity = 3;                                                   \
+          opstr = "+:" str_;                                           \
+          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);      \
+          operands[1] = symbol_relc_make_sym (exp->X_op_symbol);       \
+          operands[2] = symbol_relc_make_value (exp->X_add_number);    \
+        }                                                              \
+      else                                                             \
+        {                                                              \
+          arity = 2;                                                   \
+          opstr = str_;                                                        \
+          operands[0] = symbol_relc_make_sym (exp->X_add_symbol);      \
+          operands[1] = symbol_relc_make_sym (exp->X_op_symbol);       \
+        }                                                              \
+      break
+
+      /* Nesting nodes.  */
+
+    case O_uminus:             HANDLE_XADD_OPT1 ("0-");
+    case O_bit_not:            HANDLE_XADD_OPT1 ("~");
+    case O_logical_not:        HANDLE_XADD_OPT1 ("!");
+    case O_multiply:           HANDLE_XADD_OPT2 ("*");
+    case O_divide:             HANDLE_XADD_OPT2 ("/");
+    case O_modulus:            HANDLE_XADD_OPT2 ("%");
+    case O_left_shift:         HANDLE_XADD_OPT2 ("<<");
+    case O_right_shift:        HANDLE_XADD_OPT2 (">>");
+    case O_bit_inclusive_or:   HANDLE_XADD_OPT2 ("|");
+    case O_bit_exclusive_or:   HANDLE_XADD_OPT2 ("^");
+    case O_bit_and:            HANDLE_XADD_OPT2 ("&");
+    case O_add:                HANDLE_XADD_OPT2 ("+");
+    case O_subtract:           HANDLE_XADD_OPT2 ("-");
+    case O_eq:                 HANDLE_XADD_OPT2 ("==");
+    case O_ne:                 HANDLE_XADD_OPT2 ("!=");
+    case O_lt:                 HANDLE_XADD_OPT2 ("<");
+    case O_le:                 HANDLE_XADD_OPT2 ("<=");
+    case O_ge:                 HANDLE_XADD_OPT2 (">=");
+    case O_gt:                 HANDLE_XADD_OPT2 (">");
+    case O_logical_and:        HANDLE_XADD_OPT2 ("&&");
+    case O_logical_or:         HANDLE_XADD_OPT2 ("||");
+    }
+
+  /* Validate & reject early.  */
+  if (arity >= 1 && ((operands[0] == NULL) || (strlen (operands[0]) == 0)))
+    opstr = NULL;
+  if (arity >= 2 && ((operands[1] == NULL) || (strlen (operands[1]) == 0)))
+    opstr = NULL;
+  if (arity >= 3 && ((operands[2] == NULL) || (strlen (operands[2]) == 0)))
+    opstr = NULL;
+
+  if (opstr == NULL)
+    concat_string = NULL;
+  else
+    {
+      /* Allocate new string; include inter-operand padding gaps etc.  */
+      concat_string = xmalloc (strlen (opstr) 
+                              + 1
+                              + (arity >= 1 ? (strlen (operands[0]) + 1 ) : 0)
+                              + (arity >= 2 ? (strlen (operands[1]) + 1 ) : 0)
+                              + (arity >= 3 ? (strlen (operands[2]) + 0 ) : 0)
+                              + 1);
+      assert (concat_string != NULL);
+      
+      /* Format the thing.  */
+      sprintf (concat_string, 
+              (arity == 0 ? "%s" :
+               arity == 1 ? "%s:%s" :
+               arity == 2 ? "%s:%s:%s" :
+               /* arity == 3 */ "%s:%s:%s:%s"),
+              opstr, operands[0], operands[1], operands[2]);
+    }
+
+  /* Free operand strings (not opstr).  */
+  if (arity >= 1) xfree (operands[0]);
+  if (arity >= 2) xfree (operands[1]);
+  if (arity >= 3) xfree (operands[2]);
+
+  return concat_string;
+}
+
+#endif
This page took 0.039057 seconds and 4 git commands to generate.