* copy-relocs.cc: New file.
authorIan Lance Taylor <ian@airs.com>
Wed, 16 Apr 2008 22:54:29 +0000 (22:54 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 16 Apr 2008 22:54:29 +0000 (22:54 +0000)
* copy-relocs.h: New file.
* reloc.cc: Remove Copy_relocs code.
* reloc.h: Likewise.
* reloc-types.h (struct Reloc_types) [both versions]: Add
get_reloc_addend_noerror.
* output.h (class Output_data_reloc<elfcpp::SHT_REL>): Add
variants of add_global which take an addend which must be zero.
* i386.cc: Include "copy-relocs.h".
(class Target_i386): Change type of copy_relocs_ to variable,
update initializer.
(Target_i386::copy_reloc): Rewrite to pass to Copy_relocs class.
Change all callers.
(Target_i386::do_finalize_sections): Change handling of
copy_relocs_.
* sparc.cc: Include "copy-relocs.h".
(class Target_sparc): Change type of copy_relocs_ to variable,
update initializer.
(Target_sparc::copy_reloc): Rewrite to pass to Copy_relocs class.
Change all callers.
(Target_sparc::do_finalize_sections): Change handling of
copy_relocs_.
* x86_64.cc: Include "copy-relocs.h".
(class Target_x86_64): Change type of copy_relocs_ to variable,
update initializer.
(Target_x86_64::copy_reloc): Rewrite to pass to Copy_relocs
class.  Change all callers.
(Target_x86_64::do_finalize_sections): Change handling of
copy_relocs_.
* Makefile.am (CCFILES): Add copy-relocs.cc.
(HFILES): Add copy-relocs.h.

12 files changed:
gold/ChangeLog
gold/Makefile.am
gold/Makefile.in
gold/copy-relocs.cc [new file with mode: 0644]
gold/copy-relocs.h [new file with mode: 0644]
gold/i386.cc
gold/output.h
gold/reloc-types.h
gold/reloc.cc
gold/reloc.h
gold/sparc.cc
gold/x86_64.cc

index 30f34ef54a0d5eb642787bc8d277445f251f7196..4d1a2505d5a108c48bfb1191dacb0151d18e9b56 100644 (file)
@@ -1,5 +1,37 @@
 2008-04-16  Ian Lance Taylor  <iant@google.com>
 
+       * copy-relocs.cc: New file.
+       * copy-relocs.h: New file.
+       * reloc.cc: Remove Copy_relocs code.
+       * reloc.h: Likewise.
+       * reloc-types.h (struct Reloc_types) [both versions]: Add
+       get_reloc_addend_noerror.
+       * output.h (class Output_data_reloc<elfcpp::SHT_REL>): Add
+       variants of add_global which take an addend which must be zero.
+       * i386.cc: Include "copy-relocs.h".
+       (class Target_i386): Change type of copy_relocs_ to variable,
+       update initializer.
+       (Target_i386::copy_reloc): Rewrite to pass to Copy_relocs class.
+       Change all callers.
+       (Target_i386::do_finalize_sections): Change handling of
+       copy_relocs_.
+       * sparc.cc: Include "copy-relocs.h".
+       (class Target_sparc): Change type of copy_relocs_ to variable,
+       update initializer.
+       (Target_sparc::copy_reloc): Rewrite to pass to Copy_relocs class.
+       Change all callers.
+       (Target_sparc::do_finalize_sections): Change handling of
+       copy_relocs_.
+       * x86_64.cc: Include "copy-relocs.h".
+       (class Target_x86_64): Change type of copy_relocs_ to variable,
+       update initializer.
+       (Target_x86_64::copy_reloc): Rewrite to pass to Copy_relocs
+       class.  Change all callers.
+       (Target_x86_64::do_finalize_sections): Change handling of
+       copy_relocs_.
+       * Makefile.am (CCFILES): Add copy-relocs.cc.
+       (HFILES): Add copy-relocs.h.
+
        * Makefile.in, aclocal.m4, testsuite/Makefile.in: Rebuild.
 
        * testsuite/script_test_4.sh: Permit leading zeroes.
index 148999d39fb3127b8eb7aa5d8b8e5126f2faf35a..020fd9586d50c0a8c4ae6ebd5fa5ab10ccea8be3 100644 (file)
@@ -33,6 +33,7 @@ CCFILES = \
        binary.cc \
        common.cc \
        compressed_output.cc \
+       copy-relocs.cc \
        defstd.cc \
        dirsearch.cc \
        dynobj.cc \
@@ -66,6 +67,7 @@ HFILES = \
        binary.h \
        common.h \
        compressed_output.h \
+       copy-relocs.h \
        defstd.h \
        dirsearch.h \
        dynobj.h \
index 4ca446879a34d43563e897a596b697f31cf83d24..5c73e4b3653ac2edd098586993a6642735ed0b35 100644 (file)
@@ -73,14 +73,14 @@ ARFLAGS = cru
 libgold_a_AR = $(AR) $(ARFLAGS)
 libgold_a_LIBADD =
 am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \
-       compressed_output.$(OBJEXT) defstd.$(OBJEXT) \
-       dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \
-       ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \
-       fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
-       layout.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
-       options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
-       readsyms.$(OBJEXT) reloc.$(OBJEXT) resolve.$(OBJEXT) \
-       script-sections.$(OBJEXT) script.$(OBJEXT) \
+       compressed_output.$(OBJEXT) copy-relocs.$(OBJEXT) \
+       defstd.$(OBJEXT) dirsearch.$(OBJEXT) dynobj.$(OBJEXT) \
+       dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) errors.$(OBJEXT) \
+       expression.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
+       gold-threads.$(OBJEXT) layout.$(OBJEXT) merge.$(OBJEXT) \
+       object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
+       parameters.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \
+       resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
        stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
        version.$(OBJEXT) workqueue.$(OBJEXT) \
        workqueue-threads.$(OBJEXT)
@@ -309,6 +309,7 @@ CCFILES = \
        binary.cc \
        common.cc \
        compressed_output.cc \
+       copy-relocs.cc \
        defstd.cc \
        dirsearch.cc \
        dynobj.cc \
@@ -342,6 +343,7 @@ HFILES = \
        binary.h \
        common.h \
        compressed_output.h \
+       copy-relocs.h \
        defstd.h \
        dirsearch.h \
        dynobj.h \
