PR gold/12525
[binutils-gdb.git] / gold / sparc.cc
index 43c6e34b0b9ccb09bde296df9e7cee4604eaea7d..84614bd7a28f9c33f336efdd53c981aef31c940f 100644 (file)
@@ -1,6 +1,6 @@
 // sparc.cc -- sparc target support for gold.
 
-// Copyright 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>.
 
 // This file is part of gold.
@@ -161,12 +161,33 @@ class Target_sparc : public Sized_target<size, big_endian>
 
   // Return the size of the GOT section.
   section_size_type
-  got_size()
+  got_size() const
   {
     gold_assert(this->got_ != NULL);
     return this->got_->data_size();
   }
 
+  // Return the number of entries in the GOT.
+  unsigned int
+  got_entry_count() const
+  {
+    if (this->got_ == NULL)
+      return 0;
+    return this->got_size() / (size / 8);
+  }
+
+  // Return the number of entries in the PLT.
+  unsigned int
+  plt_entry_count() const;
+
+  // Return the offset of the first non-reserved PLT entry.
+  unsigned int
+  first_plt_entry_offset() const;
+
+  // Return the size of each PLT entry.
+  unsigned int
+  plt_entry_size() const;
+
  private:
 
   // The class which scans relocations.
@@ -177,6 +198,9 @@ class Target_sparc : public Sized_target<size, big_endian>
       : issued_non_pic_error_(false)
     { }
 
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_sparc* target,
          Sized_relobj<size, big_endian>* object,
@@ -193,6 +217,29 @@ class Target_sparc : public Sized_target<size, big_endian>
           const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
           Symbol* gsym);
 
