public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* PR26656, power10 libstdc++.so segfault in __cxxabiv1::__cxa_throw
@ 2020-09-23 22:41 Alan Modra
  2020-09-28  0:15 ` Alan Modra
  0 siblings, 1 reply; 2+ messages in thread
From: Alan Modra @ 2020-09-23 22:41 UTC (permalink / raw)
  To: binutils

This adds missing support for a power10 version of the __tls_get_addr
call stub implementing DT_PPC64_OPT PPC64_OPT_TLS.  Without this,
power10 code using __tls_get_addr fails miserably at runtime unless
the --no-tls-get-addr-optimize option is given.

	PR 26656
	* elf64-ppc.c (plt_stub_size): Add "odd" param.  Use it with
	size_power10_offset rather than calculating from start of stub.
	Add size for notoc tls_get_addr_opt stub.
	(plt_stub_pad): Add "odd" param, pass to plt_stub_size.
	(build_tls_get_addr_head, build_tls_get_addr_tail): New functions.
	(build_tls_get_addr_stub): Delete.
	(ppc_build_one_stub): Use a temp for htab->params->stub_bfd.
	Emit notoc tls_get_addr_opt stub.  Move eh_frame code to
	suit.  Adjust code to use bfd_tls_get_addr_head/tail in place
	of build_tls_get_addr_stub.
	(ppc_size_one_stub): Size notoc tls_get_addr_opt stub.
	Adjust plt_stub_size and plt_stub_pad calls.  Correct "odd"
	when padding stub.  Size eh_frame for notoc stub too.
	Correct lr_restore value.
	(ppc64_elf_relocate_section): Don't skip over first insn of
	notoc tls_get_addr_opt stub.

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4d16dc3cd4..320717cb45 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -10842,62 +10842,60 @@ eh_advance_size (unsigned int delta)
 static inline unsigned int
 plt_stub_size (struct ppc_link_hash_table *htab,
 	       struct ppc_stub_hash_entry *stub_entry,
-	       bfd_vma off)
+	       bfd_vma off,
+	       unsigned int odd)
 {
   unsigned size;
 
   if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
     {
       if (htab->params->power10_stubs != 0)
-	{
-	  bfd_vma start = (stub_entry->stub_offset
-			   + stub_entry->group->stub_sec->output_offset
-			   + stub_entry->group->stub_sec->output_section->vma);
-	  if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
-	    start += 4;
-	  size = 8 + size_power10_offset (off, start & 4);
-	}
+	size = 8 + size_power10_offset (off, odd);
       else
 	size = 8 + size_offset (off - 8);
       if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
 	size += 4;
-      return size;
     }
-
-  size = 12;
-  if (ALWAYS_EMIT_R2SAVE
-      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-    size += 4;
-  if (PPC_HA (off) != 0)
-    size += 4;
-  if (htab->opd_abi)
+  else
     {
-      size += 4;
-      if (htab->params->plt_static_chain)
+      size = 12;
+      if (ALWAYS_EMIT_R2SAVE
+	  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 	size += 4;
-      if (htab->params->plt_thread_safe
-	  && htab->elf.dynamic_sections_created
-	  && stub_entry->h != NULL
-	  && stub_entry->h->elf.dynindx != -1)
-	size += 8;
-      if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off))
+      if (PPC_HA (off) != 0)
 	size += 4;
+      if (htab->opd_abi)
+	{
+	  size += 4;
+	  if (htab->params->plt_static_chain)
+	    size += 4;
+	  if (htab->params->plt_thread_safe
+	      && htab->elf.dynamic_sections_created
+	      && stub_entry->h != NULL
+	      && stub_entry->h->elf.dynindx != -1)
+	    size += 8;
+	  if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain)
+	      != PPC_HA (off))
+	    size += 4;
+	}
     }
   if (stub_entry->h != NULL
       && is_tls_get_addr (&stub_entry->h->elf, htab)
       && htab->params->tls_get_addr_opt)
     {
-      if (htab->params->no_tls_get_addr_regsave)
+      if (!htab->params->no_tls_get_addr_regsave)
 	{
-	  size += 7 * 4;
-	  if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
-	    size += 6 * 4;
+	  size += 30 * 4;
+	  if (stub_entry->stub_type == ppc_stub_plt_call_r2save
+	      || stub_entry->stub_type == ppc_stub_plt_call_both)
+	    size += 4;
 	}
       else
 	{
-	  size += 30 * 4;
-	  if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
-	    size += 4;
+	  size += 7 * 4;
+	  if (stub_entry->stub_type == ppc_stub_plt_call_r2save
+	      || stub_entry->stub_type == ppc_stub_plt_call_both)
+	    size += 6 * 4;
 	}
     }
   return size;
@@ -10912,7 +10910,8 @@ plt_stub_size (struct ppc_link_hash_table *htab,
 static inline unsigned int
 plt_stub_pad (struct ppc_link_hash_table *htab,
 	      struct ppc_stub_hash_entry *stub_entry,
-	      bfd_vma plt_off)
+	      bfd_vma plt_off,
+	      unsigned int odd)
 {
   int stub_align;
   unsigned stub_size;
@@ -10927,7 +10926,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
     }
 
   stub_align = 1 << -htab->params->plt_stub_align;
-  stub_size = plt_stub_size (htab, stub_entry, plt_off);
+  stub_size = plt_stub_size (htab, stub_entry, plt_off, odd);
   if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
       > ((stub_size - 1) & -stub_align))
     return stub_align - (stub_off & (stub_align - 1));
@@ -11123,14 +11122,12 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 #define MR_R3_R0	0x7c030378
 #define BCTRL		0x4e800421
 
-static inline bfd_byte *
-build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
+static bfd_byte *
+build_tls_get_addr_head (struct ppc_link_hash_table *htab,
 			 struct ppc_stub_hash_entry *stub_entry,
-			 bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
+			 bfd_byte *p)
 {
   bfd *obfd = htab->params->stub_bfd;
-  bfd_byte *loc = p;
-  unsigned int i;
 
   bfd_put_32 (obfd, LD_R0_0R3 + 0, p),		p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),		p += 4;
@@ -11139,21 +11136,43 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   bfd_put_32 (obfd, ADD_R3_R12_R13, p),		p += 4;
   bfd_put_32 (obfd, BEQLR, p),			p += 4;
   bfd_put_32 (obfd, MR_R3_R0, p),		p += 4;
-  if (htab->params->no_tls_get_addr_regsave)
-    {
-      if (r != NULL)
-	r[0].r_offset += 7 * 4;
-      if (stub_entry->stub_type != ppc_stub_plt_call_r2save)
-	return build_plt_stub (htab, stub_entry, p, offset, r);
 
+  if (!htab->params->no_tls_get_addr_regsave)
+    p = tls_get_addr_prologue (obfd, p, htab);
+  else if (stub_entry->stub_type == ppc_stub_plt_call_r2save
+	   || stub_entry->stub_type == ppc_stub_plt_call_both)
+    {
       bfd_put_32 (obfd, MFLR_R0, p);
       p += 4;
       bfd_put_32 (obfd, STD_R0_0R1 + STK_LINKER (htab), p);
       p += 4;
+    }
+  return p;
+}
 
-      if (r != NULL)
-	r[0].r_offset += 2 * 4;
-      p = build_plt_stub (htab, stub_entry, p, offset, r);
+static bfd_byte *
+build_tls_get_addr_tail (struct ppc_link_hash_table *htab,
+			 struct ppc_stub_hash_entry *stub_entry,
+			 bfd_byte *p,
+			 bfd_byte *loc)
+{
+  bfd *obfd = htab->params->stub_bfd;
+
+  if (!htab->params->no_tls_get_addr_regsave)
+    {
+      bfd_put_32 (obfd, BCTRL, p - 4);
+
+      if (stub_entry->stub_type == ppc_stub_plt_call_r2save
+	  || stub_entry->stub_type == ppc_stub_plt_call_both)
+	{
+	  bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
+	  p += 4;
+	}
+      p = tls_get_addr_epilogue (obfd, p, htab);
+    }
+  else if (stub_entry->stub_type == ppc_stub_plt_call_r2save
+	   || stub_entry->stub_type == ppc_stub_plt_call_both)
+    {
       bfd_put_32 (obfd, BCTRL, p - 4);
 
       bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
@@ -11165,24 +11184,6 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
       bfd_put_32 (obfd, BLR, p);
       p += 4;
     }
-  else
-    {
-      p = tls_get_addr_prologue (obfd, p, htab);
-
-      if (r != NULL)
-	r[0].r_offset += 18 * 4;
-
-      p = build_plt_stub (htab, stub_entry, p, offset, r);
-      bfd_put_32 (obfd, BCTRL, p - 4);
-
-      if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
-	{
-	  bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
-	  p += 4;
-	}
-
-      p = tls_get_addr_epilogue (obfd, p, htab);
-    }
 
   if (htab->glink_eh_frame != NULL
       && htab->glink_eh_frame->size != 0)
@@ -11191,21 +11192,11 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
 
       base = htab->glink_eh_frame->contents + stub_entry->group->eh_base + 17;
       eh = base + stub_entry->group->eh_size;
-      if (htab->params->no_tls_get_addr_regsave)
-	{
-	  unsigned int lr_used, delta;
-	  lr_used = stub_entry->stub_offset + (p - 20 - loc);
-	  delta = lr_used - stub_entry->group->lr_restore;
-	  stub_entry->group->lr_restore = lr_used + 16;
-	  eh = eh_advance (htab->elf.dynobj, eh, delta);
-	  *eh++ = DW_CFA_offset_extended_sf;
-	  *eh++ = 65;
-	  *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
-	  *eh++ = DW_CFA_advance_loc + 4;
-	}
-      else
+
+      if (!htab->params->no_tls_get_addr_regsave)
 	{
-	  unsigned int cfa_updt, delta;
+	  unsigned int cfa_updt, delta, i;
+
 	  /* After the bctrl, lr has been modified so we need to emit
 	     .eh_frame info saying the return address is on the stack.  In
 	     fact we must put the EH info at or before the call rather
@@ -11244,10 +11235,27 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
 	  for (i = 4; i < 12; i++)
 	    *eh++ = DW_CFA_restore + i;
 	  *eh++ = DW_CFA_advance_loc + 2;
+	  *eh++ = DW_CFA_restore_extended;
+	  *eh++ = 65;
+	  stub_entry->group->eh_size = eh - base;
+	}
+      else if (stub_entry->stub_type == ppc_stub_plt_call_r2save
+	       || stub_entry->stub_type == ppc_stub_plt_call_both)
+	{
+	  unsigned int lr_used, delta;
+
+	  lr_used = stub_entry->stub_offset + (p - 20 - loc);
+	  delta = lr_used - stub_entry->group->lr_restore;
+	  stub_entry->group->lr_restore = lr_used + 16;
+	  eh = eh_advance (htab->elf.dynobj, eh, delta);
+	  *eh++ = DW_CFA_offset_extended_sf;
+	  *eh++ = 65;
+	  *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
+	  *eh++ = DW_CFA_advance_loc + 4;
+	  *eh++ = DW_CFA_restore_extended;
+	  *eh++ = 65;
+	  stub_entry->group->eh_size = eh - base;
 	}
-      *eh++ = DW_CFA_restore_extended;
-      *eh++ = 65;
-      stub_entry->group->eh_size = eh - base;
     }
   return p;
 }
@@ -11381,6 +11389,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   struct ppc_branch_hash_entry *br_entry;
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
+  bfd *obfd;
   bfd_byte *loc;
   bfd_byte *p, *relp;
   bfd_vma targ, off;
@@ -11388,6 +11397,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   asection *plt;
   int num_rel;
   int odd;
+  bfd_boolean is_tga;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
@@ -11437,6 +11447,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       off = targ - off;
 
       p = loc;
+      obfd = htab->params->stub_bfd;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
 	{
 	  bfd_vma r2off = get_r2off (info, stub_entry);
@@ -11446,23 +11457,21 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      htab->stub_error = TRUE;
 	      return FALSE;
 	    }
-	  bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+	  bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p);
 	  p += 4;
 	  if (PPC_HA (r2off) != 0)
 	    {
-	      bfd_put_32 (htab->params->stub_bfd,
-			  ADDIS_R2_R2 | PPC_HA (r2off), p);
+	      bfd_put_32 (obfd, ADDIS_R2_R2 | PPC_HA (r2off), p);
 	      p += 4;
 	    }
 	  if (PPC_LO (r2off) != 0)
 	    {
-	      bfd_put_32 (htab->params->stub_bfd,
-			  ADDI_R2_R2 | PPC_LO (r2off), p);
+	      bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (r2off), p);
 	      p += 4;
 	    }
 	  off -= p - loc;
 	}
-      bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), p);
+      bfd_put_32 (obfd, B_DOT | (off & 0x3fffffc), p);
       p += 4;
 
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
@@ -11588,19 +11597,17 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	}
 
       p = loc;
+      obfd = htab->params->stub_bfd;
       if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
 	{
 	  if (PPC_HA (off) != 0)
 	    {
-	      bfd_put_32 (htab->params->stub_bfd,
-			  ADDIS_R12_R2 | PPC_HA (off), p);
+	      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (off), p);
 	      p += 4;
-	      bfd_put_32 (htab->params->stub_bfd,
-			  LD_R12_0R12 | PPC_LO (off), p);
+	      bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (off), p);
 	    }
 	  else
-	    bfd_put_32 (htab->params->stub_bfd,
-			LD_R12_0R2 | PPC_LO (off), p);
+	    bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (off), p);
 	}
       else
 	{
@@ -11612,36 +11619,32 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      return FALSE;
 	    }
 
-	  bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+	  bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p);
 	  p += 4;
 	  if (PPC_HA (off) != 0)
 	    {
-	      bfd_put_32 (htab->params->stub_bfd,
-			  ADDIS_R12_R2 | PPC_HA (off), p);
+	      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (off), p);
 	      p += 4;
-	      bfd_put_32 (htab->params->stub_bfd,
-			  LD_R12_0R12 | PPC_LO (off), p);
+	      bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (off), p);
 	    }
 	  else
-	    bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), p);
+	    bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (off), p);
 
 	  if (PPC_HA (r2off) != 0)
 	    {
 	      p += 4;
-	      bfd_put_32 (htab->params->stub_bfd,
-			  ADDIS_R2_R2 | PPC_HA (r2off), p);
+	      bfd_put_32 (obfd, ADDIS_R2_R2 | PPC_HA (r2off), p);
 	    }
 	  if (PPC_LO (r2off) != 0)
 	    {
 	      p += 4;
-	      bfd_put_32 (htab->params->stub_bfd,
-			  ADDI_R2_R2 | PPC_LO (r2off), p);
+	      bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (r2off), p);
 	    }
 	}
       p += 4;
-      bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
+      bfd_put_32 (obfd, MTCTR_R12, p);
       p += 4;
-      bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+      bfd_put_32 (obfd, BCTR, p);
       p += 4;
       break;
 
@@ -11655,12 +11658,22 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       off = (stub_entry->stub_offset
 	     + stub_entry->group->stub_sec->output_offset
 	     + stub_entry->group->stub_sec->output_section->vma);
+      obfd = htab->params->stub_bfd;
+      is_tga = ((stub_entry->stub_type == ppc_stub_plt_call_notoc
+		 || stub_entry->stub_type == ppc_stub_plt_call_both)
+		&& is_tls_get_addr (&stub_entry->h->elf, htab)
+		&& htab->params->tls_get_addr_opt);
+      if (is_tga)
+	{
+	  p = build_tls_get_addr_head (htab, stub_entry, p);
+	  off += p - loc;
+	}
       if (stub_entry->stub_type == ppc_stub_long_branch_both
 	  || stub_entry->stub_type == ppc_stub_plt_branch_both
 	  || stub_entry->stub_type == ppc_stub_plt_call_both)
 	{
 	  off += 4;
-	  bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+	  bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p);
 	  p += 4;
 	}
       if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
@@ -11693,17 +11706,39 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (htab->params->power10_stubs != 0)
 	{
 	  bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc;
-	  p = build_power10_offset (htab->params->stub_bfd, p, off, odd, load);
+	  p = build_power10_offset (obfd, p, off, odd, load);
 	}
       else
 	{
+	  if (htab->glink_eh_frame != NULL
+	      && htab->glink_eh_frame->size != 0)
+	    {
+	      bfd_byte *base, *eh;
+	      unsigned int lr_used, delta;
+
+	      base = (htab->glink_eh_frame->contents
+		      + stub_entry->group->eh_base + 17);
+	      eh = base + stub_entry->group->eh_size;
+	      lr_used = stub_entry->stub_offset + (p - loc) + 8;
+	      delta = lr_used - stub_entry->group->lr_restore;
+	      stub_entry->group->lr_restore = lr_used + 8;
+	      eh = eh_advance (htab->elf.dynobj, eh, delta);
+	      *eh++ = DW_CFA_register;
+	      *eh++ = 65;
+	      *eh++ = 12;
+	      *eh++ = DW_CFA_advance_loc + 2;
+	      *eh++ = DW_CFA_restore_extended;
+	      *eh++ = 65;
+	      stub_entry->group->eh_size = eh - base;
+	    }
+
 	  /* The notoc stubs calculate their target (either a PLT entry or
 	     the global entry point of a function) relative to the PC
 	     returned by the "bcl" two instructions past the start of the
 	     sequence emitted by build_offset.  The offset is therefore 8
 	     less than calculated from the start of the sequence.  */
 	  off -= 8;
-	  p = build_offset (htab->params->stub_bfd, p, off,
+	  p = build_offset (obfd, p, off,
 			    stub_entry->stub_type >= ppc_stub_plt_call_notoc);
 	}
 
@@ -11715,17 +11750,19 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 		  + stub_entry->group->stub_sec->output_offset
 		  + stub_entry->group->stub_sec->output_section->vma
 		  + (p - loc));
-	  bfd_put_32 (htab->params->stub_bfd,
-		      B_DOT | ((targ - from) & 0x3fffffc), p);
+	  bfd_put_32 (obfd, B_DOT | ((targ - from) & 0x3fffffc), p);
 	}
       else
 	{
-	  bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
+	  bfd_put_32 (obfd, MTCTR_R12, p);
 	  p += 4;
-	  bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+	  bfd_put_32 (obfd, BCTR, p);
 	}
       p += 4;
 
+      if (is_tga)
+	p = build_tls_get_addr_tail (htab, stub_entry, p, loc);
+
       if (info->emitrelocations)
 	{
 	  bfd_vma roff = relp - stub_entry->group->stub_sec->contents;
@@ -11756,33 +11793,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 		return FALSE;
 	    }
 	}
-
-      if (htab->params->power10_stubs == 0
-	  && htab->glink_eh_frame != NULL
-	  && htab->glink_eh_frame->size != 0)
-	{
-	  bfd_byte *base, *eh;
-	  unsigned int lr_used, delta;
-
-	  base = (htab->glink_eh_frame->contents
-		  + stub_entry->group->eh_base + 17);
-	  eh = base + stub_entry->group->eh_size;
-	  lr_used = stub_entry->stub_offset + 8;
-	  if (stub_entry->stub_type == ppc_stub_long_branch_both
-	      || stub_entry->stub_type == ppc_stub_plt_branch_both
-	      || stub_entry->stub_type == ppc_stub_plt_call_both)
-	    lr_used += 4;
-	  delta = lr_used - stub_entry->group->lr_restore;
-	  stub_entry->group->lr_restore = lr_used + 8;
-	  eh = eh_advance (htab->elf.dynobj, eh, delta);
-	  *eh++ = DW_CFA_register;
-	  *eh++ = 65;
-	  *eh++ = 12;
-	  *eh++ = DW_CFA_advance_loc + 2;
-	  *eh++ = DW_CFA_restore_extended;
-	  *eh++ = 65;
-	  stub_entry->group->eh_size = eh - base;
-	}
       break;
 
     case ppc_stub_plt_call:
@@ -11851,12 +11861,20 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	    r[0].r_offset += 2;
 	  r[0].r_addend = targ;
 	}
-      if (stub_entry->h != NULL
-	  && is_tls_get_addr (&stub_entry->h->elf, htab)
-	  && htab->params->tls_get_addr_opt)
-	p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
-      else
-	p = build_plt_stub (htab, stub_entry, loc, off, r);
+      p = loc;
+      obfd = htab->params->stub_bfd;
+      is_tga = (stub_entry->h != NULL
+		&& is_tls_get_addr (&stub_entry->h->elf, htab)
+		&& htab->params->tls_get_addr_opt);
+      if (is_tga)
+	{
+	  p = build_tls_get_addr_head (htab, stub_entry, p);
+	  if (r != NULL)
+	    r[0].r_offset += p - loc;
+	}
+      p = build_plt_stub (htab, stub_entry, p, off, r);
+      if (is_tga)
+	p = build_tls_get_addr_tail (htab, stub_entry, p, loc);
       break;
 
     case ppc_stub_save_res:
@@ -12152,11 +12170,18 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
     case ppc_stub_plt_call_notoc:
     case ppc_stub_plt_call_both:
-      off = (stub_entry->stub_offset
-	     + stub_entry->group->stub_sec->output_offset
-	     + stub_entry->group->stub_sec->output_section->vma);
+      lr_used = 0;
+      if (is_tls_get_addr (&stub_entry->h->elf, htab)
+	  && htab->params->tls_get_addr_opt)
+	{
+	  lr_used += 7 * 4;
+	  if (!htab->params->no_tls_get_addr_regsave)
+	    lr_used += 11 * 4;
+	  else if (stub_entry->stub_type == ppc_stub_plt_call_both)
+	    lr_used += 2 * 4;
+	}
       if (stub_entry->stub_type == ppc_stub_plt_call_both)
-	off += 4;
+	lr_used += 4;
       targ = stub_entry->plt_ent->plt.offset & ~1;
       if (targ >= (bfd_vma) -2)
 	abort ();
@@ -12172,16 +12197,21 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	    plt = htab->pltlocal;
 	}
       targ += plt->output_offset + plt->output_section->vma;
+      off = (stub_entry->stub_offset
+	     + stub_entry->group->stub_sec->output_offset
+	     + stub_entry->group->stub_sec->output_section->vma
+	     + lr_used);
       odd = off & 4;
       off = targ - off;
 
       if (htab->params->plt_stub_align != 0)
 	{
-	  unsigned pad = plt_stub_pad (htab, stub_entry, off);
+	  unsigned pad = plt_stub_pad (htab, stub_entry, off, odd);
 
 	  stub_entry->group->stub_sec->size += pad;
 	  stub_entry->stub_offset = stub_entry->group->stub_sec->size;
 	  off -= pad;
+	  odd ^= pad & 4;
 	}
 
       if (info->emitrelocations)
@@ -12195,15 +12225,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  stub_entry->group->stub_sec->flags |= SEC_RELOC;
 	}
 
-      size = plt_stub_size (htab, stub_entry, off);
+      size = plt_stub_size (htab, stub_entry, off, odd);
 
       if (htab->params->power10_stubs == 0)
 	{
 	  /* After the bcl, lr has been modified so we need to emit
 	     .eh_frame info saying the return address is in r12.  */
-	  lr_used = stub_entry->stub_offset + 8;
-	  if (stub_entry->stub_type == ppc_stub_plt_call_both)
-	    lr_used += 4;
+	  lr_used += stub_entry->stub_offset + 8;
 	  /* The eh_frame info will consist of a DW_CFA_advance_loc or
 	     variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
 	     DW_CFA_restore_extended 65.  */
@@ -12211,6 +12239,29 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  stub_entry->group->eh_size += eh_advance_size (delta) + 6;
 	  stub_entry->group->lr_restore = lr_used + 8;
 	}
+      if ((stub_entry->stub_type == ppc_stub_plt_call_notoc
+	   || stub_entry->stub_type == ppc_stub_plt_call_both)
+	  && is_tls_get_addr (&stub_entry->h->elf, htab)
+	  && htab->params->tls_get_addr_opt)
+	{
+	  if (!htab->params->no_tls_get_addr_regsave)
+	    {
+	      unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4;
+	      delta = cfa_updt - stub_entry->group->lr_restore;
+	      stub_entry->group->eh_size += eh_advance_size (delta);
+	      stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
+	      stub_entry->group->lr_restore
+		= stub_entry->stub_offset + size - 4;
+	    }
+	  else if (stub_entry->stub_type == ppc_stub_plt_call_both)
+	    {
+	      lr_used = stub_entry->stub_offset + size - 20;
+	      delta = lr_used - stub_entry->group->lr_restore;
+	      stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+	      stub_entry->group->lr_restore
+		= stub_entry->stub_offset + size - 4;
+	    }
+	}
       break;
 
     case ppc_stub_plt_call:
@@ -12236,7 +12287,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (htab->params->plt_stub_align != 0)
 	{
-	  unsigned pad = plt_stub_pad (htab, stub_entry, off);
+	  unsigned pad = plt_stub_pad (htab, stub_entry, off, 0);
 
 	  stub_entry->group->stub_sec->size += pad;
 	  stub_entry->stub_offset = stub_entry->group->stub_sec->size;
@@ -12253,14 +12304,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	  stub_entry->group->stub_sec->flags |= SEC_RELOC;
 	}
 
-      size = plt_stub_size (htab, stub_entry, off);
+      size = plt_stub_size (htab, stub_entry, off, 0);
 
       if (stub_entry->h != NULL
 	  && is_tls_get_addr (&stub_entry->h->elf, htab)
 	  && htab->params->tls_get_addr_opt
 	  && stub_entry->stub_type == ppc_stub_plt_call_r2save)
 	{
-	  if (htab->params->no_tls_get_addr_regsave)
+	  if (!htab->params->no_tls_get_addr_regsave)
+	    {
+	      /* Adjustments to r1 need to be described.  */
+	      unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4;
+	      delta = cfa_updt - stub_entry->group->lr_restore;
+	      stub_entry->group->eh_size += eh_advance_size (delta);
+	      stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
+	    }
+	  else
 	    {
 	      lr_used = stub_entry->stub_offset + size - 20;
 	      /* The eh_frame info will consist of a DW_CFA_advance_loc
@@ -12269,15 +12328,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      delta = lr_used - stub_entry->group->lr_restore;
 	      stub_entry->group->eh_size += eh_advance_size (delta) + 6;
 	    }
-	  else
-	    {
-	      /* Adjustments to r1 need to be described.  */
-	      unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4;
-	      delta = cfa_updt - stub_entry->group->lr_restore;
-	      stub_entry->group->eh_size += eh_advance_size (delta);
-	      stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
-	    }
-	  stub_entry->group->lr_restore = size - 4;
+	  stub_entry->group->lr_restore = stub_entry->stub_offset + size - 4;
 	}
       break;
 
@@ -15890,22 +15941,25 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	      addend = 0;
 	      reloc_dest = DEST_STUB;
 
-	      if (((stub_entry->stub_type == ppc_stub_plt_call
-		    && ALWAYS_EMIT_R2SAVE)
-		   || stub_entry->stub_type == ppc_stub_plt_call_r2save
-		   || stub_entry->stub_type == ppc_stub_plt_call_both)
-		  && !(h != NULL
-		       && is_tls_get_addr (&h->elf, htab)
-		       && htab->params->tls_get_addr_opt)
-		  && rel + 1 < relend
-		  && rel[1].r_offset == rel->r_offset + 4
-		  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
-		relocation += 4;
-	      else if ((stub_entry->stub_type == ppc_stub_long_branch_both
-			|| stub_entry->stub_type == ppc_stub_plt_branch_both
-			|| stub_entry->stub_type == ppc_stub_plt_call_both)
-		       && r_type == R_PPC64_REL24_NOTOC)
-		relocation += 4;
+	      if ((((stub_entry->stub_type == ppc_stub_plt_call
+		     && ALWAYS_EMIT_R2SAVE)
+		    || stub_entry->stub_type == ppc_stub_plt_call_r2save
+		    || stub_entry->stub_type == ppc_stub_plt_call_both)
+		   && rel + 1 < relend
+		   && rel[1].r_offset == rel->r_offset + 4
+		   && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
+		  || ((stub_entry->stub_type == ppc_stub_long_branch_both
+		       || stub_entry->stub_type == ppc_stub_plt_branch_both
+		       || stub_entry->stub_type == ppc_stub_plt_call_both)
+		      && r_type == R_PPC64_REL24_NOTOC))
+		{
+		  /* Skip over the r2 store at the start of the stub.  */
+		  if (!(stub_entry->stub_type >= ppc_stub_plt_call
+			&& htab->params->tls_get_addr_opt
+			&& h != NULL
+			&& is_tls_get_addr (&h->elf, htab)))
+		    relocation += 4;
+		}
 
 	      if (r_type == R_PPC64_REL24_NOTOC
 		  && (stub_entry->stub_type == ppc_stub_plt_call_notoc

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: PR26656, power10 libstdc++.so segfault in __cxxabiv1::__cxa_throw
  2020-09-23 22:41 PR26656, power10 libstdc++.so segfault in __cxxabiv1::__cxa_throw Alan Modra
@ 2020-09-28  0:15 ` Alan Modra
  0 siblings, 0 replies; 2+ messages in thread
