public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [GOLD] PowerPC64 @notoc in non-power10 code
@ 2021-12-11  4:24 Alan Modra
  0 siblings, 0 replies; only message in thread
From: Alan Modra @ 2021-12-11  4:24 UTC (permalink / raw)
  To: binutils

Gold version of commit 7aba54da42.  Committed.

elfcpp/
	* powerpc.h (R_PPC64_REL24_P9NOTOC): Define.
gold/
	* powerpc.cc (Target_powerpc::maybe_skip_tls_get_addr_call,
	is_branch_reloc, max_branch_delta): Handle R_PPC64_REL24_P9NOTOC.
	(Target_powerpc::Branch_info::make_stub): Likewise.
	(struct Plt_stub_ent): Add p9notoc_, p9off_, tsize_.
	(struct Branch_stub_ent): Add p9notoc_, p9off_.
	(Stub_table::add_plt_call_entry): Handle R_PPC64_REL24_P9NOTOC.
	(Stub_table::add_long_branch_entry): Likewise.
	(Stub_table::add_eh_frame): Likewise.
	(Stub_table::plt_call_size): Return aligned size.  Adjust callers.
	Handle p9notoc_ sizing.
	(Stub_table::do_write): Write out p9notoc_ stubs.
	(Target_powerpc::Scan::get_reference_flags, local, global):
	Handle R_PPC64_REL24_P9NOTOC.
	(Target_powerpc::Relocate::relocate): Likewise.

diff --git a/elfcpp/powerpc.h b/elfcpp/powerpc.h
index b17777be7bd..3f4f79d8ab2 100644
--- a/elfcpp/powerpc.h
+++ b/elfcpp/powerpc.h
@@ -184,6 +184,7 @@ enum
   R_PPC64_PLTSEQ_NOTOC = 121,
   R_PPC64_PLTCALL_NOTOC = 122,
   R_PPC64_PCREL_OPT = 123,
+  R_PPC64_REL24_P9NOTOC = 124,
 
   R_PPC64_D34 = 128,
   R_PPC64_D34_LO = 129,
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 103eef85943..a40614cd45c 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -1329,6 +1329,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
       bool is_tls_call
 	= ((r_type == elfcpp::R_POWERPC_REL24
 	    || (size == 64 && r_type == elfcpp::R_PPC64_REL24_NOTOC)
+	    || r_type == elfcpp::R_PPC64_REL24_P9NOTOC
 	    || r_type == elfcpp::R_PPC_PLTREL24
 	    || is_plt16_reloc<size>(r_type)
 	    || r_type == elfcpp::R_PPC64_PLT_PCREL34
@@ -1891,6 +1892,7 @@ is_branch_reloc(unsigned int r_type)
 {
   return (r_type == elfcpp::R_POWERPC_REL24
 	  || (size == 64 && r_type == elfcpp::R_PPC64_REL24_NOTOC)
+	  || r_type == elfcpp::R_PPC64_REL24_P9NOTOC
 	  || r_type == elfcpp::R_PPC_PLTREL24
 	  || r_type == elfcpp::R_PPC_LOCAL24PC
 	  || r_type == elfcpp::R_POWERPC_REL14
@@ -3447,6 +3449,7 @@ max_branch_delta (unsigned int r_type)
     return 1L << 15;
   if (r_type == elfcpp::R_POWERPC_REL24
       || (size == 64 && r_type == elfcpp::R_PPC64_REL24_NOTOC)
+      || r_type == elfcpp::R_PPC64_REL24_P9NOTOC
       || r_type == elfcpp::R_PPC_PLTREL24
       || r_type == elfcpp::R_PPC_LOCAL24PC)
     return 1L << 25;
@@ -3621,12 +3624,14 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
 	}
       unsigned int local_ent = 0;
       if (size == 64
-	  && this->r_type_ != elfcpp::R_PPC64_REL24_NOTOC)
+	  && this->r_type_ != elfcpp::R_PPC64_REL24_NOTOC
+	  && this->r_type_ != elfcpp::R_PPC64_REL24_P9NOTOC)
 	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
+	      && (this->r_type_ == elfcpp::R_PPC64_REL24_NOTOC
+		  || this->r_type_ == elfcpp::R_PPC64_REL24_P9NOTOC)
 	      && (gsym != NULL
 		  ? this->object_->ppc64_needs_toc(gsym)
 		  : this->object_->ppc64_needs_toc(this->r_sym_))))
