Refactor gold to enable support for MIPS-64 relocation format.
[deliverable/binutils-gdb.git] / gold / sparc.cc
index 04a88bf21bea5939ce1774f50aacda0cf844b3ee..c97c32ceb70dae85f640e84295297cf0d8ba2d6d 100644 (file)
@@ -1,6 +1,6 @@
 // sparc.cc -- sparc target support for gold.
 
-// Copyright 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+// Copyright (C) 2008-2016 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>.
 
 // This file is part of gold.
@@ -59,7 +59,7 @@ 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), rela_ifunc_(NULL),
-      copy_relocs_(elfcpp::R_SPARC_COPY), dynbss_(NULL),
+      copy_relocs_(elfcpp::R_SPARC_COPY),
       got_mod_index_offset_(-1U), tls_get_addr_sym_(NULL),
       elf_machine_(sparc_info.machine_code), elf_flags_(0),
       elf_flags_set_(false)
@@ -131,6 +131,21 @@ class Target_sparc : public Sized_target<size, big_endian>
                          const unsigned char* plocal_symbols,
                          Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+                  Layout* layout,
+                  Sized_relobj_file<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_syms,
+                  Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<size, big_endian>*,
@@ -138,8 +153,8 @@ class Target_sparc : public Sized_target<size, big_endian>
                  const unsigned char* prelocs,
                  size_t reloc_count,
                  Output_section* output_section,
-                 off_t offset_in_output_section,
-                 const Relocatable_relocs*,
+                 typename elfcpp::Elf_types<size>::Elf_Off
+                    offset_in_output_section,
                  unsigned char* view,
                  typename elfcpp::Elf_types<size>::Elf_Addr view_address,
                  section_size_type view_size,
@@ -216,7 +231,7 @@ class Target_sparc : public Sized_target<size, big_endian>
                     const elfcpp::Ehdr<size, big_endian>& ehdr);
 
   void
-  do_adjust_elf_header(unsigned char* view, int len) const;
+  do_adjust_elf_header(unsigned char* view, int len);
 
  private:
 
@@ -237,7 +252,8 @@ class Target_sparc : public Sized_target<size, big_endian>
          unsigned int data_shndx,
          Output_section* output_section,
          const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
-         const elfcpp::Sym<size, big_endian>& lsym);
+         const elfcpp::Sym<size, big_endian>& lsym,
+         bool is_discarded);
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_sparc* target,
@@ -314,13 +330,10 @@ class Target_sparc : public Sized_target<size, big_endian>
     // Do a relocation.  Return false if the caller should not issue
     // any warnings about this relocation.
     inline bool
-    relocate(const Relocate_info<size, big_endian>*, Target_sparc*,
-            Output_section*, size_t relnum,
-            const elfcpp::Rela<size, big_endian>&,
-            unsigned int r_type, const Sized_symbol<size>*,
-            const Symbol_value<size>*,
-            unsigned char*,
-            typename elfcpp::Elf_types<size>::Elf_Addr,
+    relocate(const Relocate_info<size, big_endian>*, unsigned int,
+            Target_sparc*, Output_section*, size_t, const unsigned char*,
+            const Sized_symbol<size>*, const Symbol_value<size>*,
+            unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
             section_size_type);
 
    private:
@@ -347,15 +360,6 @@ class Target_sparc : public Sized_target<size, big_endian>
     unsigned char *reloc_adjust_addr_;
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*);
-  };
-
   // Get the GOT section, creating it if necessary.
   Output_data_got<size, big_endian>*
   got_section(Symbol_table*, Layout*);
@@ -413,10 +417,13 @@ class Target_sparc : public Sized_target<size, big_endian>
             unsigned int shndx, Output_section* output_section,
             Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
   {
+    unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
     this->copy_relocs_.copy_reloc(symtab, layout,
                                  symtab->get_sized_symbol<size>(sym),
                                  object, shndx, output_section,
-                                 reloc, this->rela_dyn_section(layout));
+                                 r_type, reloc.get_r_offset(),
+                                 reloc.get_r_addend(),
+                                 this->rela_dyn_section(layout));
   }
 
   // Information about this specific target which we pass to the
@@ -444,8 +451,6 @@ class Target_sparc : public Sized_target<size, big_endian>
   Reloc_section* rela_ifunc_;
   // Relocs saved to avoid a COPY reloc.
   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;
   unsigned int got_mod_index_offset_;
   // Cached pointer to __tls_get_addr symbol
@@ -481,7 +486,9 @@ Target::Target_info Target_sparc<32, true>::sparc_info =
   0,                   // small_common_section_flags
   0,                   // large_common_section_flags
   NULL,                        // attributes_section