+    inline bool
+    local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                       Target_sparc* ,
+                                       Sized_relobj<size, big_endian>* ,
+                                               unsigned int ,
+                                       Output_section* ,
+                                       const elfcpp::Rela<size, big_endian>& ,
+                                       unsigned int ,
+                                       const elfcpp::Sym<size, big_endian>&)
+    { return false; }
+
+    inline bool
+    global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+                                        Target_sparc* ,
+                                        Sized_relobj<size, big_endian>* ,
+                                        unsigned int ,
+                                        Output_section* ,
+                                        const elfcpp::Rela<size,
+                                                           big_endian>& ,
+                                        unsigned int , Symbol*)
+    { return false; }
+
+
   private:
     static void
     unsupported_reloc_local(Sized_relobj<size, big_endian>*,
@@ -320,6 +367,9 @@ class Target_sparc : public Sized_target<size, big_endian>
   static Target::Target_info sparc_info;
 
   // The types of GOT entries needed for this platform.
+  // These values are exposed to the ABI in an incremental link.
+  // Do not renumber existing values without changing the version
+  // number of the .gnu_incremental_inputs section.
   enum Got_type
   {
     GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
@@ -401,13 +451,13 @@ private:
   rela(unsigned char* view,
        unsigned int right_shift,
        typename elfcpp::Elf_types<valsize>::Elf_Addr dst_mask,
-       typename elfcpp::Swap<size, big_endian>::Valtype avalue,
+       typename elfcpp::Swap<size, big_endian>::Valtype value,
        typename elfcpp::Swap<size, big_endian>::Valtype addend)
   {
     typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
-    Valtype reloc = ((avalue + addend) >> right_shift);
+    Valtype reloc = ((value + addend) >> right_shift);
 
     val &= ~dst_mask;
     reloc &= dst_mask;
@@ -589,10 +639,10 @@ public:
   // R_SPARC_HI22: (Symbol + Addend) >> 10
   static inline void
   hi22(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
-    This_insn::template rela<32>(view, 10, 0x003fffff, avalue, addend);
+    This_insn::template rela<32>(view, 10, 0x003fffff, value, addend);
   }
 
   // R_SPARC_HI22: (Symbol + Addend) >> 10
@@ -620,10 +670,10 @@ public:
   // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
   static inline void
   lo10(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
-    This_insn::template rela<32>(view, 0, 0x000003ff, avalue, addend);
+    This_insn::template rela<32>(view, 0, 0x000003ff, value, addend);
   }
 
   // R_SPARC_LO10: (Symbol + Addend) & 0x3ff
@@ -682,10 +732,10 @@ public:
   // R_SPARC_13: (Symbol + Addend)
   static inline void
   rela32_13(unsigned char* view,
-           typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
-    This_insn::template rela<32>(view, 0, 0x00001fff, avalue, addend);
+    This_insn::template rela<32>(view, 0, 0x00001fff, value, addend);
   }
 
   // R_SPARC_13: (Symbol + Addend)
@@ -904,22 +954,22 @@ public:
   // R_SPARC_TLS_LDO_HIX22: @dtpoff(Symbol + Addend) >> 10
   static inline void
   ldo_hix22(unsigned char* view,
-           typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
-    This_insn::hi22(view, avalue, addend);
+    This_insn::hi22(view, value, addend);
   }
 
   // R_SPARC_TLS_LDO_LOX10: @dtpoff(Symbol + Addend) & 0x3ff
   static inline void
   ldo_lox10(unsigned char* view,
-           typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+           typename elfcpp::Elf_types<size>::Elf_Addr value,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
     typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<32, true>::readval(wv);
-    Valtype reloc = (avalue + addend);
+    Valtype reloc = (value + addend);
 
     val &= ~0x1fff;
     reloc &= 0x3ff;
@@ -930,13 +980,13 @@ public:
   // R_SPARC_TLS_LE_HIX22: (@tpoff(Symbol + Addend) ^ 0xffffffffffffffff) >> 10
   static inline void
   hix22(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
     typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<32, true>::readval(wv);
-    Valtype reloc = (avalue + addend);
+    Valtype reloc = (value + addend);
 
     val &= ~0x3fffff;
 
@@ -974,13 +1024,13 @@ public:
   // R_SPARC_TLS_LE_LOX10: (@tpoff(Symbol + Addend) & 0x3ff) | 0x1c00
   static inline void
   lox10(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr avalue,
+       typename elfcpp::Elf_types<size>::Elf_Addr value,
        typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
     typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<32, true>::readval(wv);
-    Valtype reloc = (avalue + addend);
+    Valtype reloc = (value + addend);
 
     val &= ~0x1fff;
     reloc &= 0x3ff;
@@ -1022,15 +1072,14 @@ Target_sparc<size, big_endian>::got_section(Symbol_table* symtab,
 
       this->got_ = new Output_data_got<size, big_endian>();
 
-      Output_section* os;
-      os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-                                          (elfcpp::SHF_ALLOC
-                                           | elfcpp::SHF_WRITE),
-                                          this->got_, false);
-      os->set_is_relro();
+      layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_WRITE),
+                                     this->got_, ORDER_RELRO, true);
 
       // Define _GLOBAL_OFFSET_TABLE_ at the start of the .got section.
       symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
                                    this->got_,
                                    0, 0, elfcpp::STT_OBJECT,
                                    elfcpp::STB_LOCAL,
@@ -1052,7 +1101,8 @@ Target_sparc<size, big_endian>::rela_dyn_section(Layout* layout)
       gold_assert(layout != NULL);
       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_, true);
+                                     elfcpp::SHF_ALLOC, this->rela_dyn_,
+                                     ORDER_DYNAMIC_RELOCS, false);
     }
   return this->rela_dyn_;
 }
@@ -1077,6 +1127,21 @@ class Output_data_plt_sparc : public Output_section_data
     return this->rel_;
   }
 
+  // Return the number of PLT entries.
+  unsigned int
+  entry_count() const
+  { return this->count_; }
+
+  // Return the offset of the first non-reserved PLT entry.
+  static unsigned int
+  first_plt_entry_offset()
+  { return 4 * base_plt_entry_size; }
+
+  // Return the size of a PLT entry.
+  static unsigned int
+  get_plt_entry_size()
+  { return base_plt_entry_size; }
+
  protected:
   void do_adjust_output_section(Output_section* os);
 
@@ -1154,7 +1219,8 @@ Output_data_plt_sparc<size, big_endian>::Output_data_plt_sparc(Layout* layout)
 {
   this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
-                                 elfcpp::SHF_ALLOC, this->rel_, true);
+                                 elfcpp::SHF_ALLOC, this->rel_,
+                                 ORDER_DYNAMIC_PLT_RELOCS, false);
 }
 
 template<int size, bool big_endian>
