Automatic date update in version.in
[deliverable/binutils-gdb.git] / gold / powerpc.cc
index 91353418c5091a95ba645fe9634d74aa409eb57e..314eaa7e56ce089f6f37fdc05fa9326018631df1 100644 (file)
@@ -1,6 +1,6 @@
 // powerpc.cc -- powerpc target support for gold.
 
-// Copyright (C) 2008-2017 Free Software Foundation, Inc.
+// Copyright (C) 2008-2018 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>
 //        and David Edelsohn <edelsohn@gnu.org>
 
@@ -78,8 +78,10 @@ struct Stub_table_owner
   const Output_section::Input_section* owner;
 };
 
-inline bool
-is_branch_reloc(unsigned int r_type);
+inline bool is_branch_reloc(unsigned int);
+
+template<int size>
+inline bool is_plt16_reloc(unsigned int);
 
 // Counter incremented on every Powerpc_relobj constructed.
 static uint32_t object_id = 0;
@@ -607,7 +609,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
   Target_powerpc()
     : Sized_target<size, big_endian>(&powerpc_info),
-      got_(NULL), plt_(NULL), iplt_(NULL), brlt_section_(NULL),
+      got_(NULL), plt_(NULL), iplt_(NULL), lplt_(NULL), brlt_section_(NULL),
       glink_(NULL), rela_dyn_(NULL), copy_relocs_(),
       tlsld_got_offset_(-1U),
       stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(),
@@ -860,6 +862,40 @@ class Target_powerpc : public Sized_target<size, big_endian>
     return this->iplt_;
   }
 
+  // Get the LPLT section.
+  const Output_data_plt_powerpc<size, big_endian>*
+  lplt_section() const
+  {
+    return this->lplt_;
+  }
+
+  // Return the plt offset and section for the given global sym.
+  Address
+  plt_off(const Symbol* gsym,
+         const Output_data_plt_powerpc<size, big_endian>** sec) const
+  {
+    if (gsym->type() == elfcpp::STT_GNU_IFUNC
+       && gsym->can_use_relative_reloc(false))
+      *sec = this->iplt_section();
+    else
+      *sec = this->plt_section();
+    return gsym->plt_offset();
+  }
+
+  // Return the plt offset and section for the given local sym.
+  Address
+  plt_off(const Sized_relobj_file<size, big_endian>* relobj,
+         unsigned int local_sym_index,
+         const Output_data_plt_powerpc<size, big_endian>** sec) const
+  {
+    const Symbol_value<size>* lsym = relobj->local_symbol(local_sym_index);
+    if (lsym->is_ifunc_symbol())
+      *sec = this->iplt_section();
+    else
+      *sec = this->lplt_section();
+    return relobj->local_plt_offset(local_sym_index);
+  }
+
   // Get the .glink section.
   const Output_data_glink<size, big_endian>*
   glink_section() const
@@ -1177,7 +1213,10 @@ class Target_powerpc : public Sized_target<size, big_endian>
                                 unsigned int r_type, const Symbol* gsym)
     {
       bool is_tls_call = ((r_type == elfcpp::R_POWERPC_REL24
-                          || r_type == elfcpp::R_PPC_PLTREL24)
+                          || r_type == elfcpp::R_PPC_PLTREL24
+                          || is_plt16_reloc<size>(r_type)
+                          || r_type == elfcpp::R_POWERPC_PLTSEQ
+                          || r_type == elfcpp::R_POWERPC_PLTCALL)
                          && gsym != NULL
                          && (gsym == target->tls_get_addr()
                              || gsym == target->tls_get_addr_opt()));
@@ -1351,7 +1390,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
     {
       gold::Default_comdat_behavior default_behavior;
       Comdat_behavior ret = default_behavior.get(name);
-      if (ret == CB_WARNING)
+      if (ret == CB_ERROR)
        {
          if (size == 32
              && (strcmp(name, ".fixup") == 0
@@ -1417,6 +1456,9 @@ class Target_powerpc : public Sized_target<size, big_endian>
   void
   make_iplt_section(Symbol_table*, Layout*);
 
+  void
+  make_lplt_section(Layout*);
+
   void
   make_brlt_section(Layout*);
 
@@ -1430,6 +1472,12 @@ class Target_powerpc : public Sized_target<size, big_endian>
                             Sized_relobj_file<size, big_endian>*,
                             unsigned int);
 
+  // Create a PLT entry for a local non-IFUNC symbol.
+  void
+  make_local_plt_entry(Layout*,
+                      Sized_relobj_file<size, big_endian>*,
+                      unsigned int);
+
 
   // Create a GOT entry for local dynamic __tls_get_addr.
   unsigned int
@@ -1562,6 +1610,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
   // section is emitted and marked with __rela_iplt_start and
   // __rela_iplt_end symbols.
   Output_data_plt_powerpc<size, big_endian>* iplt_;
+  // A PLT style section for local, non-ifunc symbols
+  Output_data_plt_powerpc<size, big_endian>* lplt_;
   // Section holding long branch destinations.
   Output_data_brlt_powerpc<size, big_endian>* brlt_section_;
   // The .glink section.
@@ -1625,6 +1675,7 @@ Target::Target_info Target_powerpc<32, true>::powerpc_info =
   NULL,                        // attributes_vendor
   "_start",            // entry_symbol_name
   32,                  // hash_entry_size
+  elfcpp::SHT_PROGBITS,        // unwind_section_type
 };
 
 template<>
@@ -1653,6 +1704,7 @@ Target::Target_info Target_powerpc<32, false>::powerpc_info =
   NULL,                        // attributes_vendor
   "_start",            // entry_symbol_name
   32,                  // hash_entry_size
+  elfcpp::SHT_PROGBITS,        // unwind_section_type
 };
 
 template<>
@@ -1681,6 +1733,7 @@ Target::Target_info Target_powerpc<64, true>::powerpc_info =
   NULL,                        // attributes_vendor
   "_start",            // entry_symbol_name
   32,                  // hash_entry_size
+  elfcpp::SHT_PROGBITS,        // unwind_section_type
 };
 
 template<>
