aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog32
-rw-r--r--gold/Makefile.am2
-rw-r--r--gold/Makefile.in19
-rw-r--r--gold/copy-relocs.cc235
-rw-r--r--gold/copy-relocs.h152
-rw-r--r--gold/i386.cc118
-rw-r--r--gold/output.h18
-rw-r--r--gold/reloc-types.h8
-rw-r--r--gold/reloc.cc217
-rw-r--r--gold/reloc.h96
-rw-r--r--gold/sparc.cc119
-rw-r--r--gold/x86_64.cc118
12 files changed, 515 insertions, 619 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 30f34ef..4d1a250 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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.
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 148999d..020fd95 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -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 \
diff --git a/gold/Makefile.in b/gold/Makefile.in
index 4ca4468..5c73e4b 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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
index 0000000..1e9705e
--- /dev/null
+++ b/gold/copy-relocs.cc
@@ -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
index 0000000..b7d0f5f
--- /dev/null
+++ b/gold/copy-relocs.h
@@ -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)
diff --git a/gold/i386.cc b/gold/i386.cc
index d49350a..917ec0b 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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.
diff --git a/gold/output.h b/gold/output.h
index 81685e2..4772cb4a 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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.
diff --git a/gold/reloc-types.h b/gold/reloc-types.h
index c521843..f13e64a 100644
--- a/gold/reloc-types.h
+++ b/gold/reloc-types.h
@@ -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)
diff --git a/gold/reloc.cc b/gold/reloc.cc
index c94aa9b..99a736b 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -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
@@ -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
diff --git a/gold/reloc.h b/gold/reloc.h
index 537738c..61f05e7 100644
--- a/gold/reloc.h
+++ b/gold/reloc.h
@@ -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.
diff --git a/gold/sparc.cc b/gold/sparc.cc
index e293ea1..68c3cb7 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -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.
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 105f770..6fea4e3 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -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.