@@ -511,6 +513,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compressed_output.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy-relocs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_reader.Po@am__quote@
diff --git a/gold/copy-relocs.cc b/gold/copy-relocs.cc
new file mode 100644 (file)
index 0000000..1e9705e
--- /dev/null
@@ -0,0 +1,235 @@
+// copy-relocs.cc -- handle COPY relocations for gold.
+
+// Copyright 2006, 2007, 2008 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 "symtab.h"
+#include "copy-relocs.h"
+
+namespace gold
+{
+
+// Copy_relocs::Copy_reloc_entry methods.
+
+// Emit the reloc if appropriate.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::Copy_reloc_entry::emit(
+    Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+  // If the symbol is no longer defined in a dynamic object, then we
+  // emitted a COPY relocation, and we do not want to emit this
+  // dynamic relocation.
+  if (this->sym_->is_from_dynobj())
+    reloc_section->add_global(this->sym_, this->reloc_type_,
+                             this->output_section_, this->relobj_,
+                             this->shndx_, this->address_,
+                             this->addend_);
+}
+
+// Copy_relocs methods.
+
+// Handle a relocation against a symbol which may force us to generate
+// a COPY reloc.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::copy_reloc(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_symbol<size>* sym,
+    Relobj* object,
+    unsigned int shndx,
+    Output_section *output_section,
+    const Reloc& rel,
+    Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+  if (this->need_copy_reloc(sym, object, shndx))
+    this->emit_copy_reloc(symtab, layout, sym, reloc_section);
+  else
+    {
+      // We may not need a COPY relocation.  Save this relocation to
+      // possibly be emitted later.
+      this->save(sym, object, shndx, output_section, rel);
+    }
+}
+
+// Return whether we need a COPY reloc for a relocation against SYM.
+// The relocation is begin applied to section SHNDX in OBJECT.
+
+template<int sh_type, int size, bool big_endian>
+bool
+Copy_relocs<sh_type, size, big_endian>::need_copy_reloc(
+    Sized_symbol<size>* sym,
+    Relobj* object,
+    unsigned int shndx) const
+{
+  // FIXME: Handle -z nocopyrelocs.
+
+  if (sym->symsize() == 0)
+    return false;
+
+  // If this is a readonly section, then we need a COPY reloc.
+  // Otherwise we can use a dynamic reloc.  Note that calling
+  // section_flags here can be slow, as the information is not cached;
+  // fortunately we shouldn't see too many potential COPY relocs.
+  if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0)
+    return true;
+
+  return false;
+}
+
+// Emit a COPY relocation for SYM.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::emit_copy_reloc(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_symbol<size>* sym,
+    Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+  typename elfcpp::Elf_types<size>::Elf_WXword symsize = sym->symsize();
+
+  // There is no defined way to determine the required alignment of
+  // the symbol.  We know that the symbol is defined in a dynamic
+  // object.  We start with the alignment of the section in which it
+  // is defined; presumably we do not require an alignment larger than
+  // that.  Then we reduce that alignment if the symbol is not aligned
+  // within the section.
+  gold_assert(sym->is_from_dynobj());
+  typename elfcpp::Elf_types<size>::Elf_WXword addralign =
+    sym->object()->section_addralign(sym->shndx());
+
+  typename Sized_symbol<size>::Value_type value = sym->value();
+  while ((value & (addralign - 1)) != 0)
+    addralign >>= 1;
+
+  if (this->dynbss_ == NULL)
+    {
+      this->dynbss_ = new Output_data_space(addralign);
+      layout->add_output_section_data(".bss",
+                                     elfcpp::SHT_NOBITS,
+                                     elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+                                     this->dynbss_);
+    }
+
+  Output_data_space* dynbss = this->dynbss_;
+
+  if (addralign > dynbss->addralign())
+    dynbss->set_space_alignment(addralign);
+
+  section_size_type dynbss_size =
+    convert_to_section_size_type(dynbss->current_data_size());
+  dynbss_size = align_address(dynbss_size, addralign);
+  section_size_type offset = dynbss_size;
+  dynbss->set_current_data_size(dynbss_size + symsize);
+
+  // Define the symbol as being copied.
+  symtab->define_with_copy_reloc(sym, dynbss, offset);
+
+  // Add the COPY relocation to the dynamic reloc section.
+  this->add_copy_reloc(sym, offset, reloc_section);
+}
+
+// Add a COPY relocation for SYM to RELOC_SECTION.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::add_copy_reloc(
+    Symbol* sym,
+    section_size_type offset,
+    Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+  reloc_section->add_global(sym, this->copy_reloc_type_, this->dynbss_,
+                           offset, 0);
+}
+
+// Save a relocation to possibly be emitted later.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::save(Symbol* sym, Relobj* object,
+                                            unsigned int shndx,
+                                            Output_section* output_section,
+                                            const Reloc& rel)
+{
+  unsigned int reloc_type = elfcpp::elf_r_type<size>(rel.get_r_info());
+  typename elfcpp::Elf_types<size>::Elf_Addr addend =
+    Reloc_types<sh_type, size, big_endian>::get_reloc_addend_noerror(&rel);
+  this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, object, shndx,
+                                           output_section, rel.get_r_offset(),
+                                           addend));
+}
+
+// Emit any saved relocs.
+
+template<int sh_type, int size, bool big_endian>
+void
+Copy_relocs<sh_type, size, big_endian>::emit(
+    Output_data_reloc<sh_type, true, size, big_endian>* reloc_section)
+{
+  for (typename Copy_reloc_entries::iterator p = this->entries_.begin();
+       p != this->entries_.end();
+       ++p)
+    p->emit(reloc_section);
+
+  // We no longer need the saved information.
+  this->entries_.clear();
+}
+
+// Instantiate the templates we need.
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Copy_relocs<elfcpp::SHT_REL, 32, false>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Copy_relocs<elfcpp::SHT_REL, 32, true>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Copy_relocs<elfcpp::SHT_REL, 64, false>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Copy_relocs<elfcpp::SHT_REL, 64, true>;
+
+template
+class Copy_relocs<elfcpp::SHT_RELA, 64, true>;
+#endif
+
+} // End namespace gold.
diff --git a/gold/copy-relocs.h b/gold/copy-relocs.h
new file mode 100644 (file)
index 0000000..b7d0f5f
--- /dev/null
@@ -0,0 +1,152 @@
+// copy-relocs.h -- handle COPY relocations for gold   -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 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.
+
+#ifndef GOLD_COPY_RELOCS_H
+#define GOLD_COPY_RELOCS_H
+
+#include "elfcpp.h"
+#include "reloc-types.h"
+#include "output.h"
+
+namespace gold
+{
+
+// This class is used to manage COPY relocations.  We try to avoid
+// them when possible.  A COPY relocation may be required when an
+// executable refers to a variable defined in a shared library.  COPY
+// relocations are problematic because they tie the executable to the
+// exact size of the variable in the shared library.  We can avoid
+// them if all the references to the variable are in a writeable
+// section.  In that case we can simply use dynamic relocations.
+// However, when scanning relocs, we don't know when we see the
+// relocation whether we will be forced to use a COPY relocation or
+// not.  So we have to save the relocation during the reloc scanning,
+// and then emit it as a dynamic relocation if necessary.  This class
+// implements that.  It is used by the target specific code.
+
+// The template parameter SH_TYPE is the type of the reloc section to
+// be used for COPY relocs: elfcpp::SHT_REL or elfcpp::SHT_RELA.
+
+template<int sh_type, int size, bool big_endian>
+class Copy_relocs
+{
+ private:
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reloc;
+
+ public:
+  Copy_relocs(unsigned int copy_reloc_type)
+    : copy_reloc_type_(copy_reloc_type), dynbss_(NULL), entries_()
+  { }
+
+  // This is called while scanning relocs if we see a relocation
+  // against a symbol which may force us to generate a COPY reloc.
+  // SYM is the symbol.  OBJECT is the object whose relocs we are
+  // scanning.  The relocation is being applied to section SHNDX in
+  // OBJECT.  OUTPUT_SECTION is the output section where section SHNDX
+  // will wind up.  REL is the reloc itself.  The Output_data_reloc
+  // section is where the dynamic relocs are put.
+  void
+  copy_reloc(Symbol_table*, Layout*, Sized_symbol<size>* sym, Relobj* object,
+            unsigned int shndx, Output_section* output_section,
+            const Reloc& rel,
+            Output_data_reloc<sh_type, true, size, big_endian>*);
+
+  // Return whether there are any saved relocations.
+  bool
+  any_saved_relocs() const
+  { return !this->entries_.empty(); }
+
+  // Emit any saved relocations which turn out to be needed.  This is
+  // called after all the relocs have been scanned.
+  void
+  emit(Output_data_reloc<sh_type, true, size, big_endian>*);
+
+ private:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
+
+  // This POD class holds the relocations we are saving.  We will emit
+  // these relocations if it turns out that the symbol does not
+  // require a COPY relocation.
+  class Copy_reloc_entry
+  {
+   public:
+    Copy_reloc_entry(Symbol* sym, unsigned int reloc_type,
+                    Relobj* relobj, unsigned int shndx,
+                    Output_section* output_section,
+                    Address address, Addend addend)
+      : sym_(sym), reloc_type_(reloc_type), relobj_(relobj),
+       shndx_(shndx), output_section_(output_section),
+       address_(address), addend_(addend)
+    { }
+
+    // Emit this reloc if appropriate.  This is called after we have
+    // scanned all the relocations, so we know whether we emitted a
+    // COPY relocation for SYM_.
+    void
+    emit(Output_data_reloc<sh_type, true, size, big_endian>*);
+
+   private:
+    Symbol* sym_;
+    unsigned int reloc_type_;
+    Relobj* relobj_;
+    unsigned int shndx_;
+    Output_section* output_section_;
+    Address address_;
+    Addend addend_;
+  };
+
+  // A list of relocs to be saved.
+  typedef std::vector<Copy_reloc_entry> Copy_reloc_entries;
+
+  // Return whether we need a COPY reloc.
+  bool
+  need_copy_reloc(Sized_symbol<size>* gsym, Relobj* object,
+                 unsigned int shndx) const;
+
+  // Emit a COPY reloc.
+  void
+  emit_copy_reloc(Symbol_table*, Layout*, Sized_symbol<size>*,
+                 Output_data_reloc<sh_type, true, size, big_endian>*);
+
+  // Add a COPY reloc to the dynamic reloc section.
+  void
+  add_copy_reloc(Symbol*, section_size_type,
+                Output_data_reloc<sh_type, true, size, big_endian>*);
+
+  // Save a reloc against SYM for possible emission later.
+  void
+  save(Symbol*, Relobj*, unsigned int shndx, Output_section*,
+       const Reloc& rel);
+
+  // The target specific relocation type of the COPY relocation.
+  const unsigned int copy_reloc_type_;
+  // The dynamic BSS data which goes into the .bss section.  This is
+  // where variables which require COPY relocations are placed.
+  Output_data_space* dynbss_;
+  // The list of relocs we are saving.
+  Copy_reloc_entries entries_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_COPY_RELOCS_H)
index d49350acb4572f51b807816c0d25482c79826b36..917ec0b64ac4566192042c704e6425ffc1483b25 100644 (file)
@@ -32,6 +32,7 @@
 #include "symtab.h"
 #include "layout.h"
 #include "output.h"
+#include "copy-relocs.h"
 #include "target.h"
 #include "target-reloc.h"
 #include "target-select.h"
@@ -57,7 +58,8 @@ class Target_i386 : public Sized_target<32, false>
   Target_i386()
     : Sized_target<32, false>(&i386_info),
       got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
-      copy_relocs_(NULL), dynbss_(NULL), got_mod_index_offset_(-1U)
+      copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
+      got_mod_index_offset_(-1U)
   { }
 
   // Scan the relocations to look for symbol adjustments.
@@ -349,11 +351,17 @@ class Target_i386 : public Sized_target<32, false>
             && gsym->type() != elfcpp::STT_FUNC);
   }
 