@@ -4777,33 +4782,50 @@ class Stub_table : public Output_relaxed_input_section
   struct Plt_stub_ent
   {
     Plt_stub_ent(unsigned int off, unsigned int indx)
-      : off_(off), indx_(indx), iter_(0), notoc_(0), toc_(0),
-	r2save_(0), localentry0_(0), tocoff_(0)
+      : off_(off), indx_(indx), tocoff_(0), p9off_(0), tsize_ (0), iter_(0),
+	toc_(0), notoc_(0), p9notoc_(0), r2save_(0), localentry0_(0)
     { }
 
     unsigned int off_;
     unsigned int indx_;
+    // off_ points at p10 notoc stub, tocoff_ is offset from there to
+    // toc stub, p9off_ is offset to p9notoc stub
+    unsigned int tocoff_ : 8;
+    unsigned int p9off_ : 8;
+    // The size of the toc stub, used to locate blr on tls_get_addr stub.
+    unsigned int tsize_ : 8;
+    // Stub revision management
     unsigned int iter_ : 1;
-    unsigned int notoc_ : 1;
+    // The three types of stubs.
     unsigned int toc_ : 1;
+    unsigned int notoc_ : 1;
+    unsigned int p9notoc_ : 1;
+    // Each with a possible variant saving r2 first
     unsigned int r2save_ : 1;
+    // Handy cached info from symbol
     unsigned int localentry0_ : 1;
-    unsigned int tocoff_ : 8;
   };
   struct Branch_stub_ent
   {
-    Branch_stub_ent(unsigned int off, bool notoc, bool save_res)
-      : off_(off), iter_(0), notoc_(notoc), toc_(0), save_res_(save_res),
-	other_(0), tocoff_(0)
+    Branch_stub_ent(unsigned int off)
+      : off_(off), tocoff_(0), p9off_(0), iter_(0), toc_(0), notoc_(0),
+	p9notoc_(0), save_res_(0), other_(0)
     { }
 
     unsigned int off_;
+    // off_ points at p10 notoc stub, tocoff_ is offset from there to
+    // toc stub, p9off_ is offset to p9notoc stub
+    unsigned int tocoff_ : 8;
+    unsigned int p9off_ : 8;
+    // Stub revision management
     unsigned int iter_ : 1;
-    unsigned int notoc_ : 1;
+    // Four types of stubs.
     unsigned int toc_ : 1;
+    unsigned int notoc_ : 1;
+    unsigned int p9notoc_ : 1;
     unsigned int save_res_ : 1;
+    // Handy cached info from symbol
     unsigned int other_ : 3;
-    unsigned int tocoff_ : 8;
   };
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   static const Address invalid_address = static_cast<Address>(0) - 1;
@@ -5223,13 +5245,23 @@ Stub_table<size, big_endian>::add_plt_call_entry(
 	  p.first->second.localentry0_ = 1;
 	  this->targ_->set_has_localentry0();
 	}
