Updated Vietnamese translation.
[external/binutils.git] / gold / powerpc.cc
index 36b5790..d8e8b82 100644 (file)
@@ -1,6 +1,6 @@
 // powerpc.cc -- powerpc target support for gold.
 
-// Copyright 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>
 //        and David Edelsohn <edelsohn@gnu.org>
 
@@ -62,26 +62,26 @@ class Target_powerpc : public Sized_target<size, big_endian>
   {
   }
 
-  // Process the relocations to determine unreferenced sections for 
+  // Process the relocations to determine unreferenced sections for
   // garbage collection.
   void
   gc_process_relocs(Symbol_table* symtab,
-                   Layout* layout,
-                   Sized_relobj<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_symbols);
+                   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_symbols);
 
   // Scan the relocations to look for symbol adjustments.
   void
   scan_relocs(Symbol_table* symtab,
              Layout* layout,
-             Sized_relobj<size, big_endian>* object,
+             Sized_relobj_file<size, big_endian>* object,
              unsigned int data_shndx,
              unsigned int sh_type,
              const unsigned char* prelocs,
@@ -116,7 +116,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
   void
   scan_relocatable_relocs(Symbol_table* symtab,
                          Layout* layout,
-                         Sized_relobj<size, big_endian>* object,
+                         Sized_relobj_file<size, big_endian>* object,
                          unsigned int data_shndx,
                          unsigned int sh_type,
                          const unsigned char* prelocs,
@@ -151,12 +151,33 @@ class Target_powerpc : 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.
@@ -167,9 +188,12 @@ class Target_powerpc : 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_powerpc* target,
-         Sized_relobj<size, big_endian>* object,
+         Sized_relobj_file<size, big_endian>* object,
          unsigned int data_shndx,
          Output_section* output_section,
          const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
@@ -177,19 +201,41 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
-          Sized_relobj<size, big_endian>* object,
+          Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
           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_powerpc* ,
+                                       Sized_relobj_file<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_powerpc* ,
+                                        Sized_relobj_file<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>*,
+    unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
                            unsigned int r_type);
 
     static void
-    unsupported_reloc_global(Sized_relobj<size, big_endian>*,
+    unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
                             unsigned int r_type, Symbol*);
 
     static void
@@ -224,7 +270,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
     inline void
     relocate_tls(const Relocate_info<size, big_endian>*,
                 Target_powerpc* target,
-                 size_t relnum, const elfcpp::Rela<size, big_endian>&,
+                size_t relnum, const elfcpp::Rela<size, big_endian>&,
                 unsigned int r_type, const Sized_symbol<size>*,
                 const Symbol_value<size>*,
                 unsigned char*,
@@ -248,7 +294,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
   Output_data_space*
   got2_section() const
   {
-    gold_assert (this->got2_ != NULL);
+    gold_assert(this->got2_ != NULL);
     return this->got2_;
   }
 
@@ -256,7 +302,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
   Output_data_space*
   toc_section() const
   {
-    gold_assert (this->toc_ != NULL);
+    gold_assert(this->toc_ != NULL);
     return this->toc_;
   }
 
@@ -267,7 +313,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
   // Create a GOT entry for the TLS module index.
   unsigned int
   got_mod_index_entry(Symbol_table* symtab, Layout* layout,
-                     Sized_relobj<size, big_endian>* object);
+                     Sized_relobj_file<size, big_endian>* object);
 
   // Get the PLT section.
   const Output_data_plt_powerpc<size, big_endian>*
@@ -284,7 +330,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
   // Copy a relocation against a global symbol.
   void
   copy_reloc(Symbol_table* symtab, Layout* layout,
-             Sized_relobj<size, big_endian>* object,
+            Sized_relobj_file<size, big_endian>* object,
             unsigned int shndx, Output_section* output_section,
             Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
   {
@@ -299,6 +345,9 @@ class Target_powerpc : public Sized_target<size, big_endian>
   static Target::Target_info powerpc_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
@@ -334,15 +383,20 @@ Target::Target_info Target_powerpc<32, true>::powerpc_info =
   false,               // has_resolve
   false,               // has_code_fill
   true,                        // is_default_stack_executable
+  false,               // can_icf_inline_merge_sections
   '\0',                        // wrap_char
   "/usr/lib/ld.so.1",  // dynamic_linker
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   4 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  false,                // isolate_execinstr
+  0,                    // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
-  0                    // large_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
 };
 
 template<>
@@ -355,15 +409,20 @@ Target::Target_info Target_powerpc<32, false>::powerpc_info =
   false,               // has_resolve
   false,               // has_code_fill
   true,                        // is_default_stack_executable
+  false,               // can_icf_inline_merge_sections
   '\0',                        // wrap_char
   "/usr/lib/ld.so.1",  // dynamic_linker
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   4 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  false,                // isolate_execinstr
+  0,                    // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
-  0                    // large_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
 };
 
 template<>
@@ -376,15 +435,20 @@ Target::Target_info Target_powerpc<64, true>::powerpc_info =
   false,               // has_resolve
   false,               // has_code_fill
   true,                        // is_default_stack_executable
+  false,               // can_icf_inline_merge_sections
   '\0',                        // wrap_char
   "/usr/lib/ld.so.1",  // dynamic_linker
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   8 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  false,                // isolate_execinstr
+  0,                    // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
-  0                    // large_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
 };
 
 template<>
