Supported Tizen version parsing and verification
[external/binutils.git] / gold / symtab.cc
index 1555de6..56d1e42 100644 (file)
@@ -1,6 +1,6 @@
 // symtab.cc -- the gold symbol table
 
-// Copyright (C) 2006-2017 Free Software Foundation, Inc.
+// Copyright (C) 2006-2019 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -989,8 +989,8 @@ Symbol_table::add_from_object(Object* object,
   // ins.first->second: the value (Symbol*).
   // ins.second: true if new entry was inserted, false if not.
 
-  Sized_symbol<size>* ret;
-  bool was_undefined;
+  Sized_symbol<size>* ret = NULL;
+  bool was_undefined_in_reg;
   bool was_common;
   if (!ins.second)
     {
@@ -998,7 +998,7 @@ Symbol_table::add_from_object(Object* object,
       ret = this->get_sized_symbol<size>(ins.first->second);
       gold_assert(ret != NULL);
 
-      was_undefined = ret->is_undefined();
+      was_undefined_in_reg = ret->is_undefined() && ret->in_reg();
       // Commons from plugins are just placeholders.
       was_common = ret->is_common() && ret->object()->pluginobj() == NULL;
 
@@ -1049,19 +1049,44 @@ Symbol_table::add_from_object(Object* object,
          // it, then change it to NAME/VERSION.
          ret = this->get_sized_symbol<size>(insdefault.first->second);
 
-         was_undefined = ret->is_undefined();
-         // Commons from plugins are just placeholders.
-         was_common = ret->is_common() && ret->object()->pluginobj() == NULL;
-
-         this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx, object,
-                       version, is_default_version);
-          if (parameters->options().gc_sections())
-            this->gc_mark_dyn_syms(ret);
-         ins.first->second = ret;
+         // If the existing symbol already has a version,
+         // don't override it with the new symbol.
+         // This should only happen when the new symbol
+         // is from a shared library.
+         if (ret->version() != NULL)
+           {
+             if (!object->is_dynamic())
+               {
+                 gold_warning(_("%s: conflicting default version definition"
+                                " for %s@@%s"),
+                              object->name().c_str(), name, version);
+                 if (ret->source() == Symbol::FROM_OBJECT)
+                   gold_info(_("%s: %s: previous definition of %s@@%s here"),
+                             program_name,
+                             ret->object()->name().c_str(),
+                             name, ret->version());
+               }
+             ret = NULL;
+             is_default_version = false;
+           }
+         else
+           {
+             was_undefined_in_reg = ret->is_undefined() && ret->in_reg();
+             // Commons from plugins are just placeholders.
+             was_common = (ret->is_common()
+                           && ret->object()->pluginobj() == NULL);
+
+             this->resolve(ret, sym, st_shndx, is_ordinary, orig_st_shndx,
+                           object, version, is_default_version);
+             if (parameters->options().gc_sections())
+               this->gc_mark_dyn_syms(ret);
+             ins.first->second = ret;
+           }
        }
-      else
+
+      if (ret == NULL)
        {
-         was_undefined = false;
+         was_undefined_in_reg = false;
          was_common = false;
 
          Sized_target<size, big_endian>* target =
@@ -1105,9 +1130,10 @@ Symbol_table::add_from_object(Object* object,
        ret->set_is_default();
     }
 
-  // Record every time we see a new undefined symbol, to speed up
-  // archive groups.
-  if (!was_undefined && ret->is_undefined())
+  // Record every time we see a new undefined symbol, to speed up archive
+  // groups. We only care about symbols undefined in regular objects here
+  // because undefined symbols only in dynamic objects should't trigger rescans.
+  if (!was_undefined_in_reg && ret->is_undefined() && ret->in_reg())
     {
       ++this->saw_undefined_;
       if (parameters->options().has_plugins())
@@ -1185,7 +1211,9 @@ Symbol_table::add_from_relobj(
       const char* name = sym_names + st_name;
 
       if (!parameters->options().relocatable()
-         && strcmp (name, "__gnu_lto_slim") == 0)
+         && name[0] == '_'
+         && name[1] == '_'
+         && strcmp (name + (name[2] == '_'), "__gnu_lto_slim") == 0)
         gold_info(_("%s: plugin needed to handle lto object"),
                  relobj->name().c_str());
 
@@ -1759,6 +1787,7 @@ template<int size, bool big_endian>
 Sized_symbol<size>*
 Symbol_table::define_special_symbol(const char** pname, const char** pversion,
                                    bool only_if_ref,
+                                   elfcpp::STV visibility,
                                     Sized_symbol<size>** poldsym,
                                    bool* resolve_oldsym, bool is_forced_local)
 {
@@ -1797,8 +1826,21 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
       oldsym = this->lookup(*pname, *pversion);
       if (oldsym == NULL && is_default_version)
        oldsym = this->lookup(*pname, NULL);
-      if (oldsym == NULL || !oldsym->is_undefined())
+      if (oldsym == NULL)
        return NULL;
+      if (!oldsym->is_undefined())
+       {
+         // Skip if the old definition is from a regular object.
+         if (!oldsym->is_from_dynobj())
+           return NULL;
+
+         // If the symbol has hidden or internal visibility, ignore
+         // definition and reference from a dynamic object.
+         if ((visibility == elfcpp::STV_HIDDEN
+              || visibility == elfcpp::STV_INTERNAL)
+             && !oldsym->in_reg())
+           return NULL;
+       }
 
       *pname = oldsym->name();
       if (is_default_version)
@@ -1856,10 +1898,13 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
          add_to_table = true;
          add_loc = ins.first;
 
-         if (is_default_version && !insdefault.second)
+         if (is_default_version
+             && !insdefault.second
+             && insdefault.first->second->version() == NULL)
            {
              // We are adding NAME/VERSION, and it is the default
-             // version.  We already have an entry for NAME/NULL.
+             // version.  We already have an entry for NAME/NULL
+             // that does not already have a version.
              oldsym = insdefault.first->second;
              *resolve_oldsym = true;
            }
@@ -1973,7 +2018,9 @@ Symbol_table::do_define_in_output_data(
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym,
+                                                   only_if_ref,
+                                                   visibility,
+                                                   &oldsym,
                                                    &resolve_oldsym,
                                                    is_forced_local);
 #else
@@ -1984,7 +2031,9 @@ Symbol_table::do_define_in_output_data(
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    only_if_ref, &oldsym,
+                                                    only_if_ref,
+                                                    visibility,
+                                                    &oldsym,
                                                     &resolve_oldsym,
                                                     is_forced_local);
 #else
@@ -2092,7 +2141,9 @@ Symbol_table::do_define_in_output_segment(
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym,
+                                                   only_if_ref,
+                                                   visibility,
+                                                   &oldsym,
                                                    &resolve_oldsym,
                                                    is_forced_local);
 #else
@@ -2103,7 +2154,9 @@ Symbol_table::do_define_in_output_segment(
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    only_if_ref, &oldsym,
+                                                    only_if_ref,
+                                                    visibility,
+                                                    &oldsym,
                                                     &resolve_oldsym,
                                                     is_forced_local);
 #else
@@ -2209,7 +2262,9 @@ Symbol_table::do_define_as_constant(
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym,
+                                                   only_if_ref,
+                                                   visibility,
+                                                   &oldsym,
                                                    &resolve_oldsym,
                                                    is_forced_local);
 #else
@@ -2220,7 +2275,9 @@ Symbol_table::do_define_as_constant(
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    only_if_ref, &oldsym,
+                                                    only_if_ref,
+                                                    visibility,
+                                                    &oldsym,
                                                     &resolve_oldsym,
                                                     is_forced_local);
 #else
@@ -2447,7 +2504,9 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name)
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   false, &oldsym,
+                                                   false,
+                                                   elfcpp::STV_DEFAULT,
+                                                   &oldsym,
                                                    &resolve_oldsym,
                                                    false);
 #else
@@ -2458,7 +2517,9 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
       sym = this->define_special_symbol<size, false>(&name, &version,
-                                                    false, &oldsym,
+                                                    false,
+                                                    elfcpp::STV_DEFAULT,
+                                                    &oldsym,
                                                     &resolve_oldsym,
                                                     false);
 #else
@@ -2485,8 +2546,6 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
                                 Stringpool* dynpool,
                                 Versions* versions)
 {
-  std::vector<Symbol*> as_needed_sym;
-
   // First process all the symbols which have been forced to be local,
   // as they must appear before all global symbols.
   unsigned int forced_local_count = 0;
@@ -2553,15 +2612,6 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
          syms->push_back(sym);
          dynpool->add(sym->name(), false, NULL);
 
-         // If the symbol is defined in a dynamic object and is
-         // referenced strongly in a regular object, then mark the
-         // dynamic object as needed.  This is used to implement
-         // --as-needed.
-         if (sym->is_from_dynobj()
-             && sym->in_reg()
-             && !sym->is_undef_binding_weak())
-           sym->object()->set_is_needed();
-
          // Record any version information, except those from
          // as-needed libraries not seen to be needed.  Note that the
          // is_needed state for such libraries can change in this loop.
@@ -2572,24 +2622,19 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
                  || sym->object()->is_needed())
                versions->record_version(this, dynpool, sym);
              else
-               as_needed_sym.push_back(sym);
+               {
+                 if (parameters->options().warn_drop_version())
+                   gold_warning(_("discarding version information for "
+                                  "%s@%s, defined in unused shared library %s "
+                                  "(linked with --as-needed)"),
+                                sym->name(), sym->version(),
+                                sym->object()->name().c_str());
+                 sym->clear_version();
+               }
            }
        }
     }
 
-  // Process version information for symbols from as-needed libraries.
-  for (std::vector<Symbol*>::iterator p = as_needed_sym.begin();
-       p != as_needed_sym.end();
-       ++p)
-    {
-      Symbol* sym = *p;
-
-      if (sym->object()->is_needed())
-       versions->record_version(this, dynpool, sym);
-      else
-       sym->clear_version();
-    }
-
   // Finish up the versions.  In some cases this may add new dynamic
   // symbols.
   index = versions->finalize(this, index, syms);