PR ld/12851
[binutils-gdb.git] / gas / symbols.c
index 761cebfbf094cfb5f26a63234bcc555c6b2caab8..7dc9812a1226d45a6d6e62f6ff22432fbd9883e4 100644 (file)
@@ -1,7 +1,7 @@
 /* symbols.c -symbol table-
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -48,6 +48,7 @@ static struct hash_control *local_hash;
 symbolS *symbol_rootP;
 symbolS *symbol_lastP;
 symbolS abs_symbol;
+symbolS dot_symbol;
 
 #ifdef DEBUG_SYMS
 #define debug_verify_symchain verify_symbol_chain
@@ -59,7 +60,7 @@ symbolS abs_symbol;
 #define LOCAL_LABEL_CHAR       '\002'
 
 struct obstack notes;
-#ifdef USE_UNIQUE
+#ifdef TE_PE
 /* The name of an external symbol which is
    used to make weak PE symbol names unique.  */
 const char * an_external_name;
@@ -71,7 +72,6 @@ static long dollar_label_instance (long);
 static long fb_label_instance (long);
 
 static void print_binary (FILE *, const char *, expressionS *);
-static void report_op_error (symbolS *, symbolS *, symbolS *);
 
 /* Return a pointer to a new symbol.  Die if we can't make a new
    symbol.  Fill in the symbol's values.  Add symbol to end of symbol
@@ -109,7 +109,7 @@ save_symbol_name (const char *name)
 
   name_length = strlen (name) + 1;     /* +1 for \0.  */
   obstack_grow (&notes, name, name_length);
-  ret = obstack_finish (&notes);
+  ret = (char *) obstack_finish (&notes);
 
 #ifdef tc_canonicalize_symbol_name
   ret = tc_canonicalize_symbol_name (ret);
@@ -137,7 +137,7 @@ symbol_create (const char *name, /* It is copied, the caller can destroy/modify.
 
   preserved_copy_of_name = save_symbol_name (name);
 
-  symbolP = obstack_alloc (&notes, sizeof (symbolS));
+  symbolP = (symbolS *) obstack_alloc (&notes, sizeof (symbolS));
 
   /* symbol must be born in some fixed state.  This seems as good as any.  */
   memset (symbolP, 0, sizeof (symbolS));
@@ -188,7 +188,7 @@ static unsigned long local_symbol_conversion_count;
 /* Create a local symbol and insert it into the local hash table.  */
 
 static struct local_symbol *
-local_symbol_make (const char *name, segT section, valueT value, fragS *frag)
+local_symbol_make (const char *name, segT section, valueT val, fragS *frag)
 {
   char *name_copy;
   struct local_symbol *ret;
@@ -197,12 +197,12 @@ local_symbol_make (const char *name, segT section, valueT value, fragS *frag)
 
   name_copy = save_symbol_name (name);
 
-  ret = obstack_alloc (&notes, sizeof *ret);
+  ret = (struct local_symbol *) obstack_alloc (&notes, sizeof *ret);
   ret->lsy_marker = NULL;
   ret->lsy_name = name_copy;
   ret->lsy_section = section;
   local_symbol_set_frag (ret, frag);
-  ret->lsy_value = value;
+  ret->lsy_value = val;
 
   hash_jam (local_hash, name_copy, (void *) ret);
 
@@ -246,6 +246,14 @@ local_symbol_convert (struct local_symbol *locsym)
   return ret;
 }
 \f
+static void
+define_sym_at_dot (symbolS *symbolP)
+{
+  symbolP->sy_frag = frag_now;
+  S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
+  S_SET_SEGMENT (symbolP, now_seg);
+}
+
 /* We have just seen "<name>:".
    Creates a struct symbol unless it already exists.
 
@@ -343,12 +351,7 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
            }
          if (S_GET_VALUE (symbolP) == 0)
            {
-             symbolP->sy_frag = frag_now;
-#ifdef OBJ_VMS
-             S_SET_OTHER (symbolP, const_flag);
-#endif
-             S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
-             S_SET_SEGMENT (symbolP, now_seg);
+             define_sym_at_dot (symbolP);
 #ifdef N_UNDF
              know (N_UNDF == 0);
 #endif /* if we have one, it better be zero.  */
@@ -393,12 +396,7 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
                    {
                      /* It is a .comm/.lcomm being converted to initialized
                         data.  */
-                     symbolP->sy_frag = frag_now;
-#ifdef OBJ_VMS
-                     S_SET_OTHER (symbolP, const_flag);
-#endif
-                     S_SET_VALUE (symbolP, (valueT) frag_now_fix ());
-                     S_SET_SEGMENT (symbolP, now_seg); /* Keep N_EXT bit.  */
+                     define_sym_at_dot (symbolP);
                    }
                }
              else