-  // Copy a relocation against a global symbol.
+  // Add a potential copy relocation.
   void
-  copy_reloc(const General_options*, Symbol_table*, Layout*,
-            Sized_relobj<32, false>*, unsigned int,
-            Output_section*, Symbol*, const elfcpp::Rel<32, false>&);
+  copy_reloc(Symbol_table* symtab, Layout* layout, Relobj* object,
+            unsigned int shndx, Output_section* output_section,
+            Symbol* sym, const elfcpp::Rel<32, false>& reloc)
+  {
+    this->copy_relocs_.copy_reloc(symtab, layout,
+                                 symtab->get_sized_symbol<32>(sym),
+                                 object, shndx, output_section, reloc,
+                                 this->rel_dyn_section(layout));
+  }
 
   // Information about this specific target which we pass to the
   // general Target structure.
@@ -378,7 +386,7 @@ class Target_i386 : public Sized_target<32, false>
   // The dynamic reloc section.
   Reloc_section* rel_dyn_;
   // Relocs saved to avoid a COPY reloc.
-  Copy_relocs<32, false>* copy_relocs_;
+  Copy_relocs<elfcpp::SHT_REL, 32, false> copy_relocs_;
   // Space for variables copied with a COPY reloc.
   Output_data_space* dynbss_;
   // Offset of the GOT entry for the TLS module index.