@@ -1220,10 +1286,10 @@ template<int size, bool big_endian>
 void
 Output_data_plt_sparc<size, big_endian>::do_write(Output_file* of)
 {
-  const off_t off = this->offset();
+  const off_t offset = this->offset();
   const section_size_type oview_size =
     convert_to_section_size_type(this->data_size());
-  unsigned char* const oview = of->get_output_view(off, oview_size);
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
   unsigned char* pov = oview;
 
   memset(pov, 0, base_plt_entry_size * 4);
@@ -1347,7 +1413,7 @@ Output_data_plt_sparc<size, big_endian>::do_write(Output_file* of)
 
   gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
 
-  of->write_output_view(off, oview_size, oview);
+  of->write_output_view(offset, oview_size, oview);
 }
 
 // Create a PLT entry for a global symbol.
@@ -1366,15 +1432,21 @@ Target_sparc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
       // Create the GOT sections first.
       this->got_section(symtab, layout);
 
+      // Ensure that .rela.dyn always appears before .rela.plt  This is
+      // necessary due to how, on Sparc and some other targets, .rela.dyn
+      // needs to include .rela.plt in it's range.
+      this->rela_dyn_section(layout);
+
       this->plt_ = new Output_data_plt_sparc<size, big_endian>(layout);
       layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_EXECINSTR
                                       | elfcpp::SHF_WRITE),
-                                     this->plt_, false);
+                                     this->plt_, ORDER_PLT, false);
 
       // Define _PROCEDURE_LINKAGE_TABLE_ at the start of the .plt section.
       symtab->define_in_output_data("_PROCEDURE_LINKAGE_TABLE_", NULL,
+                                   Symbol_table::PREDEFINED,
                                    this->plt_,
                                    0, 0, elfcpp::STT_OBJECT,
                                    elfcpp::STB_LOCAL,
@@ -1385,6 +1457,35 @@ Target_sparc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
   this->plt_->add_entry(gsym);
 }
 
+// Return the number of entries in the PLT.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_count() const
+{
+  if (this->plt_ == NULL)
+    return 0;
+  return this->plt_->entry_count();
+}
+
+// Return the offset of the first non-reserved PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_sparc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_sparc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_sparc<size, big_endian>::get_plt_entry_size();
+}
+
 // Create a GOT entry for the TLS module index.
 
 template<int size, bool big_endian>
@@ -1478,6 +1579,119 @@ optimize_tls_reloc(bool is_final, int r_type)
     }
 }
 
+// Get the Reference_flags for a particular relocation.
+
+template<int size, bool big_endian>
+int
+Target_sparc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+  r_type &= 0xff;
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_NONE:
+    case elfcpp::R_SPARC_REGISTER:
+    case elfcpp::R_SPARC_GNU_VTINHERIT:
+    case elfcpp::R_SPARC_GNU_VTENTRY:
+      // No symbol reference.
+      return 0;
+
+    case elfcpp::R_SPARC_UA64:
+    case elfcpp::R_SPARC_64:
+    case elfcpp::R_SPARC_HIX22:
+    case elfcpp::R_SPARC_LOX10:
+    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_HI22:
+    case elfcpp::R_SPARC_LO10:
+    case elfcpp::R_SPARC_OLO10:
+    case elfcpp::R_SPARC_UA32:
+    case elfcpp::R_SPARC_32:
+    case elfcpp::R_SPARC_UA16:
+    case elfcpp::R_SPARC_16:
+    case elfcpp::R_SPARC_11:
+    case elfcpp::R_SPARC_10:
+    case elfcpp::R_SPARC_8:
+    case elfcpp::R_SPARC_7:
+    case elfcpp::R_SPARC_6:
+    case elfcpp::R_SPARC_5:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_DISP8:
+    case elfcpp::R_SPARC_DISP16:
+    case elfcpp::R_SPARC_DISP32:
+    case elfcpp::R_SPARC_DISP64:
+    case elfcpp::R_SPARC_PC_HH22:
+    case elfcpp::R_SPARC_PC_HM10:
+    case elfcpp::R_SPARC_PC_LM22:
+    case elfcpp::R_SPARC_PC10:
+    case elfcpp::R_SPARC_PC22:
+    case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WDISP22:
+    case elfcpp::R_SPARC_WDISP19:
+    case elfcpp::R_SPARC_WDISP16:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_SPARC_PLT64:
+    case elfcpp::R_SPARC_PLT32:
+    case elfcpp::R_SPARC_HIPLT22:
+    case elfcpp::R_SPARC_LOPLT10:
+    case elfcpp::R_SPARC_PCPLT10:
+      return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_PCPLT32:
+    case elfcpp::R_SPARC_PCPLT22:
+    case elfcpp::R_SPARC_WPLT30:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT10:
+    case elfcpp::R_SPARC_GOT13:
+    case elfcpp::R_SPARC_GOT22:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+    case elfcpp::R_SPARC_TLS_LDM_HI22: // Local-dynamic
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:        // Alternate local-dynamic
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+    case elfcpp::R_SPARC_TLS_LE_HIX22:
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+    case elfcpp::R_SPARC_TLS_IE_HI22:  // Initial-exec
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_SPARC_COPY:
+    case elfcpp::R_SPARC_GLOB_DAT:
+    case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_TLS_DTPMOD64:
+    case elfcpp::R_SPARC_TLS_DTPMOD32:
+    case elfcpp::R_SPARC_TLS_DTPOFF64:
+    case elfcpp::R_SPARC_TLS_DTPOFF32:
+    case elfcpp::R_SPARC_TLS_TPOFF64:
+    case elfcpp::R_SPARC_TLS_TPOFF32:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
 // Generate a PLT entry slot for a call to __tls_get_addr
 template<int size, bool big_endian>
 void
