Full support for --sysroot.
[binutils-gdb.git] / gold / symtab.cc
index a6e79585a19714e16ff6376f546f27d3df59dabc..c9ac1c9a82579fcdaea701153d5129b2d16c7940 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>
@@ -167,10 +187,43 @@ Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
   this->symsize_ = symsize;
 }
 
+// Return true if the final value of this symbol is known at link
+// time.
+
+bool
+Symbol::final_value_is_known() const
+{
+  // If we are not generating an executable, then no final values are
+  // known, since they will change at runtime.
+  if (!parameters->output_is_executable())
+    return false;
+
+  // If the symbol is not from an object file, then it is defined, and
+  // known.
+  if (this->source_ != FROM_OBJECT)
+    return true;
+
+  // If the symbol is from a dynamic object, then the final value is
+  // not known.
+  if (this->object()->is_dynamic())
+    return false;
+
+  // If the symbol is not undefined (it is defined or common), then
+  // the final value is known.
+  if (!this->is_undefined())
+    return true;
+
+  // If the symbol is undefined, then whether the final value is known
+  // depends on whether we are doing a static link.  If we are doing a
+  // dynamic link, then the final value could be filled in at runtime.
+  // This could reasonably be the case for a weak undefined symbol.
+  return parameters->doing_static_link();
+}
+
 // Class Symbol_table.
 
 Symbol_table::Symbol_table()
-  : size_(0), saw_undefined_(0), offset_(0), table_(), namepool_(),
+  : saw_undefined_(0), offset_(0), table_(), namepool_(),
     forwarders_(), commons_(), warnings_()
 {
 }
@@ -447,16 +500,8 @@ Symbol_table::add_from_relobj(
     size_t sym_name_size,
     Symbol** sympointers)
 {
-  // We take the size from the first object we see.
-  if (this->get_size() == 0)
-    this->set_size(size);
-
-  if (size != this->get_size() || size != relobj->target()->get_size())
-    {
-      fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
-             program_name, relobj->name().c_str());
-      gold_exit(false);
-    }
+  gold_assert(size == relobj->target()->get_size());
+  gold_assert(size == parameters->get_size());
 
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
 
