* 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.
This commit is contained in:
parent
4f4995b628
commit
12c0daef5f
@ -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.
|
||||
|
@ -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 \
|
||||
|
@ -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@
|
||||
|
235
gold/copy-relocs.cc
Normal file
235
gold/copy-relocs.cc
Normal file
@ -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.
|
152
gold/copy-relocs.h
Normal file
152
gold/copy-relocs.h
Normal file
@ -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)
|
118
gold/i386.cc
118
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.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
217
gold/reloc.cc
217
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
|
||||
@ -1305,82 +1166,6 @@ template
|
||||
class Symbol_value<64>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
class Copy_relocs<32, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
class Copy_relocs<32, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
class Copy_relocs<64, false>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
class Copy_relocs<64, true>;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
void
|
||||
Copy_relocs<32, false>::emit<elfcpp::SHT_REL>(
|
||||
Output_data_reloc<elfcpp::SHT_REL, true, 32, false>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
void
|
||||
Copy_relocs<32, true>::emit<elfcpp::SHT_REL>(
|
||||
Output_data_reloc<elfcpp::SHT_REL, true, 32, true>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
void
|
||||
Copy_relocs<64, false>::emit<elfcpp::SHT_REL>(
|
||||
Output_data_reloc<elfcpp::SHT_REL, true, 64, false>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
void
|
||||
Copy_relocs<64, true>::emit<elfcpp::SHT_REL>(
|
||||
Output_data_reloc<elfcpp::SHT_REL, true, 64, true>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
void
|
||||
Copy_relocs<32, false>::emit<elfcpp::SHT_RELA>(
|
||||
Output_data_reloc<elfcpp::SHT_RELA , true, 32, false>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_BIG
|
||||
template
|
||||
void
|
||||
Copy_relocs<32, true>::emit<elfcpp::SHT_RELA>(
|
||||
Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_LITTLE
|
||||
template
|
||||
void
|
||||
Copy_relocs<64, false>::emit<elfcpp::SHT_RELA>(
|
||||
Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_64_BIG
|
||||
template
|
||||
void
|
||||
Copy_relocs<64, true>::emit<elfcpp::SHT_RELA>(
|
||||
Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>*);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TARGET_32_LITTLE
|
||||
template
|
||||
class Track_relocs<32, false>;
|
||||
|
96
gold/reloc.h
96
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.
|
||||
|
119
gold/sparc.cc
119
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.
|
||||
|
118
gold/x86_64.cc
118
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.
|
||||
|
Loading…
Reference in New Issue
Block a user