@@ -397,15 +461,20 @@ Target::Target_info Target_powerpc<64, false>::powerpc_info =
   false,               // has_resolve
   false,               // has_code_fill
   true,                        // is_default_stack_executable
+  false,               // can_icf_inline_merge_sections
   '\0',                        // wrap_char
   "/usr/lib/ld.so.1",  // dynamic_linker
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   8 * 1024,            // common_pagesize (overridable by -z common-page-size)
+  false,                // isolate_execinstr
+  0,                    // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
-  0                    // large_common_section_flags
+  0,                   // large_common_section_flags
+  NULL,                        // attributes_section
+  NULL                 // attributes_vendor
 };
 
 template<int size, bool big_endian>
@@ -439,7 +508,7 @@ private:
   rela(unsigned char* view,
        unsigned int right_shift,
        elfcpp::Elf_Xword dst_mask,
-       const Sized_relobj<size, big_endian>* object,
+       const Sized_relobj_file<size, big_endian>* object,
        const Symbol_value<size>* psymval,
        typename elfcpp::Swap<valsize, big_endian>::Valtype addend)
   {
@@ -460,7 +529,7 @@ private:
   static inline void
   rela_ua(unsigned char* view, unsigned int right_shift,
          elfcpp::Elf_Xword dst_mask,
-         const Sized_relobj<size, big_endian>* object,
+         const Sized_relobj_file<size, big_endian>* object,
          const Symbol_value<size>* psymval,
          typename elfcpp::Swap<size, big_endian>::Valtype addend)
   {
@@ -482,7 +551,7 @@ private:
   static inline void
   pcrela(unsigned char* view, unsigned int right_shift,
         elfcpp::Elf_Xword dst_mask,
-        const Sized_relobj<size, big_endian>* object,
+        const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Swap<size, big_endian>::Valtype addend,
         typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -502,7 +571,7 @@ private:
   template<int valsize>
   static inline void
   pcrela_unaligned(unsigned char* view,
-                  const Sized_relobj<size, big_endian>* object,
+                  const Sized_relobj_file<size, big_endian>* object,
                   const Symbol_value<size>* psymval,
                   typename elfcpp::Swap<size, big_endian>::Valtype addend,
                   typename elfcpp::Elf_types<size>::Elf_Addr address)
@@ -521,7 +590,7 @@ public:
   // R_POWERPC_REL32: (Symbol + Addend - Address)
   static inline void
   rel32(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       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)
@@ -530,7 +599,7 @@ public:
   // R_POWERPC_REL24: (Symbol + Addend - Address) & 0x3fffffc
   static inline void
   rel24(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       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)
@@ -542,7 +611,7 @@ public:
   // R_POWERPC_REL14: (Symbol + Addend - Address) & 0xfffc
   static inline void
   rel14(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       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)
@@ -560,7 +629,7 @@ public:
 
   static inline void
   addr16(unsigned char* view,
-        const Sized_relobj<size, big_endian>* object,
+        const Sized_relobj_file<size, big_endian>* object,
         const Symbol_value<size>* psymval,
         typename elfcpp::Elf_types<size>::Elf_Addr addend)
   { This_reloc::rela16(view, object, psymval, addend); }
@@ -583,7 +652,7 @@ public:
 
   static inline void
   addr16_lo(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   { This_reloc::rela16(view, object, psymval, addend); }
@@ -599,7 +668,7 @@ public:
 
   static inline void
   addr16_hi(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -627,7 +696,7 @@ public:
 
   static inline void
   addr16_ha(unsigned char* view,
-           const Sized_relobj<size, big_endian>* object,
+           const Sized_relobj_file<size, big_endian>* object,
            const Symbol_value<size>* psymval,
            typename elfcpp::Elf_types<size>::Elf_Addr addend)
   {
@@ -645,7 +714,7 @@ public:
   // R_PPC_REL16: (Symbol + Addend - Address) & 0xffff
   static inline void
   rel16(unsigned char* view,
-       const Sized_relobj<size, big_endian>* object,
+       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)
@@ -654,7 +723,7 @@ public:
   // R_PPC_REL16_LO: (Symbol + Addend - Address) & 0xffff
   static inline void
   rel16_lo(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          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)
@@ -663,7 +732,7 @@ public:
   // R_PPC_REL16_HI: ((Symbol + Addend - Address) >> 16) & 0xffff
   static inline void
   rel16_hi(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          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)
@@ -677,7 +746,7 @@ public:
   //                 relocation is negative, add one.
   static inline void
   rel16_ha(unsigned char* view,
-          const Sized_relobj<size, big_endian>* object,
+          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)
@@ -708,7 +777,7 @@ Target_powerpc<size, big_endian>::got_section(Symbol_table* symtab,
 
       layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                      elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
-                                     this->got_, false);
+                                     this->got_, ORDER_DATA, false);
 
       // Create the GOT2 or TOC in the .got section.
       if (size == 32)
@@ -717,7 +786,7 @@ Target_powerpc<size, big_endian>::got_section(Symbol_table* symtab,
          layout->add_output_section_data(".got2", elfcpp::SHT_PROGBITS,
                                          elfcpp::SHF_ALLOC
                                          | elfcpp::SHF_WRITE,
-                                         this->got2_, false);
+                                         this->got2_, ORDER_DATA, false);
        }
       else
        {
@@ -725,11 +794,12 @@ Target_powerpc<size, big_endian>::got_section(Symbol_table* symtab,
          layout->add_output_section_data(".toc", elfcpp::SHT_PROGBITS,
                                          elfcpp::SHF_ALLOC
                                          | elfcpp::SHF_WRITE,
-                                         this->toc_, false);
+                                         this->toc_, ORDER_DATA, false);
        }
 
       // 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,
@@ -751,7 +821,8 @@ Target_powerpc<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_;
 }
@@ -776,6 +847,21 @@ class Output_data_plt_powerpc : 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);
 
@@ -811,7 +897,8 @@ Output_data_plt_powerpc<size, big_endian>::Output_data_plt_powerpc(Layout* layou
 {
   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>
@@ -873,7 +960,7 @@ static const unsigned int addis_r12_r2    = 0x3d820000;  /* addis %r12,%r2,xxx@h
 static const unsigned int std_r2_40r1     = 0xf8410028;  /* std   %r2,40(%r1)         */
 static const unsigned int ld_r11_0r12     = 0xe96c0000;  /* ld    %r11,xxx+0@l(%r12)  */
 static const unsigned int ld_r2_0r12      = 0xe84c0000;  /* ld    %r2,xxx+8@l(%r12)   */
-                                                         /* ld    %r11,xxx+16@l(%r12) */
+                                                        /* ld    %r11,xxx+16@l(%r12) */
 
 
 // Write out the PLT.
@@ -935,15 +1022,21 @@ Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
       // Create the GOT section first.
       this->got_section(symtab, layout);
 
+      // Ensure that .rela.dyn always appears before .rela.plt  This is
+      // necessary due to how, on PowerPC 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_powerpc<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,
@@ -954,13 +1047,43 @@ Target_powerpc<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_powerpc<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_powerpc<size, big_endian>::first_plt_entry_offset() const
+{
+  return Output_data_plt_powerpc<size, big_endian>::first_plt_entry_offset();
+}
+
+// Return the size of each PLT entry.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::plt_entry_size() const
+{
+  return Output_data_plt_powerpc<size, big_endian>::get_plt_entry_size();
+}
+
 // Create a GOT entry for the TLS module index.
 
 template<int size, bool big_endian>
 unsigned int
-Target_powerpc<size, big_endian>::got_mod_index_entry(Symbol_table* symtab,
-                                                     Layout* layout,
-                                                     Sized_relobj<size, big_endian>* object)
+Target_powerpc<size, big_endian>::got_mod_index_entry(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object)
 {
   if (this->got_mod_index_offset_ == -1U)
     {
@@ -998,12 +1121,75 @@ 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_powerpc<size, big_endian>::Scan::get_reference_flags(
+                       unsigned int r_type)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_NONE:
+    case elfcpp::R_POWERPC_GNU_VTINHERIT:
+    case elfcpp::R_POWERPC_GNU_VTENTRY:
+    case elfcpp::R_PPC64_TOC:
+      // No symbol reference.
+      return 0;
+
+    case elfcpp::R_POWERPC_ADDR16:
+    case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR32:
+    case elfcpp::R_PPC64_ADDR64:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_POWERPC_REL24:
+    case elfcpp::R_PPC_LOCAL24PC:
+    case elfcpp::R_PPC_REL16:
+    case elfcpp::R_PPC_REL16_LO:
+    case elfcpp::R_PPC_REL16_HI:
+    case elfcpp::R_PPC_REL16_HA:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_PPC_PLTREL24:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_LO:
+    case elfcpp::R_PPC64_TOC16_HI:
+    case elfcpp::R_PPC64_TOC16_HA:
+    case elfcpp::R_PPC64_TOC16_DS:
+    case elfcpp::R_PPC64_TOC16_LO_DS:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_POWERPC_GOT_TPREL16:
+    case elfcpp::R_POWERPC_TLS:
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_POWERPC_COPY:
+    case elfcpp::R_POWERPC_GLOB_DAT:
+    case elfcpp::R_POWERPC_JMP_SLOT:
+    case elfcpp::R_POWERPC_RELATIVE:
+    case elfcpp::R_POWERPC_DTPMOD:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
 // Report an unsupported relocation against a local symbol.
 
 template<int size, bool big_endian>
 void
 Target_powerpc<size, big_endian>::Scan::unsupported_reloc_local(
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int r_type)
 {
   gold_error(_("%s: unsupported reloc %u against local symbol"),
@@ -1111,7 +1297,7 @@ Target_powerpc<size, big_endian>::Scan::local(
                        Symbol_table* symtab,
                        Layout* layout,
                        Target_powerpc<size, big_endian>* target,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        Output_section* output_section,
                        const elfcpp::Rela<size, big_endian>& reloc,
@@ -1133,27 +1319,27 @@ Target_powerpc<size, big_endian>::Scan::local(
       // executable), we need to create a dynamic relocation for
       // this location.
       if (parameters->options().output_is_position_independent())
-        {
-          Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+       {
+         Reloc_section* rela_dyn = target->rela_dyn_section(layout);
 
          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, r_type, output_section,
+         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, r_type, output_section,
                                  data_shndx, reloc.get_r_offset(),
                                  reloc.get_r_addend());
-            }
-          else
-            {
+           }
+         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, r_type,
+             gold_assert(lsym.get_st_value() == 0);
+             rela_dyn->add_local_relative(object, r_sym, r_type,
                                           output_section, data_shndx,
                                           reloc.get_r_offset(),
-                                          reloc.get_r_addend());
-            }
-        }
+                                          reloc.get_r_addend(), false);
+           }
+       }
       break;
 
     case elfcpp::R_POWERPC_REL24:
@@ -1174,8 +1360,8 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got<size, big_endian>* got;
+       // The symbol requires a GOT entry.
+       Output_data_got<size, big_endian>* got;
        unsigned int r_sym;
 
        got = target->got_section(symtab, layout);
@@ -1194,9 +1380,9 @@ Target_powerpc<size, big_endian>::Scan::local(
                object->set_local_got_offset(r_sym, GOT_TYPE_STANDARD, off);
                rela_dyn->add_local_relative(object, r_sym,
                                             elfcpp::R_POWERPC_RELATIVE,
-                                            got, off, 0);
+                                            got, off, 0, false);
              }
-          }
+         }
        else
          got->add_local(object, r_sym, GOT_TYPE_STANDARD);
       }
@@ -1229,7 +1415,7 @@ Target_powerpc<size, big_endian>::Scan::local(
 template<int size, bool big_endian>
 void
 Target_powerpc<size, big_endian>::Scan::unsupported_reloc_global(
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int r_type,
                        Symbol* gsym)
 {
@@ -1245,7 +1431,7 @@ Target_powerpc<size, big_endian>::Scan::global(
                                Symbol_table* symtab,
                                Layout* layout,
                                Target_powerpc<size, big_endian>* target,
-                               Sized_relobj<size, big_endian>* object,
+                               Sized_relobj_file<size, big_endian>* object,
                                unsigned int data_shndx,
                                Output_section* output_section,
                                const elfcpp::Rela<size, big_endian>& reloc,
@@ -1268,8 +1454,8 @@ Target_powerpc<size, big_endian>::Scan::global(
       // if the symbol is defined in the output file and is protected
       // or hidden.
       if (gsym->is_defined()
-          && !gsym->is_from_dynobj()
-          && !gsym->is_preemptible())
+         && !gsym->is_from_dynobj()
+         && !gsym->is_preemptible())
        break;
       target->make_plt_entry(symtab, layout, gsym);
       break;
@@ -1281,38 +1467,38 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_ADDR32:
     case elfcpp::R_PPC64_ADDR64:
       {
-        // Make a PLT entry if necessary.
-        if (gsym->needs_plt_entry())
-          {
-            target->make_plt_entry(symtab, layout, gsym);
-            // Since this is not a PC-relative relocation, we may be
-            // taking the address of a function. In that case we need to
-            // set the entry in the dynamic symbol table to the address of
-            // the PLT entry.
-            if (gsym->is_from_dynobj() && !parameters->options().shared())
-              gsym->set_needs_dynsym_value();
-          }
-        // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
-          {
-            if (gsym->may_need_copy_reloc())
-              {
-               target->copy_reloc(symtab, layout, object,
-                                  data_shndx, output_section, gsym, reloc);
-              }
-            else if ((r_type == elfcpp::R_POWERPC_ADDR32
+       // Make a PLT entry if necessary.
+       if (gsym->needs_plt_entry())
+         {
+           target->make_plt_entry(symtab, layout, gsym);
+           // Since this is not a PC-relative relocation, we may be
+           // taking the address of a function. In that case we need to
+           // set the entry in the dynamic symbol table to the address of
+           // the PLT entry.
+           if (gsym->is_from_dynobj() && !parameters->options().shared())
+             gsym->set_needs_dynsym_value();
+         }
+       // Make a dynamic relocation if necessary.
+       if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+         {
+           if (gsym->may_need_copy_reloc())
+             {
+               target->copy_reloc(symtab, layout, object,
+                                  data_shndx, output_section, gsym, reloc);
+             }
+           else if ((r_type == elfcpp::R_POWERPC_ADDR32
                      || r_type == elfcpp::R_PPC64_ADDR64)
-                     && gsym->can_use_relative_reloc(false))
-              {
-                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-                rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
+                    && gsym->can_use_relative_reloc(false))
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+               rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
                                              output_section, object,
                                              data_shndx, reloc.get_r_offset(),
-                                             reloc.get_r_addend());
-              }
-            else
-              {
-                Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+                                             reloc.get_r_addend(), false);
+             }
+           else
+             {
+               Reloc_section* rela_dyn = target->rela_dyn_section(layout);
 
                check_non_pic(object, r_type);
                if (gsym->is_from_dynobj()
@@ -1327,9 +1513,9 @@ Target_powerpc<size, big_endian>::Scan::global(
                                                output_section, object,
                                                data_shndx,
                                                reloc.get_r_offset(),
-                                               reloc.get_r_addend());
-              }
-          }
+                                               reloc.get_r_addend(), false);
+             }
+         }
       }
       break;
 
@@ -1343,10 +1529,7 @@ Target_powerpc<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())
              {
@@ -1377,31 +1560,31 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got<size, big_endian>* got;
+       // The symbol requires a GOT entry.
+       Output_data_got<size, big_endian>* got;
 
        got = target->got_section(symtab, layout);
-        if (gsym->final_value_is_known())
-          got->add_global(gsym, GOT_TYPE_STANDARD);
-        else
-          {
-            // If this symbol is not fully resolved, we need to add a
-            // dynamic relocation for it.
-            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-            if (gsym->is_from_dynobj()
-                || gsym->is_undefined()
-                || gsym->is_preemptible())
-              got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
-                                        elfcpp::R_POWERPC_GLOB_DAT);
-            else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
-              {
+       if (gsym->final_value_is_known())
+         got->add_global(gsym, GOT_TYPE_STANDARD);
+       else
+         {
+           // If this symbol is not fully resolved, we need to add a
+           // dynamic relocation for it.
+           Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+           if (gsym->is_from_dynobj()
+               || gsym->is_undefined()
+               || gsym->is_preemptible())
+             got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+                                      elfcpp::R_POWERPC_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_POWERPC_RELATIVE,
-                                             got, off, 0);
+                                             got, off, 0, false);
              }
-          }
+         }
       }
       break;
 