-      if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
+      if (r_type == elfcpp::R_PPC64_REL24_NOTOC
+	  || r_type == elfcpp::R_PPC64_REL24_P9NOTOC)
 	{
-	  if (!p.second && !p.first->second.notoc_
-	      && (!this->targ_->power10_stubs()
-		  || this->targ_->power10_stubs_auto()))
-	    this->need_resize_ = true;
-	  p.first->second.notoc_ = 1;
+	  if (this->targ_->power10_stubs()
+	      && (!this->targ_->power10_stubs_auto()
+		  || r_type == elfcpp::R_PPC64_REL24_NOTOC))
+	    {
+	      if (!p.second && !p.first->second.notoc_)
+		this->need_resize_ = true;
+	      p.first->second.notoc_ = 1;
+	    }
+	  else
+	    {
+	      if (!p.second && !p.first->second.p9notoc_)
+		this->need_resize_ = true;
+	      p.first->second.p9notoc_ = 1;
+	    }
 	}
       else
 	{
@@ -5254,7 +5286,6 @@ Stub_table<size, big_endian>::add_plt_call_entry(
       this->plt_size_ += this->plt_call_size(p.first);
       if (this->targ_->is_tls_get_addr_opt(gsym))
 	this->targ_->set_has_tls_get_addr_opt();
-      this->plt_size_ = this->plt_call_align(this->plt_size_);
     }
   return this->can_reach_stub(from, p.first->second.off_, r_type);
 }
@@ -5281,13 +5312,23 @@ Stub_table<size, big_endian>::add_plt_call_entry(
 	  p.first->second.localentry0_ = 1;
 	  this->targ_->set_has_localentry0();
 	}
-      if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
+      if (r_type == elfcpp::R_PPC64_REL24_NOTOC
+	  || r_type == elfcpp::R_PPC64_REL24_P9NOTOC)
 	{
-	  if (!p.second && !p.first->second.notoc_
-	      && (!this->targ_->power10_stubs()
-		  || this->targ_->power10_stubs_auto()))
-	    this->need_resize_ = true;
-	  p.first->second.notoc_ = 1;
+	  if (this->targ_->power10_stubs()
+	      && (!this->targ_->power10_stubs_auto()
+		  || r_type == elfcpp::R_PPC64_REL24_NOTOC))
+	    {
+	      if (!p.second && !p.first->second.notoc_)
+		this->need_resize_ = true;
+	      p.first->second.notoc_ = 1;
+	    }
+	  else
+	    {
+	      if (!p.second && !p.first->second.p9notoc_)
+		this->need_resize_ = true;
+	      p.first->second.p9notoc_ = 1;
+	    }
 	}
       else
 	{
@@ -5310,7 +5351,6 @@ Stub_table<size, big_endian>::add_plt_call_entry(
 	  p.first->second.off_ = this->plt_size_;
 	}
       this->plt_size_ += this->plt_call_size(p.first);
-      this->plt_size_ = this->plt_call_align(this->plt_size_);
     }
   return this->can_reach_stub(from, p.first->second.off_, r_type);
 }
