]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gold/powerpc.cc
2.41 Release sources
[thirdparty/binutils-gdb.git] / gold / powerpc.cc
index a40614cd45c5977b1cb355efc23036431e3f80d2..d62bdea7ecbabc4c0d420cc1cb4460008142534b 100644 (file)
@@ -1,6 +1,6 @@
 // powerpc.cc -- powerpc target support for gold.
 
-// Copyright (C) 2008-2021 Free Software Foundation, Inc.
+// Copyright (C) 2008-2023 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>
 //        and David Edelsohn <edelsohn@gnu.org>
 
@@ -636,6 +636,24 @@ enum Got_type
     GOT_TYPE_SMALL_TPREL = 7
   };
 
+// gsym->needs_plt_entry purpose is to decide whether a non-branch
+// reloc should reference a plt entry.  It can't be used to decide
+// whether branches need a plt entry.  In fact the call to
+// needs_plt_entry here is not needed;  All cases where it might
+// return true ought to be covered already.  However, since this
+// function is used to decide between plt_ and lplt_ sections in
+// plt_off, make certain that every case where make_plt_entry puts
+// entries in plt_ is covered here.
+static bool
+branch_needs_plt_entry(const Symbol* gsym)
+{
+  return (((!gsym->is_defined()
+           || gsym->is_from_dynobj()
+           || gsym->is_preemptible())
+          && !gsym->final_value_is_known())
+         || gsym->needs_plt_entry());
+}
+
 template<int size, bool big_endian>
 class Target_powerpc : public Sized_target<size, big_endian>
 {
@@ -778,6 +796,10 @@ class Target_powerpc : public Sized_target<size, big_endian>
   void
   do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
 
+  // Get the custom dynamic tag value.
+  unsigned int
+  do_dynamic_tag_custom_value(elfcpp::DT) const;
+
   // Return the value to use for a dynamic which requires special
   // treatment.
   uint64_t
@@ -927,7 +949,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
     if (gsym->type() == elfcpp::STT_GNU_IFUNC
        && gsym->can_use_relative_reloc(false))
       *sec = this->iplt_section();
-    else if (!parameters->doing_static_link())
+    else if (branch_needs_plt_entry(gsym))
       *sec = this->plt_section();
     else
       *sec = this->lplt_section();
@@ -1741,6 +1763,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
   Branches branch_info_;
   Tocsave_loc tocsave_loc_;
 
+  off_t rela_dyn_size_;
+
   bool power10_relocs_;
   bool plt_thread_safe_;
   bool plt_localentry0_;
@@ -3665,6 +3689,18 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
   return ok;
 }
 
+// Helper for do_relax, avoiding checks that size, address and offset
+// are not set more than once.
+
+static inline void
+update_current_size(Output_section_data_build* od, off_t cur_size)
+{
+  od->reset_address_and_file_offset();
+  od->set_current_data_size(cur_size);
+  od->finalize_data_size();
+  od->output_section()->set_section_offsets_need_adjustment();
+}
+
 // Relaxation hook.  This is where we do stub generation.
 
 template<int size, bool big_endian>
@@ -3730,10 +3766,11 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
            }
        }
       this->plt_thread_safe_ = thread_safe;
-    }
 