@@ -731,87 +739,6 @@ Target_i386::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
   return this->got_mod_index_offset_;
 }
 
-// Handle a relocation against a non-function symbol defined in a
-// dynamic object.  The traditional way to handle this is to generate
-// a COPY relocation to copy the variable at runtime from the shared
-// object into the executable's data segment.  However, this is
-// undesirable in general, as if the size of the object changes in the
-// dynamic object, the executable will no longer work correctly.  If
-// this relocation is in a writable section, then we can create a
-// dynamic reloc and the dynamic linker will resolve it to the correct
-// address at runtime.  However, we do not want do that if the
-// relocation is in a read-only section, as it would prevent the
-// readonly segment from being shared.  And if we have to eventually
-// generate a COPY reloc, then any dynamic relocations will be
-// useless.  So this means that if this is a writable section, we need
-// to save the relocation until we see whether we have to create a
-// COPY relocation for this symbol for any other relocation.
-
-void
-Target_i386::copy_reloc(const General_options* options,
-                       Symbol_table* symtab,
-                       Layout* layout,
-                       Sized_relobj<32, false>* object,
-                       unsigned int data_shndx,
-                       Output_section* output_section,
-                       Symbol* gsym,
-                       const elfcpp::Rel<32, false>& rel)
-{
-  Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(gsym);
-
-  if (!Copy_relocs<32, false>::need_copy_reloc(options, object,
-                                              data_shndx, ssym))
-    {
-      // So far we do not need a COPY reloc.  Save this relocation.
-      // If it turns out that we never need a COPY reloc for this
-      // symbol, then we will emit the relocation.
-      if (this->copy_relocs_ == NULL)
-       this->copy_relocs_ = new Copy_relocs<32, false>();
-      this->copy_relocs_->save(ssym, object, data_shndx, output_section, rel);
-    }
-  else
-    {
-      // Allocate space for this symbol in the .bss section.
-
-      elfcpp::Elf_types<32>::Elf_WXword symsize = ssym->symsize();
-
-      // There is no defined way to determine the required alignment
-      // of the symbol.  We pick the alignment based on the size.  We
-      // set an arbitrary maximum of 256.
-      unsigned int align;
-      for (align = 1; align < 512; align <<= 1)
-       if ((symsize & align) != 0)
-         break;
-
-      if (this->dynbss_ == NULL)
-       {
-         this->dynbss_ = new Output_data_space(align);
-         layout->add_output_section_data(".bss",
-                                         elfcpp::SHT_NOBITS,
-                                         (elfcpp::SHF_ALLOC
-                                          | elfcpp::SHF_WRITE),
-                                         this->dynbss_);
-       }
-
-      Output_data_space* dynbss = this->dynbss_;
-
-      if (align > dynbss->addralign())
-       dynbss->set_space_alignment(align);
-
-      section_size_type dynbss_size =
-       convert_to_section_size_type(dynbss->current_data_size());
-      dynbss_size = align_address(dynbss_size, align);
-      section_size_type offset = dynbss_size;
-      dynbss->set_current_data_size(dynbss_size + symsize);
-
-      symtab->define_with_copy_reloc(ssym, dynbss, offset);
-
-      // Add the COPY reloc.
-      Reloc_section* rel_dyn = this->rel_dyn_section(layout);
-      rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset);
-    }
-}
-
 // Optimize the TLS relocation type based on what we know about the
 // symbol.  IS_FINAL is true if the final address of this symbol is
 // known at link time.