@@ -1709,6 +1762,7 @@ Target::Target_info Target_powerpc<64, false>::powerpc_info =
   NULL,                        // attributes_vendor
   "_start",            // entry_symbol_name
   32,                  // hash_entry_size
+  elfcpp::SHT_PROGBITS,        // unwind_section_type
 };
 
 inline bool
@@ -1726,6 +1780,17 @@ is_branch_reloc(unsigned int r_type)
          || r_type == elfcpp::R_POWERPC_ADDR14_BRNTAKEN);
 }
 
+// Reloc resolves to plt entry.
+template<int size>
+inline bool
+is_plt16_reloc(unsigned int r_type)
+{
+  return (r_type == elfcpp::R_POWERPC_PLT16_LO
+         || r_type == elfcpp::R_POWERPC_PLT16_HI
+         || r_type == elfcpp::R_POWERPC_PLT16_HA
+         || (size == 64 && r_type == elfcpp::R_PPC64_PLT16_LO_DS));
+}
+
 // If INSN is an opcode that may be used with an @tls operand, return
 // the transformed insn for TLS optimisation, otherwise return 0.  If
 // REG is non-zero only match an insn with RB or RA equal to REG.
@@ -2431,6 +2496,35 @@ Powerpc_relobj<size, big_endian>::do_relocate_sections(
     }
   this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
                               start, this->shnum() - 1);
+
+  if (!parameters->options().output_is_position_independent())
+    {
+      Target_powerpc<size, big_endian>* target
+       = static_cast<Target_powerpc<size, big_endian>*>(
+           parameters->sized_target<size, big_endian>());
+      if (target->lplt_section() && target->lplt_section()->data_size() != 0)
+       {
+         const section_size_type offset = target->lplt_section()->offset();
+         const section_size_type oview_size
+           = convert_to_section_size_type(target->lplt_section()->data_size());
+         unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+         bool modified = false;
+         unsigned int nsyms = this->local_symbol_count();
+         for (unsigned int i = 0; i < nsyms; i++)
+           if (this->local_has_plt_offset(i))
+             {
+               Address value = this->local_symbol_value(i, 0);
+               if (size == 64)
+                 value += ppc64_local_entry_offset(i);
+               size_t off = this->local_plt_offset(i);
+               elfcpp::Swap<size, big_endian>::writeval(oview + off, value);
+               modified = true;
+             }
+         if (modified)
+           of->write_output_view(offset, oview_size, oview);
+       }
+    }
 }
 
 // Set up some symbols.
@@ -3524,7 +3618,7 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
 
       if (this->glink_ != NULL)
        {
-         int stub_size = this->glink_->pltresolve_size;
+         int stub_size = this->glink_->pltresolve_size();
          Address value = -stub_size;
          if (size == 64)
            {
@@ -3580,7 +3674,7 @@ Target_powerpc<size, big_endian>::do_plt_fde_location(const Output_data* plt,
          // There are two FDEs for a position independent glink.
          // The first covers the branch table, the second
          // __glink_PLTresolve at the end of glink.
-         off_t resolve_size = this->glink_->pltresolve_size;
+         off_t resolve_size = this->glink_->pltresolve_size();
          if (oview[9] == elfcpp::DW_CFA_nop)
            len -= resolve_size;
          else
@@ -3629,6 +3723,9 @@ class Output_data_plt_powerpc : public Output_section_data_build
   void
   add_ifunc_entry(Symbol*);
 
+  void
+  add_local_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
+
   void
   add_local_ifunc_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
 
@@ -3666,8 +3763,8 @@ class Output_data_plt_powerpc : public Output_section_data_build
   unsigned int
   first_plt_entry_offset() const
   {
-    // IPLT has no reserved entry.
-    if (this->name_[3] == 'I')
+    // IPLT and LPLT have no reserved entry.
+    if (this->name_[3] == 'I' || this->name_[3] == 'L')
       return 0;
     return this->targ_->first_plt_entry_offset();
   }
@@ -3730,6 +3827,31 @@ Output_data_plt_powerpc<size, big_endian>::add_ifunc_entry(Symbol* gsym)
     }
 }
 
+// Add an entry for a local symbol to the PLT.
+
+template<int size, bool big_endian>
+void
+Output_data_plt_powerpc<size, big_endian>::add_local_entry(
+    Sized_relobj_file<size, big_endian>* relobj,
+    unsigned int local_sym_index)
+{
+  if (!relobj->local_has_plt_offset(local_sym_index))
+    {
+      section_size_type off = this->current_data_size();
+      relobj->set_local_plt_offset(local_sym_index, off);
+      if (this->rel_)
+       {
+         unsigned int dynrel = elfcpp::R_POWERPC_RELATIVE;
+         if (size == 64 && this->targ_->abiversion() < 2)
+           dynrel = elfcpp::R_POWERPC_JMP_SLOT;
+         this->rel_->add_symbolless_local_addend(relobj, local_sym_index,
+                                                 dynrel, this, off, 0);
+       }
+      off += this->plt_entry_size();
+      this->set_current_data_size(off);
+    }
+}
+
 // Add an entry for a local ifunc symbol to the IPLT.
 
 template<int size, bool big_endian>
@@ -3850,7 +3972,7 @@ template<int size, bool big_endian>
 void
 Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of)
 {
-  if (size == 32 && this->name_[3] != 'I')
+  if (size == 32 && (this->name_[3] != 'I' && this->name_[3] != 'L'))
     {
       const section_size_type offset = this->offset();
       const section_size_type oview_size
@@ -3928,6 +4050,7 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
   if (this->iplt_ == NULL)
     {
       this->make_plt_section(symtab, layout);
+      this->make_lplt_section(layout);
 
       Reloc_section* iplt_rel = new Reloc_section(false);
       if (this->rela_dyn_->output_section())
@@ -3940,6 +4063,40 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
     }
 }
 
+// Create the LPLT section.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_lplt_section(Layout* layout)
+{
+  if (this->lplt_ == NULL)
+    {
+      Reloc_section* lplt_rel = NULL;
+      if (parameters->options().output_is_position_independent())
+       {
+         lplt_rel = new Reloc_section(false);
+         this->rela_dyn_section(layout);
+         if (this->rela_dyn_->output_section())
+           this->rela_dyn_->output_section()
+             ->add_output_section_data(lplt_rel);
+       }
+      this->lplt_
+       = new Output_data_plt_powerpc<size, big_endian>(this, lplt_rel,
+                                                       "** LPLT");
+      this->make_brlt_section(layout);
+      if (this->brlt_section_ && this->brlt_section_->output_section())
+       this->brlt_section_->output_section()
+         ->add_output_section_data(this->lplt_);
+      else
+       layout->add_output_section_data(".branch_lt",
+                                       elfcpp::SHT_PROGBITS,
+                                       elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+                                       this->lplt_,
+                                       ORDER_RELRO,
+                                       true);
+    }
+}
+
 // A section for huge long branch addresses, similar to plt section.
 
 template<int size, bool big_endian>
@@ -4030,9 +4187,8 @@ Target_powerpc<size, big_endian>::make_brlt_section(Layout* layout)
       bool is_pic = parameters->options().output_is_position_independent();
       if (is_pic)
        {
-         // When PIC we can't fill in .branch_lt (like .plt it can be
-         // a bss style section) but must initialise at runtime via
-         // dynamic relocations.
+         // When PIC we can't fill in .branch_lt but must initialise at
+         // runtime via dynamic relocations.
          this->rela_dyn_section(layout);
          brlt_rel = new Reloc_section(false);
          if (this->rela_dyn_->output_section())
@@ -4046,13 +4202,11 @@ Target_powerpc<size, big_endian>::make_brlt_section(Layout* layout)
          ->add_output_section_data(this->brlt_section_);
       else
        layout->add_output_section_data(".branch_lt",
-                                       (is_pic ? elfcpp::SHT_NOBITS
-                                        : elfcpp::SHT_PROGBITS),
+                                       elfcpp::SHT_PROGBITS,
                                        elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
                                        this->brlt_section_,
-                                       (is_pic ? ORDER_SMALL_BSS
-                                        : ORDER_SMALL_DATA),
-                                       false);
+                                       ORDER_RELRO,
+                                       true);
     }
 }
 