@@ -5384,15 +5424,33 @@ Stub_table<size, big_endian>::add_long_branch_entry(
     bool save_res)
 {
   Branch_stub_key key(to);
-  bool notoc = (size == 64 && r_type == elfcpp::R_PPC64_REL24_NOTOC);
-  Branch_stub_ent ent(this->branch_size_, notoc, save_res);
+  Branch_stub_ent ent(this->branch_size_);
   std::pair<typename Branch_stub_entries::iterator, bool> p
     = this->long_branch_stubs_.insert(std::make_pair(key, ent));
-  if (notoc)
+  if (save_res)
     {
-      if (!p.second && !p.first->second.notoc_)
+      if (!p.second && !p.first->second.save_res_)
 	this->need_resize_ = true;
-      p.first->second.notoc_ = true;
+      p.first->second.save_res_ = true;
+    }
+  else if (size == 64
+	   && (r_type == elfcpp::R_PPC64_REL24_NOTOC
+	       || r_type == elfcpp::R_PPC64_REL24_P9NOTOC))
+    {
+      if (this->targ_->power10_stubs()
+	  && (!this->targ_->power10_stubs_auto()
+	      || r_type == elfcpp::R_PPC64_REL24_NOTOC))
+	{
+	  if (!p.second && !p.first->second.notoc_)
+	    this->need_resize_ = true;
+	  p.first->second.notoc_ = true;
+	}
+      else
+	{
+	  if (!p.second && !p.first->second.p9notoc_)
+	    this->need_resize_ = true;
+	  p.first->second.p9notoc_ = true;
+	}
     }
   else
     {
@@ -5402,7 +5460,6 @@ Stub_table<size, big_endian>::add_long_branch_entry(
     }
   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_))
     {
       if (this->resizing_)
@@ -5500,11 +5557,11 @@ Stub_table<size, big_endian>::add_eh_frame(Layout* layout)
     for (plt_iter cs = this->plt_call_stubs_.begin();
 	 cs != this->plt_call_stubs_.end();
 	 ++cs)
-      if ((this->targ_->is_tls_get_addr_opt(cs->first.sym_)
-	   && cs->second.r2save_
-	   && !cs->second.localentry0_)
-	  || (cs->second.notoc_
-	      && !this->targ_->power10_stubs()))
+      if (cs->second.p9notoc_
+	  || (cs->second.toc_
+	      && cs->second.r2save_
+	      && !cs->second.localentry0_
+	      && this->targ_->is_tls_get_addr_opt(cs->first.sym_)))
 	calls.push_back(cs);
   if (calls.size() > 1)
     std::stable_sort(calls.begin(), calls.end(),
@@ -5540,37 +5597,42 @@ Stub_table<size, big_endian>::add_eh_frame(Layout* layout)
       if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
 	{
 	  off += 7 * 4;
-	  if (cs->second.r2save_
+	  if (cs->second.toc_
+	      && cs->second.r2save_
 	      && !cs->second.localentry0_)
 	    {
-	      off += 2 * 4;
+	      off += cs->second.tocoff_ + 2 * 4;
 	      eh_advance<big_endian>(fde, off - last_eh_loc);
 	      fde.resize(fde.size() + 6);
 	      unsigned char* p = &*fde.end() - 6;
 	      *p++ = elfcpp::DW_CFA_offset_extended_sf;
 	      *p++ = 65;
 	      *p++ = -(this->targ_->stk_linker() / 8) & 0x7f;
-	      unsigned int delta = this->plt_call_size(cs) - 4 - 9 * 4;
+	      unsigned int delta = cs->second.tsize_ - 9 * 4 - 4;
 	      *p++ = elfcpp::DW_CFA_advance_loc + delta / 4;
 	      *p++ = elfcpp::DW_CFA_restore_extended;
 	      *p++ = 65;
 	      last_eh_loc = off + delta;
-	      continue;
+	      off = cs->second.off_ + 7 * 4;
 	    }
 	}
       // notoc stubs also should describe LR changes, to support
       // asynchronous exceptions.
-      off += (cs->second.r2save_ ? 4 : 0) + 8;
-      eh_advance<big_endian>(fde, off - last_eh_loc);
-      fde.resize(fde.size() + 6);
-      unsigned char* p = &*fde.end() - 6;
-      *p++ = elfcpp::DW_CFA_register;
-      *p++ = 65;
-      *p++ = 12;
-      *p++ = elfcpp::DW_CFA_advance_loc + 8 / 4;
-      *p++ = elfcpp::DW_CFA_restore_extended;
-      *p++ = 65;
-      last_eh_loc = off + 8;
+      if (cs->second.p9notoc_)
+	{
+	  off += cs->second.p9off_;
+	  off += (cs->second.r2save_ ? 4 : 0) + 8;
+	  eh_advance<big_endian>(fde, off - last_eh_loc);
+	  fde.resize(fde.size() + 6);
+	  unsigned char* p = &*fde.end() - 6;
+	  *p++ = elfcpp::DW_CFA_register;
+	  *p++ = 65;
+	  *p++ = 12;
+	  *p++ = elfcpp::DW_CFA_advance_loc + 8 / 4;
+	  *p++ = elfcpp::DW_CFA_restore_extended;
+	  *p++ = 65;
+	  last_eh_loc = off + 8;
+	}
     }
 
   for (unsigned int i = 0; i < branches.size(); i++)
@@ -5842,7 +5904,7 @@ Stub_table<size, big_endian>::define_stub_syms(Symbol_table* symtab)
 	  sprintf(name, "%08x.plt_call.%s%s%s", this->uniq_, obj, symname, add);
 	  Address value
 	    = this->stub_address() - this->address() + cs->second.off_;
-	  unsigned int stub_size = this->plt_call_align(this->plt_call_size(cs));
+	  unsigned int stub_size = this->plt_call_size(cs);
 	  this->targ_->define_local(symtab, name, this, value, stub_size);
 	}
     }