-  if (pass == 1)
-    {
+      if (parameters->options().output_is_position_independent())
+       this->rela_dyn_size_
+         = this->rela_dyn_section(layout)->current_data_size();
+
       this->stub_group_size_ = parameters->options().stub_group_size();
       bool no_size_errors = true;
       if (this->stub_group_size_ == 1)
@@ -3846,7 +3883,15 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
   if (size == 64 && num_huge_branches != 0)
     this->make_brlt_section(layout);
   if (size == 64 && again)
-    this->brlt_section_->set_current_size(num_huge_branches);
+    {
+      update_current_size(this->brlt_section_, num_huge_branches * 16);
+      if (parameters->options().output_is_position_independent())
+       {
+         const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+         off_t cur = this->rela_dyn_size_ + num_huge_branches * reloc_size;
+         update_current_size(this->rela_dyn_, cur);
+       }
+    }
 
   for (typename Stub_tables::reverse_iterator p = this->stub_tables_.rbegin();
        p != this->stub_tables_.rend();
@@ -3915,15 +3960,21 @@ Target_powerpc<size, big_endian>::do_relax(int pass,
       && parameters->options().output_is_position_independent())
     {
       // Fill in the BRLT relocs.
-      this->brlt_section_->reset_brlt_sizes();
+      this->rela_dyn_->reset_data_size();
+      this->rela_dyn_->set_current_data_size(this->rela_dyn_size_);
       for (typename Branch_lookup_table::const_iterator p
             = this->branch_lookup_table_.begin();
           p != this->branch_lookup_table_.end();
           ++p)
        {
-         this->brlt_section_->add_reloc(p->first, p->second);
+         this->rela_dyn_->add_relative(elfcpp::R_POWERPC_RELATIVE,
+                                       this->brlt_section_, p->second,
+                                       p->first);
        }
-      this->brlt_section_->finalize_brlt_sizes();
+      this->rela_dyn_->finalize_data_size();
+      const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+      gold_assert(this->rela_dyn_->data_size()
+                 == this->rela_dyn_size_ + num_huge_branches * reloc_size);
     }
 
   if (!again
@@ -4133,7 +4184,7 @@ class Output_data_plt_powerpc : public Output_section_data_build
 template<int size, bool big_endian>
 void
 Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym,
-                                                    bool stash)
+                                                    bool is_local)
 {
   if (!gsym->has_plt_offset())
     {
@@ -4143,13 +4194,24 @@ Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym,
       gsym->set_plt_offset(off);
       if (this->rel_)
        {
-         gsym->set_needs_dynsym_entry();
-         unsigned int dynrel = elfcpp::R_POWERPC_JMP_SLOT;
-         this->rel_->add_global(gsym, dynrel, this, off, 0);
+         if (is_local)
+           {
+             unsigned int dynrel = elfcpp::R_POWERPC_RELATIVE;
+             if (size == 64 && this->targ_->abiversion() < 2)
+               dynrel = elfcpp::R_POWERPC_JMP_SLOT;
+             this->rel_->add_symbolless_global_addend(gsym, dynrel,
+                                                      this, off, 0);
+           }
+         else
+           {
+             gsym->set_needs_dynsym_entry();
+             unsigned int dynrel = elfcpp::R_POWERPC_JMP_SLOT;
+             this->rel_->add_global(gsym, dynrel, this, off, 0);
+           }
        }
       off += this->plt_entry_size();
       this->set_current_data_size(off);
-      if (stash)
+      if (is_local)
        {
          Local_plt_ent sym(gsym);
          this->sym_ents_.push_back(sym);
@@ -4338,7 +4400,8 @@ template<int size, bool big_endian>
 void
 Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of)
 {
-  if (!this->sym_ents_.empty())
+  if (!this->sym_ents_.empty()
+      && !parameters->options().output_is_position_independent())
     {
       const section_size_type offset = this->offset();
       const section_size_type oview_size
@@ -4492,13 +4555,7 @@ Target_powerpc<size, big_endian>::make_lplt_section(Symbol_table* symtab,
     {
       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);
-       }
+       lplt_rel = this->rela_dyn_section(layout);
       this->lplt_
        = new Output_data_plt_powerpc<size, big_endian>(this, symtab, lplt_rel,
                                                        "** LPLT");
@@ -4526,52 +4583,11 @@ class Output_data_brlt_powerpc : public Output_section_data_build
   typedef Output_data_reloc<elfcpp::SHT_RELA, true,
                            size, big_endian> Reloc_section;
 
-  Output_data_brlt_powerpc(Target_powerpc<size, big_endian>* targ,
-                          Reloc_section* brlt_rel)
+  Output_data_brlt_powerpc(Target_powerpc<size, big_endian>* targ)
     : Output_section_data_build(size == 32 ? 4 : 8),
-      rel_(brlt_rel),
       targ_(targ)
   { }
 
-  void
-  reset_brlt_sizes()
-  {
-    this->reset_data_size();
-    this->rel_->reset_data_size();
-  }
-
-  void
-  finalize_brlt_sizes()
-  {
-    this->finalize_data_size();
-    this->rel_->finalize_data_size();
-  }
-
-  // Add a reloc for an entry in the BRLT.
-  void
-  add_reloc(Address to, unsigned int off)
-  { this->rel_->add_relative(elfcpp::R_POWERPC_RELATIVE, this, off, to); }
-
-  // Update section and reloc section size.
-  void
-  set_current_size(unsigned int num_branches)
-  {
-    this->reset_address_and_file_offset();
-    this->set_current_data_size(num_branches * 16);
-    this->finalize_data_size();
-    Output_section* os = this->output_section();
-    os->set_section_offsets_need_adjustment();
-    if (this->rel_ != NULL)
-      {
-       const unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
-       this->rel_->reset_address_and_file_offset();
-       this->rel_->set_current_data_size(num_branches * reloc_size);
-       this->rel_->finalize_data_size();
-       Output_section* os = this->rel_->output_section();
-       os->set_section_offsets_need_adjustment();
-      }
-  }
-
  protected:
   void
   do_adjust_output_section(Output_section* os)
@@ -4589,8 +4605,6 @@ class Output_data_brlt_powerpc : public Output_section_data_build
   void
   do_write(Output_file*);
 
-  // The reloc section.
-  Reloc_section* rel_;
   Target_powerpc<size, big_endian>* targ_;
 };
 
@@ -4602,20 +4616,15 @@ Target_powerpc<size, big_endian>::make_brlt_section(Layout* layout)
 {
   if (size == 64 && this->brlt_section_ == NULL)
     {
-      Reloc_section* brlt_rel = NULL;
       bool is_pic = parameters->options().output_is_position_independent();
       if (is_pic)
        {
          // 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())
-           this->rela_dyn_->output_section()
-             ->add_output_section_data(brlt_rel);
        }
       this->brlt_section_
-       = new Output_data_brlt_powerpc<size, big_endian>(this, brlt_rel);
+       = new Output_data_brlt_powerpc<size, big_endian>(this);
       if (this->plt_ && is_pic && this->plt_->output_section())
        this->plt_->output_section()
          ->add_output_section_data(this->brlt_section_);
@@ -7675,22 +7684,18 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
 
   switch (r_type)
     {
+    case elfcpp::R_PPC64_TOC:
+      if (size != 64)
+       break;
+      // Fall through.
     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.
       break;
 
     case elfcpp::R_PPC64_ADDR64:
     case elfcpp::R_PPC64_UADDR64:
-    case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_POWERPC_UADDR32:
-    case elfcpp::R_POWERPC_ADDR16:
-    case elfcpp::R_POWERPC_UADDR16:
-    case elfcpp::R_POWERPC_ADDR16_LO:
-    case elfcpp::R_POWERPC_ADDR16_HI:
-    case elfcpp::R_POWERPC_ADDR16_HA:
     case elfcpp::R_PPC64_ADDR16_HIGHER34:
     case elfcpp::R_PPC64_ADDR16_HIGHERA34:
     case elfcpp::R_PPC64_ADDR16_HIGHEST34:
@@ -7700,6 +7705,16 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
     case elfcpp::R_PPC64_D34_HI30:
     case elfcpp::R_PPC64_D34_HA30:
     case elfcpp::R_PPC64_D28:
+      if (size != 64)
+       break;
+      // Fall through.
+    case elfcpp::R_POWERPC_ADDR32:
+    case elfcpp::R_POWERPC_UADDR32:
+    case elfcpp::R_POWERPC_ADDR16:
+    case elfcpp::R_POWERPC_UADDR16:
+    case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
       ref = Symbol::ABSOLUTE_REF;
       break;
 
@@ -7710,13 +7725,14 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
       ref = Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
       break;
 
-    case elfcpp::R_PPC64_REL64:
-    case elfcpp::R_POWERPC_REL32:
     case elfcpp::R_PPC_LOCAL24PC:
-    case elfcpp::R_POWERPC_REL16:
-    case elfcpp::R_POWERPC_REL16_LO:
-    case elfcpp::R_POWERPC_REL16_HI:
-    case elfcpp::R_POWERPC_REL16_HA:
+      if (size != 32)
+       break;
+      // Fall through.
+      ref = Symbol::RELATIVE_REF;
+      break;
+
+    case elfcpp::R_PPC64_REL64:
     case elfcpp::R_PPC64_REL16_HIGH:
     case elfcpp::R_PPC64_REL16_HIGHA:
     case elfcpp::R_PPC64_REL16_HIGHER:
@@ -7729,36 +7745,45 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
     case elfcpp::R_PPC64_REL16_HIGHEST34:
     case elfcpp::R_PPC64_REL16_HIGHESTA34:
     case elfcpp::R_PPC64_PCREL28:
+      if (size != 64)
+       break;
+      // Fall through.
+    case elfcpp::R_POWERPC_REL32:
+    case elfcpp::R_POWERPC_REL16:
+    case elfcpp::R_POWERPC_REL16_LO:
+    case elfcpp::R_POWERPC_REL16_HI:
+    case elfcpp::R_POWERPC_REL16_HA:
       ref = Symbol::RELATIVE_REF;
       break;
 
+    case elfcpp::R_PPC_PLTREL24:
+      if (size != 32)
+       break;
+      ref = Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+      break;
+
     case elfcpp::R_PPC64_REL24_NOTOC:
-      if (size == 32)
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
+    case elfcpp::R_PPC64_PLT16_LO_DS:
+    case elfcpp::R_PPC64_PLTSEQ_NOTOC:
+    case elfcpp::R_PPC64_PLTCALL_NOTOC:
+    case elfcpp::R_PPC64_PLT_PCREL34:
+    case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
+      if (size != 64)
        break;
       // Fall through.
-    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_POWERPC_REL24:
-    case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_POWERPC_REL14:
     case elfcpp::R_POWERPC_REL14_BRTAKEN:
     case elfcpp::R_POWERPC_REL14_BRNTAKEN:
     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_PPC64_PLTSEQ_NOTOC:
     case elfcpp::R_POWERPC_PLTCALL:
-    case elfcpp::R_PPC64_PLTCALL_NOTOC:
-    case elfcpp::R_PPC64_PLT_PCREL34:
-    case elfcpp::R_PPC64_PLT_PCREL34_NOTOC:
       ref = Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
       break;
 
-    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_GOT16_DS:
     case elfcpp::R_PPC64_GOT16_LO_DS:
     case elfcpp::R_PPC64_GOT_PCREL34:
@@ -7768,11 +7793,16 @@ 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:
+      if (size != 64)
+       break;
+      // Fall through.
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
       ref = Symbol::RELATIVE_REF;
       break;
 
-    case elfcpp::R_POWERPC_GOT_TPREL16:
-    case elfcpp::R_POWERPC_TLS:
     case elfcpp::R_PPC64_TLSGD:
     case elfcpp::R_PPC64_TLSLD:
     case elfcpp::R_PPC64_TPREL34:
@@ -7781,6 +7811,11 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
     case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
     case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
     case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
+      if (size != 64)
+       break;
+      // Fall through.
+    case elfcpp::R_POWERPC_GOT_TPREL16:
+    case elfcpp::R_POWERPC_TLS:
       ref = Symbol::TLS_REF;
       break;
 
@@ -8951,9 +8986,14 @@ Target_powerpc<size, big_endian>::Scan::global(
                  = target->rela_dyn_section(symtab, layout, is_ifunc);
                unsigned int dynrel = (is_ifunc ? elfcpp::R_POWERPC_IRELATIVE
                                       : elfcpp::R_POWERPC_RELATIVE);
-               rela_dyn->add_symbolless_global_addend(
+               // Use the "add" method that marks the reloc as being
+               // relative.  This is proper here and in other places
+               // that add IRELATIVE relocs because those relocs go
+               // into a separate section that isn't sorted, so it
+               // doesn't matter that they are marked is_relative.
+               rela_dyn->add_global_relative(
                    gsym, dynrel, output_section, object, data_shndx,
-                   reloc.get_r_offset(), reloc.get_r_addend());
+                   reloc.get_r_offset(), reloc.get_r_addend(), false);
              }
            else
              {
@@ -8982,7 +9022,7 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_PPC64_PLT16_LO_DS:
       if (!pushed_ifunc)
        {
-         if (!parameters->doing_static_link())
+         if (branch_needs_plt_entry(gsym))
            target->make_plt_entry(symtab, layout, gsym);
          else
            target->make_local_plt_entry(symtab, layout, gsym);
@@ -9001,11 +9041,7 @@ Target_powerpc<size, big_endian>::Scan::global(
          unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
          target->push_branch(ppc_object, data_shndx, reloc.get_r_offset(),
                              r_type, r_sym, reloc.get_r_addend());
-         if (gsym->needs_plt_entry()
-             || (!gsym->final_value_is_known()
-                 && (gsym->is_undefined()
-                     || gsym->is_from_dynobj()
-                     || gsym->is_preemptible())))
+         if (branch_needs_plt_entry(gsym))
            target->make_plt_entry(symtab, layout, gsym);
        }
       // Fall through.
@@ -10080,7 +10116,7 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
                                      ? NULL
                                      : this->plt_->rel_plt());
       layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
-                                     this->rela_dyn_, true, size == 32);
+                                     this->rela_dyn_, true, size == 32, true);
 
       if (size == 32)
        {
@@ -10151,6 +10187,18 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
     }
 }
 
+// Get the custom dynamic tag value.
+
+template<int size, bool big_endian>
+unsigned int
+Target_powerpc<size, big_endian>::do_dynamic_tag_custom_value(
+    elfcpp::DT tag) const
+{
+  if (tag != elfcpp::DT_RELACOUNT)
+    gold_unreachable();
+  return this->rela_dyn_->relative_reloc_count();
+}
+
 // Merge object attributes from input file called NAME with those of the
 // output.  The input object attributes are in the object pointed by PASD.
 
@@ -10671,10 +10719,8 @@ 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());
-  bool use_plt_offset
-    = (gsym != NULL
-       ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
-       : object->local_has_plt_offset(r_sym));
+  bool pltcall_to_direct = false;
+
   if (is_plt16_reloc<size>(r_type)
       || r_type == elfcpp::R_PPC64_PLT_PCREL34
       || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC
@@ -10688,21 +10734,18 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       // that the decision depends on the PLTCALL reloc, and we don't
       // know the address of that instruction when processing others
       // in the sequence.  So the decision needs to be made in
-      // do_relax().  For now, don't optimise inline plt calls.
-      if (gsym)
-       use_plt_offset = gsym->has_plt_offset();
-    }
-  if (use_plt_offset
-      && !is_got_reloc(r_type)
-      && !is_plt16_reloc<size>(r_type)
-      && r_type != elfcpp::R_PPC64_PLT_PCREL34
-      && r_type != elfcpp::R_PPC64_PLT_PCREL34_NOTOC
-      && r_type != elfcpp::R_POWERPC_PLTSEQ
-      && r_type != elfcpp::R_POWERPC_PLTCALL
-      && r_type != elfcpp::R_PPC64_PLTSEQ_NOTOC
-      && r_type != elfcpp::R_PPC64_PLTCALL_NOTOC
-      && (!psymval->is_ifunc_symbol()
-         || Scan::reloc_needs_plt_for_ifunc(target, object, r_type, false)))
+      // do_relax().
+      pltcall_to_direct = !(gsym != NULL
+                           ? gsym->has_plt_offset()
+                           : object->local_has_plt_offset(r_sym));
+    }
+  else if ((gsym != NULL
+           ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
+           : psymval->is_ifunc_symbol() && object->local_has_plt_offset(r_sym))
+          && !is_got_reloc(r_type)
+          && (!psymval->is_ifunc_symbol()
+              || Scan::reloc_needs_plt_for_ifunc(target, object, r_type,
+                                                 false)))
     {
       if (size == 64
          && gsym != NULL
@@ -10796,9 +10839,9 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       gold_assert(has_stub_value || !(os->flags() & elfcpp::SHF_ALLOC));
     }
 
-  if (use_plt_offset && (is_plt16_reloc<size>(r_type)
-                        || r_type == elfcpp::R_PPC64_PLT_PCREL34
-                        || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC))
+  if (!pltcall_to_direct && (is_plt16_reloc<size>(r_type)
+                            || r_type == elfcpp::R_PPC64_PLT_PCREL34
+                            || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC))
     {
       const Output_data_plt_powerpc<size, big_endian>* plt;
       if (gsym)
@@ -10826,7 +10869,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
            value -= target->toc_pointer();
        }
     }
-  else if (!use_plt_offset
+  else if (pltcall_to_direct
           && (is_plt16_reloc<size>(r_type)
               || r_type == elfcpp::R_POWERPC_PLTSEQ
               || r_type == elfcpp::R_PPC64_PLTSEQ_NOTOC))
@@ -10835,7 +10878,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       elfcpp::Swap<32, big_endian>::writeval(iview, nop);
       r_type = elfcpp::R_POWERPC_NONE;
     }
-  else if (!use_plt_offset
+  else if (pltcall_to_direct
           && (r_type == elfcpp::R_PPC64_PLT_PCREL34
               || r_type == elfcpp::R_PPC64_PLT_PCREL34_NOTOC))
     {
@@ -11316,8 +11359,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     }
   else if (!has_stub_value)
     {
-      if (!use_plt_offset && (r_type == elfcpp::R_POWERPC_PLTCALL
-                             || r_type == elfcpp::R_PPC64_PLTCALL_NOTOC))
+      if (pltcall_to_direct && (r_type == elfcpp::R_POWERPC_PLTCALL
+                               || r_type == elfcpp::R_PPC64_PLTCALL_NOTOC))
        {
          // PLTCALL without plt entry => convert to direct call
          Insn* iview = reinterpret_cast<Insn*>(view);
@@ -12377,10 +12420,19 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
               && gsym->is_undefined()
               && is_branch_reloc<size>(r_type))))
     {
-      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
-                            _("relocation overflow"));
-      if (has_stub_value)
-       gold_info(_("try relinking with a smaller --stub-group-size"));
+      if (os->flags() & elfcpp::SHF_ALLOC)
+       {
+         gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                                _("relocation overflow"));
+         if (has_stub_value)
+           gold_info(_("try relinking with a smaller --stub-group-size"));
+       }
+      else
+       {
+         gold_warning_at_location(relinfo, relnum, rela.get_r_offset(),
+                                  _("relocation overflow"));
+         gold_info(_("debug info may be unreliable, compile with -gdwarf64"));
+       }
     }
 
   return true;