@@ -4165,6 +4319,15 @@ write_insn(unsigned char* p, uint32_t v)
   elfcpp::Swap<32, big_endian>::writeval(p, v);
 }
 
+template<int size>
+static inline unsigned int
+param_plt_align()
+{
+  if (!parameters->options().user_set_plt_align())
+    return size == 64 ? 32 : 8;
+  return 1 << parameters->options().plt_align();
+}
+
 // Stub_table holds information about plt and long branch stubs.
 // Stubs are built in an area following some input section determined
 // by group_sections().  This input section is converted to a relaxed
@@ -4391,30 +4554,24 @@ class Stub_table : public Output_relaxed_input_section
   unsigned int
   stub_align() const
   {
-    if (size == 32)
-      return 16;
-    unsigned int min_align = 32;
+    unsigned int min_align = size == 64 ? 32 : 16;
     unsigned int user_align = 1 << parameters->options().plt_align();
     return std::max(user_align, min_align);
   }
 
   // Return the plt offset for the given call stub.
   Address
-  plt_off(typename Plt_stub_entries::const_iterator p, bool* is_iplt) const
+  plt_off(typename Plt_stub_entries::const_iterator p,
+         const Output_data_plt_powerpc<size, big_endian>** sec) const
   {
     const Symbol* gsym = p->first.sym_;
     if (gsym != NULL)
-      {
-       *is_iplt = (gsym->type() == elfcpp::STT_GNU_IFUNC
-                   && gsym->can_use_relative_reloc(false));
-       return gsym->plt_offset();
-      }
+      return this->targ_->plt_off(gsym, sec);
     else
       {
-       *is_iplt = true;
        const Sized_relobj_file<size, big_endian>* relobj = p->first.object_;
        unsigned int local_sym_index = p->first.locsym_;
-       return relobj->local_plt_offset(local_sym_index);
+       return this->targ_->plt_off(relobj, local_sym_index, sec);
       }
   }
 
@@ -4425,17 +4582,13 @@ class Stub_table : public Output_relaxed_input_section
     if (size == 32)
       {
        const Symbol* gsym = p->first.sym_;
-       if (this->targ_->is_tls_get_addr_opt(gsym))
-         return 12 * 4;
-       return 4 * 4;
+       return (4 * 4
+               + (this->targ_->is_tls_get_addr_opt(gsym) ? 8 * 4 : 0));
       }
 
-    bool is_iplt;
-    Address plt_addr = this->plt_off(p, &is_iplt);
-    if (is_iplt)
-      plt_addr += this->targ_->iplt_section()->address();
-    else
-      plt_addr += this->targ_->plt_section()->address();
+    const Output_data_plt_powerpc<size, big_endian>* plt;
+    Address plt_addr = this->plt_off(p, &plt);
+    plt_addr += plt->address();
     Address got_addr = this->targ_->got_section()->output_section()->address();
     const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
       <const Powerpc_relobj<size, big_endian>*>(p->first.object_);
@@ -4460,10 +4613,8 @@ class Stub_table : public Output_relaxed_input_section
   unsigned int
   plt_call_align(unsigned int bytes) const
   {
-    unsigned int align = 1 << parameters->options().plt_align();
-    if (align > 1)
-      bytes = (bytes + align - 1) & -align;
-    return bytes;
+    unsigned int align = param_plt_align<size>();
+    return (bytes + align - 1) & -align;
   }
 
   // Return long branch stub size.
@@ -4473,9 +4624,10 @@ class Stub_table : public Output_relaxed_input_section
     Address loc = this->stub_address() + this->last_plt_size_ + p->second;
     if (p->first.dest_ - loc + (1 << 25) < 2 << 25)
       return 4;
-    if (size == 64 || !parameters->options().output_is_position_independent())
-      return 16;
-    return 32;
+    unsigned int bytes = 16;
+    if (size == 32 && parameters->options().output_is_position_independent())
+      bytes += 16;
+    return bytes;
   }
 
   // Write out stubs.
