// sparc.cc -- sparc target support for gold.
-// Copyright 2008 Free Software Foundation, Inc.
+// Copyright 2008, 2009 Free Software Foundation, Inc.
// Written by David S. Miller <davem@davemloft.net>.
// This file is part of gold.
#include "symtab.h"
#include "layout.h"
#include "output.h"
+#include "copy-relocs.h"
#include "target.h"
#include "target-reloc.h"
#include "target-select.h"
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)
{
}
+ // Process the relocations to determine unreferenced sections for
+ // garbage collection.
+ void
+ gc_process_relocs(const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
+
// Scan the relocations to look for symbol adjustments.
void
scan_relocs(const General_options& options,
section_size_type reloc_view_size);
// Return whether SYM is defined by the ABI.
bool
- do_is_defined_by_abi(Symbol* sym) const
+ do_is_defined_by_abi(const Symbol* sym) const
{
// XXX Really need to support this better...
if (sym->type() == elfcpp::STT_SPARC_REGISTER)
private:
// The class which scans relocations.
- struct Scan
+ class Scan
{
+ public:
+ Scan()
+ : issued_non_pic_error_(false)
+ { }
+
inline void
local(const General_options& options, Symbol_table* symtab,
Layout* layout, Target_sparc* target,
const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
Symbol* gsym);
+ private:
static void
unsupported_reloc_local(Sized_relobj<size, big_endian>*,
unsigned int r_type);
static void
generate_tls_call(Symbol_table* symtab, Layout* layout,
Target_sparc* target);
+
+ void
+ check_non_pic(Relobj*, unsigned int r_type);
+
+ // Whether we have issued an error about a non-PIC compilation.
+ bool issued_non_pic_error_;
};
// The class which implements relocation.
// 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,
+ Sized_relobj<size, big_endian>* 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.
// 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;
this->got_ = new Output_data_got<size, big_endian>();
- layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
- this->got_);
+ Output_section* os;
+ os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_);
+ os->set_is_relro();
// Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
if (this->rela_dyn_ == NULL)
{
gold_assert(layout != NULL);
- this->rela_dyn_ = new Reloc_section();
+ this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->rela_dyn_);
}
protected:
void do_adjust_output_section(Output_section* os);
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
+
private:
// The size of an entry in the PLT.
static const int base_plt_entry_size = (size == 32 ? 12 : 32);
unsigned int count_;
};
+// Define the constants as required by C++ standard.
+
+template<int size, bool big_endian>
+const int Output_data_plt_sparc<size, big_endian>::base_plt_entry_size;
+
+template<int size, bool big_endian>
+const unsigned int
+Output_data_plt_sparc<size, big_endian>::plt_entries_per_block;
+
+template<int size, bool big_endian>
+const unsigned int Output_data_plt_sparc<size, big_endian>::plt_insn_chunk_size;
+
+template<int size, bool big_endian>
+const unsigned int
+Output_data_plt_sparc<size, big_endian>::plt_pointer_chunk_size;
+
+template<int size, bool big_endian>
+const unsigned int Output_data_plt_sparc<size, big_endian>::plt_block_size;
+
// Create the PLT section. The ordinary .got section is an argument,
// since we need to refer to the start.
Output_data_plt_sparc<size, big_endian>::Output_data_plt_sparc(Layout* layout)
: Output_section_data(size == 32 ? 4 : 8), count_(0)
{
- this->rel_ = new Reloc_section();
+ this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->rel_);
}
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.
object->name().c_str(), r_type);
}
+// We are about to emit a dynamic relocation of type R_TYPE. If the
+// dynamic linker does not support it, issue an error.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int r_type)
+{
+ gold_assert(r_type != elfcpp::R_SPARC_NONE);
+
+ if (size == 64)
+ {
+ switch (r_type)
+ {
+ // These are the relocation types supported by glibc for sparc 64-bit.
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_64:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_TLS_DTPMOD64:
+ case elfcpp::R_SPARC_TLS_DTPOFF64:
+ case elfcpp::R_SPARC_TLS_TPOFF64:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_OLO10:
+ case elfcpp::R_SPARC_H44:
+ case elfcpp::R_SPARC_M44:
+ case elfcpp::R_SPARC_L44:
+ case elfcpp::R_SPARC_HH22:
+ case elfcpp::R_SPARC_HM10:
+ case elfcpp::R_SPARC_LM22:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_UA32:
+ case elfcpp::R_SPARC_UA64:
+ return;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (r_type)
+ {
+ // These are the relocation types supported by glibc for sparc 32-bit.
+ case elfcpp::R_SPARC_RELATIVE:
+ case elfcpp::R_SPARC_COPY:
+ case elfcpp::R_SPARC_GLOB_DAT:
+ case elfcpp::R_SPARC_32:
+ case elfcpp::R_SPARC_JMP_SLOT:
+ case elfcpp::R_SPARC_TLS_DTPMOD32:
+ case elfcpp::R_SPARC_TLS_DTPOFF32:
+ case elfcpp::R_SPARC_TLS_TPOFF32:
+ case elfcpp::R_SPARC_TLS_LE_HIX22:
+ case elfcpp::R_SPARC_TLS_LE_LOX10:
+ case elfcpp::R_SPARC_8:
+ case elfcpp::R_SPARC_16:
+ case elfcpp::R_SPARC_DISP8:
+ case elfcpp::R_SPARC_DISP16:
+ case elfcpp::R_SPARC_DISP32:
+ case elfcpp::R_SPARC_LO10:
+ case elfcpp::R_SPARC_WDISP30:
+ case elfcpp::R_SPARC_HI22:
+ case elfcpp::R_SPARC_UA16:
+ case elfcpp::R_SPARC_UA32:
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ // This prevents us from issuing more than one error per reloc
+ // section. But we can still wind up issuing more than one
+ // error per object file.
+ if (this->issued_non_pic_error_)
+ return;
+ object->error(_("requires unsupported dynamic reloc; "
+ "recompile with -fPIC"));
+ this->issued_non_pic_error_ = true;
+ return;
+}
+
// Scan a relocation for a local symbol.
template<int size, bool big_endian>
if (parameters->options().output_is_position_independent())
{
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+
+ check_non_pic(object, r_type);
if (lsym.get_st_type() != elfcpp::STT_SECTION)
{
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
Output_data_got<size, big_endian>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- got->add_local_pair_with_rela(object, r_sym,
- lsym.get_st_shndx(),
- GOT_TYPE_TLS_PAIR,
- target->rela_dyn_section(layout),
- (size == 64 ?
- elfcpp::R_SPARC_TLS_DTPMOD64 :
- elfcpp::R_SPARC_TLS_DTPMOD32), 0);
+ unsigned int shndx = lsym.get_st_shndx();
+ bool is_ordinary;
+ shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+ if (!is_ordinary)
+ object->error(_("local symbol %u has bad shndx %u"),
+ r_sym, shndx);
+ else
+ got->add_local_pair_with_rela(object, r_sym,
+ lsym.get_st_shndx(),
+ GOT_TYPE_TLS_PAIR,
+ target->rela_dyn_section(layout),
+ (size == 64
+ ? elfcpp::R_SPARC_TLS_DTPMOD64
+ : elfcpp::R_SPARC_TLS_DTPMOD32),
+ 0);
if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
generate_tls_call(symtab, layout, target);
}
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,
{
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
{
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ check_non_pic(object, r_type);
rela_dyn->add_global(gsym, orig_r_type, output_section, object,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
{
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
{
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ check_non_pic(object, r_type);
if (gsym->is_from_dynobj()
|| gsym->is_undefined()
|| gsym->is_preemptible())
}
}
+// Process relocations for gc.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::gc_process_relocs(
+ const General_options& options,
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
+{
+ typedef Target_sparc<size, big_endian> Sparc;
+ typedef typename Target_sparc<size, big_endian>::Scan Scan;
+
+ gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan>(
+ options,
+ symtab,
+ layout,
+ this,
+ object,
+ data_shndx,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ local_symbol_count,
+ plocal_symbols);
+}
+
// Scan relocations for a section.
template<int size, bool big_endian>
// 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.
// Pick the value to use for symbols defined in shared objects.
Symbol_value<size> symval;
if (gsym != NULL
- && (gsym->is_from_dynobj()
- || (parameters->options().shared()
- && (gsym->is_undefined() || gsym->is_preemptible())))
- && gsym->has_plt_offset())
+ && gsym->use_plt_offset(r_type == elfcpp::R_SPARC_DISP8
+ || r_type == elfcpp::R_SPARC_DISP16
+ || r_type == elfcpp::R_SPARC_DISP32
+ || r_type == elfcpp::R_SPARC_DISP64
+ || r_type == elfcpp::R_SPARC_PC_HH22
+ || r_type == elfcpp::R_SPARC_PC_HM10
+ || r_type == elfcpp::R_SPARC_PC_LM22
+ || r_type == elfcpp::R_SPARC_PC10
+ || r_type == elfcpp::R_SPARC_PC22
+ || r_type == elfcpp::R_SPARC_WDISP30
+ || r_type == elfcpp::R_SPARC_WDISP22
+ || r_type == elfcpp::R_SPARC_WDISP19
+ || r_type == elfcpp::R_SPARC_WDISP16))
{
elfcpp::Elf_Xword value;