@@ -6108,9 +6170,10 @@ Stub_table<size, big_endian>::plt_call_size(
 {
   if (size == 32)
     {
-      const Symbol* gsym = p->first.sym_;
-      return (4 * 4
-	      + (this->targ_->is_tls_get_addr_opt(gsym) ? 8 * 4 : 0));
+      unsigned int bytes = 4 * 4;
+      if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
+	bytes = 12 * 4;
+      return this->plt_call_align(bytes);
     }
 
   const Output_data_plt_powerpc<size, big_endian>* plt;
@@ -6135,7 +6198,6 @@ Stub_table<size, big_endian>::plt_call_size(
 	    bytes += 8 * 4;
 	  bytes = this->plt_call_align(bytes);
 	}
-      unsigned int tail = 0;
       if (p->second.toc_)
 	{
 	  p->second.tocoff_ = bytes;
@@ -6143,18 +6205,43 @@ Stub_table<size, big_endian>::plt_call_size(
 	    {
 	      bytes += 7 * 4;
 	      if (p->second.r2save_ && !p->second.localentry0_)
-		{
-		  bytes += 2 * 4;
-		  tail = 4 * 4;
-		}
+		bytes += 2 * 4 + 4 * 4;
 	    }
 	  if (p->second.r2save_)
 	    bytes += 4;
 	  uint64_t got_addr = this->targ_->toc_pointer();
 	  uint64_t off = plt_addr - got_addr;
 	  bytes += 3 * 4 + 4 * (ha(off) != 0);
+	  p->second.tsize_ = bytes - p->second.tocoff_;
+	  bytes = this->plt_call_align(bytes);
 	}
-      return bytes + tail;
+      if (p->second.p9notoc_)
+	{
+	  p->second.p9off_ = bytes;
+	  if (this->targ_->is_tls_get_addr_opt(p->first.sym_))
+	    bytes += 7 * 4;
+	  uint64_t from = this->stub_address() + p->second.off_ + bytes + 2 * 4;
+	  uint64_t off = plt_addr - from;
+	  if (off + 0x8000 < 0x10000)
+	    bytes += 7 * 4;
+	  else if (off + 0x80008000ULL < 0x100000000ULL)
+	    bytes += 8 * 4;
+	  else
+	    {
+	      bytes += 8 * 4;
+	      if (off + 0x800000000000ULL >= 0x1000000000000ULL
+		  && ((off >> 32) & 0xffff) != 0)
+		bytes += 4;
+	      if (((off >> 32) & 0xffffffffULL) != 0)
+		bytes += 4;
+	      if (hi(off) != 0)
+		bytes += 4;
+	      if (l(off) != 0)
+		bytes += 4;
+	    }
+	  bytes = this->plt_call_align(bytes);
+	}
+      return bytes;
     }
   else
     {
@@ -6184,10 +6271,10 @@ Stub_table<size, big_endian>::plt_call_size(
 	    bytes += 7 * 4;
 	  else
 	    bytes += 8 * 4;
-	  return bytes + tail;
+	  return this->plt_call_align(bytes + tail);
 	}
 
-      if (p->second.notoc_)
+      if (p->second.p9notoc_)
 	{
 	  uint64_t from = this->stub_address() + p->second.off_ + bytes + 2 * 4;
 	  uint64_t off = plt_addr - from;
@@ -6208,7 +6295,7 @@ Stub_table<size, big_endian>::plt_call_size(
 	      if (l(off) != 0)
 		bytes += 4;
 	    }
-	  return bytes + tail;
+	  return this->plt_call_align(bytes + tail);
 	}
 
       uint64_t got_addr = this->targ_->toc_pointer();
@@ -6223,7 +6310,7 @@ Stub_table<size, big_endian>::plt_call_size(
 		    + 8 * thread_safe
 		    + 4 * (ha(off + 8 + 8 * static_chain) != ha(off)));
 	}
-      return bytes + tail;
+      return this->plt_call_align(bytes + tail);
     }
 }
 