@@ -1154,7 +1081,7 @@ Target_i386::Scan::unsupported_reloc_global(Sized_relobj<32, false>* object,
 // Scan a relocation for a global symbol.
 
 inline void
-Target_i386::Scan::global(const General_options& options,
+Target_i386::Scan::global(const General_options&,
                          Symbol_table* symtab,
                          Layout* layout,
                          Target_i386* target,
@@ -1192,7 +1119,7 @@ Target_i386::Scan::global(const General_options& options,
           {
             if (target->may_need_copy_reloc(gsym))
               {
-               target->copy_reloc(&options, symtab, layout, object,
+               target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
               }
             else if (r_type == elfcpp::R_386_32
@@ -1238,7 +1165,7 @@ Target_i386::Scan::global(const General_options& options,
           {
             if (target->may_need_copy_reloc(gsym))
               {
-               target->copy_reloc(&options, symtab, layout, object,
+               target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
               }
             else
@@ -1545,15 +1472,8 @@ Target_i386::do_finalize_sections(Layout* layout)
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
-  if (this->copy_relocs_ == NULL)
-    return;
-  if (this->copy_relocs_->any_to_emit())
-    {
-      Reloc_section* rel_dyn = this->rel_dyn_section(layout);
-      this->copy_relocs_->emit(rel_dyn);
-    }
-  delete this->copy_relocs_;
-  this->copy_relocs_ = NULL;
+  if (this->copy_relocs_.any_saved_relocs())
+    this->copy_relocs_.emit(this->rel_dyn_section(layout));
 }
 
 // Return whether a direct absolute static relocation needs to be applied.
index 81685e2cb343f391d3670474158208775c887fb2..4772cb4aaf9ab3a4c9988f3acbb3ba3150c2b105 100644 (file)
@@ -1071,6 +1071,24 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
                                     false)); }
 
+  // These are to simplify the Copy_relocs class.
+
+  void
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address,
+            Address addend)
+  {
+    gold_assert(addend == 0);
+    this->add_global(gsym, type, od, address);
+  }
+
+  void
+  add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+            unsigned int shndx, Address address, Address addend)
+  {
+    gold_assert(addend == 0);
+    this->add_global(gsym, type, od, relobj, shndx, address);
+  }
+
   // Add a RELATIVE reloc against a global symbol.  The final relocation
   // will not reference the symbol.
 
index c5218435e6acaa05d40119541e186327b38f7c61..f13e64ae273ef23ed464853a0e2da3d79cdb8d8f 100644 (file)
@@ -48,6 +48,10 @@ struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
   get_reloc_addend(const Reloc*)
   { gold_unreachable(); }
 
+  static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+  get_reloc_addend_noerror(const Reloc*)
+  { return 0; }
+
   static inline void
   set_reloc_addend(Reloc_write*,
                   typename elfcpp::Elf_types<size>::Elf_Swxword)
@@ -69,6 +73,10 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
   get_reloc_addend(const Reloc* p)
   { return p->get_r_addend(); }
 
+  static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+  get_reloc_addend_noerror(const Reloc* p)
+  { return p->get_r_addend(); }
+
   static inline void
   set_reloc_addend(Reloc_write* p,
                   typename elfcpp::Elf_types<size>::Elf_Swxword val)
index c94aa9b71690db40bc75f125929d6fe5a8c864e6..99a736bdc95a1933b9a4f5eaef3cae5e4869f5b2 100644 (file)
@@ -952,144 +952,6 @@ Merged_symbol_value<size>::value_from_output_section(
     return this->output_start_address_ + output_offset;
 }
 
-// Copy_relocs::Copy_reloc_entry methods.
-
-// Return whether we should emit this reloc.  We should emit it if the
-// symbol is still defined in a dynamic object.  If we should not emit
-// it, we clear it, to save ourselves the test next time.
-
-template<int size, bool big_endian>
-bool
-Copy_relocs<size, big_endian>::Copy_reloc_entry::should_emit()
-{
-  if (this->sym_ == NULL)
-    return false;
-  if (this->sym_->is_from_dynobj())
-    return true;
-  this->sym_ = NULL;
-  return false;
-}
-
-// Emit a reloc into a SHT_REL section.
-
-template<int size, bool big_endian>
-void
-Copy_relocs<size, big_endian>::Copy_reloc_entry::emit(
-    Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>* reloc_data)
-{
-  this->sym_->set_needs_dynsym_entry();
-  reloc_data->add_global(this->sym_, this->reloc_type_, this->output_section_,
-                         this->relobj_, this->shndx_, this->address_);
-}
-
-// Emit a reloc into a SHT_RELA section.
-
-template<int size, bool big_endian>
-void
-Copy_relocs<size, big_endian>::Copy_reloc_entry::emit(
-    Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>* reloc_data)
-{
-  this->sym_->set_needs_dynsym_entry();
-  reloc_data->add_global(this->sym_, this->reloc_type_, this->output_section_,
-                         this->relobj_, this->shndx_, this->address_,
-                        this->addend_);
-}
-
-// Copy_relocs methods.
-
-// Return whether we need a COPY reloc for a relocation against GSYM.
-// The relocation is being applied to section SHNDX in OBJECT.
-
-template<int size, bool big_endian>
-bool
-Copy_relocs<size, big_endian>::need_copy_reloc(
-    const General_options*,
-    Relobj* object,
-    unsigned int shndx,
-    Sized_symbol<size>* sym)
-{
-  // FIXME: Handle -z nocopyrelocs.
-
-  if (sym->symsize() == 0)
-    return false;
-
-  // If this is a readonly section, then we need a COPY reloc.
-  // Otherwise we can use a dynamic reloc.
-  if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0)
-    return true;
-
-  return false;
-}
-
-// Save a Rel reloc.
-
-template<int size, bool big_endian>
-void
-Copy_relocs<size, big_endian>::save(
-    Symbol* sym,
-    Relobj* relobj,
-    unsigned int shndx,
-    Output_section* output_section,
-    const elfcpp::Rel<size, big_endian>& rel)
-{
-  unsigned int reloc_type = elfcpp::elf_r_type<size>(rel.get_r_info());
-  this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx,
-                                            output_section,
-                                            rel.get_r_offset(), 0));
-}
-
-// Save a Rela reloc.
-
-template<int size, bool big_endian>
-void
-Copy_relocs<size, big_endian>::save(
-    Symbol* sym,
-    Relobj* relobj,
-    unsigned int shndx,
-    Output_section* output_section,
-    const elfcpp::Rela<size, big_endian>& rela)
-{
-  unsigned int reloc_type = elfcpp::elf_r_type<size>(rela.get_r_info());
-  this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, relobj, shndx,
-                                            output_section,
-                                           rela.get_r_offset(),
-                                           rela.get_r_addend()));
-}
-
-// Return whether there are any relocs to emit.  We don't want to emit
-// a reloc if the symbol is no longer defined in a dynamic object.
-
-template<int size, bool big_endian>
-bool
-Copy_relocs<size, big_endian>::any_to_emit()
-{
-  for (typename Copy_reloc_entries::iterator p = this->entries_.begin();
-       p != this->entries_.end();
-       ++p)
-    {
-      if (p->should_emit())
-       return true;
-    }
-  return false;
-}
-
-// Emit relocs.
-
-template<int size, bool big_endian>
-template<int sh_type>
-void
-Copy_relocs<size, big_endian>::emit(
-    Output_data_reloc<sh_type, true, size, big_endian>* reloc_data)
-{
-  for (typename Copy_reloc_entries::iterator p = this->entries_.begin();
-       p != this->entries_.end();
-       ++p)
-    {
-      if (p->should_emit())
-       p->emit(reloc_data);
-    }
-}
-
 // Track_relocs methods.
 
 // Initialize the class to track the relocs.  This gets the object,
@@ -1186,8 +1048,7 @@ Track_relocs<size, big_endian>::advance(off_t offset)
   return ret;
 }
 
-// Instantiate the templates we need.  We could use the configure
-// script to restrict this to only the ones for implemented targets.
+// Instantiate the templates we need.
 
 #ifdef HAVE_TARGET_32_LITTLE
 template
@@ -1305,82 +1166,6 @@ template
 class Symbol_value<64>;
 #endif
 
-#ifdef HAVE_TARGET_32_LITTLE
-template
-class Copy_relocs<32, false>;
-#endif
-
-#ifdef HAVE_TARGET_32_BIG
-template
-class Copy_relocs<32, true>;
-#endif
-
-#ifdef HAVE_TARGET_64_LITTLE
-template
-class Copy_relocs<64, false>;
-#endif
-
-#ifdef HAVE_TARGET_64_BIG
-template
-class Copy_relocs<64, true>;
-#endif
-
-#ifdef HAVE_TARGET_32_LITTLE
-template
-void
-Copy_relocs<32, false>::emit<elfcpp::SHT_REL>(
-    Output_data_reloc<elfcpp::SHT_REL, true, 32, false>*);
-#endif
-
-#ifdef HAVE_TARGET_32_BIG
-template
-void
-Copy_relocs<32, true>::emit<elfcpp::SHT_REL>(
-    Output_data_reloc<elfcpp::SHT_REL, true, 32, true>*);
-#endif
-
-#ifdef HAVE_TARGET_64_LITTLE
-template
-void
-Copy_relocs<64, false>::emit<elfcpp::SHT_REL>(
-    Output_data_reloc<elfcpp::SHT_REL, true, 64, false>*);
-#endif
-
-#ifdef HAVE_TARGET_64_BIG
-template
-void
-Copy_relocs<64, true>::emit<elfcpp::SHT_REL>(
-    Output_data_reloc<elfcpp::SHT_REL, true, 64, true>*);
-#endif
-
-#ifdef HAVE_TARGET_32_LITTLE
-template
-void
-Copy_relocs<32, false>::emit<elfcpp::SHT_RELA>(
-    Output_data_reloc<elfcpp::SHT_RELA , true, 32, false>*);
-#endif
-
-#ifdef HAVE_TARGET_32_BIG
-template
-void
-Copy_relocs<32, true>::emit<elfcpp::SHT_RELA>(
-    Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>*);
-#endif
-
-#ifdef HAVE_TARGET_64_LITTLE
-template
-void
-Copy_relocs<64, false>::emit<elfcpp::SHT_RELA>(
-    Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>*);
-#endif
-
-#ifdef HAVE_TARGET_64_BIG
-template
-void
-Copy_relocs<64, true>::emit<elfcpp::SHT_RELA>(
-    Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>*);
-#endif
-
 #ifdef HAVE_TARGET_32_LITTLE
 template
 class Track_relocs<32, false>;
