This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: gold bug combining .bss sections...


David Miller <davem@davemloft.net> writes:

>> >> > If, for example, we have a normal .bss in the final link with only a
>> >> > necessary alignment of 4, and we also have a dynbss .bss with a copy
>> >> > reloc needing an alignment of 8, gold outputs the final combined .bss
>> >> > section with only an alignment of 4.
>> >> 
>> >> I just committed this patch which I think should fix this problem.
>> >
>> > Unfortunately it does not.  (I remembered to remove the
>> > .bss alignment hack in my sparc copy reloc function before
>> > testing).
>> 
>> Hmmmm, well, it does seem to fix it in the limited sense that the
>> alignment of the .bss section in two_file_shared_2_test is 8, whereas
>> you indicated that it was previously 4.  That is, I suspect that now
>> something else is failing.
>> 
>> Since I don't have easy access to a SPARC system, how does the new
>> binary fail?
>
> t17data is not 8 byte aligned, so we take a SIGBUS.
>
> t17data is a copy reloc which needs to be 8 byte aligned
> but it isn't.
>
> Perhaps when the various .bss section data are combined, things that
> were aligned end up not being so.


Looking into this I was reminded of the ugly duplication of the copy
reloc handling, so I rewrote the copy reloc support.

I reworked the way we determine the alignment of copied symbols.  Let
me know if this still fails on SPARC.

I committed the patch below.

Ian


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.


Index: Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/Makefile.am,v
retrieving revision 1.34
diff -p -u -r1.34 Makefile.am
--- Makefile.am	15 Apr 2008 05:16:51 -0000	1.34
+++ Makefile.am	16 Apr 2008 22:46:44 -0000
@@ -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: copy-relocs.cc
===================================================================
RCS file: copy-relocs.cc
diff -N copy-relocs.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ copy-relocs.cc	16 Apr 2008 22:46:44 -0000
@@ -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.
Index: copy-relocs.h
===================================================================
RCS file: copy-relocs.h
diff -N copy-relocs.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ copy-relocs.h	16 Apr 2008 22:46:44 -0000
@@ -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: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.69
diff -p -u -r1.69 i386.cc
--- i386.cc	11 Apr 2008 23:37:24 -0000	1.69
+++ i386.cc	16 Apr 2008 22:46:44 -0000
@@ -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<
   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<
             && 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<
   // 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_
   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_glo
 // 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_
           {
             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_
           {
             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
 
   // 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: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.63
diff -p -u -r1.63 output.h
--- output.h	15 Apr 2008 04:06:41 -0000	1.63
+++ output.h	16 Apr 2008 22:46:44 -0000
@@ -1071,6 +1071,24 @@ class Output_data_reloc<elfcpp::SHT_REL,
   { 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: reloc-types.h
===================================================================
RCS file: /cvs/src/src/gold/reloc-types.h,v
retrieving revision 1.4
diff -p -u -r1.4 reloc-types.h
--- reloc-types.h	13 Mar 2008 21:04:21 -0000	1.4
+++ reloc-types.h	16 Apr 2008 22:46:44 -0000
@@ -48,6 +48,10 @@ struct Reloc_types<elfcpp::SHT_REL, size
   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, siz
   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: reloc.cc
===================================================================
RCS file: /cvs/src/src/gold/reloc.cc,v
retrieving revision 1.34
diff -p -u -r1.34 reloc.cc
--- reloc.cc	2 Apr 2008 20:58:21 -0000	1.34
+++ reloc.cc	16 Apr 2008 22:46:44 -0000
@@ -952,144 +952,6 @@ Merged_symbol_value<size>::value_from_ou
     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(
   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
@@ -1307,82 +1168,6 @@ class Symbol_value<64>;
 
 #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>;
 #endif
 
Index: reloc.h
===================================================================
RCS file: /cvs/src/src/gold/reloc.h,v
retrieving revision 1.22
diff -p -u -r1.22 reloc.h
--- reloc.h	13 Mar 2008 21:04:21 -0000	1.22
+++ reloc.h	16 Apr 2008 22:46:44 -0000
@@ -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: sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.2
diff -p -u -r1.2 sparc.cc
--- sparc.cc	15 Apr 2008 21:41:29 -0000	1.2
+++ sparc.cc	16 Apr 2008 22:46:45 -0000
@@ -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
   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
 
   // 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
   // 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_
   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::un
 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::gl
 	  {
 	    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::gl
           {
             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_final
 
   // 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: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.62
diff -p -u -r1.62 x86_64.cc
--- x86_64.cc	11 Apr 2008 23:37:24 -0000	1.62
+++ x86_64.cc	16 Apr 2008 22:46:45 -0000
@@ -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_targe
   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_targe
             && 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_targe
   // 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(Symbo
   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_g
 // 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 Genera
           {
             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 Genera
           {
             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(Layo
 
   // 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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]