@@ -431,6 +429,7 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
            {
              as_bad (_("symbol `%s' is already defined"), sym_name);
              symbolP = symbol_clone (symbolP, 0);
+             define_sym_at_dot (symbolP);
            }
        }
 
@@ -445,9 +444,6 @@ colon (/* Just seen "x:" - rattle symbols & frags.  */
     {
       symbolP = symbol_new (sym_name, now_seg, (valueT) frag_now_fix (),
                            frag_now);
-#ifdef OBJ_VMS
-      S_SET_OTHER (symbolP, const_flag);
-#endif /* OBJ_VMS */
 
       symbol_table_insert (symbolP);
     }
@@ -555,6 +551,9 @@ symbol_clone (symbolS *orgsymP, int replace)
   symbolS *newsymP;
   asymbol *bsymorg, *bsymnew;
 
+  /* Make sure we never clone the dot special symbol.  */
+  gas_assert (orgsymP != &dot_symbol);
+
   /* 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
@@ -563,15 +562,15 @@ symbol_clone (symbolS *orgsymP, int replace)
     orgsymP = local_symbol_convert ((struct local_symbol *) orgsymP);
   bsymorg = orgsymP->bsym;
 
-  newsymP = obstack_alloc (&notes, sizeof (*newsymP));
+  newsymP = (symbolS *) 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;
+  bsymnew->flags = bsymorg->flags & ~BSF_SECTION_SYM;
+  bsymnew->section = bsymorg->section;
   bfd_copy_private_symbol_data (bfd_asymbol_bfd (bsymorg), bsymorg,
                                bfd_asymbol_bfd (bsymnew), bsymnew);
 
@@ -643,7 +642,8 @@ symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward)
 
       /* Re-using sy_resolving here, as this routine cannot get called from
         symbol resolution code.  */
-      if (symbolP->bsym->section == expr_section && !symbolP->sy_resolving)
+      if ((symbolP->bsym->section == expr_section || symbolP->sy_forward_ref)
+         && !symbolP->sy_resolving)
        {
          symbolP->sy_resolving = 1;
          add_symbol = symbol_clone_if_forward_ref (add_symbol, is_forward);
@@ -654,7 +654,20 @@ symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward)
       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);
+       {
+         if (symbolP != &dot_symbol)
+           {
+             symbolP = symbol_clone (symbolP, 0);
+             symbolP->sy_resolving = 0;
+           }
+         else
+           {
+             symbolP = symbol_temp_new_now ();
+#ifdef tc_new_dot_label
+             tc_new_dot_label (symbolP);
+#endif
+           }
+       }
 
       symbolP->sy_value.X_add_symbol = add_symbol;
       symbolP->sy_value.X_op_symbol = op_symbol;
@@ -950,55 +963,65 @@ use_complex_relocs_for (symbolS * symp)
 #endif
 
 static void