@@ -6400,6 +6487,19 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 		      else
 			write_insn<big_endian>(p, bctr);
 		    }
+		  if (cs->second.p9notoc_)
+		    {
+		      if (this->targ_->is_tls_get_addr_opt(cs->first.sym_))
+			this->build_tls_opt_head(&p, false);
+		      Address from = this->stub_address() + (p - oview);
+		      Address delta = plt_addr - from;
+		      p = build_notoc_offset<big_endian>(p, delta, true);
+		      write_insn<big_endian>(p, mtctr_12);
+		      p += 4;
+		      write_insn<big_endian>(p, bctr);
+		      p += 4;
+		      p = oview + this->plt_call_align(p - oview);
+		    }
 		}
 	      else
 		{
@@ -6494,6 +6594,23 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 		      write_insn<big_endian>(p, bctr);
 		    }
 		}
+	      if (bs->second.p9notoc_)
+		{
+		  unsigned char* startp = p;
+		  p = build_notoc_offset<big_endian>(p, delta, false);
+		  delta -= p - startp;
+		  startp = p;
+		  if (delta + (1 << 25) < 2 << 25)
+		    write_insn<big_endian>(p, b | (delta & 0x3fffffc));
+		  else
+		    {
+		      write_insn<big_endian>(p, mtctr_12);
+		      p += 4;
+		      write_insn<big_endian>(p, bctr);
+		    }
+		  p += 4;
+		  delta -= p - startp;
+		}
 	    }
 	  else
 	    {
@@ -6544,7 +6661,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
 		  write_insn<big_endian>(p, std_2_1 + this->targ_->stk_toc());
 		  p += 4;
 		}
-	      if (cs->second.notoc_)
+	      if (cs->second.p9notoc_)
 		{
 		  Address from = this->stub_address() + (p - oview) + 8;
 		  Address off = plt_addr - from;
@@ -6722,9 +6839,9 @@ 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_)
+	  if (!bs->second.p9notoc_)
 	    delta += elfcpp::ppc64_decode_local_entry(bs->second.other_);