index 537738c877809ba362d4df5d7775622188b5783d..61f05e78d214b4626be96ba98d5810cd4766e5e6 100644 (file)
@@ -613,102 +613,6 @@ public:
   { This::template pcrela<64>(view, object, psymval, addend, address); }
 };
 
-// We try to avoid COPY relocations when possible.  A COPY relocation
-// may be required when an executable refers to a variable defined in
-// a shared library.  COPY relocations are problematic because they
-// tie the executable to the exact size of the variable in the shared
-// library.  We can avoid them if all the references to the variable
-// are in a writeable section.  In that case we can simply use dynamic
-// relocations.  However, when scanning relocs, we don't know when we
-// see the relocation whether we will be forced to use a COPY
-// relocation or not.  So we have to save the relocation during the
-// reloc scanning, and then emit it as a dynamic relocation if
-// necessary.  This class implements that.  It is used by the target
-// specific code.
-
-template<int size, bool big_endian>
-class Copy_relocs
-{
- public:
-  Copy_relocs()
-    : entries_()
-  { }
-
-  // Return whether we need a COPY reloc for a reloc against GSYM,
-  // which is being applied to section SHNDX in OBJECT.
-  static bool
-  need_copy_reloc(const General_options*, Relobj* object, unsigned int shndx,
-                 Sized_symbol<size>* gsym);
-
-  // Save a Rel against SYM for possible emission later.  SHNDX is the
-  // index of the section to which the reloc is being applied.
-  void
-  save(Symbol* sym, Relobj*, unsigned int shndx,
-       Output_section* output_section, const elfcpp::Rel<size, big_endian>&);
-
-  // Save a Rela against SYM for possible emission later.
-  void
-  save(Symbol* sym, Relobj*, unsigned int shndx,
-       Output_section* output_section, const elfcpp::Rela<size, big_endian>&);
-
-  // Return whether there are any relocs to emit.  This also discards
-  // entries which need not be emitted.
-  bool
-  any_to_emit();
-
-  // Emit relocs for each symbol which did not get a COPY reloc (i.e.,
-  // is still defined in the dynamic object).
-  template<int sh_type>
-  void
-  emit(Output_data_reloc<sh_type, true, size, big_endian>*);
-
- private:
-  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
-  typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
-
-  // This POD class holds the entries we are saving.
-  class Copy_reloc_entry
-  {
-   public:
-    Copy_reloc_entry(Symbol* sym, unsigned int reloc_type,
-                    Relobj* relobj, unsigned int shndx,
-                    Output_section* output_section,
-                    Address address, Addend addend)
-      : sym_(sym), reloc_type_(reloc_type), relobj_(relobj),
-       shndx_(shndx), output_section_(output_section),
-       address_(address), addend_(addend)
-    { }
-
-    // Return whether we should emit this reloc.  If we should not
-    // emit, we clear it.
-    bool
-    should_emit();
-
-    // Emit this reloc.
-
-    void
-    emit(Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>*);
-
-    void
-    emit(Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>*);
-
-   private:
-    Symbol* sym_;
-    unsigned int reloc_type_;
-    Relobj* relobj_;
-    unsigned int shndx_;
-    Output_section* output_section_;
-    Address address_;
-    Addend addend_;
-  };
-
-  // A list of relocs to be saved.
-  typedef std::vector<Copy_reloc_entry> Copy_reloc_entries;
-
-  // The list of relocs we are saving.
-  Copy_reloc_entries entries_;
-};
-
 // Track relocations while reading a section.  This lets you ask for
 // the relocation at a certain offset, and see how relocs occur
 // between points of interest.
index e293ea19c1d617952e9241117b42542dd28fd16b..68c3cb7794a0ee4a42decc6a15b2245ebe5e9e42 100644 (file)
@@ -34,6 +34,7 @@
 #include "symtab.h"
 #include "layout.h"
 #include "output.h"
+#include "copy-relocs.h"
 #include "target.h"
 #include "target-reloc.h"
 #include "target-select.h"
@@ -57,8 +58,8 @@ class Target_sparc : public Sized_target<size, big_endian>
   Target_sparc()
     : Sized_target<size, big_endian>(&sparc_info),
       got_(NULL), plt_(NULL), rela_dyn_(NULL),
-      copy_relocs_(NULL), dynbss_(NULL), got_mod_index_offset_(-1U),
-      tls_get_addr_sym_(NULL)
+      copy_relocs_(elfcpp::R_SPARC_COPY), dynbss_(NULL),
+      got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL)
   {
   }
 
@@ -283,9 +284,15 @@ class Target_sparc : public Sized_target<size, big_endian>
 
   // Copy a relocation against a global symbol.
   void
-  copy_reloc(const General_options*, Symbol_table*, Layout*,
-            Sized_relobj<size, big_endian>*, unsigned int,
-            Output_section*, Symbol*, const elfcpp::Rela<size, big_endian>&);
+  copy_reloc(Symbol_table* symtab, Layout* layout, Relobj* object,
+            unsigned int shndx, Output_section* output_section,
+            Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
+  {
+    this->copy_relocs_.copy_reloc(symtab, layout,
+                                 symtab->get_sized_symbol<size>(sym),
+                                 object, shndx, output_section,
+                                 reloc, this->rela_dyn_section(layout));
+  }
 
   // Information about this specific target which we pass to the
   // general Target structure.
@@ -306,7 +313,7 @@ class Target_sparc : public Sized_target<size, big_endian>
   // The dynamic reloc section.
   Reloc_section* rela_dyn_;
   // Relocs saved to avoid a COPY reloc.
-  Copy_relocs<size, big_endian>* copy_relocs_;
+  Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
   // Space for variables copied with a COPY reloc.
   Output_data_space* dynbss_;
   // Offset of the GOT entry for the TLS module index;
@@ -1365,89 +1372,6 @@ Target_sparc<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
   return this->got_mod_index_offset_;
 }
 
