gold: Allow use_plt_offset to be specified for global relocations.
[binutils-gdb.git] / gold / sparc.cc
index 12e1dee1d64014b1a85d5f3b90f669bf74c0f5b1..e1bdc8e0f37aa57669f87f458b346cc66ccfcff3 100644 (file)
@@ -617,6 +617,29 @@ public:
     elfcpp::Swap<32, true>::writeval(wv, val | reloc);
   }
 
+  // R_SPARC_WDISP10: (Symbol + Addend - Address) >> 2
+  static inline void
+  wdisp10(unsigned char* view,
+         const Sized_relobj_file<size, big_endian>* object,
+         const Symbol_value<size>* psymval,
+         typename elfcpp::Elf_types<size>::Elf_Addr addend,
+         typename elfcpp::Elf_types<size>::Elf_Addr address)
+  {
+    typedef typename elfcpp::Swap<32, true>::Valtype Valtype;
+    Valtype* wv = reinterpret_cast<Valtype*>(view);
+    Valtype val = elfcpp::Swap<32, true>::readval(wv);
+    Valtype reloc = ((psymval->value(object, addend) - address)
+                    >> 2);
+
+    // The relocation value is split between the low bits 5-12,
+    // and high bits 19-20.
+    val &= ~((0x3 << 19) | (0xff << 5));
+    reloc = (((reloc & 0x300) << (19 - 8))
+            | ((reloc & 0xff) << (5 - 0)));
+
+    elfcpp::Swap<32, true>::writeval(wv, val | reloc);
+  }
+
   // R_SPARC_PC22: (Symbol + Addend - Address) >> 10
   static inline void
   pc22(unsigned char* view,
@@ -832,6 +855,16 @@ public:
                                        addend, address);
   }
 
+  // R_SPARC_H34: (Symbol + Addend) >> 12
+  static inline void
+  h34(unsigned char* view,
+      const Sized_relobj_file<size, big_endian>* object,
+      const Symbol_value<size>* psymval,
+      typename elfcpp::Elf_types<size>::Elf_Addr  addend)
+  {
+    This_insn::template rela<32>(view, 12, 0x003fffff, object, psymval, addend);
+  }
+
   // R_SPARC_H44: (Symbol + Addend) >> 22
   static inline void
   h44(unsigned char* view,
@@ -1605,6 +1638,7 @@ Target_sparc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_SPARC_64:
     case elfcpp::R_SPARC_HIX22:
     case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H34:
     case elfcpp::R_SPARC_H44:
     case elfcpp::R_SPARC_M44:
     case elfcpp::R_SPARC_L44:
@@ -1639,6 +1673,7 @@ Target_sparc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_SPARC_WDISP22:
     case elfcpp::R_SPARC_WDISP19:
     case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_WDISP10:
       return Symbol::RELATIVE_REF;
 
     case elfcpp::R_SPARC_PLT64:
@@ -1755,6 +1790,7 @@ Target_sparc<size, big_endian>::Scan::check_non_pic(Relobj* object, unsigned int
        case elfcpp::R_SPARC_LO10:
        case elfcpp::R_SPARC_HI22:
        case elfcpp::R_SPARC_OLO10:
+       case elfcpp::R_SPARC_H34:
        case elfcpp::R_SPARC_H44:
        case elfcpp::R_SPARC_M44:
        case elfcpp::R_SPARC_L44:
@@ -1861,6 +1897,7 @@ Target_sparc<size, big_endian>::Scan::local(
 
     case elfcpp::R_SPARC_HIX22:
     case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H34:
     case elfcpp::R_SPARC_H44:
     case elfcpp::R_SPARC_M44:
     case elfcpp::R_SPARC_L44:
@@ -1911,6 +1948,7 @@ Target_sparc<size, big_endian>::Scan::local(
     case elfcpp::R_SPARC_WDISP22:
     case elfcpp::R_SPARC_WDISP19:
     case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_WDISP10:
     case elfcpp::R_SPARC_DISP8:
     case elfcpp::R_SPARC_DISP16:
     case elfcpp::R_SPARC_DISP32:
@@ -1998,14 +2036,14 @@ Target_sparc<size, big_endian>::Scan::local(
                  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);
+                 got->add_local_pair_with_rel(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);
              }
@@ -2186,6 +2224,7 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_WDISP22:
     case elfcpp::R_SPARC_WDISP19:
     case elfcpp::R_SPARC_WDISP16:
+    case elfcpp::R_SPARC_WDISP10:
       {
        if (gsym->needs_plt_entry())
          target->make_plt_entry(symtab, layout, gsym);
@@ -2214,6 +2253,7 @@ Target_sparc<size, big_endian>::Scan::global(
     case elfcpp::R_SPARC_64:
     case elfcpp::R_SPARC_HIX22:
     case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H34:
     case elfcpp::R_SPARC_H44:
     case elfcpp::R_SPARC_M44:
     case elfcpp::R_SPARC_L44:
@@ -2293,7 +2333,7 @@ Target_sparc<size, big_endian>::Scan::global(
                 rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
                                              output_section, object,
                                              data_shndx, reloc.get_r_offset(),
-                                             reloc.get_r_addend());
+                                             reloc.get_r_addend(), false);
               }
             else
               {
@@ -2339,15 +2379,15 @@ Target_sparc<size, big_endian>::Scan::global(
             if (gsym->is_from_dynobj()
                 || gsym->is_undefined()
                 || gsym->is_preemptible())
-              got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
-                                        elfcpp::R_SPARC_GLOB_DAT);
+              got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+                                      elfcpp::R_SPARC_GLOB_DAT);
             else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
               {
                unsigned int off = got->add_constant(0);
 
                gsym->set_got_offset(GOT_TYPE_STANDARD, off);
                rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
-                                             got, off, 0);
+                                             got, off, 0, false);
              }
           }
       }