-	  if (bs->second.notoc_)
+	  if (bs->second.p9notoc_)
 	    {
 	      unsigned char* startp = p;
 	      p = build_notoc_offset<big_endian>(p, off, false);
@@ -7619,6 +7736,7 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(
       if (size == 32)
 	break;
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_POWERPC_REL14:
@@ -7861,6 +7979,7 @@ Target_powerpc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
       if (size == 32)
 	break;
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_POWERPC_ADDR24:
     case elfcpp::R_POWERPC_ADDR14:
     case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
@@ -8124,6 +8243,7 @@ Target_powerpc<size, big_endian>::Scan::local(
       if (size == 32)
 	break;
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_PPC_LOCAL24PC:
@@ -8873,6 +8993,7 @@ Target_powerpc<size, big_endian>::Scan::global(
       if (size == 32)
 	break;
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_POWERPC_REL24:
       if (!is_ifunc)
@@ -10630,15 +10751,25 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 		  const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
 		  elfcpp::Shdr<size, big_endian> shdr(relinfo->reloc_shdr);
 		  size_t reloc_count = shdr.get_sh_size() / reloc_size;
-		  if (size == 64
-		      && r_type != elfcpp::R_PPC64_REL24_NOTOC)
-		    value += ent->tocoff_;
+		  if (size == 64)
+		    {
+		      if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
+			{
+			  if (!ent->notoc_)
+			    value += ent->p9off_;
+			}
+		      else if (r_type == elfcpp::R_PPC64_REL24_P9NOTOC)
+			value += ent->p9off_;
+		      else
+			value += ent->tocoff_;
+		    }
 		  if (size == 64
 		      && ent->r2save_
 		      && !(gsym != NULL
 			   && target->is_tls_get_addr_opt(gsym)))
 		    {
-		      if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
+		      if (r_type == elfcpp::R_PPC64_REL24_NOTOC
+			  || r_type == elfcpp::R_PPC64_REL24_P9NOTOC)
 			{
 			  if (!(target->power10_stubs()
 				&& target->power10_stubs_auto()))
@@ -11078,6 +11209,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 		  unsigned int r_type2
 		    = elfcpp::elf_r_type<size>(next_rela.get_r_info());
 		  if ((r_type2 == elfcpp::R_PPC64_REL24_NOTOC
+		       || r_type2 == elfcpp::R_PPC64_REL24_P9NOTOC
 		       || r_type2 == elfcpp::R_PPC64_PLTCALL_NOTOC)
 		      && next_rela.get_r_offset() == rela.get_r_offset())
 		    is_pcrel = true;
@@ -11118,6 +11250,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 	      unsigned int r_type2
 		= elfcpp::elf_r_type<size>(next_rela.get_r_info());
 	      if ((r_type2 == elfcpp::R_PPC64_REL24_NOTOC
+		   || r_type2 == elfcpp::R_PPC64_REL24_P9NOTOC
 		   || r_type2 == elfcpp::R_PPC64_PLTCALL_NOTOC)
 		  && next_rela.get_r_offset() == rela.get_r_offset())
 		is_pcrel = true;
@@ -11227,7 +11360,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (max_branch != 0
 	  && (value + local_ent - address + max_branch >= 2 * max_branch
 	      || (size == 64
-		  && r_type == elfcpp::R_PPC64_REL24_NOTOC
+		  && (r_type == elfcpp::R_PPC64_REL24_NOTOC
+		      || r_type == elfcpp::R_PPC64_REL24_NOTOC)
 		  && (gsym != NULL
 		      ? object->ppc64_needs_toc(gsym)
 		      : object->ppc64_needs_toc(r_sym)))))
@@ -11250,9 +11384,18 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
 		      value = (stub_table->stub_address()
 			       + stub_table->plt_size()
 			       + ent->off_);
-		      if (size == 64
-			  && r_type != elfcpp::R_PPC64_REL24_NOTOC)
-			value += ent->tocoff_;
+		      if (size == 64)
+			{
+			  if (r_type == elfcpp::R_PPC64_REL24_NOTOC)
+			    {
+			      if (!ent->notoc_)
+				value += ent->p9off_;
+			    }
+			  else if (r_type == elfcpp::R_PPC64_REL24_P9NOTOC)
+			    value += ent->p9off_;
+			  else
+			    value += ent->tocoff_;
+			}
 		    }
 		  has_stub_value = true;
 		}
@@ -11268,6 +11411,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (size == 32)
 	break;
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_PPC64_REL64:
     case elfcpp::R_POWERPC_REL32:
     case elfcpp::R_POWERPC_REL24:
@@ -11802,6 +11946,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (size == 32)
 	break;
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_POWERPC_ADDR24:
     case elfcpp::R_POWERPC_ADDR14:
     case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
@@ -11905,6 +12050,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (size == 32)
 	goto unsupp; // R_PPC_EMB_RELSDA
       // Fall through.
+    case elfcpp::R_PPC64_REL24_P9NOTOC:
     case elfcpp::R_POWERPC_ADDR24:
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-12-11  4:24 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-11  4:24 [GOLD] PowerPC64 @notoc in non-power10 code Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).