-// Handle a relocation against a non-function symbol defined in a
-// dynamic object.  The traditional way to handle this is to generate
-// a COPY relocation to copy the variable at runtime from the shared
-// object into the executable's data segment.  However, this is
-// undesirable in general, as if the size of the object changes in the
-// dynamic object, the executable will no longer work correctly.  If
-// this relocation is in a writable section, then we can create a
-// dynamic reloc and the dynamic linker will resolve it to the correct
-// address at runtime.  However, we do not want do that if the
-// relocation is in a read-only section, as it would prevent the
-// readonly segment from being shared.  And if we have to eventually
-// generate a COPY reloc, then any dynamic relocations will be
-// useless.  So this means that if this is a writable section, we need
-// to save the relocation until we see whether we have to create a
-// COPY relocation for this symbol for any other relocation.
-
-template<int size, bool big_endian>
-void
-Target_sparc<size, big_endian>::copy_reloc(const General_options* options,
-                                          Symbol_table* symtab,
-                                          Layout* layout,
-                                          Sized_relobj<size, big_endian>* object,
-                                          unsigned int data_shndx,
-                                          Output_section* output_section,
-                                          Symbol* gsym,
-                                          const elfcpp::Rela<size, big_endian>& rel)
-{
-  Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(gsym);
-
-  if (!Copy_relocs<size, big_endian>::need_copy_reloc(options, object,
-                                                     data_shndx, ssym))
-    {
-      // So far we do not need a COPY reloc.  Save this relocation.
-      // If it turns out that we never need a COPY reloc for this
-      // symbol, then we will emit the relocation.
-      if (this->copy_relocs_ == NULL)
-       this->copy_relocs_ = new Copy_relocs<size, big_endian>();
-      this->copy_relocs_->save(ssym, object, data_shndx, output_section, rel);
-    }
-  else
-    {
-      // Allocate space for this symbol in the .bss section.
-
-      typename elfcpp::Elf_types<size>::Elf_WXword symsize = ssym->symsize();
-
-      // There is no defined way to determine the required alignment
-      // of the symbol.  We pick the alignment based on the size.  We
-      // set an arbitrary maximum of 256.
-      unsigned int align;
-      // XXX remove this when bss alignment issue is fixed...
-      for (align = (size == 32 ? 4 : 8); align < 512; align <<= 1)
-       if ((symsize & align) != 0)
-         break;
-
-      if (this->dynbss_ == NULL)
-       {
-         this->dynbss_ = new Output_data_space(align);
-         layout->add_output_section_data(".bss",
-                                         elfcpp::SHT_NOBITS,
-                                         (elfcpp::SHF_ALLOC
-                                          | elfcpp::SHF_WRITE),
-                                         this->dynbss_);
-       }
-
-      Output_data_space* dynbss = this->dynbss_;
-
-      if (align > dynbss->addralign())
-       dynbss->set_space_alignment(align);
-
-      section_size_type dynbss_size =
-       convert_to_section_size_type(dynbss->current_data_size());
-      dynbss_size = align_address(dynbss_size, align);
-      section_size_type offset = dynbss_size;
-      dynbss->set_current_data_size(dynbss_size + symsize);
-
-      symtab->define_with_copy_reloc(ssym, dynbss, offset);
-
-      // Add the COPY reloc.
-      Reloc_section* rela_dyn = this->rela_dyn_section(layout);
-      rela_dyn->add_global(ssym, elfcpp::R_SPARC_COPY, dynbss, offset, 0);
-    }
-}
-
 // Optimize the TLS relocation type based on what we know about the
 // symbol.  IS_FINAL is true if the final address of this symbol is
 // known at link time.