@@ -1666,28 +1880,28 @@ Target_sparc<size, big_endian>::Scan::local(
       if (parameters->options().output_is_position_independent())
         {
           Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+          unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
 
          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());
               rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
                                  data_shndx, reloc.get_r_offset(),
                                  reloc.get_r_addend());
             }
           else
             {
-             unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
               gold_assert(lsym.get_st_value() == 0);
-              rela_dyn->add_local_relative(object, r_sym, orig_r_type,
-                                          output_section, data_shndx,
-                                          reloc.get_r_offset(),
-                                          reloc.get_r_addend());
+             rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type,
+                                                   output_section, data_shndx,
+                                                   reloc.get_r_offset(),
+                                                   reloc.get_r_addend());
             }
         }
       break;
 
     case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WPLT30:
     case elfcpp::R_SPARC_WDISP22:
     case elfcpp::R_SPARC_WDISP19:
     case elfcpp::R_SPARC_WDISP16:
@@ -1699,6 +1913,9 @@ Target_sparc<size, big_endian>::Scan::local(
     case elfcpp::R_SPARC_PC22:
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
     case elfcpp::R_SPARC_GOT10:
     case elfcpp::R_SPARC_GOT13:
     case elfcpp::R_SPARC_GOT22:
@@ -1829,13 +2046,13 @@ Target_sparc<size, big_endian>::Scan::local(
                    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                    unsigned int off = got->add_constant(0);
 
-                   object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET,
-                                                off);
-                   rela_dyn->add_local_relative(object, r_sym,
-                                                (size == 64 ?
-                                                 elfcpp::R_SPARC_TLS_TPOFF64 :
-                                                 elfcpp::R_SPARC_TLS_TPOFF32),
-                                                got, off, 0);
+                   object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET, off);
+
+                   rela_dyn->add_symbolless_local_addend(object, r_sym,
+                                                         (size == 64 ?
+                                                          elfcpp::R_SPARC_TLS_TPOFF64 :
+                                                          elfcpp::R_SPARC_TLS_TPOFF32),
+                                                         got, off, 0);
                  }
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
@@ -1851,9 +2068,9 @@ Target_sparc<size, big_endian>::Scan::local(
                 gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
                 unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                 Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-                rela_dyn->add_local_relative(object, r_sym, r_type,
-                                            output_section, data_shndx,
-                                            reloc.get_r_offset(), 0);
+                rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+                                                     output_section, data_shndx,
+                                                     reloc.get_r_offset(), 0);
              }
            break;
          }
