[GOLD] Remove addend from Local_got_entry_key
[binutils-gdb.git] / gold / powerpc.cc
index e35cbcf6c0b7935ab213e38f95e88bdace32883e..11b98695e640ca7398983211c941ef1114cc4da5 100644 (file)
@@ -1,6 +1,6 @@
 // powerpc.cc -- powerpc target support for gold.
 
-// Copyright (C) 2008-2020 Free Software Foundation, Inc.
+// Copyright (C) 2008-2021 Free Software Foundation, Inc.
 // Written by David S. Miller <davem@davemloft.net>
 //        and David Edelsohn <edelsohn@gnu.org>
 
@@ -101,6 +101,7 @@ public:
     : Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
       uniq_(object_id++), special_(0), relatoc_(0), toc_(0),
       has_small_toc_reloc_(false), opd_valid_(false),
+      no_tls_marker_(false), tls_marker_(false), tls_opt_error_(false),
       e_flags_(ehdr.get_e_flags()), no_toc_opt_(), opd_ent_(),
       access_from_map_(), has14_(), stub_table_index_(), st_other_(),
       attributes_section_data_(NULL)
@@ -161,6 +162,30 @@ public:
     return this->no_toc_opt_[off];
   }
 
+  void
+  set_no_tls_marker()
+  {
+    if (!this->no_tls_marker_ && this->tls_marker_)
+      this->tls_opt_error_ = true;
+    this->no_tls_marker_ = true;
+  }
+
+  bool
+  no_tls_marker() const
+  { return this->no_tls_marker_; }
+
+  void
+  set_tls_marker()
+  { this->tls_marker_ = true; }
+
+  bool
+  tls_marker() const
+  { return this->tls_marker_; }
+
+  bool
+  tls_opt_error() const
+  { return this->tls_opt_error_; }
+
   // The .got2 section shndx.
   unsigned int
   got2_shndx() const
@@ -454,6 +479,19 @@ private:
   // access_from_map_.
   bool opd_valid_;
 
+  // Set when finding a __tls_get_addr call without marker relocs.
+  // Such a call disables GD and LD tls optimisations for the object file.
+  bool no_tls_marker_;
+
+  // Set when finding a __tls_get_addr call with marker relocs, or
+  // when finding a relocation that needs __tls_get_addr calls with
+  // marker relocs.
+  bool tls_marker_;
+
+  // Set when seeing a __tls_get_addr call without marker relocs after
+  // seeing some __tls_get_addr calls with marker relocs.
+  bool tls_opt_error_;
+
   // Header e_flags
   elfcpp::Elf_Word e_flags_;
 
@@ -647,10 +685,9 @@ class Target_powerpc : public Sized_target<size, big_endian>
       glink_(NULL), rela_dyn_(NULL), copy_relocs_(),
       tlsld_got_offset_(-1U),
       stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(),
-      power10_stubs_(false), plt_thread_safe_(false), plt_localentry0_(false),
+      power10_relocs_(false), plt_thread_safe_(false), plt_localentry0_(false),
       plt_localentry0_init_(false), has_localentry0_(false),
-      has_tls_get_addr_opt_(false),
-      tprel_opt_(parameters->options().tls_optimize()),
+      has_tls_get_addr_opt_(false), no_tprel_opt_(false),
       relax_failed_(false), relax_fail_count_(0),
       stub_group_size_(0), savres_section_(0),
       tls_get_addr_(NULL), tls_get_addr_opt_(NULL),
@@ -757,10 +794,10 @@ class Target_powerpc : public Sized_target<size, big_endian>
   }
 
   // Accessor
-  const Tocsave_loc
+  const Tocsave_loc*
   tocsave_loc() const
   {
-    return this->tocsave_loc_;
+    return &this->tocsave_loc_;
   }
 
   void
@@ -1079,16 +1116,18 @@ class Target_powerpc : public Sized_target<size, big_endian>
     sym->set_dynsym_index(-1U);
   }
 
+  void
+  set_power10_relocs()
+  {
+      this->power10_relocs_ = true;
+  }
+
   bool
   power10_stubs() const
-  { return this->power10_stubs_; }
-
-  void
-  set_power10_stubs()
   {
-    if (parameters->options().power10_stubs_enum()
-       != General_options::POWER10_STUBS_NO)
-      this->power10_stubs_ = true;
+    return (this->power10_relocs_
+           && (parameters->options().power10_stubs_enum()
+               != General_options::POWER10_STUBS_NO));
   }
 
   bool
@@ -1106,6 +1145,10 @@ class Target_powerpc : public Sized_target<size, big_endian>
   plt_localentry0() const
   { return this->plt_localentry0_; }
 
