daily update
[deliverable/binutils-gdb.git] / gold / sparc.cc
index 2812fe1437049a331dbbd9c805d2534348055c39..aa8bbbd912e2d765cdf8402a7c2ac7a22ca6b67e 100644 (file)
@@ -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)
   {
   }
 
@@ -149,8 +150,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 +175,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 +187,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 +296,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 +325,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 +1001,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 +1029,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 +1059,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 +1105,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 +1131,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 +1392,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 +1480,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 +1644,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 +1745,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 +1876,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 +1944,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 +2000,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 +2017,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())
@@ -2226,15 +2292,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.
This page took 0.027793 seconds and 4 git commands to generate.