@@ -544,16 +589,8 @@ Symbol_table::add_from_dynobj(
     size_t versym_size,
     const std::vector<const char*>* version_map)
 {
-  // We take the size from the first object we see.
-  if (this->get_size() == 0)
-    this->set_size(size);
-
-  if (size != this->get_size() || size != dynobj->target()->get_size())
-    {
-      fprintf(stderr, _("%s: %s: mixing 32-bit and 64-bit ELF objects\n"),
-             program_name, dynobj->name().c_str());
-      gold_exit(false);
-    }
+  gold_assert(size == dynobj->target()->get_size());
+  gold_assert(size == parameters->get_size());
 
   if (versym != NULL && versym_size / 2 < count)
     {
@@ -676,8 +713,6 @@ Symbol_table::define_special_symbol(const Target* target, const char** pname,
                                     Sized_symbol<size>** poldsym
                                     ACCEPT_SIZE_ENDIAN)
 {
-  gold_assert(this->size_ == size);
-
   Symbol* oldsym;
   Sized_symbol<size>* sym;
   bool add_to_table = false;
@@ -761,8 +796,7 @@ Symbol_table::define_in_output_data(const Target* target, const char* name,
                                    bool offset_is_from_end,
                                    bool only_if_ref)
 {
-  gold_assert(target->get_size() == this->size_);
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
       return this->do_define_in_output_data<32>(target, name, version, od,
@@ -774,7 +808,7 @@ Symbol_table::define_in_output_data(const Target* target, const char* name,
       gold_unreachable();
 #endif
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
       return this->do_define_in_output_data<64>(target, name, version, od,
@@ -811,7 +845,7 @@ Symbol_table::do_define_in_output_data(
   Sized_symbol<size>* sym;
   Sized_symbol<size>* oldsym;
 
-  if (target->is_big_endian())
+  if (parameters->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) (
@@ -835,7 +869,7 @@ Symbol_table::do_define_in_output_data(
   if (sym == NULL)
     return NULL;
 
-  gold_assert(version == NULL);
+  gold_assert(version == NULL || oldsym != NULL);
   sym->init(name, od, value, symsize, type, binding, visibility, nonvis,
            offset_is_from_end);
 
@@ -858,8 +892,7 @@ Symbol_table::define_in_output_segment(const Target* target, const char* name,
                                       Symbol::Segment_offset_base offset_base,
                                       bool only_if_ref)
 {
-  gold_assert(target->get_size() == this->size_);
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
       return this->do_define_in_output_segment<32>(target, name, version, os,
@@ -870,7 +903,7 @@ Symbol_table::define_in_output_segment(const Target* target, const char* name,
       gold_unreachable();
 #endif
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
       return this->do_define_in_output_segment<64>(target, name, version, os,
@@ -906,19 +939,31 @@ Symbol_table::do_define_in_output_segment(
   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, &oldsym
-        SELECT_SIZE_ENDIAN(size, true));
+  if (parameters->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, &oldsym
+          SELECT_SIZE_ENDIAN(size, true));
+#else
+      gold_unreachable();
+#endif
+    }
   else
-    sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, &name, &version, only_if_ref, &oldsym
-        SELECT_SIZE_ENDIAN(size, false));
+    {
+#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, &oldsym
+          SELECT_SIZE_ENDIAN(size, false));
+#else
+      gold_unreachable();
+#endif
+    }
 
   if (sym == NULL)
     return NULL;
 
-  gold_assert(version == NULL);
+  gold_assert(version == NULL || oldsym != NULL);
   sym->init(name, os, value, symsize, type, binding, visibility, nonvis,
            offset_base);
 
@@ -939,8 +984,7 @@ Symbol_table::define_as_constant(const Target* target, const char* name,
                                 elfcpp::STB binding, elfcpp::STV visibility,
                                 unsigned char nonvis, bool only_if_ref)
 {
-  gold_assert(target->get_size() == this->size_);
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
       return this->do_define_as_constant<32>(target, name, version, value,
@@ -950,7 +994,7 @@ Symbol_table::define_as_constant(const Target* target, const char* name,
       gold_unreachable();
 #endif
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
 #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
       return this->do_define_as_constant<64>(target, name, version, value,
@@ -983,19 +1027,31 @@ Symbol_table::do_define_as_constant(
   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, &oldsym
-        SELECT_SIZE_ENDIAN(size, true));
+  if (parameters->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, &oldsym
+          SELECT_SIZE_ENDIAN(size, true));
+#else
+      gold_unreachable();
+#endif
+    }
   else
-    sym = this->define_special_symbol SELECT_SIZE_ENDIAN_NAME(size, false) (
-        target, &name, &version, only_if_ref, &oldsym
-        SELECT_SIZE_ENDIAN(size, false));
+    {
+#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, &oldsym
+          SELECT_SIZE_ENDIAN(size, false));
+#else
+      gold_unreachable();
+#endif
+    }
 
   if (sym == NULL)
     return NULL;
 
-  gold_assert(version == NULL);
+  gold_assert(version == NULL || oldsym != NULL);
   sym->init(name, value, symsize, type, binding, visibility, nonvis);
 
   if (oldsym != NULL
@@ -1115,10 +1171,22 @@ Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff,
   this->first_dynamic_global_index_ = dyn_global_index;
   this->dynamic_count_ = dyncount;
 
-  if (this->size_ == 32)
-    ret = this->sized_finalize<32>(index, off, pool);
-  else if (this->size_ == 64)
-    ret = this->sized_finalize<64>(index, off, pool);
+  if (parameters->get_size() == 32)
+    {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_32_LITTLE)
+      ret = this->sized_finalize<32>(index, off, pool);
+#else
+      gold_unreachable();
+#endif
+    }
+  else if (parameters->get_size() == 64)
+    {
+#if defined(HAVE_TARGET_64_BIG) || defined(HAVE_TARGET_64_LITTLE)
+      ret = this->sized_finalize<64>(index, off, pool);
+#else
+      gold_unreachable();
+#endif
+    }
   else
     gold_unreachable();
 
@@ -1265,19 +1333,43 @@ void
 Symbol_table::write_globals(const Target* target, const Stringpool* sympool,
                            const Stringpool* dynpool, Output_file* of) const
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (target->is_big_endian())
-       this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->sized_write_globals<32, true>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->sized_write_globals<32, false>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (target->is_big_endian())
-       this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->sized_write_globals<64, true>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->sized_write_globals<64, false>(target, sympool, dynpool, of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -1287,7 +1379,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
@@ -1339,6 +1431,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:
@@ -1357,7 +1450,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
@@ -1393,7 +1487,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;
        }
@@ -1404,7 +1498,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));
        }
     }
@@ -1421,15 +1515,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()));
@@ -1439,24 +1535,47 @@ Symbol_table::sized_write_symbol(Sized_symbol<size>* sym,
 // Write out a section symbol.  Return the update offset.
 
 void
-Symbol_table::write_section_symbol(const Target* target,
-                                  const Output_section *os,
+Symbol_table::write_section_symbol(const Output_section *os,
                                   Output_file* of,
                                   off_t offset) const
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (target->is_big_endian())
-       this->sized_write_section_symbol<32, true>(os, of, offset);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->sized_write_section_symbol<32, true>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_section_symbol<32, false>(os, of, offset);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->sized_write_section_symbol<32, false>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (target->is_big_endian())
-       this->sized_write_section_symbol<64, true>(os, of, offset);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->sized_write_section_symbol<64, true>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write_section_symbol<64, false>(os, of, offset);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->sized_write_section_symbol<64, false>(os, of, offset);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -1526,7 +1645,8 @@ Warnings::note_warnings(Symbol_table* symtab)
            Task_locker_obj<Object> tl(*p->second.object);
            const unsigned char* c;
            off_t len;
-           c = p->second.object->section_contents(p->second.shndx, &len);
+           c = p->second.object->section_contents(p->second.shndx, &len,
+                                                  false);
            p->second.set_text(reinterpret_cast<const char*>(c), len);
          }
        }