*** empty log message ***
[binutils-gdb.git] / gold / sparc.cc
index 234c5f5aa0aac0ba576ad4d703e22e67d7158778..e2d59b943a47fd99995b8e11fdfe71334c23cf87 100644 (file)
@@ -193,6 +193,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>*,
@@ -1686,25 +1709,17 @@ Target_sparc<size, big_endian>::Scan::local(
             }
           else
             {
-             unsigned int shndx = lsym.get_st_shndx();
-             bool is_ordinary;
-
               gold_assert(lsym.get_st_value() == 0);
-             shndx = object->adjust_sym_shndx(r_sym, shndx,
-                                              &is_ordinary);
-             if (!is_ordinary)
-               object->error(_("section symbol %u has bad shndx %u"),
-                             r_sym, shndx);
-             else
-               rela_dyn->add_local_section(object, shndx,
-                                           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:
@@ -1847,13 +1862,15 @@ Target_sparc<size, big_endian>::Scan::local(
                if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_OFFSET))
                  {
                    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                   unsigned int off = got->add_constant(0);
 
-                   got->add_local_with_rela(object, r_sym,
-                                            GOT_TYPE_TLS_OFFSET,
-                                            rela_dyn,
-                                            (size == 64 ?
-                                             elfcpp::R_SPARC_TLS_TPOFF64 :
-                                             elfcpp::R_SPARC_TLS_TPOFF32));
+                   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)
@@ -1869,9 +1886,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(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;
          }
@@ -2046,6 +2063,38 @@ Target_sparc<size, big_endian>::Scan::global(
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
+           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,
@@ -2066,10 +2115,19 @@ Target_sparc<size, big_endian>::Scan::global(
                 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());
+               if (gsym->is_from_dynobj()
+                   || gsym->is_undefined()
+                   || gsym->is_preemptible())
+                 rela_dyn->add_global(gsym, orig_r_type, output_section,
+                                      object, data_shndx,
+                                      reloc.get_r_offset(),
+                                      reloc.get_r_addend());
+               else
+                 rela_dyn->add_symbolless_global_addend(gsym, orig_r_type,
+                                                        output_section,
+                                                        object, data_shndx,
+                                                        reloc.get_r_offset(),
+                                                        reloc.get_r_addend());
               }
           }
       }
@@ -2201,10 +2259,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(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;