+  bool
+  has_localentry0() const
+  { return this->has_localentry0_; }
+
   void
   set_has_localentry0()
   {
@@ -1148,11 +1191,11 @@ class Target_powerpc : public Sized_target<size, big_endian>
 
   bool
   tprel_opt() const
-  { return this->tprel_opt_; }
+  { return !this->no_tprel_opt_ && parameters->options().tls_optimize(); }
 
   void
-  set_tprel_opt(bool val)
-  { this->tprel_opt_ = val; }
+  set_no_tprel_opt()
+  { this->no_tprel_opt_ = true; }
 
   // Remember any symbols seen with non-zero localentry, even those
   // not providing a definition
@@ -1705,13 +1748,13 @@ class Target_powerpc : public Sized_target<size, big_endian>
   Branches branch_info_;
   Tocsave_loc tocsave_loc_;
 
-  bool power10_stubs_;
+  bool power10_relocs_;
   bool plt_thread_safe_;
   bool plt_localentry0_;
   bool plt_localentry0_init_;
   bool has_localentry0_;
   bool has_tls_get_addr_opt_;
-  bool tprel_opt_;
+  bool no_tprel_opt_;
 
   bool relax_failed_;
   int relax_fail_count_;
@@ -1878,6 +1921,19 @@ is_plt16_reloc(unsigned int r_type)
          || (size == 64 && r_type == elfcpp::R_PPC64_PLT16_LO_DS));
 }
 
+// GOT_TYPE_STANDARD (ie. not TLS) GOT relocs
+inline bool
+is_got_reloc(unsigned int r_type)
+{
+  return (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
+         || r_type == elfcpp::R_PPC64_GOT_PCREL34);
+}
+
 // 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.
@@ -2748,8 +2804,6 @@ Powerpc_relobj<size, big_endian>::do_relocate_sections(
            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;
@@ -3520,6 +3574,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
       from += (this->object_->output_section(this->shndx_)->address()
               + this->offset_);
       Address to;
+      unsigned int other = 0;
       if (gsym != NULL)
        {
          switch (gsym->source())
@@ -3548,7 +3603,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
          if (status != Symbol_table::CFVS_OK)
            return true;
          if (size == 64)
-           to += this->object_->ppc64_local_entry_offset(gsym);
+           other = gsym->nonvis() >> 3;
        }
       else
        {
@@ -3566,7 +3621,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
            return true;
          to = symval.value(this->object_, 0);
          if (size == 64)
-           to += this->object_->ppc64_local_entry_offset(this->r_sym_);
+           other = this->object_->st_other(this->r_sym_) >> 5;
        }
       if (!(size == 32 && this->r_type_ == elfcpp::R_PPC_PLTREL24))
        to += this->addend_;
@@ -3579,7 +3634,11 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
                                         &to, &dest_shndx))
            return true;
        }
-      Address delta = to - from;
+      unsigned int local_ent = 0;
+      if (size == 64
+         && this->r_type_ != elfcpp::R_PPC64_REL24_NOTOC)
+       local_ent = elfcpp::ppc64_decode_local_entry(other);
+      Address delta = to + local_ent - from;
       if (delta + max_branch_offset >= 2 * max_branch_offset
          || (size == 64
              && this->r_type_ == elfcpp::R_PPC64_REL24_NOTOC
@@ -3601,7 +3660,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
                           && gsym->output_data() == target->savres_section());
          ok = stub_table->add_long_branch_entry(this->object_,
                                                 this->r_type_,
-                                                from, to, save_res);
+                                                from, to, other, save_res);
        }
     }
   if (!ok)
@@ -3925,7 +3984,6 @@ Target_powerpc<size, big_endian>::do_plt_fde_location(const Output_data* plt,
       // See Output_data_glink::do_write() for glink contents.
       if (len == 0)
        {
-         gold_assert(parameters->doing_static_link());
          // Static linking may need stubs, to support ifunc and long
          // branches.  We need to create an output section for
          // .eh_frame early in the link process, to have a place to
@@ -4190,6 +4248,7 @@ static const uint32_t cmpwi_11_0  = 0x2c0b0000;
 static const uint32_t cror_15_15_15    = 0x4def7b82;
 static const uint32_t cror_31_31_31    = 0x4ffffb82;
 static const uint32_t ld_0_1           = 0xe8010000;
+static const uint32_t ld_0_11          = 0xe80b0000;
 static const uint32_t ld_0_12          = 0xe80c0000;
 static const uint32_t ld_2_1           = 0xe8410000;
 static const uint32_t ld_2_2           = 0xe8420000;
@@ -4572,9 +4631,9 @@ static const unsigned char glink_eh_frame_fde_64v1[] =
   0, 0, 0, 0,                          // Replaced with offset to .glink.
   0, 0, 0, 0,                          // Replaced with size of .glink.
   0,                                   // Augmentation size.
-  elfcpp::DW_CFA_advance_loc + 1,
+  elfcpp::DW_CFA_advance_loc + 2,
   elfcpp::DW_CFA_register, 65, 12,
-  elfcpp::DW_CFA_advance_loc + 5,
+  elfcpp::DW_CFA_advance_loc + 4,
   elfcpp::DW_CFA_restore_extended, 65
 };
 
@@ -4584,9 +4643,20 @@ static const unsigned char glink_eh_frame_fde_64v2[] =
   0, 0, 0, 0,                          // Replaced with offset to .glink.
   0, 0, 0, 0,                          // Replaced with size of .glink.
   0,                                   // Augmentation size.
-  elfcpp::DW_CFA_advance_loc + 1,
+  elfcpp::DW_CFA_advance_loc + 2,
+  elfcpp::DW_CFA_register, 65, 0,
+  elfcpp::DW_CFA_advance_loc + 2,
+  elfcpp::DW_CFA_restore_extended, 65
+};
+
+static const unsigned char glink_eh_frame_fde_64v2_localentry0[] =
+{
+  0, 0, 0, 0,                          // Replaced with offset to .glink.
+  0, 0, 0, 0,                          // Replaced with size of .glink.
+  0,                                   // Augmentation size.
+  elfcpp::DW_CFA_advance_loc + 3,
   elfcpp::DW_CFA_register, 65, 0,
-  elfcpp::DW_CFA_advance_loc + 7,
+  elfcpp::DW_CFA_advance_loc + 2,
   elfcpp::DW_CFA_restore_extended, 65
 };
 