-  NULL                 // attributes_vendor
+  NULL,                        // attributes_vendor
+  "_start",            // entry_symbol_name
+  32,                  // hash_entry_size
 };
 
 template<>
@@ -507,7 +514,9 @@ Target::Target_info Target_sparc<64, true>::sparc_info =
   0,                   // small_common_section_flags
   0,                   // large_common_section_flags
   NULL,                        // attributes_section
-  NULL                 // attributes_vendor
+  NULL,                        // attributes_vendor
+  "_start",            // entry_symbol_name
+  32,                  // hash_entry_size
 };
 
 // We have to take care here, even when operating in little-endian
@@ -1105,13 +1114,12 @@ public:
   // R_SPARC_GOTDATA_OP_HIX22: @gdopoff(Symbol + Addend) >> 10
   static inline void
   gdop_hix22(unsigned char* view,
-            typename elfcpp::Elf_types<size>::Elf_Addr value,
-            typename elfcpp::Elf_types<size>::Elf_Addr addend)
+            typename elfcpp::Elf_types<size>::Elf_Addr value)
   {
     typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<32, true>::readval(wv);
-    int32_t reloc = static_cast<int32_t>(value + addend);
+    int32_t reloc = static_cast<int32_t>(value);
 
     val &= ~0x3fffff;
 
@@ -1168,13 +1176,12 @@ public:
   // R_SPARC_GOTDATA_OP_LOX10: (@gdopoff(Symbol + Addend) & 0x3ff) | 0x1c00
   static inline void
   gdop_lox10(unsigned char* view,
-            typename elfcpp::Elf_types<size>::Elf_Addr value,
-            typename elfcpp::Elf_types<size>::Elf_Addr addend)
+            typename elfcpp::Elf_types<size>::Elf_Addr value)
   {
     typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<32, true>::readval(wv);
-    int32_t reloc = static_cast<int32_t>(value + addend);
+    int32_t reloc = static_cast<int32_t>(value);
 
     if (reloc < 0)
       reloc = (reloc & 0x3ff) | 0x1c00;
@@ -1618,7 +1625,7 @@ Output_data_plt_sparc<size, big_endian>::address_for_global(const Symbol* gsym)
   if (gsym->type() == elfcpp::STT_GNU_IFUNC
       && gsym->can_use_relative_reloc(false))
     offset = plt_index_to_offset(this->count_ + 4);
-  return this->address() + offset;
+  return this->address() + offset + gsym->plt_offset();
 }
 
 // Return the PLT address to use for a local symbol.  These are always
@@ -1627,10 +1634,12 @@ Output_data_plt_sparc<size, big_endian>::address_for_global(const Symbol* gsym)
 template<int size, bool big_endian>
 uint64_t
 Output_data_plt_sparc<size, big_endian>::address_for_local(
-       const Relobj*,
-       unsigned int)
+       const Relobj* object,
+       unsigned int r_sym)
 {
-  return this->address() + plt_index_to_offset(this->count_ + 4);
+  return (this->address()
+         + plt_index_to_offset(this->count_ + 4)
+         + object->local_plt_offset(r_sym));
 }
 
 static const unsigned int sparc_nop = 0x01000000;