From: Alan Modra @ 2020-09-28  0:15 UTC (permalink / raw)
  To: binutils

Some missing NULL checks meant a stub for a local symbol used a stub
looking like the __tls_get_addr_opt stub.

	PR 26656
	* elf64-ppc.c (ppc_build_one_stub, ppc_size_one_stub): Check for
	NULL stub_entry->h before calling is_tls_get_addr.

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 4194802d48..35f3cbef1e 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -11678,6 +11678,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       obfd = htab->params->stub_bfd;
       is_tga = ((stub_entry->stub_type == ppc_stub_plt_call_notoc
 		 || stub_entry->stub_type == ppc_stub_plt_call_both)
+		&& stub_entry->h != NULL
 		&& is_tls_get_addr (&stub_entry->h->elf, htab)
 		&& htab->params->tls_get_addr_opt);
       if (is_tga)
@@ -12188,7 +12189,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
     case ppc_stub_plt_call_notoc:
     case ppc_stub_plt_call_both:
       lr_used = 0;
-      if (is_tls_get_addr (&stub_entry->h->elf, htab)
+      if (stub_entry->h != NULL
+	  && is_tls_get_addr (&stub_entry->h->elf, htab)
 	  && htab->params->tls_get_addr_opt)
 	{
 	  lr_used += 7 * 4;
@@ -12258,6 +12260,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	}
       if ((stub_entry->stub_type == ppc_stub_plt_call_notoc
 	   || stub_entry->stub_type == ppc_stub_plt_call_both)
+	  && stub_entry->h != NULL
 	  && is_tls_get_addr (&stub_entry->h->elf, htab)
 	  && htab->params->tls_get_addr_opt)
 	{

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2020-09-28  0:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-23 22:41 PR26656, power10 libstdc++.so segfault in __cxxabiv1::__cxa_throw Alan Modra
2020-09-28  0:15 ` 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).