Fix versions of copied symbols.
authorIan Lance Taylor <iant@google.com>
Mon, 22 Oct 2007 23:08:22 +0000 (23:08 +0000)
committerIan Lance Taylor <iant@google.com>
Mon, 22 Oct 2007 23:08:22 +0000 (23:08 +0000)
gold/dynobj.cc
gold/dynobj.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/resolve.cc
gold/symtab.cc
gold/symtab.h
gold/x86_64.cc

index 2bf2373b846cb493fbe2a27e55a905e55881dd87..499eda70da3d5b702dcb5eddbe57f89f3b3a9f04 100644 (file)
@@ -1190,11 +1190,28 @@ Versions::~Versions()
     delete *p;
 }
 
+// Return the dynamic object which a symbol refers to.
+
+Dynobj*
+Versions::get_dynobj_for_sym(const Symbol_table* symtab,
+                            const Symbol* sym) const
+{
+  if (sym->is_copied_from_dynobj())
+    return symtab->get_copy_source(sym);
+  else
+    {
+      Object* object = sym->object();
+      gold_assert(object->is_dynamic());
+      return static_cast<Dynobj*>(object);
+    }
+}
+
 // Record version information for a symbol going into the dynamic
 // symbol table.
 
 void
 Versions::record_version(const General_options* options,
+                        const Symbol_table* symtab,
                         Stringpool* dynpool, const Symbol* sym)
 {
   gold_assert(!this->is_finalized_);
@@ -1203,7 +1220,7 @@ Versions::record_version(const General_options* options,
   Stringpool::Key version_key;
   const char* version = dynpool->add(sym->version(), false, &version_key);
 
-  if (!sym->is_from_dynobj())
+  if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
     {
       if (parameters->output_is_shared())
         this->add_def(options, sym, version, version_key);
@@ -1211,11 +1228,7 @@ Versions::record_version(const General_options* options,
   else
     {
       // This is a version reference.
-
-      Object* object = sym->object();
-      gold_assert(object->is_dynamic());
-      Dynobj* dynobj = static_cast<Dynobj*>(object);
-
+      Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym);
       this->add_need(dynpool, dynobj->soname(), version, version_key);
     }
 }
@@ -1375,14 +1388,15 @@ Versions::finalize(const Target* target, Symbol_table* symtab,
 // pointers.
 
 unsigned int
-Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
+Versions::version_index(const Symbol_table* symtab, const Stringpool* dynpool,
+                       const Symbol* sym) const
 {
   Stringpool::Key version_key;
   const char* version = dynpool->find(sym->version(), &version_key);
   gold_assert(version != NULL);
 
   Key k;
-  if (!sym->is_from_dynobj())
+  if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
     {
       if (!parameters->output_is_shared())
         return elfcpp::VER_NDX_GLOBAL;
@@ -1390,9 +1404,7 @@ Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
     }
   else
     {
-      Object* object = sym->object();
-      gold_assert(object->is_dynamic());
-      Dynobj* dynobj = static_cast<Dynobj*>(object);
+      Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym);
 
       Stringpool::Key filename_key;
       const char* filename = dynpool->find(dynobj->soname(), &filename_key);
@@ -1412,7 +1424,8 @@ Versions::version_index(const Stringpool* dynpool, const Symbol* sym) const
 
 template<int size, bool big_endian>
 void
-Versions::symbol_section_contents(const Stringpool* dynpool,
+Versions::symbol_section_contents(const Symbol_table* symtab,
+                                 const Stringpool* dynpool,
                                  unsigned int local_symcount,
                                  const std::vector<Symbol*>& syms,
                                  unsigned char** pp,
@@ -1437,7 +1450,7 @@ Versions::symbol_section_contents(const Stringpool* dynpool,
       if (version == NULL)
        version_index = elfcpp::VER_NDX_GLOBAL;
       else
-       version_index = this->version_index(dynpool, *p);
+       version_index = this->version_index(symtab, dynpool, *p);
       elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2,
                                             version_index);
     }
@@ -1561,6 +1574,7 @@ class Sized_dynobj<64, true>;
 template
 void
 Versions::symbol_section_contents<32, false>(
+    const Symbol_table*,
     const Stringpool*,
     unsigned int,
     const std::vector<Symbol*>&,
@@ -1573,6 +1587,7 @@ Versions::symbol_section_contents<32, false>(
 template
 void
 Versions::symbol_section_contents<32, true>(
+    const Symbol_table*,
     const Stringpool*,
     unsigned int,
     const std::vector<Symbol*>&,
@@ -1585,6 +1600,7 @@ Versions::symbol_section_contents<32, true>(
 template
 void
 Versions::symbol_section_contents<64, false>(
+    const Symbol_table*,
     const Stringpool*,
     unsigned int,
     const std::vector<Symbol*>&,
@@ -1597,6 +1613,7 @@ Versions::symbol_section_contents<64, false>(
 template
 void
 Versions::symbol_section_contents<64, true>(
+    const Symbol_table*,
     const Stringpool*,
     unsigned int,
     const std::vector<Symbol*>&,
index e6b0a526b01ab8d74fb16df5b8babab018af7eb9..78caaf9da3063626c88b611423f90c3a46b4a099 100644 (file)
@@ -411,7 +411,8 @@ class Versions
   // SYM is going into the dynamic symbol table and has a version.
   // Record the appropriate version information.
   void
-  record_version(const General_options*, Stringpool*, const Symbol* sym);
+  record_version(const General_options*, const Symbol_table* symtab,
+                Stringpool*, const Symbol* sym);
 
   // Set the version indexes.  DYNSYM_INDEX is the index we should use
   // for the next dynamic symbol.  We add new dynamic symbols to SYMS
@@ -434,7 +435,8 @@ class Versions
   // version section (.gnu.version).
   template<int size, bool big_endian>
   void
-  symbol_section_contents(const Stringpool*, unsigned int local_symcount,
+  symbol_section_contents(const Symbol_table*, const Stringpool*,
+                         unsigned int local_symcount,
                          const std::vector<Symbol*>& syms,
                          unsigned char**, unsigned int*
                           ACCEPT_SIZE_ENDIAN) const;
@@ -472,9 +474,14 @@ class Versions
   add_need(Stringpool*, const char* filename, const char* name,
           Stringpool::Key);
 
+  // Get the dynamic object to use for SYM.
+  Dynobj*
+  get_dynobj_for_sym(const Symbol_table*, const Symbol* sym) const;
+
   // Return the version index to use for SYM.
   unsigned int
-  version_index(const Stringpool*, const Symbol* sym) const;
+  version_index(const Symbol_table*, const Stringpool*,
+               const Symbol* sym) const;
 
   // We keep a hash table mapping canonicalized name/version pairs to
   // a version base.
index 4532bfd09cb29931d73846f3db6e5a2482393e42..26888bfffb499d36924e367d86c963eac5ec6bef 100644 (file)
@@ -649,14 +649,9 @@ Target_i386::copy_reloc(const General_options* options,
       off_t offset = dynbss_size;
       dynbss->set_space_size(dynbss_size + symsize);
 
-      // Define the symbol in the .dynbss section.
-      symtab->define_in_output_data(this, ssym->name(), ssym->version(),
-                                   dynbss, offset, symsize, ssym->type(),
-                                   ssym->binding(), ssym->visibility(),
-                                   ssym->nonvis(), false, false);
+      symtab->define_with_copy_reloc(this, ssym, dynbss, offset);
 
       // Add the COPY reloc.
-      ssym->set_needs_dynsym_entry();
       Reloc_section* rel_dyn = this->rel_dyn_section(layout);
       rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset);
     }
index 727b335097e4ac05638f14e2a1539773e970a605..ae2b23f6e96f47918469cf669f33d1d919e2ac0e 100644 (file)
@@ -578,7 +578,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 
       // Create the version sections.  We can't do this until the
       // dynamic string table is complete.
-      this->create_version_sections(&versions, local_dynamic_count,
+      this->create_version_sections(&versions, symtab, local_dynamic_count,
                                    dynamic_symbols, dynstr);
     }
 
@@ -1214,6 +1214,7 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
 
 void
 Layout::create_version_sections(const Versions* versions,
+                               const Symbol_table* symtab,
                                unsigned int local_symcount,
                                const std::vector<Symbol*>& dynamic_symbols,
                                const Output_section* dynstr)
@@ -1228,7 +1229,7 @@ Layout::create_version_sections(const Versions* versions,
 #ifdef HAVE_TARGET_32_BIG
           this->sized_create_version_sections
               SELECT_SIZE_ENDIAN_NAME(32, true)(
-                  versions, local_symcount, dynamic_symbols, dynstr
+                 versions, symtab, local_symcount, dynamic_symbols, dynstr
                   SELECT_SIZE_ENDIAN(32, true));
 #else
           gold_unreachable();
@@ -1239,7 +1240,7 @@ Layout::create_version_sections(const Versions* versions,
 #ifdef HAVE_TARGET_32_LITTLE
           this->sized_create_version_sections
               SELECT_SIZE_ENDIAN_NAME(32, false)(
-                  versions, local_symcount, dynamic_symbols, dynstr
+                 versions, symtab, local_symcount, dynamic_symbols, dynstr
                   SELECT_SIZE_ENDIAN(32, false));
 #else
           gold_unreachable();
@@ -1253,7 +1254,7 @@ Layout::create_version_sections(const Versions* versions,
 #ifdef HAVE_TARGET_64_BIG
           this->sized_create_version_sections
               SELECT_SIZE_ENDIAN_NAME(64, true)(
-                  versions, local_symcount, dynamic_symbols, dynstr
+                  versions, symtab, local_symcount, dynamic_symbols, dynstr
                   SELECT_SIZE_ENDIAN(64, true));
 #else
           gold_unreachable();
@@ -1264,7 +1265,7 @@ Layout::create_version_sections(const Versions* versions,
 #ifdef HAVE_TARGET_64_LITTLE
           this->sized_create_version_sections
               SELECT_SIZE_ENDIAN_NAME(64, false)(
-                  versions, local_symcount, dynamic_symbols, dynstr
+                  versions, symtab, local_symcount, dynamic_symbols, dynstr
                   SELECT_SIZE_ENDIAN(64, false));
 #else
           gold_unreachable();
@@ -1281,6 +1282,7 @@ template<int size, bool big_endian>
 void
 Layout::sized_create_version_sections(
     const Versions* versions,
+    const Symbol_table* symtab,
     unsigned int local_symcount,
     const std::vector<Symbol*>& dynamic_symbols,
     const Output_section* dynstr
@@ -1294,7 +1296,7 @@ Layout::sized_create_version_sections(
   unsigned char* vbuf;
   unsigned int vsize;
   versions->symbol_section_contents SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
-      &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize
+      symtab, &this->dynpool_, local_symcount, dynamic_symbols, &vbuf, &vsize
       SELECT_SIZE_ENDIAN(size, big_endian));
 
   Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2);
index 441be9448417986ae4a4db0dde05b1013d068853..409290a6bbce2fa8084d718d1913f835ee673c64 100644 (file)
@@ -257,6 +257,7 @@ class Layout
   // Create the version sections.
   void
   create_version_sections(const Versions*,
+                         const Symbol_table*,
                          unsigned int local_symcount,
                          const std::vector<Symbol*>& dynamic_symbols,
                          const Output_section* dynstr);
@@ -264,6 +265,7 @@ class Layout
   template<int size, bool big_endian>
   void
   sized_create_version_sections(const Versions* versions,
+                               const Symbol_table*,
                                unsigned int local_symcount,
                                const std::vector<Symbol*>& dynamic_symbols,
                                const Output_section* dynstr
index 8836a3afed7cf87c5e1c0019a01bfc4e350523c1..7d141c02534c2e0dee0b04d46f8b96e99bc93739 100644 (file)
@@ -620,6 +620,8 @@ Symbol_table::should_override_with_special(const Symbol* to)
 void
 Symbol::override_base_with_special(const Symbol* from)
 {
+  gold_assert(this->name_ == from->name_ || this->has_alias());
+
   this->source_ = from->source_;
   switch (from->source_)
     {
@@ -652,6 +654,20 @@ Symbol::override_base_with_special(const Symbol* from)
 
   // Special symbols are always considered to be regular symbols.
   this->in_reg_ = true;
+
+  if (from->needs_dynsym_entry_)
+    this->needs_dynsym_entry_ = true;
+  if (from->needs_dynsym_value_)
+    this->needs_dynsym_value_ = true;
+
+  // We shouldn't see these flags.  If we do, we need to handle them
+  // somehow.
+  gold_assert(!from->is_target_special_ || this->is_target_special_);
+  gold_assert(!from->is_forwarder_);
+  gold_assert(!from->has_got_offset_);
+  gold_assert(!from->has_plt_offset_);
+  gold_assert(!from->has_warning_);
+  gold_assert(!from->is_copied_from_dynobj_);
 }
 
 // Override a symbol with a special symbol.
index 3eee9be85456b299823f57b9c9db9de07afdbc75..1f120dd190d1bf36be8b1f71d344fe3d345277f4 100644 (file)
@@ -66,6 +66,7 @@ Symbol::init_fields(const char* name, const char* version,
   this->has_got_offset_ = false;
   this->has_plt_offset_ = false;
   this->has_warning_ = false;
+  this->is_copied_from_dynobj_ = false;
 }
 
 // Initialize the fields in the base class Symbol for SYM in OBJECT.
@@ -1223,6 +1224,70 @@ Symbol_table::define_symbols(const Layout* layout, const Target* target,
     }
 }
 
+// Define CSYM using a COPY reloc.  POSD is the Output_data where the
+// symbol should be defined--typically a .dyn.bss section.  VALUE is
+// the offset within POSD.
+
+template<int size>
+void
+Symbol_table::define_with_copy_reloc(const Target* target,
+                                    Sized_symbol<size>* csym,
+                                    Output_data* posd, uint64_t value)
+{
+  gold_assert(csym->is_from_dynobj());
+  gold_assert(!csym->is_copied_from_dynobj());
+  Object* object = csym->object();
+  gold_assert(object->is_dynamic());
+  Dynobj* dynobj = static_cast<Dynobj*>(object);
+
+  // Our copied variable has to override any variable in a shared
+  // library.
+  elfcpp::STB binding = csym->binding();
+  if (binding == elfcpp::STB_WEAK)
+    binding = elfcpp::STB_GLOBAL;
+
+  this->define_in_output_data(target, csym->name(), csym->version(),
+                             posd, value, csym->symsize(),
+                             csym->type(), binding,
+                             csym->visibility(), csym->nonvis(),
+                             false, false);
+
+  csym->set_is_copied_from_dynobj();
+  csym->set_needs_dynsym_entry();
+
+  this->copied_symbol_dynobjs_[csym] = dynobj;
+
+  // We have now defined all aliases, but we have not entered them all
+  // in the copied_symbol_dynobjs_ map.
+  if (csym->has_alias())
+    {
+      Symbol* sym = csym;
+      while (true)
+       {
+         sym = this->weak_aliases_[sym];
+         if (sym == csym)
+           break;
+         gold_assert(sym->output_data() == posd);
+
+         sym->set_is_copied_from_dynobj();
+         this->copied_symbol_dynobjs_[sym] = dynobj;
+       }
+    }
+}
+
+// SYM is defined using a COPY reloc.  Return the dynamic object where
+// the original definition was found.
+
+Dynobj*
+Symbol_table::get_copy_source(const Symbol* sym) const
+{
+  gold_assert(sym->is_copied_from_dynobj());
+  Copied_symbol_dynobjs::const_iterator p =
+    this->copied_symbol_dynobjs_.find(sym);
+  gold_assert(p != this->copied_symbol_dynobjs_.end());
+  return p->second;
+}
+
 // Set the dynamic symbol indexes.  INDEX is the index of the first
 // global dynamic symbol.  Pointers to the symbols are stored into the
 // vector SYMS.  The names are added to DYNPOOL.  This returns an
@@ -1257,7 +1322,7 @@ Symbol_table::set_dynsym_indexes(const General_options* options,
 
          // Record any version information.
          if (sym->version() != NULL)
-           versions->record_version(options, dynpool, sym);
+           versions->record_version(options, this, dynpool, sym);
        }
     }
 
@@ -1901,6 +1966,22 @@ Symbol_table::add_from_dynobj<64, true>(
     const std::vector<const char*>* version_map);
 #endif
 
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<32>(const Target* target,
+                                        Sized_symbol<32>* sym,
+                                        Output_data* posd, uint64_t value);
+#endif
+
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+template
+void
+Symbol_table::define_with_copy_reloc<64>(const Target* target,
+                                        Sized_symbol<64>* sym,
+                                        Output_data* posd, uint64_t value);
+#endif
+
 #ifdef HAVE_TARGET_32_LITTLE
 template
 void
@@ -1933,5 +2014,4 @@ Warnings::issue_warning<64, true>(const Symbol* sym,
                                  size_t relnum, off_t reloffset) const;
 #endif
 
-
 } // End namespace gold.
index f7576b9fd82619255f5f23322bfcb219f0e34432..49ceb7a03235c0404a550d195025c9f4a1e91f79 100644 (file)
@@ -422,6 +422,17 @@ class Symbol
   set_has_warning()
   { this->has_warning_ = true; }
 
+  // Return whether this symbol is defined by a COPY reloc from a
+  // dynamic object.
+  bool
+  is_copied_from_dynobj() const
+  { return this->is_copied_from_dynobj_; }
+
+  // Mark this symbol as defined by a COPY reloc.
+  void
+  set_is_copied_from_dynobj()
+  { this->is_copied_from_dynobj_ = true; }
+
  protected:
   // Instances of this class should always be created at a specific
   // size.
@@ -573,6 +584,9 @@ class Symbol
   bool needs_dynsym_value_ : 1;
   // True if there is a warning for this symbol.
   bool has_warning_ : 1;
+  // True if we are using a COPY reloc for this symbol, so that the
+  // real definition lives in a dynamic object.
+  bool is_copied_from_dynobj_ : 1;
 };
 
 // The parts of a symbol which are size specific.  Using a template
@@ -870,6 +884,14 @@ class Symbol_table
   define_symbols(const Layout*, const Target*, int count,
                 const Define_symbol_in_segment*);  
 
+  // Define SYM using a COPY reloc.  POSD is the Output_data where the
+  // symbol should be defined--typically a .dyn.bss section.  VALUE is
+  // the offset within POSD.
+  template<int size>
+  void
+  define_with_copy_reloc(const Target*, Sized_symbol<size>* sym,
+                        Output_data* posd, uint64_t value);
+
   // Look up a symbol.
   Symbol*
   lookup(const char*, const char* version = NULL) const;
@@ -915,6 +937,11 @@ class Symbol_table
                size_t relnum, off_t reloffset) const
   { this->warnings_.issue_warning(sym, relinfo, relnum, reloffset); }
 
+  // SYM is defined using a COPY reloc.  Return the dynamic object
+  // where the original definition was found.
+  Dynobj*
+  get_copy_source(const Symbol* sym) const;
+
   // Set the dynamic symbol indexes.  INDEX is the index of the first
   // global dynamic symbol.  Pointers to the symbols are stored into
   // the vector.  The names are stored into the Stringpool.  This
@@ -1089,55 +1116,52 @@ class Symbol_table
                        Symbol_table_eq> Symbol_table_type;
 
   // The type of the list of common symbols.
-
   typedef std::vector<Symbol*> Commons_type;
 
+  // A map from symbols with COPY relocs to the dynamic objects where
+  // they are defined.
+  typedef Unordered_map<const Symbol*, Dynobj*> Copied_symbol_dynobjs;
+
   // We increment this every time we see a new undefined symbol, for
   // use in archive groups.
   int saw_undefined_;
-
   // The index of the first global symbol in the output file.
   unsigned int first_global_index_;
-
   // The file offset within the output symtab section where we should
   // write the table.
   off_t offset_;
-
   // The number of global symbols we want to write out.
   size_t output_count_;
-
   // The file offset of the global dynamic symbols, or 0 if none.
   off_t dynamic_offset_;
-
   // The index of the first global dynamic symbol.
   unsigned int first_dynamic_global_index_;
-
   // The number of global dynamic symbols, or 0 if none.
   off_t dynamic_count_;
-
   // The symbol hash table.
   Symbol_table_type table_;
-
   // A pool of symbol names.  This is used for all global symbols.
   // Entries in the hash table point into this pool.
   Stringpool namepool_;
-
   // Forwarding symbols.
   Unordered_map<const Symbol*, Symbol*> forwarders_;
-
   // Weak aliases.  A symbol in this list points to the next alias.
   // The aliases point to each other in a circular list.
   Unordered_map<Symbol*, Symbol*> weak_aliases_;
-
   // We don't expect there to be very many common symbols, so we keep
   // a list of them.  When we find a common symbol we add it to this
   // list.  It is possible that by the time we process the list the
   // symbol is no longer a common symbol.  It may also have become a
   // forwarder.
   Commons_type commons_;
-
   // Manage symbol warnings.
   Warnings warnings_;
+  // When we emit a COPY reloc for a symbol, we define it in an
+  // Output_data.  When it's time to emit version information for it,
+  // we need to know the dynamic object in which we found the original
+  // definition.  This maps symbols with COPY relocs to the dynamic
+  // object where they were defined.
+  Copied_symbol_dynobjs copied_symbol_dynobjs_;
 };
 
 // We inline get_sized_symbol for efficiency.
index b6a8a4a2a7775ebfb5476dd80e9960f271be39e0..0af7a16483c131735234a3ffd9a4105907497494 100644 (file)
@@ -621,14 +621,9 @@ Target_x86_64::copy_reloc(const General_options* options,
       off_t offset = dynbss_size;
       dynbss->set_space_size(dynbss_size + symsize);
 
-      // Define the symbol in the .dynbss section.
-      symtab->define_in_output_data(this, ssym->name(), ssym->version(),
-                                   dynbss, offset, symsize, ssym->type(),
-                                   ssym->binding(), ssym->visibility(),
-                                   ssym->nonvis(), false, false);
+      symtab->define_with_copy_reloc(this, ssym, dynbss, offset);
 
       // Add the COPY reloc.
-      ssym->set_needs_dynsym_entry();
       Reloc_section* rela_dyn = this->rela_dyn_section(layout);
       rela_dyn->add_global(ssym, elfcpp::R_X86_64_COPY, dynbss, offset, 0);
     }