@@ -4504,7 +4656,8 @@ class Stub_table : public Output_relaxed_input_section
       if (size != 32)
        this->addend_ = addend;
       else if (parameters->options().output_is_position_independent()
-              && r_type == elfcpp::R_PPC_PLTREL24)
+              && (r_type == elfcpp::R_PPC_PLTREL24
+                  || r_type == elfcpp::R_POWERPC_PLTCALL))
        {
          this->addend_ = addend;
          if (this->addend_ >= 32768)
@@ -4521,7 +4674,8 @@ class Stub_table : public Output_relaxed_input_section
       if (size != 32)
        this->addend_ = addend;
       else if (parameters->options().output_is_position_independent()
-              && r_type == elfcpp::R_PPC_PLTREL24)
+              && (r_type == elfcpp::R_PPC_PLTREL24
+                  || r_type == elfcpp::R_POWERPC_PLTCALL))
        this->addend_ = addend;
     }
 
@@ -4884,7 +5038,6 @@ class Output_data_glink : public Output_section_data
  public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   static const Address invalid_address = static_cast<Address>(0) - 1;
-  static const int pltresolve_size = 16*4;
 
   Output_data_glink(Target_powerpc<size, big_endian>* targ)
     : Output_section_data(16), targ_(targ), global_entry_stubs_(),
@@ -4900,12 +5053,33 @@ class Output_data_glink : public Output_section_data
   Address
   find_global_entry(const Symbol*) const;
 
+  unsigned int
+  global_entry_align(unsigned int off) const
+  {
+    unsigned int align = param_plt_align<size>();
+    return (off + align - 1) & -align;
+  }
+
+  unsigned int
+  global_entry_off() const
+  {
+    return this->global_entry_align(this->end_branch_table_);
+  }
+
   Address
   global_entry_address() const
   {
     gold_assert(this->is_data_size_valid());
-    unsigned int global_entry_off = (this->end_branch_table_ + 15) & -16;
-    return this->address() + global_entry_off;
+    return this->address() + this->global_entry_off();
+  }
+
+  int
+  pltresolve_size() const
+  {
+    if (size == 64)
+      return (8
+             + (this->targ_->abiversion() < 2 ? 11 * 4 : 14 * 4));
+    return 16 * 4;
   }
 
  protected:
@@ -4977,10 +5151,11 @@ template<int size, bool big_endian>
 void
 Output_data_glink<size, big_endian>::add_global_entry(const Symbol* gsym)
 {
+  unsigned int off = this->global_entry_align(this->ge_size_);
   std::pair<typename Global_entry_stub_entries::iterator, bool> p
-    = this->global_entry_stubs_.insert(std::make_pair(gsym, this->ge_size_));
+    = this->global_entry_stubs_.insert(std::make_pair(gsym, off));
   if (p.second)
-    this->ge_size_ += 16;
+    this->ge_size_ = off + 16;
 }
 
 template<int size, bool big_endian>
@@ -5007,11 +5182,11 @@ Output_data_glink<size, big_endian>::set_final_data_size()
          total += 4 * (count - 1);
 
          total += -total & 15;
-         total += this->pltresolve_size;
+         total += this->pltresolve_size();
        }
       else
        {
-         total += this->pltresolve_size;
+         total += this->pltresolve_size();
 
          // space for branch table
          total += 4 * count;
@@ -5024,7 +5199,7 @@ Output_data_glink<size, big_endian>::set_final_data_size()
        }
     }
   this->end_branch_table_ = total;
-  total = (total + 15) & -16;
+  total = this->global_entry_align(total);
   total += this->ge_size_;
 
   this->set_data_size(total);