@@ -2389,14 +2429,14 @@ Target_sparc<size, big_endian>::Scan::global(
                 // dtv-relative offset.
                 Output_data_got<size, big_endian>* got
                     = target->got_section(symtab, layout);
-                got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_PAIR,
-                                               target->rela_dyn_section(layout),
-                                              (size == 64 ?
-                                               elfcpp::R_SPARC_TLS_DTPMOD64 :
-                                               elfcpp::R_SPARC_TLS_DTPMOD32),
-                                              (size == 64 ?
-                                               elfcpp::R_SPARC_TLS_DTPOFF64 :
-                                               elfcpp::R_SPARC_TLS_DTPOFF32));
+                got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+                                             target->rela_dyn_section(layout),
+                                             (size == 64
+                                              ? elfcpp::R_SPARC_TLS_DTPMOD64
+                                              : elfcpp::R_SPARC_TLS_DTPMOD32),
+                                             (size == 64
+                                              ? elfcpp::R_SPARC_TLS_DTPOFF64
+                                              : elfcpp::R_SPARC_TLS_DTPOFF32));
 
                // Emit R_SPARC_WPLT30 against "__tls_get_addr"
                if (r_type == elfcpp::R_SPARC_TLS_GD_CALL)
@@ -2407,11 +2447,11 @@ Target_sparc<size, big_endian>::Scan::global(
                 // Create a GOT entry for the tp-relative offset.
                 Output_data_got<size, big_endian>* got
                     = target->got_section(symtab, layout);
-                got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
-                                          target->rela_dyn_section(layout),
-                                         (size == 64 ?
-                                          elfcpp::R_SPARC_TLS_TPOFF64 :
-                                          elfcpp::R_SPARC_TLS_TPOFF32));
+                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                        target->rela_dyn_section(layout),
+                                        (size == 64 ?
+                                         elfcpp::R_SPARC_TLS_TPOFF64 :
+                                         elfcpp::R_SPARC_TLS_TPOFF32));
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
@@ -2462,11 +2502,11 @@ Target_sparc<size, big_endian>::Scan::global(
                // Create a GOT entry for the tp-relative offset.
                Output_data_got<size, big_endian>* got
                  = target->got_section(symtab, layout);
-               got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
-                                         target->rela_dyn_section(layout),
-                                         (size == 64 ?
-                                          elfcpp::R_SPARC_TLS_TPOFF64 :
-                                          elfcpp::R_SPARC_TLS_TPOFF32));
+               got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                        target->rela_dyn_section(layout),
+                                        (size == 64
+                                         ? elfcpp::R_SPARC_TLS_TPOFF64
+                                         : elfcpp::R_SPARC_TLS_TPOFF32));
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_global(object, r_type, gsym);
@@ -2749,6 +2789,10 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       Reloc::wdisp16(view, object, psymval, addend, address);
       break;
 
+    case elfcpp::R_SPARC_WDISP10:
+      Reloc::wdisp10(view, object, psymval, addend, address);
+      break;
+
     case elfcpp::R_SPARC_HI22:
       Reloc::hi22(view, object, psymval, addend);
       break;
@@ -2900,6 +2944,10 @@ Target_sparc<size, big_endian>::Relocate::relocate(
       Reloc::lox10(view, object, psymval, addend);
       break;
 
+    case elfcpp::R_SPARC_H34:
+      Reloc::h34(view, object, psymval, addend);
+      break;
+
     case elfcpp::R_SPARC_H44:
       Reloc::h44(view, object, psymval, addend);
       break;