@@ -4657,7 +4727,7 @@ class Stub_table : public Output_relaxed_input_section
   {
     Branch_stub_ent(unsigned int off, bool notoc, bool save_res)
       : off_(off), iter_(0), notoc_(notoc), toc_(0), save_res_(save_res),
-       tocoff_(0)
+       other_(0), tocoff_(0)
     { }
 
     unsigned int off_;
@@ -4665,6 +4735,7 @@ class Stub_table : public Output_relaxed_input_section
     unsigned int notoc_ : 1;
     unsigned int toc_ : 1;
     unsigned int save_res_ : 1;
+    unsigned int other_ : 3;
     unsigned int tocoff_ : 8;
   };
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
@@ -4731,7 +4802,7 @@ class Stub_table : public Output_relaxed_input_section
   // Add a long branch stub.
   bool
   add_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
-                       unsigned int, Address, Address, bool);
+                       unsigned int, Address, Address, unsigned int, bool);
 
   const Branch_stub_ent*
   find_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
@@ -5251,6 +5322,7 @@ Stub_table<size, big_endian>::add_long_branch_entry(
     unsigned int r_type,
     Address from,
     Address to,
+    unsigned int other,
     bool save_res)
 {
   Branch_stub_key key(object, to);
@@ -5270,6 +5342,8 @@ Stub_table<size, big_endian>::add_long_branch_entry(
        this->need_resize_ = true;
       p.first->second.toc_ = true;
     }
+  if (size == 64 && p.first->second.other_ == 0)
+    p.first->second.other_ = other;
   gold_assert(save_res == p.first->second.save_res_);
   if (p.second || (this->resizing_ && !p.first->second.iter_))
     {
@@ -5525,7 +5599,8 @@ class Output_data_glink : public Output_section_data
   {
     if (size == 64)
       return (8
-             + (this->targ_->abiversion() < 2 ? 11 * 4 : 14 * 4));
+             + (this->targ_->abiversion() < 2 ? 11 * 4
+                : this->targ_->has_localentry0() ? 14 * 4 : 13 * 4));
     return 16 * 4;
   }
 
@@ -5568,6 +5643,12 @@ Output_data_glink<size, big_endian>::add_eh_frame(Layout* layout)
                                     sizeof (Eh_cie<64>::eh_frame_cie),
                                     glink_eh_frame_fde_64v1,
                                     sizeof (glink_eh_frame_fde_64v1));
+      else if (this->targ_->has_localentry0())
+       layout->add_eh_frame_for_plt(this,
+                                    Eh_cie<64>::eh_frame_cie,
+                                    sizeof (Eh_cie<64>::eh_frame_cie),
+                                    glink_eh_frame_fde_64v2_localentry0,
+                                    sizeof (glink_eh_frame_fde_64v2));
       else
        layout->add_eh_frame_for_plt(this,
                                     Eh_cie<64>::eh_frame_cie,
@@ -6160,6 +6241,7 @@ Stub_table<size, big_endian>::branch_stub_size(
        }
     }
 
