diff options
author | Ian Lance Taylor <ian@airs.com> | 2008-04-16 22:54:29 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 2008-04-16 22:54:29 +0000 |
commit | 12c0daef5f792cf27f8d0897794bb32729dc370b (patch) | |
tree | a282dbfb5ea5b87e31cd1eb4e61bf04584bcd9f7 | |
parent | 4f4995b6282c41516d0bd895832ced99d799a744 (diff) | |
download | gdb-12c0daef5f792cf27f8d0897794bb32729dc370b.zip gdb-12c0daef5f792cf27f8d0897794bb32729dc370b.tar.gz gdb-12c0daef5f792cf27f8d0897794bb32729dc370b.tar.bz2 |
* 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.
-rw-r--r-- | gold/ChangeLog | 32 | ||||
-rw-r--r-- | gold/Makefile.am | 2 | ||||
-rw-r--r-- | gold/Makefile.in | 19 | ||||
-rw-r--r-- | gold/copy-relocs.cc | 235 | ||||
-rw-r--r-- | gold/copy-relocs.h | 152 | ||||
-rw-r--r-- | gold/i386.cc | 118 | ||||
-rw-r--r-- | gold/output.h | 18 | ||||
-rw-r--r-- | gold/reloc-types.h | 8 | ||||
-rw-r--r-- | gold/reloc.cc | 217 | ||||
-rw-r--r-- | gold/reloc.h | 96 | ||||
-rw-r--r-- | gold/sparc.cc | 119 | ||||
-rw-r--r-- | gold/x86_64.cc | 118 |
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. |