@@ -1439,7 +1622,7 @@ void
 Target_powerpc<size, big_endian>::gc_process_relocs(
                        Symbol_table* symtab,
                        Layout* layout,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        unsigned int,
                        const unsigned char* prelocs,
@@ -1452,7 +1635,8 @@ Target_powerpc<size, big_endian>::gc_process_relocs(
   typedef Target_powerpc<size, big_endian> Powerpc;
   typedef typename Target_powerpc<size, big_endian>::Scan Scan;
 
-  gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan>(
+  gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan,
+                         typename Target_powerpc::Relocatable_size_for_reloc>(
     symtab,
     layout,
     this,
@@ -1473,7 +1657,7 @@ void
 Target_powerpc<size, big_endian>::scan_relocs(
                        Symbol_table* symtab,
                        Layout* layout,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        unsigned int sh_type,
                        const unsigned char* prelocs,
@@ -1502,8 +1686,11 @@ Target_powerpc<size, big_endian>::scan_relocs(
     Output_section* os = layout->add_output_section_data(".sdata", 0,
                                                         elfcpp::SHF_ALLOC
                                                         | elfcpp::SHF_WRITE,
-                                                        sdata, false);
+                                                        sdata,
+                                                        ORDER_SMALL_DATA,
+                                                        false);
     symtab->define_in_output_data("_SDA_BASE_", NULL,
+                                 Symbol_table::PREDEFINED,
                                  os,
                                  32768, 0,
                                  elfcpp::STT_OBJECT,
@@ -1536,37 +1723,11 @@ Target_powerpc<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, size == 32);
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
@@ -1597,12 +1758,7 @@ Target_powerpc<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_POWERPC_REL24
-                             || r_type == elfcpp::R_PPC_LOCAL24PC
-                             || r_type == elfcpp::R_PPC_REL16
-                             || r_type == elfcpp::R_PPC_REL16_LO
-                             || r_type == elfcpp::R_PPC_REL16_HI
-                             || r_type == elfcpp::R_PPC_REL16_HA))
+      && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
       elfcpp::Elf_Xword value;
 
@@ -1613,13 +1769,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       psymval = &symval;
     }
 
-  const Sized_relobj<size, big_endian>* object = relinfo->object;
+  const Sized_relobj_file<size, big_endian>* object = relinfo->object;
   elfcpp::Elf_Xword addend = rela.get_r_addend();
 
   // 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;
   unsigned int got2_offset = 0;
   switch (r_type)
@@ -1641,21 +1796,20 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_PPC64_GOT16_DS:
     case elfcpp::R_PPC64_GOT16_LO_DS:
       if (gsym != NULL)
-        {
-          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
-          got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
-        }
+       {
+         gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+         got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
+       }
       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_STANDARD));