-report_op_error (symbolS *symp, symbolS *left, symbolS *right)
+report_op_error (symbolS *symp, symbolS *left, operatorT op, symbolS *right)
 {
   char *file;
   unsigned int line;
-  segT seg_left = S_GET_SEGMENT (left);
-  segT seg_right = right ? S_GET_SEGMENT (right) : 0;
+  segT seg_left = left ? S_GET_SEGMENT (left) : 0;
+  segT seg_right = S_GET_SEGMENT (right);
+  const char *opname;
+
+  switch (op)
+    {
+    default:
+      abort ();
+      return;
+
+    case O_uminus:             opname = "-"; break;
+    case O_bit_not:            opname = "~"; break;
+    case O_logical_not:                opname = "!"; break;
+    case O_multiply:           opname = "*"; break;
+    case O_divide:             opname = "/"; break;
+    case O_modulus:            opname = "%"; break;
+    case O_left_shift:         opname = "<<"; break;
+    case O_right_shift:                opname = ">>"; break;
+    case O_bit_inclusive_or:   opname = "|"; break;
+    case O_bit_or_not:         opname = "|~"; break;
+    case O_bit_exclusive_or:   opname = "^"; break;
+    case O_bit_and:            opname = "&"; break;
+    case O_add:                        opname = "+"; break;
+    case O_subtract:           opname = "-"; break;
+    case O_eq:                 opname = "=="; break;
+    case O_ne:                 opname = "!="; break;
+    case O_lt:                 opname = "<"; break;
+    case O_le:                 opname = "<="; break;
+    case O_ge:                 opname = ">="; break;
+    case O_gt:                 opname = ">"; break;
+    case O_logical_and:                opname = "&&"; break;
+    case O_logical_or:         opname = "||"; break;
+    }
 
   if (expr_symbol_where (symp, &file, &line))
     {
-      if (seg_left == undefined_section)
+      if (left)
        as_bad_where (file, line,
-                     _("undefined symbol `%s' in operation"),
-                     S_GET_NAME (left));
-      if (seg_right == undefined_section)
+                     _("invalid operands (%s and %s sections) for `%s'"),
+                     seg_left->name, seg_right->name, opname);
+      else
        as_bad_where (file, line,
-                     _("undefined symbol `%s' in operation"),
-                     S_GET_NAME (right));
-      if (seg_left != undefined_section
-         && seg_right != undefined_section)
-       {
-         if (right)
-           as_bad_where (file, line,
-                         _("invalid sections for operation on `%s' and `%s'"),
-                         S_GET_NAME (left), S_GET_NAME (right));
-         else
-           as_bad_where (file, line,
-                         _("invalid section for operation on `%s'"),
-                         S_GET_NAME (left));
-       }
-
+                     _("invalid operand (%s section) for `%s'"),
+                     seg_right->name, opname);
     }
   else
     {
-      if (seg_left == undefined_section)
-       as_bad (_("undefined symbol `%s' in operation setting `%s'"),
-               S_GET_NAME (left), S_GET_NAME (symp));
-      if (seg_right == undefined_section)
-       as_bad (_("undefined symbol `%s' in operation setting `%s'"),
-               S_GET_NAME (right), S_GET_NAME (symp));
-      if (seg_left != undefined_section
-         && seg_right != undefined_section)
-       {
-         if (right)
-           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 (_("invalid section for operation on `%s' setting `%s'"),
-                   S_GET_NAME (left), S_GET_NAME (symp));
-       }
+      const char *sname = S_GET_NAME (symp);
+
+      if (left)
+       as_bad (_("invalid operands (%s and %s sections) for `%s' when setting `%s'"),
+               seg_left->name, seg_right->name, opname, sname);
+      else
+       as_bad (_("invalid operand (%s section) for `%s' when setting `%s'"),
+               seg_right->name, opname, sname);
     }
 }
 
@@ -1191,8 +1214,8 @@ resolve_symbol_value (symbolS *symp)
                  symp->sy_value.X_add_number = final_val;
                  /* Use X_op_symbol as a flag.  */
                  symp->sy_value.X_op_symbol = add_symbol;
-                 final_seg = seg_left;
                }
+             final_seg = seg_left;
              final_val = 0;
              resolved = symbol_resolved_p (add_symbol);
              symp->sy_resolving = 0;
