gold: Ignore def/ref from a dynamic object for special symbols
[deliverable/binutils-gdb.git] / gold / symtab.cc
index a53f6c93fb472f5f10522c0e2155448df261167a..d1f71e02d0edadb490b1b5fc51a46fba8bd56b35 100644 (file)
@@ -1,6 +1,6 @@
 // symtab.cc -- the gold symbol table
 
-// Copyright (C) 2006-2016 Free Software Foundation, Inc.
+// Copyright (C) 2006-2017 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -47,8 +47,8 @@ namespace gold
 
 // Class Symbol.
 
-// Initialize fields in Symbol.  This initializes everything except u_
-// and source_.
+// Initialize fields in Symbol.  This initializes everything except
+// u1_, u2_ and source_.
 
 void
 Symbol::init_fields(const char* name, const char* version,
@@ -80,6 +80,8 @@ Symbol::init_fields(const char* name, const char* version,
   this->undef_binding_set_ = false;
   this->undef_binding_weak_ = false;
   this->is_predefined_ = false;
+  this->is_protected_ = false;
+  this->non_zero_localentry_ = false;
 }
 
 // Return the demangled version of the symbol's name, but only
@@ -118,8 +120,8 @@ Symbol::init_base_object(const char* name, const char* version, Object* object,
 {
   this->init_fields(name, version, sym.get_st_type(), sym.get_st_bind(),
                    sym.get_st_visibility(), sym.get_st_nonvis());
-  this->u_.from_object.object = object;
-  this->u_.from_object.shndx = st_shndx;
+  this->u1_.object = object;
+  this->u2_.shndx = st_shndx;
   this->is_ordinary_shndx_ = is_ordinary;
   this->source_ = FROM_OBJECT;
   this->in_reg_ = !object->is_dynamic();
@@ -138,8 +140,8 @@ Symbol::init_base_output_data(const char* name, const char* version,
                              bool is_predefined)
 {
   this->init_fields(name, version, type, binding, visibility, nonvis);
-  this->u_.in_output_data.output_data = od;
-  this->u_.in_output_data.offset_is_from_end = offset_is_from_end;
+  this->u1_.output_data = od;
+  this->u2_.offset_is_from_end = offset_is_from_end;
   this->source_ = IN_OUTPUT_DATA;
   this->in_reg_ = true;
   this->in_real_elf_ = true;
@@ -158,8 +160,8 @@ Symbol::init_base_output_segment(const char* name, const char* version,
                                 bool is_predefined)
 {
   this->init_fields(name, version, type, binding, visibility, nonvis);
-  this->u_.in_output_segment.output_segment = os;
-  this->u_.in_output_segment.offset_base = offset_base;
+  this->u1_.output_segment = os;
+  this->u2_.offset_base = offset_base;
   this->source_ = IN_OUTPUT_SEGMENT;
   this->in_reg_ = true;
   this->in_real_elf_ = true;
@@ -204,8 +206,8 @@ Symbol::allocate_base_common(Output_data* od)
 {
   gold_assert(this->is_common());
   this->source_ = IN_OUTPUT_DATA;
-  this->u_.in_output_data.output_data = od;
-  this->u_.in_output_data.offset_is_from_end = false;
+  this->u1_.output_data = od;
+  this->u2_.offset_is_from_end = false;
 }
 
 // Initialize the fields in Sized_symbol for SYM in OBJECT.
@@ -486,19 +488,19 @@ Symbol::output_section() const
     {
     case FROM_OBJECT:
       {
-       unsigned int shndx = this->u_.from_object.shndx;
+       unsigned int shndx = this->u2_.shndx;
        if (shndx != elfcpp::SHN_UNDEF && this->is_ordinary_shndx_)
          {
-           gold_assert(!this->u_.from_object.object->is_dynamic());
-           gold_assert(this->u_.from_object.object->pluginobj() == NULL);
-           Relobj* relobj = static_cast<Relobj*>(this->u_.from_object.object);
+           gold_assert(!this->u1_.object->is_dynamic());
+           gold_assert(this->u1_.object->pluginobj() == NULL);
+           Relobj* relobj = static_cast<Relobj*>(this->u1_.object);
            return relobj->output_section(shndx);
          }
        return NULL;
       }
 
     case IN_OUTPUT_DATA:
-      return this->u_.in_output_data.output_data->output_section();
+      return this->u1_.output_data->output_section();
 
     case IN_OUTPUT_SEGMENT:
     case IS_CONSTANT:
@@ -525,8 +527,8 @@ Symbol::set_output_section(Output_section* os)
       break;
     case IS_CONSTANT:
       this->source_ = IN_OUTPUT_DATA;
-      this->u_.in_output_data.output_data = os;
-      this->u_.in_output_data.offset_is_from_end = false;
+      this->u1_.output_data = os;
+      this->u2_.offset_is_from_end = false;
       break;
     case IN_OUTPUT_SEGMENT:
     case IS_UNDEFINED:
@@ -544,8 +546,8 @@ Symbol::set_output_segment(Output_segment* os, Segment_offset_base base)
 {
   gold_assert(this->is_predefined_);
   this->source_ = IN_OUTPUT_SEGMENT;
-  this->u_.in_output_segment.output_segment = os;
-  this->u_.in_output_segment.offset_base = base;
+  this->u1_.output_segment = os;
+  this->u2_.offset_base = base;
 }
 
 // Set the symbol to undefined.  This is used for pre-defined
@@ -865,6 +867,9 @@ Symbol_table::define_default_version(Sized_symbol<size>* sym,
       // other is defined in a shared object, then they are different
       // symbols.
 
+      // If the two symbols are from different shared objects,
+      // they are different symbols.
+
       // Otherwise, we just resolve the symbols as though they were
       // the same.
 
@@ -876,6 +881,11 @@ Symbol_table::define_default_version(Sized_symbol<size>* sym,
       else if (pdef->second->visibility() != elfcpp::STV_DEFAULT
               && sym->is_from_dynobj())
        ;
+      else if (pdef->second->is_from_dynobj()
+              && sym->is_from_dynobj()
+              && pdef->second->is_defined()
+              && pdef->second->object() != sym->object())
+        ;
       else
        {
          const Sized_symbol<size>* symdef;
@@ -1175,7 +1185,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());
 
@@ -1317,6 +1329,9 @@ Symbol_table::add_from_relobj(
       res = this->add_from_object(relobj, name, name_key, ver, ver_key,
                                  is_default_version, *psym, st_shndx,
                                  is_ordinary, orig_st_shndx);
+
+      if (res == NULL)
+       continue;
       
       if (is_forced_local)
        this->force_local(res);
@@ -1398,6 +1413,9 @@ Symbol_table::add_from_pluginobj(
                              is_default_version, *sym, st_shndx,
                              is_ordinary, st_shndx);
 
+  if (res == NULL)
+    return NULL;
+
   if (is_forced_local)
     this->force_local(res);
 
@@ -1594,6 +1612,9 @@ Symbol_table::add_from_dynobj(
            }
        }
 
+      if (res == NULL)
+       continue;
+
       // Note that it is possible that RES was overridden by an
       // earlier object, in which case it can't be aliased here.
       if (st_shndx != elfcpp::SHN_UNDEF
@@ -1603,6 +1624,13 @@ Symbol_table::add_from_dynobj(
          && res->object() == dynobj)
        object_symbols.push_back(res);
 
+      // If the symbol has protected visibility in the dynobj,
+      // mark it as such if it was not overridden.
+      if (res->source() == Symbol::FROM_OBJECT
+          && res->object() == dynobj
+          && sym.get_st_visibility() == elfcpp::STV_PROTECTED)
+        res->set_is_protected();
+
       if (sympointers != NULL)
        (*sympointers)[i] = res;
     }
@@ -1625,7 +1653,6 @@ Symbol_table::add_from_incrobj(
 
   Stringpool::Key ver_key = 0;
   bool is_default_version = false;
-  bool is_forced_local = false;
 
   Stringpool::Key name_key;
   name = this->namepool_.add(name, true, &name_key);
@@ -1635,9 +1662,6 @@ Symbol_table::add_from_incrobj(
                              is_default_version, *sym, st_shndx,
                              is_ordinary, st_shndx);
 
-  if (is_forced_local)
-    this->force_local(res);
-
   return res;
 }
 
@@ -1737,8 +1761,9 @@ 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* resolve_oldsym, bool is_forced_local)
 {
   *resolve_oldsym = false;
   *poldsym = NULL;
@@ -1747,7 +1772,7 @@ Symbol_table::define_special_symbol(const char** pname, const char** pversion,
   // the version script.
   std::string v;
   bool is_default_version = false;
-  if (*pversion == NULL)
+  if (!is_forced_local && *pversion == NULL)
     {
       bool is_global;
       if (this->version_script_.get_symbol_version(*pname, &v, &is_global))
@@ -1775,8 +1800,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)
@@ -1945,13 +1983,17 @@ Symbol_table::do_define_in_output_data(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
   bool resolve_oldsym;
+  const bool is_forced_local = binding == elfcpp::STB_LOCAL;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym,
-                                                   &resolve_oldsym);
+                                                   only_if_ref,
+                                                   visibility,
+                                                   &oldsym,
+                                                   &resolve_oldsym,
+                                                   is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -1960,8 +2002,11 @@ 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,
-                                                    &resolve_oldsym);
+                                                    only_if_ref,
+                                                    visibility,
+                                                    &oldsym,
+                                                    &resolve_oldsym,
+                                                    is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -1976,8 +2021,7 @@ Symbol_table::do_define_in_output_data(
 
   if (oldsym == NULL)
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(sym);
       else if (version != NULL)
        sym->set_is_default();
@@ -1992,8 +2036,7 @@ Symbol_table::do_define_in_output_data(
   else
     {
       if (defined == PREDEFINED
-         && (binding == elfcpp::STB_LOCAL
-             || this->version_script_.symbol_is_local(name)))
+         && (is_forced_local || this->version_script_.symbol_is_local(name)))
        this->force_local(oldsym);
       delete sym;
       return oldsym;
@@ -2063,13 +2106,17 @@ Symbol_table::do_define_in_output_segment(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
   bool resolve_oldsym;
+  const bool is_forced_local = binding == elfcpp::STB_LOCAL;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym,
-                                                   &resolve_oldsym);
+                                                   only_if_ref,
+                                                   visibility,
+                                                   &oldsym,
+                                                   &resolve_oldsym,
+                                                   is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2078,8 +2125,11 @@ 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,
-                                                    &resolve_oldsym);
+                                                    only_if_ref,
+                                                    visibility,
+                                                    &oldsym,
+                                                    &resolve_oldsym,
+                                                    is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2094,8 +2144,7 @@ Symbol_table::do_define_in_output_segment(
 
   if (oldsym == NULL)
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(sym);
       else if (version != NULL)
        sym->set_is_default();
@@ -2109,8 +2158,7 @@ Symbol_table::do_define_in_output_segment(
     return sym;
   else
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(oldsym);
       delete sym;
       return oldsym;
@@ -2179,13 +2227,17 @@ Symbol_table::do_define_as_constant(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
   bool resolve_oldsym;
+  const bool is_forced_local = binding == elfcpp::STB_LOCAL;
 
   if (parameters->target().is_big_endian())
     {
 #if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
       sym = this->define_special_symbol<size, true>(&name, &version,
-                                                   only_if_ref, &oldsym,
-                                                   &resolve_oldsym);
+                                                   only_if_ref,
+                                                   visibility,
+                                                   &oldsym,
+                                                   &resolve_oldsym,
+                                                   is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2194,8 +2246,11 @@ 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,
-                                                    &resolve_oldsym);
+                                                    only_if_ref,
+                                                    visibility,
+                                                    &oldsym,
+                                                    &resolve_oldsym,
+                                                    is_forced_local);
 #else
       gold_unreachable();
 #endif
@@ -2214,8 +2269,7 @@ Symbol_table::do_define_as_constant(
       if ((version == NULL
           || name != version
           || value != 0)
-         && (binding == elfcpp::STB_LOCAL
-             || this->version_script_.symbol_is_local(name)))
+         && (is_forced_local || this->version_script_.symbol_is_local(name)))
        this->force_local(sym);
       else if (version != NULL
               && (name != version || value != 0))
@@ -2231,8 +2285,7 @@ Symbol_table::do_define_as_constant(
     return sym;
   else
     {
-      if (binding == elfcpp::STB_LOCAL
-         || this->version_script_.symbol_is_local(name))
+      if (is_forced_local || this->version_script_.symbol_is_local(name))
        this->force_local(oldsym);
       delete sym;
       return oldsym;
@@ -2422,8 +2475,11 @@ 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,
-                                                   &resolve_oldsym);
+                                                   false,
+                                                   elfcpp::STV_DEFAULT,
+                                                   &oldsym,
+                                                   &resolve_oldsym,
+                                                   false);
 #else
       gold_unreachable();
 #endif
@@ -2432,8 +2488,11 @@ 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,
-                                                    &resolve_oldsym);
+                                                    false,
+                                                    elfcpp::STV_DEFAULT,
+                                                    &oldsym,
+                                                    &resolve_oldsym,
+                                                    false);
 #else
       gold_unreachable();
 #endif
@@ -2447,18 +2506,42 @@ Symbol_table::add_undefined_symbol_from_command_line(const char* name)
 }
 
 // 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
-// updated dynamic symbol index.
+// global dynamic symbol.  Pointers to the global symbols are stored
+// into the vector SYMS.  The names are added to DYNPOOL.
+// This returns an updated dynamic symbol index.
 
 unsigned int
 Symbol_table::set_dynsym_indexes(unsigned int index,
+                                unsigned int* pforced_local_count,
                                 std::vector<Symbol*>* syms,
                                 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;
+  for (Forced_locals::iterator p = this->forced_locals_.begin();
+       p != this->forced_locals_.end();
+       ++p)
+    {
+      Symbol* sym = *p;
+      gold_assert(sym->is_forced_local());
+      if (sym->has_dynsym_index())
+        continue;
+      if (!sym->should_add_dynsym_entry(this))
+       sym->set_dynsym_index(-1U);
+      else
+        {
+          sym->set_dynsym_index(index);
+          ++index;
+          ++forced_local_count;
+         dynpool->add(sym->name(), false, NULL);
+        }
+    }
+  *pforced_local_count = forced_local_count;
+
   // Allow a target to set dynsym indexes.
   if (parameters->target().has_custom_set_dynsym_indexes())
     {
@@ -2468,6 +2551,8 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
            ++p)
         {
           Symbol* sym = p->second;
+          if (sym->is_forced_local())
+           continue;
           if (!sym->should_add_dynsym_entry(this))
             sym->set_dynsym_index(-1U);
           else
@@ -2484,6 +2569,9 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
     {
       Symbol* sym = p->second;
 
+      if (sym->is_forced_local())
+        continue;
+
       // Note that SYM may already have a dynamic symbol index, since
       // some symbols appear more than once in the symbol table, with
       // and without a version.
@@ -2555,7 +2643,12 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
 // Set the final values for all the symbols.  The index of the first
 // global symbol in the output file is *PLOCAL_SYMCOUNT.  Record the
 // file offset OFF.  Add their names to POOL.  Return the new file
-// offset.  Update *PLOCAL_SYMCOUNT if necessary.
+// offset.  Update *PLOCAL_SYMCOUNT if necessary.  DYNOFF and
+// DYN_GLOBAL_INDEX refer to the start of the symbols that will be
+// written from the global symbol table in Symtab::write_globals(),
+// which will include forced-local symbols.  DYN_GLOBAL_INDEX is
+// not necessarily the same as the sh_info field for the .dynsym
+// section, which will point to the first real global symbol.
 
 off_t
 Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index,
@@ -3090,12 +3183,23 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
            // In object files symbol values are section
            // relative.
            if (parameters->options().relocatable())
-             sym_value -= od->address();
+             {
+               Output_section* os = od->output_section();
+               gold_assert(os != NULL);
+               sym_value -= os->address();
+             }
          }
          break;
 
        case Symbol::IN_OUTPUT_SEGMENT:
-         shndx = elfcpp::SHN_ABS;
+         {
+           Output_segment* oseg = sym->output_segment();
+           Output_section* osect = oseg->first_section();
+           if (osect == NULL)
+             shndx = elfcpp::SHN_ABS;
+           else
+             shndx = osect->out_shndx();
+         }
          break;
 
        case Symbol::IS_CONSTANT:
@@ -3817,6 +3921,21 @@ Sized_symbol<32>::init_output_data(const char* name, const char* version,
                                   unsigned char nonvis,
                                   bool offset_is_from_end,
                                   bool is_predefined);
+
+template
+void
+Sized_symbol<32>::init_constant(const char* name, const char* version,
+                               Value_type value, Size_type symsize,
+                               elfcpp::STT type, elfcpp::STB binding,
+                               elfcpp::STV visibility, unsigned char nonvis,
+                               bool is_predefined);
+
+template
+void
+Sized_symbol<32>::init_undefined(const char* name, const char* version,
+                                Value_type value, elfcpp::STT type,
+                                elfcpp::STB binding, elfcpp::STV visibility,
+                                unsigned char nonvis);
 #endif
 
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
@@ -3830,6 +3949,21 @@ Sized_symbol<64>::init_output_data(const char* name, const char* version,
                                   unsigned char nonvis,
                                   bool offset_is_from_end,
                                   bool is_predefined);
+
+template
+void
+Sized_symbol<64>::init_constant(const char* name, const char* version,
+                               Value_type value, Size_type symsize,
+                               elfcpp::STT type, elfcpp::STB binding,
+                               elfcpp::STV visibility, unsigned char nonvis,
+                               bool is_predefined);
+
+template
+void
+Sized_symbol<64>::init_undefined(const char* name, const char* version,
+                                Value_type value, elfcpp::STT type,
+                                elfcpp::STB binding, elfcpp::STV visibility,
+                                unsigned char nonvis);
 #endif
 
 #ifdef HAVE_TARGET_32_LITTLE
This page took 0.030963 seconds and 4 git commands to generate.