Let special symbols override existing symbols rather than
authorIan Lance Taylor <iant@google.com>
Wed, 19 Sep 2007 06:02:29 +0000 (06:02 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 19 Sep 2007 06:02:29 +0000 (06:02 +0000)
reinitializing them.

gold/resolve.cc
gold/symtab.cc
gold/symtab.h

index e5ca6e38c9991f3ef713fa5663bd966925b0e644..599aad46d13a3a84b438ce47d15fdf91c3e62c7f 100644 (file)
@@ -51,6 +51,25 @@ Sized_symbol<size>::override(const elfcpp::Sym<size, big_endian>& sym,
   this->symsize_ = sym.get_st_size();
 }
 
+// The resolve functions build a little code for each symbol.
+// Bit 0: 0 for global, 1 for weak.
+// Bit 1: 0 for regular object, 1 for shared object
+// Bits 2-3: 0 for normal, 1 for undefined, 2 for common
+// This gives us values from 0 to 11.
+
+static const int global_or_weak_shift = 0;
+static const unsigned int global_flag = 0 << global_or_weak_shift;
+static const unsigned int weak_flag = 1 << global_or_weak_shift;
+
+static const int regular_or_dynamic_shift = 1;
+static const unsigned int regular_flag = 0 << regular_or_dynamic_shift;
+static const unsigned int dynamic_flag = 1 << regular_or_dynamic_shift;
+
+static const int def_undef_or_common_shift = 2;
+static const unsigned int def_flag = 0 << def_undef_or_common_shift;
+static const unsigned int undef_flag = 1 << def_undef_or_common_shift;
+static const unsigned int common_flag = 2 << def_undef_or_common_shift;
+
 // Resolve a symbol.  This is called the second and subsequent times
 // we see a symbol.  TO is the pre-existing symbol.  SYM is the new
 // symbol, seen in OBJECT.  VERSION of the version of SYM.
@@ -71,121 +90,138 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       return;
     }
 
-  // Build a little code for each symbol.
-  // Bit 0: 0 for global, 1 for weak.
-  // Bit 1: 0 for regular object, 1 for shared object
-  // Bits 2-3: 0 for normal, 1 for undefined, 2 for common
-  // This gives us values from 0 to 11:
-
-  enum
-  {
-    DEF = 0,
-    WEAK_DEF = 1,
-    DYN_DEF = 2,
-    DYN_WEAK_DEF = 3,
-    UNDEF = 4,
-    WEAK_UNDEF = 5,
-    DYN_UNDEF = 6,
-    DYN_WEAK_UNDEF = 7,
-    COMMON = 8,
-    WEAK_COMMON = 9,
-    DYN_COMMON = 10,
-    DYN_WEAK_COMMON = 11
-  };
+  if (!object->is_dynamic())
+    {
+      // Record that we've seen this symbol in a regular object.
+      to->set_in_reg();
+    }
+  else
+    {
+      // Record that we've seen this symbol in a dynamic object.
+      to->set_in_dyn();
+    }
 
-  int tobits;
-  switch (to->binding())
+  unsigned int frombits;
+  switch (sym.get_st_bind())
     {
     case elfcpp::STB_GLOBAL:
-      tobits = 0;
+      frombits = global_flag;
       break;
 
     case elfcpp::STB_WEAK:
-      tobits = 1;
+      frombits = weak_flag;
       break;
 
     case elfcpp::STB_LOCAL:
-      // We should only see externally visible symbols in the symbol
-      // table.
-      gold_unreachable();
+      fprintf(stderr,
+             _("%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"),
+             program_name, object->name().c_str(), to->name());
+      gold_exit(false);
 
     default:
-      // Any target which wants to handle STB_LOOS, etc., needs to
-      // define a resolve method.
-      gold_unreachable();
+      fprintf(stderr,
+             _("%s: %s: unsupported symbol binding %d for symbol %s\n"),
+             program_name, object->name().c_str(),
+             static_cast<int>(sym.get_st_bind()), to->name());
+      gold_exit(false);
     }
 
-  if (to->source() == Symbol::FROM_OBJECT
-      && to->object()->is_dynamic())
-    tobits |= (1 << 1);
+  if (!object->is_dynamic())
+    frombits |= regular_flag;
+  else
+    frombits |= dynamic_flag;
 