@@ -1241,7 +1264,7 @@ resolve_symbol_value (symbolS *symp)
                ~S -> S ^ ~0    only permitted on absolute  */
          if (op != O_logical_not && seg_left != absolute_section
              && finalize_syms)
-           report_op_error (symp, add_symbol, NULL);
+           report_op_error (symp, NULL, op, add_symbol);
 
          if (final_seg == expr_section || final_seg == undefined_section)
            final_seg = absolute_section;
@@ -1318,7 +1341,7 @@ resolve_symbol_value (symbolS *symp)
             probably need to be changed for an object file format which
             supports arbitrary expressions, such as IEEE-695.  */
          if (!(seg_left == absolute_section
-                  && seg_right == absolute_section)
+               && seg_right == absolute_section)
              && !(op == O_eq || op == O_ne)
              && !((op == O_subtract
                    || op == O_lt || op == O_le || op == O_ge || op == O_gt)
@@ -1329,7 +1352,7 @@ resolve_symbol_value (symbolS *symp)
              /* Don't emit messages unless we're finalizing the symbol value,
                 otherwise we may get the same message multiple times.  */
              if (finalize_syms)
-               report_op_error (symp, add_symbol, op_symbol);
+               report_op_error (symp, add_symbol, op, op_symbol);
              /* However do not move the symbol into the absolute section
                 if it cannot currently be resolved - this would confuse
                 other parts of the assembler into believing that the
@@ -1453,7 +1476,7 @@ static void
 resolve_local_symbol (const char *key ATTRIBUTE_UNUSED, void *value)
 {
   if (value != NULL)
-    resolve_symbol_value (value);
+    resolve_symbol_value ((symbolS *) value);
 }
 
 /* Resolve all local symbols.  */
@@ -1482,21 +1505,21 @@ snapshot_symbol (symbolS **symbolPP, valueT *valueP, segT *segP, fragS **fragPP)
     }
   else
     {
-      expressionS expr = symbolP->sy_value;
+      expressionS exp = symbolP->sy_value;
 
-      if (!symbolP->sy_resolved && expr.X_op != O_illegal)
+      if (!symbolP->sy_resolved && exp.X_op != O_illegal)
        {
          int resolved;
 
          if (symbolP->sy_resolving)
            return 0;
          symbolP->sy_resolving = 1;
-         resolved = resolve_expression (&expr);
+         resolved = resolve_expression (&exp);
          symbolP->sy_resolving = 0;
          if (!resolved)
            return 0;
 
-         switch (expr.X_op)
+         switch (exp.X_op)
            {
            case O_constant:
            case O_register:
@@ -1505,23 +1528,20 @@ snapshot_symbol (symbolS **symbolPP, valueT *valueP, segT *segP, fragS **fragPP)
              /* Fall thru.  */
            case O_symbol:
            case O_symbol_rva:
-             symbolP = expr.X_add_symbol;
+             symbolP = exp.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;
+      *symbolPP = symbolP;
+      *valueP = exp.X_add_number;
       *segP = symbolP->bsym->section;
       *fragPP = symbolP->sy_frag;
 
       if (*segP == expr_section)
-       switch (expr.X_op)
+       switch (exp.X_op)
          {
          case O_constant: *segP = absolute_section; break;
          case O_register: *segP = reg_section; break;
@@ -1603,7 +1623,7 @@ define_dollar_label (long label)
     {
       dollar_labels = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long));
       dollar_label_instances = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long));
-      dollar_label_defines = xmalloc (DOLLAR_LABEL_BUMP_BY);
+      dollar_label_defines = (char *) xmalloc (DOLLAR_LABEL_BUMP_BY);
       dollar_label_max = DOLLAR_LABEL_BUMP_BY;
       dollar_label_count = 0;
     }
@@ -1614,7 +1634,7 @@ define_dollar_label (long label)
                                         dollar_label_max * sizeof (long));
       dollar_label_instances = (long *) xrealloc ((char *) dollar_label_instances,
                                          dollar_label_max * sizeof (long));
