Browse Source
* 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.msnyder-reverse-20080609-branch
12 changed files with 515 additions and 619 deletions
@ -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.
|
|||
@ -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)
|
|||
Loading…
Reference in new issue