@@ -5131,27 +5306,15 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 
       if (!this->plt_call_stubs_.empty())
        {
-         // The base address of the .plt section.
-         Address plt_base = this->targ_->plt_section()->address();
-         Address iplt_base = invalid_address;
-
          // Write out plt call stubs.
          typename Plt_stub_entries::const_iterator cs;
          for (cs = this->plt_call_stubs_.begin();
               cs != this->plt_call_stubs_.end();
               ++cs)
            {
-             bool is_iplt;
-             Address pltoff = this->plt_off(cs, &is_iplt);
-             Address plt_addr = pltoff;
-             if (is_iplt)
-               {
-                 if (iplt_base == invalid_address)
-                   iplt_base = this->targ_->iplt_section()->address();
-                 plt_addr += iplt_base;
-               }
-             else
-               plt_addr += plt_base;
+             const Output_data_plt_powerpc<size, big_endian>* plt;
+             Address pltoff = this->plt_off(cs, &plt);
+             Address plt_addr = pltoff + plt->address();
              const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
                <const Powerpc_relobj<size, big_endian>*>(cs->first.object_);
              Address got_addr = got_os_addr + ppcobj->toc_base_offset();
@@ -5175,7 +5338,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                    = ((pltoff - this->targ_->first_plt_entry_offset())
                       / this->targ_->plt_entry_size());
                  Address glinkoff
-                   = (this->targ_->glink_section()->pltresolve_size
+                   = (this->targ_->glink_section()->pltresolve_size()
                       + pltindex * 8);
                  if (pltindex > 32768)
                    glinkoff += (pltindex - 32768) * 4;
@@ -5370,9 +5533,6 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
     {
       if (!this->plt_call_stubs_.empty())
        {
-         // The base address of the .plt section.
-         Address plt_base = this->targ_->plt_section()->address();
-         Address iplt_base = invalid_address;
          // The address of _GLOBAL_OFFSET_TABLE_.
          Address g_o_t = invalid_address;
 
@@ -5382,16 +5542,9 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
               cs != this->plt_call_stubs_.end();
               ++cs)
            {
-             bool is_iplt;
-             Address plt_addr = this->plt_off(cs, &is_iplt);
-             if (is_iplt)
-               {
-                 if (iplt_base == invalid_address)
-                   iplt_base = this->targ_->iplt_section()->address();
-                 plt_addr += iplt_base;
-               }
-             else
-               plt_addr += plt_base;
+             const Output_data_plt_powerpc<size, big_endian>* plt;
+             Address plt_addr = this->plt_off(cs, &plt);
+             plt_addr += plt->address();
 
              p = oview + cs->second.off_;
              const Symbol* gsym = cs->first.sym_;
@@ -5441,26 +5594,24 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 
                  Address off = plt_addr - got_addr;
                  if (ha(off) == 0)
-                   {
-                     write_insn<big_endian>(p +  0, lwz_11_30 + l(off));
-                     write_insn<big_endian>(p +  4, mtctr_11);
-                     write_insn<big_endian>(p +  8, bctr);
-                   }
+                   write_insn<big_endian>(p, lwz_11_30 + l(off));
                  else
                    {
-                     write_insn<big_endian>(p +  0, addis_11_30 + ha(off));
-                     write_insn<big_endian>(p +  4, lwz_11_11 + l(off));
-                     write_insn<big_endian>(p +  8, mtctr_11);
-                     write_insn<big_endian>(p + 12, bctr);
+                     write_insn<big_endian>(p, addis_11_30 + ha(off));
+                     p += 4;
+                     write_insn<big_endian>(p, lwz_11_11 + l(off));
                    }
                }
              else
                {
-                 write_insn<big_endian>(p +  0, lis_11 + ha(plt_addr));
-                 write_insn<big_endian>(p +  4, lwz_11_11 + l(plt_addr));
-                 write_insn<big_endian>(p +  8, mtctr_11);
-                 write_insn<big_endian>(p + 12, bctr);
+                 write_insn<big_endian>(p, lis_11 + ha(plt_addr));
+                 p += 4;
+                 write_insn<big_endian>(p, lwz_11_11 + l(plt_addr));
                }
+             p += 4;
+             write_insn<big_endian>(p, mtctr_11);
+             p += 4;
+             write_insn<big_endian>(p, bctr);
            }
        }
 
@@ -5479,23 +5630,29 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
            write_insn<big_endian>(p, b | (delta & 0x3fffffc));
          else if (!parameters->options().output_is_position_independent())
            {
-             write_insn<big_endian>(p +  0, lis_12 + ha(bs->first.dest_));
-             write_insn<big_endian>(p +  4, addi_12_12 + l(bs->first.dest_));
-             write_insn<big_endian>(p +  8, mtctr_12);
-             write_insn<big_endian>(p + 12, bctr);
+             write_insn<big_endian>(p, lis_12 + ha(bs->first.dest_));
+             p += 4;
+             write_insn<big_endian>(p, addi_12_12 + l(bs->first.dest_));
            }
          else
            {
              delta -= 8;
-             write_insn<big_endian>(p +  0, mflr_0);
-             write_insn<big_endian>(p +  4, bcl_20_31);
-             write_insn<big_endian>(p +  8, mflr_12);
-             write_insn<big_endian>(p + 12, addis_12_12 + ha(delta));
-             write_insn<big_endian>(p + 16, addi_12_12 + l(delta));
-             write_insn<big_endian>(p + 20, mtlr_0);
-             write_insn<big_endian>(p + 24, mtctr_12);
-             write_insn<big_endian>(p + 28, bctr);
+             write_insn<big_endian>(p, mflr_0);
+             p += 4;
+             write_insn<big_endian>(p, bcl_20_31);
+             p += 4;
+             write_insn<big_endian>(p, mflr_12);
+             p += 4;
+             write_insn<big_endian>(p, addis_12_12 + ha(delta));
+             p += 4;
+             write_insn<big_endian>(p, addi_12_12 + l(delta));
+             p += 4;
+             write_insn<big_endian>(p, mtlr_0);
            }
+         p += 4;
+         write_insn<big_endian>(p, mtctr_12);
+         p += 4;
+         write_insn<big_endian>(p, bctr);
        }
     }
   if (this->need_save_res_)
@@ -5563,8 +5720,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
              write_insn<big_endian>(p, ld_11_11 + 8),          p += 4;
            }
          write_insn<big_endian>(p, bctr),                      p += 4;
-         while (p < oview + this->pltresolve_size)
-           write_insn<big_endian>(p, nop), p += 4;
+         gold_assert(p == oview + this->pltresolve_size());
 
          // Write lazy link call stubs.
          uint32_t indx = 0;
@@ -5590,7 +5746,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
 
       Address plt_base = this->targ_->plt_section()->address();
       Address iplt_base = invalid_address;