@@ -1967,10 +2184,7 @@ Target_sparc<size, big_endian>::Scan::global(
        if (gsym->needs_plt_entry())
          target->make_plt_entry(symtab, layout, gsym);
        // Make a dynamic relocation if necessary.
-       int flags = Symbol::NON_PIC_REF;
-       if (gsym->type() == elfcpp::STT_FUNC)
-         flags |= Symbol::FUNCTION_CALL;
-       if (gsym->needs_dynamic_reloc(flags))
+       if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
          {
            if (gsym->may_need_copy_reloc())
              {
@@ -2026,8 +2240,40 @@ Target_sparc<size, big_endian>::Scan::global(
               gsym->set_needs_dynsym_value();
           }
         // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
           {
+           unsigned int r_off = reloc.get_r_offset();
+
+           // The assembler can sometimes emit unaligned relocations
+           // for dwarf2 cfi directives. 
+           switch (r_type)
+             {
+             case elfcpp::R_SPARC_16:
+               if (r_off & 0x1)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA16;
+               break;
+             case elfcpp::R_SPARC_32:
+               if (r_off & 0x3)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA32;
+               break;
+             case elfcpp::R_SPARC_64:
+               if (r_off & 0x7)
+                 orig_r_type = r_type = elfcpp::R_SPARC_UA64;
+               break;
+             case elfcpp::R_SPARC_UA16:
+               if (!(r_off & 0x1))
+                 orig_r_type = r_type = elfcpp::R_SPARC_16;
+               break;
+             case elfcpp::R_SPARC_UA32:
+               if (!(r_off & 0x3))
+                 orig_r_type = r_type = elfcpp::R_SPARC_32;
+               break;
+             case elfcpp::R_SPARC_UA64:
+               if (!(r_off & 0x7))
+                 orig_r_type = r_type = elfcpp::R_SPARC_64;
+               break;
+             }
+
             if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
@@ -2056,16 +2302,19 @@ Target_sparc<size, big_endian>::Scan::global(
                                       reloc.get_r_offset(),
                                       reloc.get_r_addend());
                else
-                 rela_dyn->add_global_relative(gsym, orig_r_type,
-                                               output_section, object,
-                                               data_shndx,
-                                               reloc.get_r_offset(),
-                                               reloc.get_r_addend());
+                 rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                        output_section,
+                                                        object, data_shndx,
+                                                        reloc.get_r_offset(),
+                                                        reloc.get_r_addend());
               }
           }
       }
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
     case elfcpp::R_SPARC_GOT10:
     case elfcpp::R_SPARC_GOT13:
     case elfcpp::R_SPARC_GOT22:
@@ -2189,10 +2438,10 @@ Target_sparc<size, big_endian>::Scan::global(
            if (parameters->options().shared())
              {
                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-               rela_dyn->add_global_relative(gsym, orig_r_type,
-                                             output_section, object,
-                                             data_shndx, reloc.get_r_offset(),
-                                             0);
+               rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                      output_section, object,
+                                                      data_shndx, reloc.get_r_offset(),
+                                                      0);
              }
            break;
 
