PR 9812
[binutils-gdb.git] / gold / sparc.cc
index 2812fe1437049a331dbbd9c805d2534348055c39..476aa3286d673a6803f19bf0f9ec8791a2e0d764 100644 (file)
@@ -1,6 +1,6 @@
 // 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.
@@ -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,11 +58,27 @@ 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)
   {
   }
 
+  // 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,
@@ -129,7 +146,7 @@ class Target_sparc : public Sized_target<size, big_endian>
                           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)
@@ -149,8 +166,13 @@ class Target_sparc : public Sized_target<size, big_endian>
  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,
@@ -169,6 +191,7 @@ class Target_sparc : public Sized_target<size, big_endian>
           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);
@@ -180,6 +203,12 @@ class Target_sparc : public Sized_target<size, big_endian>
     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.
@@ -283,9 +312,16 @@ 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,
+             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.
@@ -306,7 +342,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;
@@ -982,9 +1018,12 @@ Target_sparc<size, big_endian>::got_section(Symbol_table* symtab,
 
       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,
@@ -1007,7 +1046,7 @@ Target_sparc<size, big_endian>::rela_dyn_section(Layout* layout)
   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_);
     }
@@ -1037,6 +1076,11 @@ class Output_data_plt_sparc : public Output_section_data
  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);
@@ -1078,6 +1122,25 @@ class Output_data_plt_sparc : public Output_section_data
   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.
 
@@ -1085,7 +1148,7 @@ template<int size, bool big_endian>
 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_);
 }
@@ -1346,89 +1409,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.
@@ -1517,6 +1497,97 @@ Target_sparc<size, big_endian>::Scan::unsupported_reloc_local(
             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>
@@ -1590,6 +1661,8 @@ Target_sparc<size, big_endian>::Scan::local(
       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());
@@ -1689,13 +1762,21 @@ Target_sparc<size, big_endian>::Scan::local(
                 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);
              }
@@ -1812,7 +1893,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,
@@ -1880,13 +1961,14 @@ 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
              {
                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());
@@ -1935,7 +2017,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
@@ -1952,6 +2034,7 @@ Target_sparc<size, big_endian>::Scan::global(
               {
                 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())
@@ -2144,6 +2227,42 @@ Target_sparc<size, big_endian>::Scan::global(
     }
 }
 
+// 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>
@@ -2226,15 +2345,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.
@@ -2272,10 +2384,19 @@ Target_sparc<size, big_endian>::Relocate::relocate(
   // 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;