2010-03-22 Doug Kwan <dougkwan@google.com>
[binutils-gdb.git] / gold / sparc.cc
index 9bca176ce7e0976508433e771431ec7952db1da9..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>*,
@@ -1369,6 +1392,11 @@ 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
@@ -1670,28 +1698,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:
@@ -1836,13 +1864,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)
@@ -1858,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_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;
          }
@@ -2035,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,
@@ -2063,11 +2123,11 @@ 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());
               }
           }
       }
@@ -2199,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_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;
 
@@ -2341,7 +2401,7 @@ Target_sparc<size, big_endian>::do_finalize_sections(
                                  ? NULL
                                  : this->plt_->rel_plt());
   layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
-                                 this->rela_dyn_, true);
+                                 this->rela_dyn_, true, true);
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.