@@ -1831,7 +1755,7 @@ Target_sparc<size, big_endian>::Scan::unsupported_reloc_global(
 template<int size, bool big_endian>
 inline void
 Target_sparc<size, big_endian>::Scan::global(
-                               const General_options& options,
+                               const General_options&,
                                Symbol_table* symtab,
                                Layout* layout,
                                Target_sparc<size, big_endian>* target,
@@ -1899,7 +1823,7 @@ Target_sparc<size, big_endian>::Scan::global(
          {
            if (target->may_need_copy_reloc(gsym))
              {
-               target->copy_reloc(&options, symtab, layout, object,
+               target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym,
                                   reloc);
              }
@@ -1954,7 +1878,7 @@ Target_sparc<size, big_endian>::Scan::global(
           {
             if (target->may_need_copy_reloc(gsym))
               {
-               target->copy_reloc(&options, symtab, layout, object,
+               target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
               }
             else if ((r_type == elfcpp::R_SPARC_32
@@ -2245,15 +2169,8 @@ Target_sparc<size, big_endian>::do_finalize_sections(Layout* layout)
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
-  if (this->copy_relocs_ == NULL)
-    return;
-  if (this->copy_relocs_->any_to_emit())
-    {
-      Reloc_section* rela_dyn = this->rela_dyn_section(layout);
-      this->copy_relocs_->emit(rela_dyn);
-    }
-  delete this->copy_relocs_;
-  this->copy_relocs_ = NULL;
+  if (this->copy_relocs_.any_saved_relocs())
+    this->copy_relocs_.emit(this->rela_dyn_section(layout));
 }
 
 // Perform a relocation.
index 105f77074f1e61ef499894633c7661825ad9c638..6fea4e3837683f86f6a21856acb2455a9e5d6596 100644 (file)
@@ -32,6 +32,7 @@
 #include "symtab.h"
 #include "layout.h"
 #include "output.h"
+#include "copy-relocs.h"
 #include "target.h"
 #include "target-reloc.h"
 #include "target-select.h"
@@ -61,7 +62,8 @@ class Target_x86_64 : public Sized_target<64, false>
   Target_x86_64()
     : Sized_target<64, false>(&x86_64_info),
       got_(NULL), plt_(NULL), got_plt_(NULL), rela_dyn_(NULL),
-      copy_relocs_(NULL), dynbss_(NULL), got_mod_index_offset_(-1U)
+      copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
+      got_mod_index_offset_(-1U)
   { }
 
   // Scan the relocations to look for symbol adjustments.
@@ -354,11 +356,17 @@ class Target_x86_64 : public Sized_target<64, false>
             && gsym->type() != elfcpp::STT_FUNC);
   }
 
-  // Copy a relocation against a global symbol.
+  // Add a potential copy relocation.
   void
-  copy_reloc(const General_options*, Symbol_table*, Layout*,
-            Sized_relobj<64, false>*, unsigned int,
-            Output_section*, Symbol*, const elfcpp::Rela<64, false>&);
+  copy_reloc(Symbol_table* symtab, Layout* layout, Relobj* object,
+            unsigned int shndx, Output_section* output_section,
+            Symbol* sym, const elfcpp::Rela<64, false>& reloc)
+  {
+    this->copy_relocs_.copy_reloc(symtab, layout,
+                                 symtab->get_sized_symbol<64>(sym),
+                                 object, shndx, output_section,
+                                 reloc, this->rela_dyn_section(layout));
+  }
 
   // Information about this specific target which we pass to the
   // general Target structure.
@@ -381,7 +389,7 @@ class Target_x86_64 : public Sized_target<64, false>
   // The dynamic reloc section.
   Reloc_section* rela_dyn_;
   // Relocs saved to avoid a COPY reloc.
-  Copy_relocs<64, false>* copy_relocs_;
+  Copy_relocs<elfcpp::SHT_RELA, 64, false> copy_relocs_;
   // Space for variables copied with a COPY reloc.
   Output_data_space* dynbss_;
   // Offset of the GOT entry for the TLS module index.
@@ -803,87 +811,6 @@ Target_x86_64::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
   return this->got_mod_index_offset_;
 }
 
-// Handle a relocation against a non-function symbol defined in a
-// dynamic object.  The traditional way to handle this is to generate
-// a COPY relocation to copy the variable at runtime from the shared
-// object into the executable's data segment.  However, this is
-// undesirable in general, as if the size of the object changes in the
-// dynamic object, the executable will no longer work correctly.  If
-// this relocation is in a writable section, then we can create a
-// dynamic reloc and the dynamic linker will resolve it to the correct
-// address at runtime.  However, we do not want do that if the
-// relocation is in a read-only section, as it would prevent the
-// readonly segment from being shared.  And if we have to eventually
-// generate a COPY reloc, then any dynamic relocations will be
-// useless.  So this means that if this is a writable section, we need
-// to save the relocation until we see whether we have to create a
-// COPY relocation for this symbol for any other relocation.
-
-void
-Target_x86_64::copy_reloc(const General_options* options,
-                          Symbol_table* symtab,
-                          Layout* layout,
-                          Sized_relobj<64, false>* object,
-                          unsigned int data_shndx,
-                          Output_section* output_section,
-                          Symbol* gsym,
-                          const elfcpp::Rela<64, false>& rela)
-{
-  Sized_symbol<64>* ssym = symtab->get_sized_symbol<64>(gsym);
-
-  if (!Copy_relocs<64, false>::need_copy_reloc(options, object,
-                                              data_shndx, ssym))
-    {
-      // So far we do not need a COPY reloc.  Save this relocation.
-      // If it turns out that we never need a COPY reloc for this
-      // symbol, then we will emit the relocation.
-      if (this->copy_relocs_ == NULL)
-       this->copy_relocs_ = new Copy_relocs<64, false>();
-      this->copy_relocs_->save(ssym, object, data_shndx, output_section, rela);
-    }
-  else
-    {
-      // Allocate space for this symbol in the .bss section.
-
-      elfcpp::Elf_types<64>::Elf_WXword symsize = ssym->symsize();
-
-      // There is no defined way to determine the required alignment
-      // of the symbol.  We pick the alignment based on the size.  We
-      // set an arbitrary maximum of 256.
-      unsigned int align;
-      for (align = 1; align < 512; align <<= 1)
-       if ((symsize & align) != 0)
-         break;
-
-      if (this->dynbss_ == NULL)
-       {
-         this->dynbss_ = new Output_data_space(align);
-         layout->add_output_section_data(".bss",
-                                         elfcpp::SHT_NOBITS,
-                                         (elfcpp::SHF_ALLOC
-                                          | elfcpp::SHF_WRITE),
-                                         this->dynbss_);
-       }
-
-      Output_data_space* dynbss = this->dynbss_;
-
-      if (align > dynbss->addralign())
-       dynbss->set_space_alignment(align);
-
-      section_size_type dynbss_size = dynbss->current_data_size();
-      dynbss_size = align_address(dynbss_size, align);
-      section_size_type offset = dynbss_size;
-      dynbss->set_current_data_size(dynbss_size + symsize);
-
-      symtab->define_with_copy_reloc(ssym, dynbss, offset);
-
-      // Add the COPY reloc.
-      Reloc_section* rela_dyn = this->rela_dyn_section(layout);
-      rela_dyn->add_global(ssym, elfcpp::R_X86_64_COPY, dynbss, offset, 0);
-    }
-}
-
-
 // Optimize the TLS relocation type based on what we know about the
 // symbol.  IS_FINAL is true if the final address of this symbol is
 // known at link time.
@@ -1254,7 +1181,7 @@ Target_x86_64::Scan::unsupported_reloc_global(Sized_relobj<64, false>* object,
 // Scan a relocation for a global symbol.
 
 inline void
-Target_x86_64::Scan::global(const General_options& options,
+Target_x86_64::Scan::global(const General_options&,
                             Symbol_table* symtab,
                             Layout* layout,
                             Target_x86_64* target,
@@ -1294,7 +1221,7 @@ Target_x86_64::Scan::global(const General_options& options,
           {
             if (target->may_need_copy_reloc(gsym))
               {
-                target->copy_reloc(&options, symtab, layout, object,
+                target->copy_reloc(symtab, layout, object,
                                    data_shndx, output_section, gsym, reloc);
               }
             else if (r_type == elfcpp::R_X86_64_64
@@ -1334,7 +1261,7 @@ Target_x86_64::Scan::global(const General_options& options,
           {
             if (target->may_need_copy_reloc(gsym))
               {
-                target->copy_reloc(&options, symtab, layout, object,
+                target->copy_reloc(symtab, layout, object,
                                    data_shndx, output_section, gsym, reloc);
               }
             else
@@ -1633,15 +1560,8 @@ Target_x86_64::do_finalize_sections(Layout* layout)
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
-  if (this->copy_relocs_ == NULL)
-    return;
-  if (this->copy_relocs_->any_to_emit())
-    {
-      Reloc_section* rela_dyn = this->rela_dyn_section(layout);
-      this->copy_relocs_->emit(rela_dyn);
-    }
-  delete this->copy_relocs_;
-  this->copy_relocs_ = NULL;
+  if (this->copy_relocs_.any_saved_relocs())
+    this->copy_relocs_.emit(this->rela_dyn_section(layout));
 }
 
 // Perform a relocation.