-  switch (to->shndx())
+  switch (sym.get_st_shndx())
     {
     case elfcpp::SHN_UNDEF:
-      tobits |= (1 << 2);
+      frombits |= undef_flag;
       break;
 
     case elfcpp::SHN_COMMON:
-      tobits |= (2 << 2);
+      frombits |= common_flag;
       break;
 
     default:
-      if (to->type() == elfcpp::STT_COMMON)
-       tobits |= (2 << 2);
+      if (sym.get_st_type() == elfcpp::STT_COMMON)
+       frombits |= common_flag;
+      else
+        frombits |= def_flag;
       break;
     }
 
-  int frombits;
-  switch (sym.get_st_bind())
+  bool adjust_common_sizes;
+  if (Symbol_table::should_override(to, frombits, &adjust_common_sizes))
+    {
+      typename Sized_symbol<size>::Size_type tosize = to->symsize();
+
+      to->override(sym, object, version);
+
+      if (adjust_common_sizes && tosize > to->symsize())
+        to->set_symsize(tosize);
+    }
+  else
+    {
+      if (adjust_common_sizes && sym.get_st_size() > to->symsize())
+        to->set_symsize(sym.get_st_size());
+    }
+}
+
+// Handle the core of symbol resolution.  This is called with the
+// existing symbol, TO, and a bitflag describing the new symbol.  This
+// returns true if we should override the existing symbol with the new
+// one, and returns false otherwise.  It sets *ADJUST_COMMON_SIZES to
+// true if we should set the symbol size to the maximum of the TO and
+// FROM sizes.  It handles error conditions.
+
+bool
+Symbol_table::should_override(const Symbol* to, unsigned int frombits,
+                              bool* adjust_common_sizes)
+{
+  *adjust_common_sizes = false;
+
+  unsigned int tobits;
+  switch (to->binding())
     {
     case elfcpp::STB_GLOBAL:
-      frombits = 0;
+      tobits = global_flag;
       break;
 
     case elfcpp::STB_WEAK:
-      frombits = 1;
+      tobits = weak_flag;
       break;
 
     case elfcpp::STB_LOCAL:
-      fprintf(stderr,
-             _("%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"),
-             program_name, object->name().c_str(), to->name());
-      gold_exit(false);
+      // We should only see externally visible symbols in the symbol
+      // table.
+      gold_unreachable();
 
     default:
-      fprintf(stderr,
-             _("%s: %s: unsupported symbol binding %d for symbol %s\n"),
-             program_name, object->name().c_str(),
-             static_cast<int>(sym.get_st_bind()), to->name());
-      gold_exit(false);
+      // Any target which wants to handle STB_LOOS, etc., needs to
+      // define a resolve method.
+      gold_unreachable();
     }
 
-  if (!object->is_dynamic())
-    {
-      // Record that we've seen this symbol in a regular object.
-      to->set_in_reg();
-    }
+  if (to->source() == Symbol::FROM_OBJECT
+      && to->object()->is_dynamic())
+    tobits |= dynamic_flag;
   else
-    {
-      frombits |= (1 << 1);
+    tobits |= regular_flag;
 
-      // Record that we've seen this symbol in a dynamic object.
-      to->set_in_dyn();
-    }
-
-  switch (sym.get_st_shndx())
+  switch (to->shndx())
     {
     case elfcpp::SHN_UNDEF:
-      frombits |= (1 << 2);
+      tobits |= undef_flag;
       break;
 
     case elfcpp::SHN_COMMON:
-      frombits |= (2 << 2);
+      tobits |= common_flag;
       break;
 
     default:
-      if (sym.get_st_type() == elfcpp::STT_COMMON)
-       frombits |= (2 << 2);
+      if (to->type() == elfcpp::STT_COMMON)
+       tobits |= common_flag;
+      else
+        tobits |= def_flag;
       break;
     }
 
@@ -199,14 +235,31 @@ Symbol_table::resolve(Sized_symbol<size>* to,
   // but that is no easier to understand than this large switch
   // statement.
 
+  // These are the values generated by the bit codes.
+  enum
+  {
+    DEF =              global_flag | regular_flag | def_flag,
+    WEAK_DEF =         weak_flag   | regular_flag | def_flag,
+    DYN_DEF =          global_flag | dynamic_flag | def_flag,
+    DYN_WEAK_DEF =     weak_flag   | dynamic_flag | def_flag,
+    UNDEF =            global_flag | regular_flag | undef_flag,
+    WEAK_UNDEF =       weak_flag   | regular_flag | undef_flag,
+    DYN_UNDEF =        global_flag | dynamic_flag | undef_flag,
+    DYN_WEAK_UNDEF =   weak_flag   | dynamic_flag | undef_flag,
+    COMMON =           global_flag | regular_flag | common_flag,
+    WEAK_COMMON =      weak_flag   | regular_flag | common_flag,
+    DYN_COMMON =       global_flag | dynamic_flag | common_flag,
+    DYN_WEAK_COMMON =  weak_flag   | dynamic_flag | common_flag
+  };
+
   switch (tobits * 16 + frombits)
     {
     case DEF * 16 + DEF:
       // Two definitions of the same symbol.
-      fprintf(stderr, "%s: %s: multiple definition of %s\n",
-             program_name, object->name().c_str(), to->name());
+      fprintf(stderr, "%s: multiple definition of %s\n",
+             program_name, to->name());
       // FIXME: Report locations.  Record that we have seen an error.
-      return;
+      return false;
 
     case WEAK_DEF * 16 + DEF:
       // We've seen a weak definition, and now we see a strong
@@ -217,8 +270,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       // are currently compatible with the GNU linker.  In the future
       // we should add a target specific option to change this.
       // FIXME.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case DYN_DEF * 16 + DEF:
     case DYN_WEAK_DEF * 16 + DEF:
@@ -226,8 +278,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       // definition in a regular object.  The definition in the
       // regular object overrides the definition in the dynamic
       // object.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case UNDEF * 16 + DEF:
     case WEAK_UNDEF * 16 + DEF:
@@ -235,8 +286,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_UNDEF * 16 + DEF:
       // We've seen an undefined reference, and now we see a
       // definition.  We use the definition.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + DEF:
     case WEAK_COMMON * 16 + DEF:
@@ -245,56 +295,51 @@ Symbol_table::resolve(Sized_symbol<size>* to,
       // We've seen a common symbol and now we see a definition.  The
       // definition overrides.  FIXME: We should optionally issue, version a
       // warning.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case DEF * 16 + WEAK_DEF:
     case WEAK_DEF * 16 + WEAK_DEF:
       // We've seen a definition and now we see a weak definition.  We
       // ignore the new weak definition.
-      return;
+      return false;
 
     case DYN_DEF * 16 + WEAK_DEF:
     case DYN_WEAK_DEF * 16 + WEAK_DEF:
       // We've seen a dynamic definition and now we see a regular weak
       // definition.  The regular weak definition overrides.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case UNDEF * 16 + WEAK_DEF:
     case WEAK_UNDEF * 16 + WEAK_DEF:
     case DYN_UNDEF * 16 + WEAK_DEF:
     case DYN_WEAK_UNDEF * 16 + WEAK_DEF:
       // A weak definition of a currently undefined symbol.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + WEAK_DEF:
     case WEAK_COMMON * 16 + WEAK_DEF:
       // A weak definition does not override a common definition.
-      return;
+      return false;
 
     case DYN_COMMON * 16 + WEAK_DEF:
     case DYN_WEAK_COMMON * 16 + WEAK_DEF:
       // A weak definition does override a definition in a dynamic
       // object.  FIXME: We should optionally issue a warning.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case DEF * 16 + DYN_DEF:
     case WEAK_DEF * 16 + DYN_DEF:
     case DYN_DEF * 16 + DYN_DEF:
     case DYN_WEAK_DEF * 16 + DYN_DEF:
       // Ignore a dynamic definition if we already have a definition.
-      return;
+      return false;
 
     case UNDEF * 16 + DYN_DEF:
     case WEAK_UNDEF * 16 + DYN_DEF:
     case DYN_UNDEF * 16 + DYN_DEF:
     case DYN_WEAK_UNDEF * 16 + DYN_DEF:
       // Use a dynamic definition if we have a reference.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + DYN_DEF:
     case WEAK_COMMON * 16 + DYN_DEF:
@@ -302,7 +347,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_COMMON * 16 + DYN_DEF:
       // Ignore a dynamic definition if we already have a common
       // definition.
-      return;
+      return false;
 
     case DEF * 16 + DYN_WEAK_DEF:
     case WEAK_DEF * 16 + DYN_WEAK_DEF:
@@ -310,15 +355,14 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_DEF * 16 + DYN_WEAK_DEF:
       // Ignore a weak dynamic definition if we already have a
       // definition.
-      return;
+      return false;
 
     case UNDEF * 16 + DYN_WEAK_DEF:
     case WEAK_UNDEF * 16 + DYN_WEAK_DEF:
     case DYN_UNDEF * 16 + DYN_WEAK_DEF:
     case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF:
       // Use a weak dynamic definition if we have a reference.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + DYN_WEAK_DEF:
     case WEAK_COMMON * 16 + DYN_WEAK_DEF:
@@ -326,7 +370,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_DEF:
       // Ignore a weak dynamic definition if we already have a common
       // definition.
-      return;
+      return false;
 
     case DEF * 16 + UNDEF:
     case WEAK_DEF * 16 + UNDEF:
@@ -334,21 +378,20 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_DEF * 16 + UNDEF:
     case UNDEF * 16 + UNDEF:
       // A new undefined reference tells us nothing.
-      return;
+      return false;
 
     case WEAK_UNDEF * 16 + UNDEF:
     case DYN_UNDEF * 16 + UNDEF:
     case DYN_WEAK_UNDEF * 16 + UNDEF:
       // A strong undef overrides a dynamic or weak undef.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + UNDEF:
     case WEAK_COMMON * 16 + UNDEF:
     case DYN_COMMON * 16 + UNDEF:
     case DYN_WEAK_COMMON * 16 + UNDEF:
       // A new undefined reference tells us nothing.
-      return;
+      return false;
 
     case DEF * 16 + WEAK_UNDEF:
     case WEAK_DEF * 16 + WEAK_UNDEF:
@@ -363,7 +406,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_COMMON * 16 + WEAK_UNDEF:
     case DYN_WEAK_COMMON * 16 + WEAK_UNDEF:
       // A new weak undefined reference tells us nothing.
-      return;
+      return false;
 
     case DEF * 16 + DYN_UNDEF:
     case WEAK_DEF * 16 + DYN_UNDEF:
@@ -378,7 +421,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_COMMON * 16 + DYN_UNDEF:
     case DYN_WEAK_COMMON * 16 + DYN_UNDEF:
       // A new dynamic undefined reference tells us nothing.
-      return;
+      return false;
 
     case DEF * 16 + DYN_WEAK_UNDEF:
     case WEAK_DEF * 16 + DYN_WEAK_UNDEF:
@@ -393,50 +436,41 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_COMMON * 16 + DYN_WEAK_UNDEF:
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_UNDEF:
       // A new weak dynamic undefined reference tells us nothing.
-      return;
+      return false;
 
     case DEF * 16 + COMMON:
       // A common symbol does not override a definition.
-      return;
+      return false;
 
     case WEAK_DEF * 16 + COMMON:
     case DYN_DEF * 16 + COMMON:
     case DYN_WEAK_DEF * 16 + COMMON:
       // A common symbol does override a weak definition or a dynamic
       // definition.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case UNDEF * 16 + COMMON:
     case WEAK_UNDEF * 16 + COMMON:
     case DYN_UNDEF * 16 + COMMON:
     case DYN_WEAK_UNDEF * 16 + COMMON:
       // A common symbol is a definition for a reference.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + COMMON:
       // Set the size to the maximum.
-      if (sym.get_st_size() > to->symsize())
-       to->set_symsize(sym.get_st_size());
-      return;
+      *adjust_common_sizes = true;
+      return false;
 
     case WEAK_COMMON * 16 + COMMON:
       // I'm not sure just what a weak common symbol means, but
       // presumably it can be overridden by a regular common symbol.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case DYN_COMMON * 16 + COMMON:
     case DYN_WEAK_COMMON * 16 + COMMON:
-      {
-       // Use the real common symbol, but adjust the size if necessary.
-       typename Sized_symbol<size>::Size_type symsize = to->symsize();
-       to->override(sym, object, version);
-       if (to->symsize() < symsize)
-         to->set_symsize(symsize);
-      }
-      return;
+      // Use the real common symbol, but adjust the size if necessary.
+      *adjust_common_sizes = true;
+      return true;
 
     case DEF * 16 + WEAK_COMMON:
     case WEAK_DEF * 16 + WEAK_COMMON:
@@ -444,15 +478,14 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_DEF * 16 + WEAK_COMMON:
       // Whatever a weak common symbol is, it won't override a
       // definition.
-      return;
+      return false;
 
     case UNDEF * 16 + WEAK_COMMON:
     case WEAK_UNDEF * 16 + WEAK_COMMON:
     case DYN_UNDEF * 16 + WEAK_COMMON:
     case DYN_WEAK_UNDEF * 16 + WEAK_COMMON:
       // A weak common symbol is better than an undefined symbol.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + WEAK_COMMON:
     case WEAK_COMMON * 16 + WEAK_COMMON:
@@ -460,7 +493,7 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_COMMON * 16 + WEAK_COMMON:
       // Ignore a weak common symbol in the presence of a real common
       // symbol.
-      return;
+      return false;
 
     case DEF * 16 + DYN_COMMON:
     case WEAK_DEF * 16 + DYN_COMMON:
@@ -468,54 +501,114 @@ Symbol_table::resolve(Sized_symbol<size>* to,
     case DYN_WEAK_DEF * 16 + DYN_COMMON:
       // Ignore a dynamic common symbol in the presence of a
       // definition.
-      return;
+      return false;
 
     case UNDEF * 16 + DYN_COMMON:
     case WEAK_UNDEF * 16 + DYN_COMMON:
     case DYN_UNDEF * 16 + DYN_COMMON:
     case DYN_WEAK_UNDEF * 16 + DYN_COMMON:
       // A dynamic common symbol is a definition of sorts.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + DYN_COMMON:
     case WEAK_COMMON * 16 + DYN_COMMON:
     case DYN_COMMON * 16 + DYN_COMMON:
     case DYN_WEAK_COMMON * 16 + DYN_COMMON:
       // Set the size to the maximum.
-      if (sym.get_st_size() > to->symsize())
-       to->set_symsize(sym.get_st_size());
-      return;
+      *adjust_common_sizes = true;
+      return false;
 
     case DEF * 16 + DYN_WEAK_COMMON:
     case WEAK_DEF * 16 + DYN_WEAK_COMMON:
     case DYN_DEF * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_DEF * 16 + DYN_WEAK_COMMON:
       // A common symbol is ignored in the face of a definition.
-      return;
+      return false;
 
     case UNDEF * 16 + DYN_WEAK_COMMON:
     case WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
     case DYN_UNDEF * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_UNDEF * 16 + DYN_WEAK_COMMON:
       // I guess a weak common symbol is better than a definition.
-      to->override(sym, object, version);
-      return;
+      return true;
 
     case COMMON * 16 + DYN_WEAK_COMMON:
     case WEAK_COMMON * 16 + DYN_WEAK_COMMON:
     case DYN_COMMON * 16 + DYN_WEAK_COMMON:
     case DYN_WEAK_COMMON * 16 + DYN_WEAK_COMMON:
       // Set the size to the maximum.
-      if (sym.get_st_size() > to->symsize())
-       to->set_symsize(sym.get_st_size());
-      return;
+      *adjust_common_sizes = true;
+      return false;
 
     default:
       gold_unreachable();
     }
 }
 
+// A special case of should_override which is only called for a strong
+// defined symbol from a regular object file.  This is used when
+// defining special symbols.
+
+bool
+Symbol_table::should_override_with_special(const Symbol* to)
+{
+  bool adjust_common_sizes;
+  unsigned int frombits = global_flag | regular_flag | def_flag;
+  bool ret = Symbol_table::should_override(to, frombits, &adjust_common_sizes);
+  gold_assert(!adjust_common_sizes);
+  return ret;
+}
+
+// Override symbol base with a special symbol.
+
+void
+Symbol::override_base_with_special(const Symbol* from)
+{
+  this->source_ = from->source_;
+  switch (from->source_)
+    {
+    case FROM_OBJECT:
+      this->u_.from_object = from->u_.from_object;
+      break;
+    case IN_OUTPUT_DATA:
+      this->u_.in_output_data = from->u_.in_output_data;
+      break;
+    case IN_OUTPUT_SEGMENT:
+      this->u_.in_output_segment = from->u_.in_output_segment;
+      break;
+    case CONSTANT:
+      break;
+    default:
+      gold_unreachable();
+      break;
+    }
+
+  if (from->version_ != NULL && this->version_ != from->version_)
+    {
+      gold_assert(this->version_ == NULL);
+      this->version_ = from->version_;
+    }
+
+  this->type_ = from->type_;
+  this->binding_ = from->binding_;
+  this->visibility_ = from->visibility_;
+  this->nonvis_ = from->nonvis_;
+
+  // Special symbols are always considered to be regular symbols.
+  this->in_reg_ = true;
+}
+
+// Override a symbol with a special symbol.
+
+template<int size>
+void
+Sized_symbol<size>::override_with_special(const Sized_symbol<size>* from)
+{
+  this->override_base_with_special(from);
+  this->value_ = from->value_;
+  this->symsize_ = from->symsize_;
+}
+
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones needed for implemented
 // targets.
@@ -560,4 +653,16 @@ Symbol_table::resolve<64, true>(
     const char* version);
 #endif
 
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Sized_symbol<32>::override_with_special(const Sized_symbol<32>*);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Sized_symbol<64>::override_with_special(const Sized_symbol<64>*);
+#endif
+
 } // End namespace gold.
index b7f4aaa4ab0e1a605cda380d91113430071fdbc0..d29f751ad8c1ae3384c2082b144b95b15fbb1e93 100644 (file)
@@ -666,28 +666,28 @@ Symbol_table::add_from_dynobj(
 
 // Create and return a specially defined symbol.  If ONLY_IF_REF is
 // true, then only create the symbol if there is a reference to it.
+// If this does not return NULL, it sets *POLDSYM to the existing
+// symbol if there is one.
 
 template<int size, bool big_endian>
 Sized_symbol<size>*
 Symbol_table::define_special_symbol(const Target* target, const char* name,
-                                   const char* version, bool only_if_ref
+                                   const char* version, bool only_if_ref,
+                                    Sized_symbol<size>** poldsym
                                     ACCEPT_SIZE_ENDIAN)
 {
   gold_assert(this->size_ == size);
 
   Symbol* oldsym;
   Sized_symbol<size>* sym;
+  bool add_to_table = false;
+  typename Symbol_table_type::iterator add_loc = this->table_.end();
 
   if (only_if_ref)
     {
       oldsym = this->lookup(name, version);
       if (oldsym == NULL || !oldsym->is_undefined())
        return NULL;
-      sym = NULL;
-
-      // Canonicalize NAME and VERSION.
-      name = oldsym->name();
-      version = oldsym->version();
     }
   else
     {
@@ -710,53 +710,38 @@ Symbol_table::define_special_symbol(const Target* target, const char* name,
          // We already have a symbol table entry for NAME/VERSION.
          oldsym = ins.first->second;
          gold_assert(oldsym != NULL);
-         sym = NULL;
        }
       else
        {
          // We haven't seen this symbol before.
          gold_assert(ins.first->second == NULL);
-
-         if (!target->has_make_symbol())
-           sym = new Sized_symbol<size>();
-         else
-           {
-             gold_assert(target->get_size() == size);
-             gold_assert(target->is_big_endian() ? big_endian : !big_endian);
-             typedef Sized_target<size, big_endian> My_target;
-             const My_target* sized_target =
-               static_cast<const My_target*>(target);
-             sym = sized_target->make_symbol();
-             if (sym == NULL)
-               return NULL;
-           }
-
-         ins.first->second = sym;
+          add_to_table = true;
+          add_loc = ins.first;
          oldsym = NULL;
        }
     }
 
-  if (oldsym != NULL)
+  if (!target->has_make_symbol())
+    sym = new Sized_symbol<size>();
+  else
     {
-      gold_assert(sym == NULL);
+      gold_assert(target->get_size() == size);
+      gold_assert(target->is_big_endian() ? big_endian : !big_endian);
+      typedef Sized_target<size, big_endian> My_target;
+      const My_target* sized_target =
+          static_cast<const My_target*>(target);
+      sym = sized_target->make_symbol();
+      if (sym == NULL)
+        return NULL;
+    }
 
-      sym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
-                                                           SELECT_SIZE(size));
-      gold_assert(sym->source() == Symbol::FROM_OBJECT);
-      const int old_shndx = sym->shndx();
-      if (old_shndx != elfcpp::SHN_UNDEF
-         && old_shndx != elfcpp::SHN_COMMON
-         && !sym->object()->is_dynamic())
-       {
-         fprintf(stderr, "%s: linker defined: multiple definition of %s\n",
-                 program_name, name);
-         // FIXME: Report old location.  Record that we have seen an
-         // error.
-         return NULL;
-       }
+  if (add_to_table)
+    add_loc->second = sym;
+  else
+    gold_assert(oldsym != NULL);
 
-      // Our new definition is going to override the old reference.
-    }
+  *poldsym = this->get_sized_symbol SELECT_SIZE_NAME(size) (oldsym
+                                                            SELECT_SIZE(size));
 
   return sym;
 }
@@ -775,15 +760,29 @@ Symbol_table::define_in_output_data(const Target* target, const char* name,
 {
   gold_assert(target->get_size() == this->size_);
   if (this->size_ == 32)
-    return this->do_define_in_output_data<32>(target, name, version, od, value,
-                                             symsize, type, binding,
-                                             visibility, nonvis,
-                                             offset_is_from_end, only_if_ref);
+    {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+      return this->do_define_in_output_data<32>(target, name, version, od,
+                                                value, symsize, type, binding,
+                                                visibility, nonvis,
+                                                offset_is_from_end,
+                                                only_if_ref);
+#else
+      gold_unreachable();
+#endif
+    }
   else if (this->size_ == 64)
-    return this->do_define_in_output_data<64>(target, name, version, od, value,
-                                             symsize, type, binding,
-                                             visibility, nonvis,
-                                             offset_is_from_end, only_if_ref);
+    {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+      return this->do_define_in_output_data<64>(target, name, version, od,
+                                                value, symsize, type, binding,
+                                                visibility, nonvis,
+                                                offset_is_from_end,
+                                                only_if_ref);
+#else
+      gold_unreachable();
+#endif
+    }
   else
     gold_unreachable();
 }
@@ -807,12 +806,13 @@ Symbol_table::do_define_in_output_data(
     bool only_if_ref)
 {
   Sized_symbol<size>* sym;
+  Sized_symbol<size>* oldsym;
 
   if (target->is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-          target, name, version, only_if_ref
+          target, name, version, only_if_ref, &oldsym
           SELECT_SIZE_ENDIAN(size, true));
 #else
       gold_unreachable();
@@ -822,7 +822,7 @@ Symbol_table::do_define_in_output_data(
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-          target, name, version, only_if_ref
+          target, name, version, only_if_ref, &oldsym
           SELECT_SIZE_ENDIAN(size, false));
 #else
       gold_unreachable();
@@ -835,6 +835,10 @@ Symbol_table::do_define_in_output_data(
   sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
            offset_is_from_end);
 
+  if (oldsym != NULL
+      && Symbol_table::should_override_with_special(oldsym))
+    oldsym->override_with_special(sym);
+
   return sym;
 }
 
@@ -852,15 +856,27 @@ Symbol_table::define_in_output_segment(const Target* target, const char* name,
 {
   gold_assert(target->get_size() == this->size_);
   if (this->size_ == 32)
-    return this->do_define_in_output_segment<32>(target, name, version, os,
-                                                value, symsize, type, binding,
-                                                visibility, nonvis,
-                                                offset_base, only_if_ref);
+    {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+      return this->do_define_in_output_segment<32>(target, name, version, os,
+                                                   value, symsize, type,
+                                                   binding, visibility, nonvis,
+                                                   offset_base, only_if_ref);
+#else
+      gold_unreachable();
+#endif
+    }
   else if (this->size_ == 64)
-    return this->do_define_in_output_segment<64>(target, name, version, os,
-                                                value, symsize, type, binding,
-                                                visibility, nonvis,
-                                                offset_base, only_if_ref);
+    {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+      return this->do_define_in_output_segment<64>(target, name, version, os,
+                                                   value, symsize, type,
+                                                   binding, visibility, nonvis,
+                                                   offset_base, only_if_ref);
+#else
+      gold_unreachable();
+#endif
+    }
   else
     gold_unreachable();
 }
@@ -884,14 +900,15 @@ Symbol_table::do_define_in_output_segment(
     bool only_if_ref)
 {
   Sized_symbol<size>* sym;
+  Sized_symbol<size>* oldsym;
 
   if (target->is_big_endian())
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, name, version, only_if_ref
+        target, name, version, only_if_ref, &oldsym
         SELECT_SIZE_ENDIAN(size, true));
   else
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, name, version, only_if_ref
+        target, name, version, only_if_ref, &oldsym
         SELECT_SIZE_ENDIAN(size, false));
 
   if (sym == NULL)
@@ -900,6 +917,10 @@ Symbol_table::do_define_in_output_segment(
   sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
            offset_base);
 
+  if (oldsym != NULL
+      && Symbol_table::should_override_with_special(oldsym))
+    oldsym->override_with_special(sym);
+
   return sym;
 }
 
@@ -915,13 +936,25 @@ Symbol_table::define_as_constant(const Target* target, const char* name,
 {
   gold_assert(target->get_size() == this->size_);
   if (this->size_ == 32)
-    return this->do_define_as_constant<32>(target, name, version, value,
-                                          symsize, type, binding, visibility,
-                                          nonvis, only_if_ref);
+    {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+      return this->do_define_as_constant<32>(target, name, version, value,
+                                             symsize, type, binding,
+                                             visibility, nonvis, only_if_ref);
+#else
+      gold_unreachable();
+#endif
+    }
   else if (this->size_ == 64)
-    return this->do_define_as_constant<64>(target, name, version, value,
-                                          symsize, type, binding, visibility,
-                                          nonvis, only_if_ref);
+    {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+      return this->do_define_as_constant<64>(target, name, version, value,
+                                             symsize, type, binding,
+                                             visibility, nonvis, only_if_ref);
+#else
+      gold_unreachable();
+#endif
+    }
   else
     gold_unreachable();
 }
@@ -943,14 +976,15 @@ Symbol_table::do_define_as_constant(
     bool only_if_ref)
 {
   Sized_symbol<size>* sym;
+  Sized_symbol<size>* oldsym;
 
   if (target->is_big_endian())
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, true) (
-        target, name, version, only_if_ref
+        target, name, version, only_if_ref, &oldsym
         SELECT_SIZE_ENDIAN(size, true));
   else
     sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, name, version, only_if_ref
+        target, name, version, only_if_ref, &oldsym
         SELECT_SIZE_ENDIAN(size, false));
 
   if (sym == NULL)
@@ -958,6 +992,10 @@ Symbol_table::do_define_as_constant(
 
   sym->init(name, value, symsize, type, binding, visibility, nonvis);
 
+  if (oldsym != NULL
+      && Symbol_table::should_override_with_special(oldsym))
+    oldsym->override_with_special(sym);
+
   return sym;
 }
 
index 816afb3884a8380053882a8c53fbed1124cff834..534ee0d9fae3b37f5ea1598bc3d0d21efcfede6b 100644 (file)
@@ -404,6 +404,10 @@ class Symbol
   override_base(const elfcpp::Sym<size, big_endian>&, Object* object,
                const char* version);
 
+  // Override existing symbol with a special symbol.
+  void
+  override_base_with_special(const Symbol* from);
+
  private:
   Symbol(const Symbol&);
   Symbol& operator=(const Symbol&);
@@ -549,6 +553,10 @@ class Sized_symbol : public Symbol
   override(const elfcpp::Sym<size, big_endian>&, Object* object,
           const char* version);
 
+  // Override existing symbol with a special symbol.
+  void
+  override_with_special(const Sized_symbol<size>*);
+
   // Return the symbol's value.
   Value_type
   value() const
@@ -905,12 +913,22 @@ class Symbol_table
   resolve(Sized_symbol<size>* to, const Sized_symbol<size>* from,
           const char* version ACCEPT_SIZE_ENDIAN);
 
+  // Whether we should override a symbol, based on flags in
+  // resolve.cc.
+  static bool
+  should_override(const Symbol*, unsigned int, bool*);
+
+  // Whether we should override a symbol with a special symbol which
+  // is automatically defined by the linker.
+  static bool
+  should_override_with_special(const Symbol*);
+
   // Define a special symbol.
   template<int size, bool big_endian>
   Sized_symbol<size>*
   define_special_symbol(const Target* target, const char* name,
-                       const char* version, bool only_if_ref
-                       ACCEPT_SIZE_ENDIAN);
+                       const char* version, bool only_if_ref,
+                       Sized_symbol<size>** poldsym ACCEPT_SIZE_ENDIAN);
 
   // Define a symbol in an Output_data, sized version.
   template<int size>