@@ -2240,8 +2249,12 @@ Target_sparc<size, big_endian>::Scan::local(
                        Output_section* output_section,
                        const elfcpp::Rela<size, big_endian>& reloc,
                        unsigned int r_type,
-                       const elfcpp::Sym<size, big_endian>& lsym)
+                       const elfcpp::Sym<size, big_endian>& lsym,
+                       bool is_discarded)
 {
+  if (is_discarded)
+    return;
+
   bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
   unsigned int orig_r_type = r_type;
   r_type &= 0xff;
@@ -2626,7 +2639,8 @@ Target_sparc<size, big_endian>::Scan::global(
        // Make a dynamic relocation if necessary.
        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
          {
-           if (gsym->may_need_copy_reloc())
+           if (parameters->options().output_is_executable()
+               && gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym,
@@ -2715,7 +2729,8 @@ Target_sparc<size, big_endian>::Scan::global(
                break;
              }
 
-           if (gsym->may_need_copy_reloc())
+           if (!parameters->options().output_is_position_independent()
+               && gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -3027,9 +3042,10 @@ Target_sparc<size, big_endian>::gc_process_relocs(
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
-  gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan,
-                         typename Target_sparc::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, big_endian, Sparc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -3061,7 +3077,8 @@ Target_sparc<size, big_endian>::scan_relocs(
                        const unsigned char* plocal_symbols)
 {
   typedef Target_sparc<size, big_endian> Sparc;
-  typedef typename Target_sparc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   if (sh_type == elfcpp::SHT_REL)
     {
@@ -3070,7 +3087,7 @@ Target_sparc<size, big_endian>::scan_relocs(
       return;
     }
 
-  gold::scan_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan>(
+  gold::scan_relocs<size, big_endian, Sparc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -3156,17 +3173,19 @@ template<int size, bool big_endian>
 inline bool
 Target_sparc<size, big_endian>::Relocate::relocate(
                        const Relocate_info<size, big_endian>* relinfo,
+                       unsigned int,
                        Target_sparc* target,
                        Output_section*,
                        size_t relnum,
-                       const elfcpp::Rela<size, big_endian>& rela,
-                       unsigned int r_type,
+                       const unsigned char* preloc,
                        const Sized_symbol<size>* gsym,
                        const Symbol_value<size>* psymval,
                        unsigned char* view,
                        typename elfcpp::Elf_types<size>::Elf_Addr address,
                        section_size_type view_size)
 {
+  const elfcpp::Rela<size, big_endian> rela(preloc);
+  unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
   bool orig_is_ifunc = psymval->is_ifunc_symbol();
   r_type &= 0xff;
 
@@ -3181,6 +3200,10 @@ Target_sparc<size, big_endian>::Relocate::relocate(
          return false;
        }
     }
+
+  if (view == NULL)
+    return true;
+
   if (this->reloc_adjust_addr_ == view)
     view -= 4;
 
@@ -3194,7 +3217,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
     {
       elfcpp::Elf_Xword value;
 
-      value = target->plt_address_for_global(gsym) + gsym->plt_offset();
+      value = target->plt_address_for_global(gsym);
 
       symval.set_output_value(value);
 
@@ -3205,8 +3228,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
       if (object->local_has_plt_offset(r_sym))
        {
-         symval.set_output_value(target->plt_address_for_local(object, r_sym)
-                                 + object->local_plt_offset(r_sym));
+         symval.set_output_value(target->plt_address_for_local(object, r_sym));
          psymval = &symval;
        }
     }
@@ -3231,7 +3253,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
              && !gsym->is_preemptible()
              && !orig_is_ifunc))
        {
-         got_offset = psymval->value(object, 0) - target->got_address();
+         got_offset = psymval->value(object, addend) - target->got_address();
          gdop_valid = true;
          break;
        }
@@ -3371,7 +3393,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
       if (gdop_valid)
        {
-         Reloc::gdop_lox10(view, got_offset, addend);
+         Reloc::gdop_lox10(view, got_offset);
          break;
        }
       /* Fall through.  */
@@ -3382,7 +3404,7 @@ Target_sparc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
       if (gdop_valid)
        {
-         Reloc::gdop_hix22(view, got_offset, addend);
+         Reloc::gdop_hix22(view, got_offset);
          break;
        }
       /* Fall through.  */
@@ -4128,11 +4150,13 @@ Target_sparc<size, big_endian>::relocate_section(
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_section<size, big_endian, Sparc, elfcpp::SHT_RELA,
-    Sparc_relocate>(
+  gold::relocate_section<size, big_endian, Sparc, Sparc_relocate,
+                        gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -4145,20 +4169,6 @@ Target_sparc<size, big_endian>::relocate_section(
     reloc_symbol_changes);
 }
 
-// Return the size of a relocation while scanning during a relocatable
-// link.
-
-template<int size, bool big_endian>
-unsigned int
-Target_sparc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
-    unsigned int,
-    Relobj*)
-{
-  // We are always SHT_RELA, so we should never get here.
-  gold_unreachable();
-  return 0;
-}
-
 // Scan the relocs during a relocatable link.
 
 template<int size, bool big_endian>
@@ -4177,13 +4187,14 @@ Target_sparc<size, big_endian>::scan_relocatable_relocs(
                        const unsigned char* plocal_symbols,
                        Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_RELA);
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
-      Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -4197,6 +4208,45 @@ Target_sparc<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::emit_relocs_scan(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<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_syms,
+    Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Emit relocations for a section.
 
 template<int size, bool big_endian>
@@ -4207,23 +4257,24 @@ Target_sparc<size, big_endian>::relocate_relocs(
     const unsigned char* prelocs,
     size_t reloc_count,
     Output_section* output_section,
-    off_t offset_in_output_section,
-    const Relocatable_relocs* rr,
+    typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
     section_size_type view_size,
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+  gold::relocate_relocs<size, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
     output_section,
     offset_in_output_section,
-    rr,
     view,
     view_address,
     view_size,
@@ -4328,7 +4379,7 @@ template<int size, bool big_endian>
 void
 Target_sparc<size, big_endian>::do_adjust_elf_header(
     unsigned char* view,
-    int len) const
+    int len)
 {
   elfcpp::Ehdr_write<size, big_endian> oehdr(view);
 
This page took 0.029883 seconds and 4 git commands to generate.