-      dollar_label_defines = xrealloc (dollar_label_defines, dollar_label_max);
+      dollar_label_defines = (char *) xrealloc (dollar_label_defines, dollar_label_max);
     }                          /* if we needed to grow  */
 
   dollar_labels[dollar_label_count] = label;
@@ -1863,17 +1883,17 @@ decode_local_label_name (char *s)
   int instance_number;
   char *type;
   const char *message_format;
-  int index = 0;
+  int lindex = 0;
 
 #ifdef LOCAL_LABEL_PREFIX
-  if (s[index] == LOCAL_LABEL_PREFIX)
-    ++index;
+  if (s[lindex] == LOCAL_LABEL_PREFIX)
+    ++lindex;
 #endif
 
-  if (s[index] != 'L')
+  if (s[lindex] != 'L')
     return s;
 
-  for (label_number = 0, p = s + index + 1; ISDIGIT (*p); ++p)
+  for (label_number = 0, p = s + lindex + 1; ISDIGIT (*p); ++p)
     label_number = (10 * label_number) + *p - '0';
 
   if (*p == DOLLAR_LABEL_CHAR)
@@ -1887,7 +1907,7 @@ decode_local_label_name (char *s)
     instance_number = (10 * instance_number) + *p - '0';
 
   message_format = _("\"%d\" (instance number %d of a %s label)");
-  symbol_decode = obstack_alloc (&notes, strlen (message_format) + 30);
+  symbol_decode = (char *) obstack_alloc (&notes, strlen (message_format) + 30);
   sprintf (symbol_decode, message_format, label_number, instance_number, type);
 
   return symbol_decode;
@@ -2055,6 +2075,7 @@ S_FORCE_RELOC (symbolS *s, int strict)
           && ((s->bsym->flags & BSF_WEAK) != 0
               || (EXTERN_FORCE_RELOC
                   && (s->bsym->flags & BSF_GLOBAL) != 0)))
+         || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0
          || s->bsym->section == undefined_section
          || bfd_is_com_section (s->bsym->section));
 }
@@ -2203,7 +2224,7 @@ S_SET_EXTERNAL (symbolS *s)
   s->bsym->flags |= BSF_GLOBAL;
   s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK);
 
-#ifdef USE_UNIQUE
+#ifdef TE_PE
   if (! an_external_name && S_GET_NAME(s)[0] != '.')
     an_external_name = S_GET_NAME (s);
 #endif
@@ -2385,6 +2406,20 @@ symbol_set_value_expression (symbolS *s, const expressionS *exp)
   S_CLEAR_WEAKREFR (s);
 }
 
+/* Return whether 2 symbols are the same.  */
+
+int
+symbol_same_p (symbolS *s1, symbolS *s2)
+{
+  if (s1->bsym == NULL
+      && local_symbol_converted_p ((struct local_symbol *) s1))
+    s1 = local_symbol_get_real_symbol ((struct local_symbol *) s1);
+  if (s2->bsym == NULL
+      && local_symbol_converted_p ((struct local_symbol *) s2))
+    s2 = local_symbol_get_real_symbol ((struct local_symbol *) s2);
+  return s1 == s2;
+}
+
 /* Return a pointer to the X_add_number component of a symbol.  */
 
 offsetT *
@@ -2731,6 +2766,17 @@ symbol_begin (void)
   if (LOCAL_LABELS_FB)
     fb_label_init ();
 }
+
+void
+dot_symbol_init (void)
+{
+  dot_symbol.bsym = bfd_make_empty_symbol (stdoutput);
+  if (dot_symbol.bsym == NULL)
+    as_fatal ("bfd_make_empty_symbol: %s", bfd_errmsg (bfd_get_error ()));
+  dot_symbol.bsym->name = ".";
+  dot_symbol.sy_forward_ref = 1;
+  dot_symbol.sy_value.X_op = O_constant;
+}
 \f
 int indent_level;