@@ -2260,9 +2509,10 @@ Target_sparc<size, big_endian>::gc_process_relocs(
                        const unsigned char* plocal_symbols)
 {
   typedef Target_sparc<size, big_endian> Sparc;
-  typedef typename Target_sparc<size, big_endian>::Scan scan;
+  typedef typename Target_sparc<size, big_endian>::Scan Scan;
 
-  gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, scan>(
+  gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan,
+                         typename Target_sparc::Relocatable_size_for_reloc>(
     symtab,
     layout,
     this,
@@ -2294,7 +2544,7 @@ 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 typename Target_sparc<size, big_endian>::Scan Scan;
 
   if (sh_type == elfcpp::SHT_REL)
     {
@@ -2303,7 +2553,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, elfcpp::SHT_RELA, Scan>(
     symtab,
     layout,
     this,
@@ -2327,37 +2577,11 @@ Target_sparc<size, big_endian>::do_finalize_sections(
     Symbol_table*)
 {
   // Fill in some more dynamic tags.
-  Output_data_dynamic* const odyn = layout->dynamic_data();
-  if (odyn != NULL)
-    {
-      if (this->plt_ != NULL
-         && this->plt_->output_section() != NULL)
-       {
-         const Output_data* od = this->plt_->rel_plt();
-         odyn->add_section_size(elfcpp::DT_PLTRELSZ, od);
-         odyn->add_section_address(elfcpp::DT_JMPREL, od);
-         odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_RELA);
-
-         odyn->add_section_address(elfcpp::DT_PLTGOT, this->plt_);
-       }
-
-      if (this->rela_dyn_ != NULL
-         && this->rela_dyn_->output_section() != NULL)
-       {
-         const Output_data* od = this->rela_dyn_;
-         odyn->add_section_address(elfcpp::DT_RELA, od);
-         odyn->add_section_size(elfcpp::DT_RELASZ, od);
-         odyn->add_constant(elfcpp::DT_RELAENT,
-                            elfcpp::Elf_sizes<size>::rela_size);
-       }
-
-      if (!parameters->options().shared())
-       {
-         // The value of the DT_DEBUG tag is filled in by the dynamic
-         // linker at run time, and used by the debugger.
-         odyn->add_constant(elfcpp::DT_DEBUG, 0);
-       }
-    }
+  const Reloc_section* rel_plt = (this->plt_ == NULL
+                                 ? NULL
+                                 : this->plt_->rel_plt());
+  layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
+                                 this->rela_dyn_, true, true);
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
@@ -2401,25 +2625,13 @@ 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->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))
+      && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
-      elfcpp::Elf_Xword avalue;
+      elfcpp::Elf_Xword value;
 
-      avalue = target->plt_section()->address() + gsym->plt_offset();
+      value = target->plt_section()->address() + gsym->plt_offset();
 
-      symval.set_output_value(avalue);
+      symval.set_output_value(value);
 
       psymval = &symval;
     }
@@ -2430,10 +2642,12 @@ Target_sparc<size, big_endian>::Relocate::relocate(
   // Get the GOT offset if needed.  Unlike i386 and x86_64, our GOT
   // pointer points to the beginning, not the end, of the table.
   // So we just use the plain offset.
-  bool have_got_offset = false;
   unsigned int got_offset = 0;
   switch (r_type)
     {
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
     case elfcpp::R_SPARC_GOT10:
     case elfcpp::R_SPARC_GOT13:
     case elfcpp::R_SPARC_GOT22:
@@ -2448,7 +2662,6 @@ Target_sparc<size, big_endian>::Relocate::relocate(
           gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
           got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
         }
-      have_got_offset = true;
       break;
 
     default:
@@ -2469,14 +2682,30 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       break;
 
     case elfcpp::R_SPARC_16:
-      Relocate_functions<size, big_endian>::rela16(view, object,
-                                                  psymval, addend);
+      if (rela.get_r_offset() & 0x1)
+       {
+         // The assembler can sometimes emit unaligned relocations
+         // for dwarf2 cfi directives. 
+         Reloc::ua16(view, object, psymval, addend);
+       }
+      else
+       Relocate_functions<size, big_endian>::rela16(view, object,
+                                                    psymval, addend);
       break;
 
     case elfcpp::R_SPARC_32:
       if (!parameters->options().output_is_position_independent())
-       Relocate_functions<size, big_endian>::rela32(view, object,
-                                                    psymval, addend);
+       {
+         if (rela.get_r_offset() & 0x3)
+           {
+             // The assembler can sometimes emit unaligned relocations
+             // for dwarf2 cfi directives. 
+             Reloc::ua32(view, object, psymval, addend);
+           }
+         else
+           Relocate_functions<size, big_endian>::rela32(view, object,
+                                                        psymval, addend);
+       }
       break;
 
     case elfcpp::R_SPARC_DISP8:
@@ -2532,10 +2761,15 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       Reloc::lo10(view, got_offset, addend);
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP:
+      break;
+
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
     case elfcpp::R_SPARC_GOT13:
       Reloc::rela32_13(view, got_offset, addend);
       break;
 
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
     case elfcpp::R_SPARC_GOT22:
       Reloc::hi22(view, got_offset, addend);
       break;
@@ -2585,8 +2819,17 @@ Target_sparc<size, big_endian>::Relocate::relocate(
 
     case elfcpp::R_SPARC_64:
       if (!parameters->options().output_is_position_independent())
-             Relocate_functions<size, big_endian>::rela64(view, object,
-                                                          psymval, addend);
+       {
+         if (rela.get_r_offset() & 0x7)
+           {
+             // The assembler can sometimes emit unaligned relocations
+             // for dwarf2 cfi directives. 
+             Reloc::ua64(view, object, psymval, addend);
+           }
+         else
+           Relocate_functions<size, big_endian>::rela64(view, object,
+                                                        psymval, addend);
+       }
       break;
 
     case elfcpp::R_SPARC_OLO10:
@@ -2740,7 +2983,7 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
   typedef typename elfcpp::Swap<32, true>::Valtype Insntype;
 
   const elfcpp::Elf_Xword addend = rela.get_r_addend();
-  typename elfcpp::Elf_types<size>::Elf_Addr avalue = psymval->value(object, 0);
+  typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
 
   const bool is_final =
     (gsym == NULL
@@ -2760,18 +3003,18 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
          Insntype* wv = reinterpret_cast<Insntype*>(view);
          Insntype val;
 
-         avalue -= tls_segment->memsz();
+         value -= tls_segment->memsz();
 
          switch (r_type)
            {
            case elfcpp::R_SPARC_TLS_GD_HI22:
              // TLS_GD_HI22 --> TLS_LE_HIX22
-             Reloc::hix22(view, avalue, addend);
+             Reloc::hix22(view, value, addend);
              break;
 
            case elfcpp::R_SPARC_TLS_GD_LO10:
              // TLS_GD_LO10 --> TLS_LE_LOX10
-             Reloc::lox10(view, avalue, addend);
+             Reloc::lox10(view, value, addend);
              break;
 
            case elfcpp::R_SPARC_TLS_GD_ADD:
@@ -2795,13 +3038,13 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
           if (gsym != NULL)
             {
               gold_assert(gsym->has_got_offset(got_type));
-              avalue = gsym->got_offset(got_type);
+              value = gsym->got_offset(got_type);
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
               gold_assert(object->local_has_got_offset(r_sym, got_type));
-              avalue = object->local_got_offset(r_sym, got_type);
+              value = object->local_got_offset(r_sym, got_type);
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
            {
@@ -2812,12 +3055,12 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
                {
                case elfcpp::R_SPARC_TLS_GD_HI22:
                  // TLS_GD_HI22 --> TLS_IE_HI22
-                 Reloc::hi22(view, avalue, addend);
+                 Reloc::hi22(view, value, addend);
                  break;
 
                case elfcpp::R_SPARC_TLS_GD_LO10:
                  // TLS_GD_LO10 --> TLS_IE_LO10
-                 Reloc::lo10(view, avalue, addend);
+                 Reloc::lo10(view, value, addend);
                  break;
 
                case elfcpp::R_SPARC_TLS_GD_ADD:
@@ -2836,7 +3079,7 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
                  // The compiler can put the TLS_GD_ADD instruction
                  // into the delay slot of the call.  If so, we need
                  // to transpose the two instructions so that the
-                 // the new sequence works properly.
+                 // new sequence works properly.
                  //
                  // The test we use is if the instruction in the
                  // delay slot is an add with destination register
@@ -2867,24 +3110,24 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
              switch (r_type)
                {
                case elfcpp::R_SPARC_TLS_GD_HI22:
-                 Reloc::hi22(view, avalue, addend);
+                 Reloc::hi22(view, value, addend);
                  break;
                case elfcpp::R_SPARC_TLS_GD_LO10:
-                 Reloc::lo10(view, avalue, addend);
+                 Reloc::lo10(view, value, addend);
                  break;
                case elfcpp::R_SPARC_TLS_GD_ADD:
                  break;
                case elfcpp::R_SPARC_TLS_GD_CALL:
                  {
                    Symbol_value<size> symval;
-                   elfcpp::Elf_Xword xvalue;
+                   elfcpp::Elf_Xword value;
                    Symbol* tsym;
 
                    tsym = target->tls_get_addr_sym_;
                    gold_assert(tsym);
-                   xvalue = (target->plt_section()->address() +
-                             tsym->plt_offset());
-                   symval.set_output_value(xvalue);
+                   value = (target->plt_section()->address() +
+                            tsym->plt_offset());
+                   symval.set_output_value(value);
                    Reloc::wdisp30(view, object, &symval, addend, address);
                  }
                  break;
@@ -2939,14 +3182,14 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
            case elfcpp::R_SPARC_TLS_LDM_CALL:
              {
                Symbol_value<size> symval;
-               elfcpp::Elf_Xword xvalue;
+               elfcpp::Elf_Xword value;
                Symbol* tsym;
 
                tsym = target->tls_get_addr_sym_;
                gold_assert(tsym);
-               xvalue = (target->plt_section()->address() +
-                         tsym->plt_offset());
-               symval.set_output_value(xvalue);
+               value = (target->plt_section()->address() +
+                        tsym->plt_offset());
+               symval.set_output_value(value);
                Reloc::wdisp30(view, object, &symval, addend, address);
              }
              break;
@@ -2964,20 +3207,20 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
     case elfcpp::R_SPARC_TLS_LDO_HIX22:
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-         avalue -= tls_segment->memsz();
-         Reloc::hix22(view, avalue, addend);
+         value -= tls_segment->memsz();
+         Reloc::hix22(view, value, addend);
        }
       else
-       Reloc::ldo_hix22(view, avalue, addend);
+       Reloc::ldo_hix22(view, value, addend);
       break;
     case elfcpp::R_SPARC_TLS_LDO_LOX10:
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-         avalue -= tls_segment->memsz();
-         Reloc::lox10(view, avalue, addend);
+         value -= tls_segment->memsz();
+         Reloc::lox10(view, value, addend);
        }
       else
-       Reloc::ldo_lox10(view, avalue, addend);
+       Reloc::ldo_lox10(view, value, addend);
       break;
     case elfcpp::R_SPARC_TLS_LDO_ADD:
       if (optimized_type == tls::TLSOPT_TO_LE)
@@ -3018,16 +3261,16 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
     case elfcpp::R_SPARC_TLS_IE_LO10:
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-         avalue -= tls_segment->memsz();
+         value -= tls_segment->memsz();
          switch (r_type)
            {
            case elfcpp::R_SPARC_TLS_IE_HI22:
              // IE_HI22 --> LE_HIX22
-             Reloc::hix22(view, avalue, addend);
+             Reloc::hix22(view, value, addend);
              break;
            case elfcpp::R_SPARC_TLS_IE_LO10:
              // IE_LO10 --> LE_LOX10
-             Reloc::lox10(view, avalue, addend);
+             Reloc::lox10(view, value, addend);
              break;
            }
          break;
@@ -3039,23 +3282,23 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
          if (gsym != NULL)
            {
              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
-             avalue = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+             value = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
            }
          else
            {
              unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
              gold_assert(object->local_has_got_offset(r_sym,
                                                       GOT_TYPE_TLS_OFFSET));
-             avalue = object->local_got_offset(r_sym,
-                                               GOT_TYPE_TLS_OFFSET);
+             value = object->local_got_offset(r_sym,
+                                              GOT_TYPE_TLS_OFFSET);
            }
          switch (r_type)
            {
            case elfcpp::R_SPARC_TLS_IE_HI22:
-             Reloc::hi22(view, avalue, addend);
+             Reloc::hi22(view, value, addend);
              break;
            case elfcpp::R_SPARC_TLS_IE_LO10:
-             Reloc::lo10(view, avalue, addend);
+             Reloc::lo10(view, value, addend);
              break;
            }
          break;
@@ -3076,8 +3319,8 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
       // have been created for this location, so do not apply it now.
       if (!parameters->options().shared())
        {
-         avalue -= tls_segment->memsz();
-         Reloc::hix22(view, avalue, addend);
+         value -= tls_segment->memsz();
+         Reloc::hix22(view, value, addend);
        }
       break;
 
@@ -3086,8 +3329,8 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls(
       // have been created for this location, so do not apply it now.
       if (!parameters->options().shared())
        {
-         avalue -= tls_segment->memsz();
-         Reloc::lox10(view, avalue, addend);
+         value -= tls_segment->memsz();
+         Reloc::lox10(view, value, addend);
        }
       break;
     }
@@ -3238,18 +3481,18 @@ public:
                      (size == 64 ? "elf64-sparc" : "elf32-sparc"))
   { }
 
-  Target* do_recognize(int amachine, int, int)
+  Target* do_recognize(int machine, int, int)
   {
     switch (size)
       {
       case 64:
-       if (amachine != elfcpp::EM_SPARCV9)
+       if (machine != elfcpp::EM_SPARCV9)
          return NULL;
        break;
 
       case 32:
-       if (amachine != elfcpp::EM_SPARC
-           && amachine != elfcpp::EM_SPARC32PLUS)
+       if (machine != elfcpp::EM_SPARC
+           && machine != elfcpp::EM_SPARC32PLUS)
          return NULL;
        break;