gold: Ignore def/ref from a dynamic object for special symbols
[deliverable/binutils-gdb.git] / gold / symtab.cc
index 6865190f880d3e4ce027c6b025d281ab5402788a..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,
@@ -81,6 +81,7 @@ Symbol::init_fields(const char* name, const char* version,
   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
@@ -119,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();
@@ -139,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;
@@ -159,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;
@@ -205,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.
@@ -487,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:
@@ -526,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:
@@ -545,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
@@ -1184,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());
 
@@ -1758,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;
@@ -1768,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))
@@ -1796,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)
@@ -1966,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
@@ -1981,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
@@ -1997,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();
@@ -2013,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;
@@ -2084,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
@@ -2099,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
@@ -2115,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();
@@ -2130,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;
@@ -2200,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
@@ -2215,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
@@ -2235,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))
@@ -2252,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;
@@ -2443,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
@@ -2453,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
@@ -2468,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())
     {
@@ -2489,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
@@ -2505,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.
@@ -2576,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,
@@ -3120,7 +3192,14 @@ Symbol_table::sized_write_globals(const Stringpool* sympool,
          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:
This page took 0.029795 seconds and 4 git commands to generate.