+  off += elfcpp::ppc64_decode_local_entry(p->second.other_);
   if (off + (1 << 25) < 2 << 25)
     return bytes + 4;
   if (!this->targ_->power10_stubs()
@@ -6339,6 +6421,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                }
              if (bs->second.toc_)
                {
+                 delta += elfcpp::ppc64_decode_local_entry(bs->second.other_);
                  if (delta + (1 << 25) >= 2 << 25)
                    {
                      Address brlt_addr
@@ -6372,6 +6455,8 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
            }
          else
            {
+             if (!bs->second.notoc_)
+               delta += elfcpp::ppc64_decode_local_entry(bs->second.other_);
              if (bs->second.notoc_ || delta + (1 << 25) >= 2 << 25)
                {
                  unsigned char* startp = p;
@@ -6602,6 +6687,8 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
          p = oview + off;
          Address loc = this->stub_address() + off;
          Address delta = bs->first.dest_ - loc;
+         if (!bs->second.notoc_)
+           delta += elfcpp::ppc64_decode_local_entry(bs->second.other_);
          if (bs->second.notoc_)
            {
              unsigned char* startp = p;
@@ -6798,15 +6885,25 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
            }
          else
            {
+             if (this->targ_->has_localentry0())
+               {
+                 write_insn<big_endian>(p, std_2_1 + 24),      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, mflr_11),               p += 4;
-             write_insn<big_endian>(p, std_2_1 + 24),          p += 4;
-             write_insn<big_endian>(p, ld_2_11 + l(-16)),      p += 4;
              write_insn<big_endian>(p, mtlr_0),                p += 4;
+             if (this->targ_->has_localentry0())
+               {
+                 write_insn<big_endian>(p, ld_0_11 + l(-20)),  p += 4;
+               }
+             else
+               {
+                 write_insn<big_endian>(p, ld_0_11 + l(-16)),  p += 4;
+               }
              write_insn<big_endian>(p, sub_12_12_11),          p += 4;
-             write_insn<big_endian>(p, add_11_2_11),           p += 4;
-             write_insn<big_endian>(p, addi_0_12 + l(-48)),    p += 4;
+             write_insn<big_endian>(p, add_11_0_11),           p += 4;
+             write_insn<big_endian>(p, addi_0_12 + l(-44)),    p += 4;
              write_insn<big_endian>(p, ld_12_11 + 0),          p += 4;
              write_insn<big_endian>(p, srdi_0_0_2),            p += 4;
              write_insn<big_endian>(p, mtctr_12),              p += 4;
@@ -7804,28 +7901,47 @@ Target_powerpc<size, big_endian>::Scan::local(
     const elfcpp::Sym<size, big_endian>& lsym,
     bool is_discarded)
 {
-  this->maybe_skip_tls_get_addr_call(target, r_type, NULL);
+  Powerpc_relobj<size, big_endian>* ppc_object
+    = static_cast<Powerpc_relobj<size, big_endian>*>(object);
+
+  switch (this->maybe_skip_tls_get_addr_call(target, r_type, NULL))
+    {
+    case Track_tls::NOT_EXPECTED:
+      ppc_object->set_no_tls_marker();
+      break;
+    default:
+      break;
+    }
 
   if ((size == 64 && r_type == elfcpp::R_PPC64_TLSGD)
       || (size == 32 && r_type == elfcpp::R_PPC_TLSGD))
     {
       this->expect_tls_get_addr_call();
-      const tls::Tls_optimization tls_type = target->optimize_tls_gd(true);
-      if (tls_type != tls::TLSOPT_NONE)
-       this->skip_next_tls_get_addr_call();
+      if (!ppc_object->no_tls_marker())
+       {
+         tls::Tls_optimization tls_type = target->optimize_tls_gd(true);
+         if (tls_type != tls::TLSOPT_NONE)
+           {
+             this->skip_next_tls_get_addr_call();
+             ppc_object->set_tls_marker();
+           }
+       }
     }
   else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSLD)
           || (size == 32 && r_type == elfcpp::R_PPC_TLSLD))
     {
       this->expect_tls_get_addr_call();
-      const tls::Tls_optimization tls_type = target->optimize_tls_ld();
-      if (tls_type != tls::TLSOPT_NONE)
-       this->skip_next_tls_get_addr_call();
+      if (!ppc_object->no_tls_marker())
+       {
+         tls::Tls_optimization tls_type = target->optimize_tls_ld();
+         if (tls_type != tls::TLSOPT_NONE)
+           {
+             this->skip_next_tls_get_addr_call();
+             ppc_object->set_tls_marker();
+           }
+       }
     }
 
-  Powerpc_relobj<size, big_endian>* ppc_object
-    = static_cast<Powerpc_relobj<size, big_endian>*>(object);
-
   if (is_discarded)
     {
       if (size == 64
@@ -8120,7 +8236,9 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
     case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
       {
-       const tls::Tls_optimization tls_type = target->optimize_tls_gd(true);
+       tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+       if (!ppc_object->no_tls_marker())
+         tls_type = target->optimize_tls_gd(true);
        if (tls_type == tls::TLSOPT_NONE)
          {
            Output_data_got_powerpc<size, big_endian>* got
@@ -8133,6 +8251,7 @@ Target_powerpc<size, big_endian>::Scan::local(
        else if (tls_type == tls::TLSOPT_TO_LE)
          {
            // no GOT relocs needed for Local Exec.
+           ppc_object->set_tls_marker();
          }
        else
          gold_unreachable();
@@ -8145,7 +8264,9 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
     case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
       {
-       const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+       tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+       if (!ppc_object->no_tls_marker())
+         tls_type = target->optimize_tls_ld();
        if (tls_type == tls::TLSOPT_NONE)
          target->tlsld_got_offset(symtab, layout, object);
        else if (tls_type == tls::TLSOPT_TO_LE)
@@ -8157,6 +8278,7 @@ Target_powerpc<size, big_endian>::Scan::local(
                gold_assert(os != NULL);
                os->set_needs_symtab_index();
              }
+           ppc_object->set_tls_marker();
          }
        else
          gold_unreachable();
@@ -8182,7 +8304,7 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_GOT_TPREL16_HI:
     case elfcpp::R_POWERPC_GOT_TPREL16_HA:
       {
-       const tls::Tls_optimization tls_type = target->optimize_tls_ie(true);
+       tls::Tls_optimization tls_type = target->optimize_tls_ie(true);
        if (tls_type == tls::TLSOPT_NONE)
          {
            unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
@@ -8412,7 +8534,7 @@ Target_powerpc<size, big_endian>::Scan::local(
              uint32_t insn = elfcpp::Swap<32, big_endian>::readval(view + off);
              if ((insn & ((0x3fu << 26) | 0x1f << 16))
                  != ((15u << 26) | ((size == 32 ? 2 : 13) << 16)))
-               target->set_tprel_opt(false);
+               target->set_no_tprel_opt();
            }
        }
       break;
@@ -8427,7 +8549,7 @@ Target_powerpc<size, big_endian>::Scan::local(
        break;
       // Fall through.
     case elfcpp::R_POWERPC_TPREL16_HI:
-      target->set_tprel_opt(false);
+      target->set_no_tprel_opt();
       break;
     default:
       break;
@@ -8451,7 +8573,7 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
     case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
     case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
-      target->set_power10_stubs();
+      target->set_power10_relocs();
       break;
     default:
       break;
@@ -8486,9 +8608,19 @@ Target_powerpc<size, big_endian>::Scan::global(
     unsigned int r_type,
     Symbol* gsym)
 {
-  if (this->maybe_skip_tls_get_addr_call(target, r_type, gsym)
-      == Track_tls::SKIP)
-    return;
+  Powerpc_relobj<size, big_endian>* ppc_object
+    = static_cast<Powerpc_relobj<size, big_endian>*>(object);
+
+  switch (this->maybe_skip_tls_get_addr_call(target, r_type, gsym))
+    {
+    case Track_tls::NOT_EXPECTED:
+      ppc_object->set_no_tls_marker();
+      break;
+    case Track_tls::SKIP:
+      return;
+    default:
+      break;
+    }
 
   if (target->replace_tls_get_addr(gsym))
     // Change a __tls_get_addr reference to __tls_get_addr_opt
@@ -8499,23 +8631,32 @@ Target_powerpc<size, big_endian>::Scan::global(
       || (size == 32 && r_type == elfcpp::R_PPC_TLSGD))
     {
       this->expect_tls_get_addr_call();
-      const bool final = gsym->final_value_is_known();
-      const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
-      if (tls_type != tls::TLSOPT_NONE)
-       this->skip_next_tls_get_addr_call();
+      if (!ppc_object->no_tls_marker())
+       {
+         bool final = gsym->final_value_is_known();
+         tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+         if (tls_type != tls::TLSOPT_NONE)
+           {
+             this->skip_next_tls_get_addr_call();
+             ppc_object->set_tls_marker();
+           }
+       }
     }
   else if ((size == 64 && r_type == elfcpp::R_PPC64_TLSLD)
           || (size == 32 && r_type == elfcpp::R_PPC_TLSLD))
     {
       this->expect_tls_get_addr_call();
-      const tls::Tls_optimization tls_type = target->optimize_tls_ld();
-      if (tls_type != tls::TLSOPT_NONE)
-       this->skip_next_tls_get_addr_call();
+      if (!ppc_object->no_tls_marker())
+       {
+         tls::Tls_optimization tls_type = target->optimize_tls_ld();
+         if (tls_type != tls::TLSOPT_NONE)
+           {
+             this->skip_next_tls_get_addr_call();
+             ppc_object->set_tls_marker();
+           }
+       }
     }
 
-  Powerpc_relobj<size, big_endian>* ppc_object
-    = static_cast<Powerpc_relobj<size, big_endian>*>(object);
-
   // A STT_GNU_IFUNC symbol may require a PLT entry.
   bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
   bool pushed_ifunc = false;
@@ -8892,8 +9033,12 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_GOT_TLSGD16_HI:
     case elfcpp::R_POWERPC_GOT_TLSGD16_HA:
       {
-       const bool final = gsym->final_value_is_known();
-       const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+       tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+       if (!ppc_object->no_tls_marker())
+         {
+           bool final = gsym->final_value_is_known();
+           tls_type = target->optimize_tls_gd(final);
+         }
        if (tls_type == tls::TLSOPT_NONE)
          {
            Output_data_got_powerpc<size, big_endian>* got
@@ -8925,10 +9070,12 @@ Target_powerpc<size, big_endian>::Scan::global(
                                                           got, off, 0);
                  }
              }
+           ppc_object->set_tls_marker();
          }
        else if (tls_type == tls::TLSOPT_TO_LE)
          {
            // no GOT relocs needed for Local Exec.
+           ppc_object->set_tls_marker();
          }
        else
          gold_unreachable();
@@ -8941,7 +9088,9 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_GOT_TLSLD16_HI:
     case elfcpp::R_POWERPC_GOT_TLSLD16_HA:
       {
-       const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+       tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+       if (!ppc_object->no_tls_marker())
+         tls_type = target->optimize_tls_ld();
        if (tls_type == tls::TLSOPT_NONE)
          target->tlsld_got_offset(symtab, layout, object);
        else if (tls_type == tls::TLSOPT_TO_LE)
@@ -8953,6 +9102,7 @@ Target_powerpc<size, big_endian>::Scan::global(
                gold_assert(os != NULL);
                os->set_needs_symtab_index();
              }
+           ppc_object->set_tls_marker();
          }
        else
          gold_unreachable();
@@ -8985,8 +9135,8 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_GOT_TPREL16_HI:
     case elfcpp::R_POWERPC_GOT_TPREL16_HA:
       {
-       const bool final = gsym->final_value_is_known();
-       const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
+       bool final = gsym->final_value_is_known();
+       tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
        if (tls_type == tls::TLSOPT_NONE)
          {
            if (!gsym->has_got_offset(GOT_TYPE_TPREL))
@@ -9209,7 +9359,7 @@ Target_powerpc<size, big_endian>::Scan::global(
              uint32_t insn = elfcpp::Swap<32, big_endian>::readval(view + off);
              if ((insn & ((0x3fu << 26) | 0x1f << 16))
                  != ((15u << 26) | ((size == 32 ? 2 : 13) << 16)))
-               target->set_tprel_opt(false);
+               target->set_no_tprel_opt();
            }
        }
       break;
@@ -9224,7 +9374,7 @@ Target_powerpc<size, big_endian>::Scan::global(
        break;
       // Fall through.
     case elfcpp::R_POWERPC_TPREL16_HI:
-      target->set_tprel_opt(false);
+      target->set_no_tprel_opt();
       break;
     default:
       break;
@@ -9248,7 +9398,7 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_PPC64_GOT_TLSLD_PCREL34:
     case elfcpp::R_PPC64_GOT_DTPREL_PCREL34:
     case elfcpp::R_PPC64_GOT_TPREL_PCREL34:
-      target->set_power10_stubs();
+      target->set_power10_relocs();
       break;
     default:
       break;
@@ -9590,6 +9740,13 @@ Target_powerpc<size, big_endian>::scan_relocs(
     needs_special_offset_handling,
     local_symbol_count,
     plocal_symbols);
+
+  if (this->plt_localentry0_ && this->power10_relocs_)
+    {
+      gold_warning(_("--plt-localentry is incompatible with "
+                    "power10 pc-relative code"));
+      this->plt_localentry0_ = false;
+    }
 }
 
 // Functor class for processing the global symbol table.
@@ -10291,11 +10448,25 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 
   const elfcpp::Rela<size, big_endian> rela(preloc);
   unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
+  Powerpc_relobj<size, big_endian>* const object
+    = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
   switch (this->maybe_skip_tls_get_addr_call(target, r_type, gsym))
     {
     case Track_tls::NOT_EXPECTED:
-      gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
-                            _("__tls_get_addr call lacks marker reloc"));
+      if (!parameters->options().shared()
+         && parameters->options().tls_optimize())
+       {
+         // It is a hard error to see a __tls_get_addr call without
+         // marker relocs after seeing calls with marker relocs in the
+         // same object file, because dynamic relocation accounting
+         // will be wrong.
+         if (object->tls_opt_error())
+           gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                                  _("__tls_get_addr call lacks marker reloc"));
+         else
+           gold_warning_at_location(relinfo, relnum, rela.get_r_offset(),
+                                    _("__tls_get_addr call lacks marker reloc"));
+       }
       break;
     case Track_tls::EXPECTED:
       // We have already complained.
@@ -10328,8 +10499,6 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
   // Offset from start of insn to d-field reloc.
   const int d_offset = big_endian ? 2 : 0;
 
-  Powerpc_relobj<size, big_endian>* const object
-    = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
   Address value = 0;
   bool has_stub_value = false;
   bool localentry0 = false;
@@ -10339,6 +10508,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
        ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
        : object->local_has_plt_offset(r_sym));
   if (has_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
@@ -10401,21 +10571,24 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
                    value += ent->tocoff_;
                  if (size == 64
                      && ent->r2save_
-                     && r_type == elfcpp::R_PPC64_REL24_NOTOC)
-                   {
-                     if (!(target->power10_stubs()
-                           && target->power10_stubs_auto()))
-                       value += 4;
-                   }
-                 else if (size == 64
-                          && ent->r2save_
-                          && relnum < reloc_count - 1)
+                     && !(gsym != NULL
+                          && target->is_tls_get_addr_opt(gsym)))
                    {
-                     Reltype next_rela(preloc + reloc_size);
-                     if (elfcpp::elf_r_type<size>(next_rela.get_r_info())
-                         == elfcpp::R_PPC64_TOCSAVE
-                         && next_rela.get_r_offset() == rela.get_r_offset() + 4)
-                       value += 4;
+                     if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
+                       {
+                         if (!(target->power10_stubs()
+                               && target->power10_stubs_auto()))
+                           value += 4;
+                       }
+                     else if (relnum < reloc_count - 1)
+                       {
+                         Reltype next_rela(preloc + reloc_size);
+                         if (elfcpp::elf_r_type<size>(next_rela.get_r_info())
+                             == elfcpp::R_PPC64_TOCSAVE
+                             && (next_rela.get_r_offset()
+                                 == rela.get_r_offset() + 4))
+                           value += 4;
+                       }
                    }
                  localentry0 = ent->localentry0_;
                  has_stub_value = true;
@@ -10478,13 +10651,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       elfcpp::Swap<32, big_endian>::writeval(iview + 1, pnop & 0xffffffff);
       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
-          || r_type == elfcpp::R_PPC64_GOT_PCREL34)
+  else if (is_got_reloc(r_type))
     {
       if (gsym != NULL)
        {
@@ -10582,8 +10749,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
           || r_type == elfcpp::R_PPC64_GOT_TLSGD_PCREL34)
     {
       // First instruction of a global dynamic sequence, arg setup insn.
-      const bool final = gsym == NULL || gsym->final_value_is_known();
-      const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+      tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+      if (!object->no_tls_marker())
+       {
+         bool final = gsym == NULL || gsym->final_value_is_known();
+         tls_type = target->optimize_tls_gd(final);
+       }
       enum Got_type got_type = GOT_TYPE_STANDARD;
       if (tls_type == tls::TLSOPT_NONE)
        got_type = GOT_TYPE_TLSGD;
@@ -10688,7 +10859,9 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
           || r_type == elfcpp::R_PPC64_GOT_TLSLD_PCREL34)
     {
       // First instruction of a local dynamic sequence, arg setup insn.
-      const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+      tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+      if (!object->no_tls_marker())
+       tls_type = target->optimize_tls_ld();
       if (tls_type == tls::TLSOPT_NONE)
        {
          value = target->tlsld_got_offset();
@@ -10767,8 +10940,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
           || r_type == elfcpp::R_PPC64_GOT_TPREL_PCREL34)
     {
       // First instruction of initial exec sequence.
-      const bool final = gsym == NULL || gsym->final_value_is_known();
-      const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
+      bool final = gsym == NULL || gsym->final_value_is_known();
+      tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
       if (tls_type == tls::TLSOPT_NONE)
        {
          if (gsym != NULL)
@@ -10833,8 +11006,12 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       // Second instruction of a global dynamic sequence,
       // the __tls_get_addr call
       this->expect_tls_get_addr_call(relinfo, relnum, rela.get_r_offset());
-      const bool final = gsym == NULL || gsym->final_value_is_known();
-      const tls::Tls_optimization tls_type = target->optimize_tls_gd(final);
+      tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+      if (!object->no_tls_marker())
+       {
+         bool final = gsym == NULL || gsym->final_value_is_known();
+         tls_type = target->optimize_tls_gd(final);
+       }
       if (tls_type != tls::TLSOPT_NONE)
        {
          if (tls_type == tls::TLSOPT_TO_IE)
@@ -10885,7 +11062,9 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       // Second instruction of a local dynamic sequence,
       // the __tls_get_addr call
       this->expect_tls_get_addr_call(relinfo, relnum, rela.get_r_offset());
-      const tls::Tls_optimization tls_type = target->optimize_tls_ld();
+      tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+      if (!object->no_tls_marker())
+       tls_type = target->optimize_tls_ld();
       if (tls_type == tls::TLSOPT_TO_LE)
        {
          bool is_pcrel = false;
@@ -10921,8 +11100,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
   else if (r_type == elfcpp::R_POWERPC_TLS)
     {
       // Second instruction of an initial exec sequence
-      const bool final = gsym == NULL || gsym->final_value_is_known();
-      const tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
+      bool final = gsym == NULL || gsym->final_value_is_known();
+      tls::Tls_optimization tls_type = target->optimize_tls_ie(final);
       if (tls_type == tls::TLSOPT_TO_LE)
        {
          Address roff = rela.get_r_offset() & 3;
@@ -10986,14 +11165,15 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
                || r_type == elfcpp::R_POWERPC_PLT16_HA)))
        addend = rela.get_r_addend();
       value = psymval->value(object, addend);
+      unsigned int local_ent = 0;
       if (size == 64 && is_branch_reloc<size>(r_type))
        {
          if (target->abiversion() >= 2)
            {
              if (gsym != NULL)
-               value += object->ppc64_local_entry_offset(gsym);
+               local_ent = object->ppc64_local_entry_offset(gsym);
              else
-               value += object->ppc64_local_entry_offset(r_sym);
+               local_ent = object->ppc64_local_entry_offset(r_sym);
            }
          else
            {
@@ -11002,9 +11182,9 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
                                        &value, &dest_shndx);
            }
        }
-      Address max_branch_offset = max_branch_delta<size>(r_type);
-      if (max_branch_offset != 0
-         && (value - address + max_branch_offset >= 2 * max_branch_offset
+      Address max_branch = max_branch_delta<size>(r_type);
+      if (max_branch != 0
+         && (value + local_ent - address + max_branch >= 2 * max_branch
              || (size == 64
                  && r_type == elfcpp::R_PPC64_REL24_NOTOC
                  && (gsym != NULL
@@ -11021,6 +11201,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
                {
                  if (ent->save_res_)
                    value = (value - target->savres_section()->address()
+                            + stub_table->stub_address()
+                            + stub_table->plt_size()
                             + stub_table->branch_size());
                  else
                    {
@@ -11035,6 +11217,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
                }
            }
        }
+      if (!has_stub_value)
+       value += local_ent;
     }
 
   switch (r_type)
@@ -11878,8 +12062,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
          loc.object = relinfo->object;
          loc.shndx = relinfo->data_shndx;
          loc.offset = rela.get_r_offset();
-         Tocsave_loc::const_iterator p = target->tocsave_loc().find(loc);
-         if (p != target->tocsave_loc().end())
+         const Tocsave_loc *tocsave = target->tocsave_loc();
+         if (tocsave->find(loc) != tocsave->end())
            {
              // If we've generated plt calls using this tocsave, then
              // the nop needs to be changed to save r2.
@@ -12372,8 +12556,13 @@ Target_powerpc<size, big_endian>::relocate_relocs(
            {
              // First instruction of a global dynamic sequence,
              // arg setup insn.
-             const bool final = gsym == NULL || gsym->final_value_is_known();
-             switch (this->optimize_tls_gd(final))
+             tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+             if (!object->no_tls_marker())
+               {
+                 bool final = gsym == NULL || gsym->final_value_is_known();
+                 tls_type = this->optimize_tls_gd(final);
+               }
+             switch (tls_type)
                {
                case tls::TLSOPT_TO_IE:
                  r_type += (elfcpp::R_POWERPC_GOT_TPREL16
@@ -12400,7 +12589,10 @@ Target_powerpc<size, big_endian>::relocate_relocs(
            {
              // First instruction of a local dynamic sequence,
              // arg setup insn.
-             if (this->optimize_tls_ld() == tls::TLSOPT_TO_LE)
+             tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+             if (!object->no_tls_marker())
+               tls_type = this->optimize_tls_ld();
+             if (tls_type == tls::TLSOPT_TO_LE)
                {
                  if (r_type == elfcpp::R_POWERPC_GOT_TLSLD16
                      || r_type == elfcpp::R_POWERPC_GOT_TLSLD16_LO)
@@ -12426,7 +12618,7 @@ Target_powerpc<size, big_endian>::relocate_relocs(
                   || r_type == elfcpp::R_POWERPC_GOT_TPREL16_HA)
            {
              // First instruction of initial exec sequence.
-             const bool final = gsym == NULL || gsym->final_value_is_known();
+             bool final = gsym == NULL || gsym->final_value_is_known();
              if (this->optimize_tls_ie(final) == tls::TLSOPT_TO_LE)
                {
                  if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
@@ -12444,8 +12636,13 @@ Target_powerpc<size, big_endian>::relocate_relocs(
            {
              // Second instruction of a global dynamic sequence,
              // the __tls_get_addr call
-             const bool final = gsym == NULL || gsym->final_value_is_known();
-             switch (this->optimize_tls_gd(final))
+             tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+             if (!object->no_tls_marker())
+               {
+                 bool final = gsym == NULL || gsym->final_value_is_known();
+                 tls_type = this->optimize_tls_gd(final);
+               }
+             switch (tls_type)
                {
                case tls::TLSOPT_TO_IE:
                  r_type = elfcpp::R_POWERPC_NONE;
@@ -12465,7 +12662,10 @@ Target_powerpc<size, big_endian>::relocate_relocs(
            {
              // Second instruction of a local dynamic sequence,
              // the __tls_get_addr call
-             if (this->optimize_tls_ld() == tls::TLSOPT_TO_LE)
+             tls::Tls_optimization tls_type = tls::TLSOPT_NONE;
+             if (!object->no_tls_marker())
+               tls_type = this->optimize_tls_ld();
+             if (tls_type == tls::TLSOPT_TO_LE)
                {
                  const Output_section* os = relinfo->layout->tls_segment()
                    ->first_section();
@@ -12481,7 +12681,7 @@ Target_powerpc<size, big_endian>::relocate_relocs(
          else if (r_type == elfcpp::R_POWERPC_TLS)
            {
              // Second instruction of an initial exec sequence
-             const bool final = gsym == NULL || gsym->final_value_is_known();
+             bool final = gsym == NULL || gsym->final_value_is_known();
              if (this->optimize_tls_ie(final) == tls::TLSOPT_TO_LE)
                {
                  r_type = elfcpp::R_POWERPC_TPREL16_LO;