-      unsigned int global_entry_off = (this->end_branch_table_ + 15) & -16;
+      unsigned int global_entry_off = this->global_entry_off();
       Address global_entry_base = this->address() + global_entry_off;
       typename Global_entry_stub_entries::const_iterator ge;
       for (ge = this->global_entry_stubs_.begin();
@@ -5631,7 +5787,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
 
       // Write out pltresolve branch table.
       p = oview;
-      unsigned int the_end = oview_size - this->pltresolve_size;
+      unsigned int the_end = oview_size - this->pltresolve_size();
       unsigned char* end_p = oview + the_end;
       while (p < end_p - 8 * 4)
        write_insn<big_endian>(p, b + end_p - p), p += 4;
@@ -5639,68 +5795,85 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
        write_insn<big_endian>(p, nop), p += 4;
 
       // Write out pltresolve call stub.
+      end_p = oview + oview_size;
       if (parameters->options().output_is_position_independent())
        {
          Address res0_off = 0;
          Address after_bcl_off = the_end + 12;
          Address bcl_res0 = after_bcl_off - res0_off;
 
-         write_insn<big_endian>(p +  0, addis_11_11 + ha(bcl_res0));
-         write_insn<big_endian>(p +  4, mflr_0);
-         write_insn<big_endian>(p +  8, bcl_20_31);
-         write_insn<big_endian>(p + 12, addi_11_11 + l(bcl_res0));
-         write_insn<big_endian>(p + 16, mflr_12);
-         write_insn<big_endian>(p + 20, mtlr_0);
-         write_insn<big_endian>(p + 24, sub_11_11_12);
+         write_insn<big_endian>(p, addis_11_11 + ha(bcl_res0));
+         p += 4;
+         write_insn<big_endian>(p, mflr_0);
+         p += 4;
+         write_insn<big_endian>(p, bcl_20_31);
+         p += 4;
+         write_insn<big_endian>(p, addi_11_11 + l(bcl_res0));
+         p += 4;
+         write_insn<big_endian>(p, mflr_12);
+         p += 4;
+         write_insn<big_endian>(p, mtlr_0);
+         p += 4;
+         write_insn<big_endian>(p, sub_11_11_12);
+         p += 4;
 
          Address got_bcl = g_o_t + 4 - (after_bcl_off + this->address());
 
-         write_insn<big_endian>(p + 28, addis_12_12 + ha(got_bcl));
+         write_insn<big_endian>(p, addis_12_12 + ha(got_bcl));
+         p += 4;
          if (ha(got_bcl) == ha(got_bcl + 4))
            {
-             write_insn<big_endian>(p + 32, lwz_0_12 + l(got_bcl));
-             write_insn<big_endian>(p + 36, lwz_12_12 + l(got_bcl + 4));
+             write_insn<big_endian>(p, lwz_0_12 + l(got_bcl));
+             p += 4;
+             write_insn<big_endian>(p, lwz_12_12 + l(got_bcl + 4));
            }
          else
            {
-             write_insn<big_endian>(p + 32, lwzu_0_12 + l(got_bcl));
-             write_insn<big_endian>(p + 36, lwz_12_12 + 4);
+             write_insn<big_endian>(p, lwzu_0_12 + l(got_bcl));
+             p += 4;
+             write_insn<big_endian>(p, lwz_12_12 + 4);
            }
-         write_insn<big_endian>(p + 40, mtctr_0);
-         write_insn<big_endian>(p + 44, add_0_11_11);
-         write_insn<big_endian>(p + 48, add_11_0_11);
-         write_insn<big_endian>(p + 52, bctr);
-         write_insn<big_endian>(p + 56, nop);
-         write_insn<big_endian>(p + 60, nop);
+         p += 4;
+         write_insn<big_endian>(p, mtctr_0);
+         p += 4;
+         write_insn<big_endian>(p, add_0_11_11);
+         p += 4;
+         write_insn<big_endian>(p, add_11_0_11);
        }
       else
        {
          Address res0 = this->address();
 
-         write_insn<big_endian>(p + 0, lis_12 + ha(g_o_t + 4));
-         write_insn<big_endian>(p + 4, addis_11_11 + ha(-res0));
+         write_insn<big_endian>(p, lis_12 + ha(g_o_t + 4));
+         p += 4;
+         write_insn<big_endian>(p, addis_11_11 + ha(-res0));
+         p += 4;
          if (ha(g_o_t + 4) == ha(g_o_t + 8))
-           write_insn<big_endian>(p + 8, lwz_0_12 + l(g_o_t + 4));
+           write_insn<big_endian>(p, lwz_0_12 + l(g_o_t + 4));
          else
-           write_insn<big_endian>(p + 8, lwzu_0_12 + l(g_o_t + 4));
-         write_insn<big_endian>(p + 12, addi_11_11 + l(-res0));
-         write_insn<big_endian>(p + 16, mtctr_0);
-         write_insn<big_endian>(p + 20, add_0_11_11);
+           write_insn<big_endian>(p, lwzu_0_12 + l(g_o_t + 4));
+         p += 4;
+         write_insn<big_endian>(p, addi_11_11 + l(-res0));
+         p += 4;
+         write_insn<big_endian>(p, mtctr_0);
+         p += 4;
+         write_insn<big_endian>(p, add_0_11_11);
+         p += 4;
          if (ha(g_o_t + 4) == ha(g_o_t + 8))
-           write_insn<big_endian>(p + 24, lwz_12_12 + l(g_o_t + 8));
+           write_insn<big_endian>(p, lwz_12_12 + l(g_o_t + 8));
          else
-           write_insn<big_endian>(p + 24, lwz_12_12 + 4);
-         write_insn<big_endian>(p + 28, add_11_0_11);
-         write_insn<big_endian>(p + 32, bctr);
-         write_insn<big_endian>(p + 36, nop);
-         write_insn<big_endian>(p + 40, nop);
-         write_insn<big_endian>(p + 44, nop);
-         write_insn<big_endian>(p + 48, nop);
-         write_insn<big_endian>(p + 52, nop);
-         write_insn<big_endian>(p + 56, nop);
-         write_insn<big_endian>(p + 60, nop);
+           write_insn<big_endian>(p, lwz_12_12 + 4);
+         p += 4;
+         write_insn<big_endian>(p, add_11_0_11);
+       }
+      p += 4;
+      write_insn<big_endian>(p, bctr);
+      p += 4;
+      while (p < end_p)
+       {
+         write_insn<big_endian>(p, nop);
+         p += 4;
        }
-      p += 64;
     }
 
   of->write_output_view(off, oview_size, oview);
@@ -6080,6 +6253,20 @@ Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
     }
 }
 
+// Make a PLT entry for a local symbol.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::make_local_plt_entry(
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* relobj,
+    unsigned int r_sym)
+{
+  if (this->lplt_ == NULL)
+    this->make_lplt_section(layout);
+  this->lplt_->add_local_entry(relobj, r_sym);
+}
+
 // Make a PLT entry for a local STT_GNU_IFUNC symbol.
 
 template<int size, bool big_endian>
@@ -6197,6 +6384,10 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
     case elfcpp::R_PPC64_TOC16_HA:
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
+    case elfcpp::R_POWERPC_PLT16_LO:
+    case elfcpp::R_POWERPC_PLT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HA:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
       ref = Symbol::RELATIVE_REF;
       break;
 
@@ -6380,6 +6571,16 @@ Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
     case elfcpp::R_PPC64_GOT16_LO_DS:
       return false;
 
+    // PLT relocs are OK and need a PLT entry.
+    case elfcpp::R_POWERPC_PLT16_LO:
+    case elfcpp::R_POWERPC_PLT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HA:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
+    case elfcpp::R_POWERPC_PLTSEQ:
+    case elfcpp::R_POWERPC_PLTCALL:
+      return true;
+      break;
+
     // Function calls are good, and these do need a PLT entry.
     case elfcpp::R_POWERPC_ADDR24:
     case elfcpp::R_POWERPC_ADDR14:
@@ -6514,6 +6715,8 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_GNU_VTENTRY:
     case elfcpp::R_POWERPC_TLS:
     case elfcpp::R_PPC64_ENTRY:
+    case elfcpp::R_POWERPC_PLTSEQ:
+    case elfcpp::R_POWERPC_PLTCALL:
       break;
 
     case elfcpp::R_PPC64_TOC:
@@ -6605,6 +6808,17 @@ Target_powerpc<size, big_endian>::Scan::local(
        }
       break;
 
+    case elfcpp::R_POWERPC_PLT16_LO:
+    case elfcpp::R_POWERPC_PLT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HA:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
+      if (!is_ifunc)
+       {
+         unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+         target->make_local_plt_entry(layout, object, r_sym);
+       }
+      break;
+
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_PPC_LOCAL24PC:
@@ -7063,6 +7277,8 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_PPC_LOCAL24PC:
     case elfcpp::R_POWERPC_TLS:
     case elfcpp::R_PPC64_ENTRY:
+    case elfcpp::R_POWERPC_PLTSEQ:
+    case elfcpp::R_POWERPC_PLTCALL:
       break;
 
     case elfcpp::R_PPC64_TOC:
@@ -7198,6 +7414,14 @@ Target_powerpc<size, big_endian>::Scan::global(
       }
       break;
 
+    case elfcpp::R_POWERPC_PLT16_LO:
+    case elfcpp::R_POWERPC_PLT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HA:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
+      if (!pushed_ifunc)
+       target->make_plt_entry(symtab, layout, gsym);
+      break;
+
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_POWERPC_REL24:
       if (!is_ifunc)
@@ -8161,7 +8385,7 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
              this->glink_->finalize_data_size();
              odyn->add_section_plus_offset(elfcpp::DT_PPC64_GLINK,
                                            this->glink_,
-                                           (this->glink_->pltresolve_size
+                                           (this->glink_->pltresolve_size()
                                             - 32));
            }
          if (this->has_localentry0_ || this->has_tls_get_addr_opt_)
@@ -8284,6 +8508,10 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     Address address,
     section_size_type view_size)
 {
+  typedef Powerpc_relocate_functions<size, big_endian> Reloc;
+  typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
+  typedef typename elfcpp::Rela<size, big_endian> Reltype;
+
   if (view == NULL)
     return true;
 
@@ -8302,14 +8530,22 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       // We have already complained.
       break;
     case Track_tls::SKIP:
+      if (is_plt16_reloc<size>(r_type)
+         || r_type == elfcpp::R_POWERPC_PLTSEQ)
+       {
+         Insn* iview = reinterpret_cast<Insn*>(view);
+         elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+       }
+      else if (size == 64 && r_type == elfcpp::R_POWERPC_PLTCALL)
+       {
+         Insn* iview = reinterpret_cast<Insn*>(view);
+         elfcpp::Swap<32, big_endian>::writeval(iview + 1, nop);
+       }
       return true;
     case Track_tls::NORMAL:
       break;
     }
 
-  typedef Powerpc_relocate_functions<size, big_endian> Reloc;
-  typedef typename elfcpp::Swap<32, big_endian>::Valtype Insn;
-  typedef typename elfcpp::Rela<size, big_endian> Reltype;
   // Offset from start of insn to d-field reloc.
   const int d_offset = big_endian ? 2 : 0;
 
@@ -8319,9 +8555,14 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
   bool has_stub_value = false;
   bool localentry0 = false;
   unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
