Break out default pbytes argument to read and get_view routines,
[deliverable/binutils-gdb.git] / gold / symtab.cc
index b7f4aaa4ab0e1a605cda380d91113430071fdbc0..8cd55cdaf6ff2cc7323b78954169bbdcf75eaf56 100644 (file)
@@ -1,5 +1,25 @@
 // symtab.cc -- the gold symbol table
 
+// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
 #include "gold.h"
 
 #include <stdint.h>
@@ -666,38 +686,41 @@ 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.  This canonicalizes *PNAME and *PVERSION.
 
 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
+Symbol_table::define_special_symbol(const Target* target, const char** pname,
+                                   const char** pversion, 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);
+      oldsym = this->lookup(*pname, *pversion);
       if (oldsym == NULL || !oldsym->is_undefined())
        return NULL;
-      sym = NULL;
 
-      // Canonicalize NAME and VERSION.
-      name = oldsym->name();
-      version = oldsym->version();
+      *pname = oldsym->name();
+      *pversion = oldsym->version();
     }
   else
     {
       // Canonicalize NAME and VERSION.
       Stringpool::Key name_key;
-      name = this->namepool_.add(name, &name_key);
+      *pname = this->namepool_.add(*pname, &name_key);
 
       Stringpool::Key version_key = 0;
-      if (version != NULL)
-       version = this->namepool_.add(version, &version_key);
+      if (*pversion != NULL)
+       *pversion = this->namepool_.add(*pversion, &version_key);
 
       Symbol* const snull = NULL;
       std::pair<typename Symbol_table_type::iterator, bool> ins =
@@ -710,53 +733,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 +783,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 +829,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 +845,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();
@@ -832,9 +855,14 @@ Symbol_table::do_define_in_output_data(
   if (sym == NULL)
     return NULL;
 
+  gold_assert(version == NULL || oldsym != NULL);
   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 +880,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,22 +924,28 @@ 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)
     return NULL;
 
+  gold_assert(version == NULL || oldsym != NULL);
   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 +961,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,21 +1001,27 @@ 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)
     return NULL;
 
+  gold_assert(version == NULL || oldsym != NULL);
   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;
 }
 
@@ -1243,7 +1307,7 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
 
 template<int size, bool big_endian>
 void
-Symbol_table::sized_write_globals(const Target*,
+Symbol_table::sized_write_globals(const Target* target,
                                  const Stringpool* sympool,
                                  const Stringpool* dynpool,
                                  Output_file* of) const
@@ -1295,6 +1359,7 @@ Symbol_table::sized_write_globals(const Target*,
        }
 
       unsigned int shndx;
+      typename elfcpp::Elf_types<32>::Elf_Addr value = sym->value();
       switch (sym->source())
        {
        case Symbol::FROM_OBJECT:
@@ -1313,7 +1378,8 @@ Symbol_table::sized_write_globals(const Target*,
            Object* symobj = sym->object();
            if (symobj->is_dynamic())
              {
-               // FIXME.
+               if (sym->needs_dynsym_value())
+                 value = target->dynsym_value(sym);
                shndx = elfcpp::SHN_UNDEF;
              }
            else if (in_shndx == elfcpp::SHN_UNDEF
@@ -1349,7 +1415,7 @@ Symbol_table::sized_write_globals(const Target*,
       if (sym_index != -1U)
        {
          this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
-              sym, shndx, sympool, ps
+             sym, sym->value(), shndx, sympool, ps
               SELECT_SIZE_ENDIAN(size, big_endian));
          ps += sym_size;
        }
@@ -1360,7 +1426,7 @@ Symbol_table::sized_write_globals(const Target*,
          gold_assert(dynsym_index < dynamic_count);
          unsigned char* pd = dynamic_view + (dynsym_index * sym_size);
          this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
-              sym, shndx, dynpool, pd
+             sym, value, shndx, dynpool, pd
               SELECT_SIZE_ENDIAN(size, big_endian));
        }
     }
@@ -1377,15 +1443,17 @@ Symbol_table::sized_write_globals(const Target*,
 
 template<int size, bool big_endian>
 void
-Symbol_table::sized_write_symbol(Sized_symbol<size>* sym,
-                                unsigned int shndx,
-                                const Stringpool* pool,
-                                unsigned char* p
-                                 ACCEPT_SIZE_ENDIAN) const
+Symbol_table::sized_write_symbol(
+    Sized_symbol<size>* sym,
+    typename elfcpp::Elf_types<size>::Elf_Addr value,
+    unsigned int shndx,
+    const Stringpool* pool,
+    unsigned char* p
+    ACCEPT_SIZE_ENDIAN) const
 {
   elfcpp::Sym_write<size, big_endian> osym(p);
   osym.put_st_name(pool->get_offset(sym->name()));
-  osym.put_st_value(sym->value());
+  osym.put_st_value(value);
   osym.put_st_size(sym->symsize());
   osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type()));
   osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis()));
This page took 0.030458 seconds and 4 git commands to generate.