-          got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
-        }
-      have_got_offset = true;
+       {
+         unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+         gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+         got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+       }
       break;
 
       // R_PPC_PLTREL24 is rather special.  If non-zero,
-      // the addend specifies the GOT pointer offset within .got2.  
+      // the addend specifies the GOT pointer offset within .got2.
     case elfcpp::R_PPC_PLTREL24:
       if (addend >= 32768)
        {
@@ -1664,7 +1818,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
          got2_offset = got2->offset();
          addend += got2_offset;
        }
-      have_got_offset = true;
       break;
 
     default:
@@ -1818,8 +1971,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate_tls(
                        section_size_type)
 {
   Output_segment* tls_segment = relinfo->layout->tls_segment();
-  typedef Powerpc_relocate_functions<size, big_endian> Reloc;
-  const Sized_relobj<size, big_endian>* object = relinfo->object;
+  const Sized_relobj_file<size, big_endian>* object = relinfo->object;
 
   const elfcpp::Elf_Xword addend = rela.get_r_addend();
   typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
@@ -1893,7 +2045,7 @@ void
 Target_powerpc<size, big_endian>::scan_relocatable_relocs(
                        Symbol_table* symtab,
                        Layout* layout,
-                       Sized_relobj<size, big_endian>* object,
+                       Sized_relobj_file<size, big_endian>* object,
                        unsigned int data_shndx,
                        unsigned int sh_type,
                        const unsigned char* prelocs,
@@ -1979,12 +2131,16 @@ class Target_selector_powerpc : public Target_selector
 public:
   Target_selector_powerpc()
     : Target_selector(elfcpp::EM_NONE, size, big_endian,
-                     (size == 64 ?
-                      (big_endian ? "elf64-powerpc" : "elf64-powerpcle") :
-                      (big_endian ? "elf32-powerpc" : "elf32-powerpcle")))
+                     (size == 64
+                      ? (big_endian ? "elf64-powerpc" : "elf64-powerpcle")
+                      : (big_endian ? "elf32-powerpc" : "elf32-powerpcle")),
+                     (size == 64
+                      ? (big_endian ? "elf64ppc" : "elf64lppc")
+                      : (big_endian ? "elf32ppc" : "elf32lppc")))
   { }
 
-  Target* do_recognize(int machine, int, int)
+  virtual Target*
+  do_recognize(Input_file*, off_t, int machine, int, int)
   {
     switch (size)
       {
@@ -2005,7 +2161,8 @@ public:
     return this->instantiate_target();
   }
 
-  Target* do_instantiate_target()
+  virtual Target*
+  do_instantiate_target()
   { return new Target_powerpc<size, big_endian>(); }
 };