-  if ((gsym != NULL
+  bool has_plt_offset
+    = (gsym != NULL
        ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
-       : object->local_has_plt_offset(r_sym))
+       : object->local_has_plt_offset(r_sym));
+  if (has_plt_offset
+      && !is_plt16_reloc<size>(r_type)
+      && r_type != elfcpp::R_POWERPC_PLTSEQ
+      && r_type != elfcpp::R_POWERPC_PLTCALL
       && (!psymval->is_ifunc_symbol()
          || Scan::reloc_needs_plt_for_ifunc(target, object, r_type, false)))
     {
@@ -8393,12 +8634,46 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       gold_assert(has_stub_value || !(os->flags() & elfcpp::SHF_ALLOC));
     }
 
-  if (r_type == elfcpp::R_POWERPC_GOT16
-      || r_type == elfcpp::R_POWERPC_GOT16_LO
-      || r_type == elfcpp::R_POWERPC_GOT16_HI
-      || r_type == elfcpp::R_POWERPC_GOT16_HA
-      || r_type == elfcpp::R_PPC64_GOT16_DS
-      || r_type == elfcpp::R_PPC64_GOT16_LO_DS)
+  if (has_plt_offset && is_plt16_reloc<size>(r_type))
+    {
+      const Output_data_plt_powerpc<size, big_endian>* plt;
+      if (gsym)
+       value = target->plt_off(gsym, &plt);
+      else
+       value = target->plt_off(object, r_sym, &plt);
+      value += plt->address();
+
+      if (size == 64)
+       value -= (target->got_section()->output_section()->address()
+                 + object->toc_base_offset());
+      else if (parameters->options().output_is_position_independent())
+       {
+         if (rela.get_r_addend() >= 32768)
+           {
+             unsigned int got2 = object->got2_shndx();
+             value -= (object->get_output_section_offset(got2)
+                       + object->output_section(got2)->address()
+                       + rela.get_r_addend());
+           }
+         else
+           value -= (target->got_section()->address()
+                     + target->got_section()->g_o_t());
+       }
+    }
+  else if (!has_plt_offset
+          && (is_plt16_reloc<size>(r_type)
+              || r_type == elfcpp::R_POWERPC_PLTSEQ))
+    {
+      Insn* iview = reinterpret_cast<Insn*>(view);
+      elfcpp::Swap<32, big_endian>::writeval(iview, nop);
+      r_type = elfcpp::R_POWERPC_NONE;
+    }
+  else if (r_type == elfcpp::R_POWERPC_GOT16
+          || r_type == elfcpp::R_POWERPC_GOT16_LO
+          || r_type == elfcpp::R_POWERPC_GOT16_HI
+          || r_type == elfcpp::R_POWERPC_GOT16_HA
+          || r_type == elfcpp::R_PPC64_GOT16_DS
+          || r_type == elfcpp::R_PPC64_GOT16_LO_DS)
     {
       if (gsym != NULL)
        {
@@ -8729,8 +9004,24 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     }
   else if (!has_stub_value)
     {
+      if (!has_plt_offset && r_type == elfcpp::R_POWERPC_PLTCALL)
+       {
+         // PLTCALL without plt entry => convert to direct call
+         Insn* iview = reinterpret_cast<Insn*>(view);
+         Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+         insn = (insn & 1) | b;
+         elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+         if (size == 32)
+           r_type = elfcpp::R_PPC_PLTREL24;
+         else
+           r_type = elfcpp::R_POWERPC_REL24;
+       }
       Address addend = 0;
-      if (!(size == 32 && r_type == elfcpp::R_PPC_PLTREL24))
+      if (!(size == 32
+           && (r_type == elfcpp::R_PPC_PLTREL24
+               || r_type == elfcpp::R_POWERPC_PLT16_LO
+               || r_type == elfcpp::R_POWERPC_PLT16_HI
+               || r_type == elfcpp::R_POWERPC_PLT16_HA)))
        addend = rela.get_r_addend();
       value = psymval->value(object, addend);
       if (size == 64 && is_branch_reloc(r_type))
@@ -8897,6 +9188,23 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       }
       break;
 
+    case elfcpp::R_POWERPC_PLT16_HA:
+      if (size == 32
+         && !parameters->options().output_is_position_independent())
+       {
+         Insn* iview = reinterpret_cast<Insn*>(view - d_offset);
+         Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
+
+         // Convert addis to lis.
+         if ((insn & (0x3f << 26)) == 15u << 26
+             && (insn & (0x1f << 16)) != 0)
+           {
+             insn &= ~(0x1f << 16);
+             elfcpp::Swap<32, big_endian>::writeval(iview, insn);
+           }
+       }
+      break;
+
     default:
       break;
     }
@@ -9237,6 +9545,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_POWERPC_TLS:
     case elfcpp::R_POWERPC_GNU_VTINHERIT:
     case elfcpp::R_POWERPC_GNU_VTENTRY:
+    case elfcpp::R_POWERPC_PLTSEQ:
+    case elfcpp::R_POWERPC_PLTCALL:
       break;
 
     case elfcpp::R_PPC64_ADDR64:
@@ -9298,6 +9608,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_POWERPC_REL16_LO:
     case elfcpp::R_PPC64_TOC16_LO:
     case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_PLT16_LO:
     case elfcpp::R_POWERPC_SECTOFF_LO:
     case elfcpp::R_POWERPC_TPREL16_LO:
     case elfcpp::R_POWERPC_DTPREL16_LO:
@@ -9324,6 +9635,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_POWERPC_REL16_HI:
     case elfcpp::R_PPC64_TOC16_HI:
     case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_PLT16_HI:
     case elfcpp::R_POWERPC_SECTOFF_HI:
     case elfcpp::R_POWERPC_TPREL16_HI:
     case elfcpp::R_POWERPC_DTPREL16_HI:
@@ -9345,6 +9657,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_POWERPC_REL16_HA:
     case elfcpp::R_PPC64_TOC16_HA:
     case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_POWERPC_PLT16_HA:
     case elfcpp::R_POWERPC_SECTOFF_HA:
     case elfcpp::R_POWERPC_TPREL16_HA:
     case elfcpp::R_POWERPC_DTPREL16_HA:
@@ -9417,6 +9730,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_PPC64_TOC16_LO_DS:
     case elfcpp::R_PPC64_GOT16_DS:
     case elfcpp::R_PPC64_GOT16_LO_DS:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
     case elfcpp::R_PPC64_SECTOFF_DS:
     case elfcpp::R_PPC64_SECTOFF_LO_DS:
       maybe_dq_reloc = true;
@@ -9475,9 +9789,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 
     case elfcpp::R_POWERPC_PLT32:
     case elfcpp::R_POWERPC_PLTREL32:
-    case elfcpp::R_POWERPC_PLT16_LO:
-    case elfcpp::R_POWERPC_PLT16_HI:
-    case elfcpp::R_POWERPC_PLT16_HA:
     case elfcpp::R_PPC_SDAREL16:
     case elfcpp::R_POWERPC_ADDR30:
     case elfcpp::R_PPC64_PLT64:
@@ -9486,7 +9797,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_PPC64_PLTGOT16_LO:
     case elfcpp::R_PPC64_PLTGOT16_HI:
     case elfcpp::R_PPC64_PLTGOT16_HA:
-    case elfcpp::R_PPC64_PLT16_LO_DS:
     case elfcpp::R_PPC64_PLTGOT16_DS:
     case elfcpp::R_PPC64_PLTGOT16_LO_DS:
     case elfcpp::R_PPC_EMB_RELSDA:
@@ -9613,7 +9923,11 @@ public:
   inline Relocatable_relocs::Reloc_strategy
   global_strategy(unsigned int r_type, Relobj*, unsigned int)
   {
-    if (r_type == elfcpp::R_PPC_PLTREL24)
+    if (size == 32
+       && (r_type == elfcpp::R_PPC_PLTREL24
+           || r_type == elfcpp::R_POWERPC_PLT16_LO
+           || r_type == elfcpp::R_POWERPC_PLT16_HI
+           || r_type == elfcpp::R_POWERPC_PLT16_HA))
       return Relocatable_relocs::RELOC_SPECIAL;
     return Relocatable_relocs::RELOC_COPY;
   }
@@ -10187,8 +10501,6 @@ Target_selector_powerpc<64, false> target_selector_ppc64le;
 
 // Instantiate these constants for -O0
 template<int size, bool big_endian>
-const int Output_data_glink<size, big_endian>::pltresolve_size;
-template<int size, bool big_endian>
 const typename Output_data_glink<size, big_endian>::Address
   Output_data_glink<size, big_endian>::invalid_address;
 template<int size, bool big_endian>
This page took 0.054125 seconds and 4 git commands to generate.