This is the mail archive of the binutils-cvs@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb/binutils-2_29-branch] __tls_get_addr_opt stub eh_frame info


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=247a9b458793e449e3a8e26349acba99e8c0453a

commit 247a9b458793e449e3a8e26349acba99e8c0453a
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Jul 25 13:52:32 2017 +0930

    __tls_get_addr_opt stub eh_frame info
    
    Since the __tls_get_addr_opt stub saves LR and makes a call, eh_frame
    info should be generated to describe how to unwind through the stub.
    
    The patch also changes the way the backend iterates over stubs, from
    looking at all sections in stub_bfd to which all dynamic sections are
    attached as well, to iterating over the group list, which gets just
    the stub sections.  Most binaries will have just one or two stub
    groups, so this is a little faster.
    
    bfd/
    	* elf64-ppc.c (struct map_stub): Add tls_get_addr_opt_bctrl.
    	(stub_eh_frame_size): New function.
    	(ppc_size_one_stub): Set group tls_get_addr_opt_bctrl.
    	(group_sections): Init group tls_get_addr_opt_bctrl.
    	(ppc64_elf_size_stubs): Update sizing and initialization of
    	.eh_frame.  Iteration over stubs via group list.
    	(ppc64_elf_build_stubs): Iterate over stubs via group list.
    	(ppc64_elf_finish_dynamic_sections): Update finalization of
    	.eh_frame.
    ld/
    	* testsuite/ld-powerpc/tlsopt5.s: Add cfi.
    	* testsuite/ld-powerpc/tlsopt5.d: Update.
    	* testsuite/ld-powerpc/tlsopt5.wf: New file.
    	* testsuite/ld-powerpc/powerpc.exp: Perform new tlsopt5 test.

Diff:
---
 bfd/ChangeLog                       |  12 +++
 bfd/elf64-ppc.c                     | 191 +++++++++++++++++++++---------------
 ld/ChangeLog                        |   7 ++
 ld/testsuite/ld-powerpc/powerpc.exp |   2 +-
 ld/testsuite/ld-powerpc/tlsopt5.d   |   4 +-
 ld/testsuite/ld-powerpc/tlsopt5.s   |   2 +
 ld/testsuite/ld-powerpc/tlsopt5.wf  |  32 ++++++
 7 files changed, 166 insertions(+), 84 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f9b5515..71e285a 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,15 @@
+2017-07-25  Alan Modra  <amodra@gmail.com>
+
+	* elf64-ppc.c (struct map_stub): Add tls_get_addr_opt_bctrl.
+	(stub_eh_frame_size): New function.
+	(ppc_size_one_stub): Set group tls_get_addr_opt_bctrl.
+	(group_sections): Init group tls_get_addr_opt_bctrl.
+	(ppc64_elf_size_stubs): Update sizing and initialization of
+	.eh_frame.  Iteration over stubs via group list.
+	(ppc64_elf_build_stubs): Iterate over stubs via group list.
+	(ppc64_elf_finish_dynamic_sections): Update finalization of
+	.eh_frame.
+
 2017-08-18  Nick Clifton  <nickc@redhat.com>
 
 	Import from mainline:
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 689eac8..55a6728 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -3919,6 +3919,9 @@ struct map_stub
   /* Whether to emit a copy of register save/restore functions in this
      group.  */
   int needs_save_res;
+  /* The offset of the __tls_get_addr_opt plt stub bctrl in this group,
+     or -1u if no such stub with bctrl exists.  */
+  unsigned int tls_get_addr_opt_bctrl;
 };
 
 struct ppc_stub_hash_entry {
@@ -11411,6 +11414,15 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 	      - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
 
       size = plt_stub_size (htab, stub_entry, off);
+      if (stub_entry->h != NULL
+	  && (stub_entry->h == htab->tls_get_addr_fd
+	      || stub_entry->h == htab->tls_get_addr)
+	  && htab->params->tls_get_addr_opt
+	  && (ALWAYS_EMIT_R2SAVE
+	      || stub_entry->stub_type == ppc_stub_plt_call_r2save))
+	stub_entry->group->tls_get_addr_opt_bctrl
+	  = stub_entry->group->stub_sec->size + size - 5 * 4;
+
       if (htab->params->plt_stub_align)
 	size += plt_stub_pad (htab, stub_entry, off);
       if (info->emitrelocations)
@@ -12277,6 +12289,7 @@ group_sections (struct bfd_link_info *info,
 	  group->link_sec = curr;
 	  group->stub_sec = NULL;
 	  group->needs_save_res = 0;
+	  group->tls_get_addr_opt_bctrl = -1u;
 	  group->next = htab->group;
 	  htab->group = group;
 	  do
@@ -12327,6 +12340,27 @@ static const unsigned char glink_eh_frame_cie[] =
   DW_CFA_def_cfa, 1, 0			/* def_cfa: r1 offset 0.  */
 };
 
+static size_t
+stub_eh_frame_size (struct map_stub *group, size_t align)
+{
+  size_t this_size = 17;
+  if (group->tls_get_addr_opt_bctrl != -1u)
+    {
+      unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4;
+      if (to_bctrl < 64)
+	this_size += 1;
+      else if (to_bctrl < 256)
+	this_size += 2;
+      else if (to_bctrl < 65536)
+	this_size += 3;
+      else
+	this_size += 5;
+      this_size += 6;
+    }
+  this_size = (this_size + align - 1) & -align;
+  return this_size;
+}
+
 /* Stripping output sections is normally done before dynamic section
    symbols have been allocated.  This function is called later, and
    handles cases like htab->brlt which is mapped to its own output
@@ -12429,7 +12463,6 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       bfd *input_bfd;
       unsigned int bfd_indx;
       struct map_stub *group;
-      asection *stub_sec;
 
       htab->stub_iteration += 1;
 
@@ -12747,11 +12780,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 
       /* We may have added some stubs.  Find out the new size of the
 	 stub sections.  */
-      for (stub_sec = htab->params->stub_bfd->sections;
-	   stub_sec != NULL;
-	   stub_sec = stub_sec->next)
-	if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+      for (group = htab->group; group != NULL; group = group->next)
+	if (group->stub_sec != NULL)
 	  {
+	    asection *stub_sec = group->stub_sec;
+
 	    if (htab->stub_iteration <= STUB_SHRINK_ITER
 		|| stub_sec->rawsize < stub_sec->size)
 	      /* Past STUB_SHRINK_ITER, rawsize is the max size seen.  */
@@ -12786,11 +12819,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 	{
 	  size_t size = 0, align = 4;
 
-	  for (stub_sec = htab->params->stub_bfd->sections;
-	       stub_sec != NULL;
-	       stub_sec = stub_sec->next)
-	    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
-	      size += (17 + align - 1) & -align;
+	  for (group = htab->group; group != NULL; group = group->next)
+	    if (group->stub_sec != NULL)
+	      size += stub_eh_frame_size (group, align);
 	  if (htab->glink != NULL && htab->glink->size != 0)
 	    size += (24 + align - 1) & -align;
 	  if (size != 0)
@@ -12802,24 +12833,20 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 	}
 
       if (htab->params->plt_stub_align != 0)
-	for (stub_sec = htab->params->stub_bfd->sections;
-	     stub_sec != NULL;
-	     stub_sec = stub_sec->next)
-	  if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
-	    stub_sec->size = ((stub_sec->size
-			       + (1 << htab->params->plt_stub_align) - 1)
-			      & -(1 << htab->params->plt_stub_align));
-
-      for (stub_sec = htab->params->stub_bfd->sections;
-	   stub_sec != NULL;
-	   stub_sec = stub_sec->next)
-	if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
-	    && stub_sec->rawsize != stub_sec->size
+	for (group = htab->group; group != NULL; group = group->next)
+	  if (group->stub_sec != NULL)
+	    group->stub_sec->size = ((group->stub_sec->size
+				      + (1 << htab->params->plt_stub_align) - 1)
+				     & -(1 << htab->params->plt_stub_align));
+
+      for (group = htab->group; group != NULL; group = group->next)
+	if (group->stub_sec != NULL
+	    && group->stub_sec->rawsize != group->stub_sec->size
 	    && (htab->stub_iteration <= STUB_SHRINK_ITER
-		|| stub_sec->rawsize < stub_sec->size))
+		|| group->stub_sec->rawsize < group->stub_sec->size))
 	  break;
 
-      if (stub_sec == NULL
+      if (group == NULL
 	  && (htab->glink_eh_frame == NULL
 	      || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
 	break;
@@ -12834,7 +12861,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       bfd_vma val;
       bfd_byte *p, *last_fde;
       size_t last_fde_len, size, align, pad;
-      asection *stub_sec;
+      struct map_stub *group;
 
       p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
       if (p == NULL)
@@ -12849,13 +12876,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
       p += last_fde_len + 4;
 
-      for (stub_sec = htab->params->stub_bfd->sections;
-	   stub_sec != NULL;
-	   stub_sec = stub_sec->next)
-	if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+      for (group = htab->group; group != NULL; group = group->next)
+	if (group->stub_sec != NULL)
 	  {
 	    last_fde = p;
-	    last_fde_len = ((17 + align - 1) & -align) - 4;
+	    last_fde_len = stub_eh_frame_size (group, align) - 4;
 	    /* FDE length.  */
 	    bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
 	    p += 4;
@@ -12866,12 +12891,44 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 	    /* Offset to stub section, written later.  */
 	    p += 4;
 	    /* stub section size.  */
-	    bfd_put_32 (htab->elf.dynobj, stub_sec->size, p);
+	    bfd_put_32 (htab->elf.dynobj, group->stub_sec->size, p);
 	    p += 4;
 	    /* Augmentation.  */
 	    p += 1;
+	    if (group->tls_get_addr_opt_bctrl != -1u)
+	      {
+		unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4;
+
+		/* This FDE needs more than just the default.
+		   Describe __tls_get_addr_opt stub LR.  */
+		if (to_bctrl < 64)
+		  *p++ = DW_CFA_advance_loc + to_bctrl;
+		else if (to_bctrl < 256)
+		  {
+		    *p++ = DW_CFA_advance_loc1;
+		    *p++ = to_bctrl;
+		  }
+		else if (to_bctrl < 65536)
+		  {
+		    *p++ = DW_CFA_advance_loc2;
+		    bfd_put_16 (htab->elf.dynobj, to_bctrl, p);
+		    p += 2;
+		  }
+		else
+		  {
+		    *p++ = DW_CFA_advance_loc4;
+		    bfd_put_32 (htab->elf.dynobj, to_bctrl, p);
+		    p += 4;
+		  }
+		*p++ = DW_CFA_offset_extended_sf;
+		*p++ = 65;
+		*p++ = -(STK_LINKER (htab) / 8) & 0x7f;
+		*p++ = DW_CFA_advance_loc + 4;
+		*p++ = DW_CFA_restore_extended;
+		*p++ = 65;
+	      }
 	    /* Pad.  */
-	    p += ((17 + align - 1) & -align) - 17;
+	    p = last_fde + last_fde_len + 4;
 	  }
       if (htab->glink != NULL && htab->glink->size != 0)
 	{
@@ -13140,10 +13197,8 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
     return FALSE;
 
   /* Allocate memory to hold the linker stubs.  */
-  for (stub_sec = htab->params->stub_bfd->sections;
-       stub_sec != NULL;
-       stub_sec = stub_sec->next)
-    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
+  for (group = htab->group; group != NULL; group = group->next)
+    if ((stub_sec = group->stub_sec) != NULL
 	&& stub_sec->size != 0)
       {
 	stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
@@ -13325,18 +13380,14 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
     htab->relbrlt->reloc_count = 0;
 
   if (htab->params->plt_stub_align != 0)
-    for (stub_sec = htab->params->stub_bfd->sections;
-	 stub_sec != NULL;
-	 stub_sec = stub_sec->next)
-      if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+    for (group = htab->group; group != NULL; group = group->next)
+      if ((stub_sec = group->stub_sec) != NULL)
 	stub_sec->size = ((stub_sec->size
 			   + (1 << htab->params->plt_stub_align) - 1)
 			  & -(1 << htab->params->plt_stub_align));
 
-  for (stub_sec = htab->params->stub_bfd->sections;
-       stub_sec != NULL;
-       stub_sec = stub_sec->next)
-    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+  for (group = htab->group; group != NULL; group = group->next)
+    if ((stub_sec = group->stub_sec) != NULL)
       {
 	stub_sec_count += 1;
 	if (stub_sec->rawsize != stub_sec->size
@@ -13348,7 +13399,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   /* Note that the glink_eh_frame check here is not only testing that
      the generated size matched the calculated size but also that
      bfd_elf_discard_info didn't make any changes to the section.  */
-  if (stub_sec != NULL
+  if (group != NULL
       || (htab->glink_eh_frame != NULL
 	  && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
     {
@@ -15768,55 +15819,40 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
     {
       bfd_vma val;
       bfd_byte *p;
-      asection *stub_sec;
+      struct map_stub *group;
       size_t align = 4;
 
       p = htab->glink_eh_frame->contents;
       p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
-      for (stub_sec = htab->params->stub_bfd->sections;
-	   stub_sec != NULL;
-	   stub_sec = stub_sec->next)
-	if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+
+      for (group = htab->group; group != NULL; group = group->next)
+	if (group->stub_sec != NULL)
 	  {
-	    /* FDE length.  */
-	    p += 4;
-	    /* CIE pointer.  */
-	    p += 4;
 	    /* Offset to stub section.  */
-	    val = (stub_sec->output_section->vma
-		   + stub_sec->output_offset);
+	    val = (group->stub_sec->output_section->vma
+		   + group->stub_sec->output_offset);
 	    val -= (htab->glink_eh_frame->output_section->vma
 		    + htab->glink_eh_frame->output_offset
-		    + (p - htab->glink_eh_frame->contents));
+		    + (p + 8 - htab->glink_eh_frame->contents));
 	    if (val + 0x80000000 > 0xffffffff)
 	      {
 		info->callbacks->einfo
 		  (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
-		   stub_sec->name);
+		   group->stub_sec->name);
 		return FALSE;
 	      }
-	    bfd_put_32 (dynobj, val, p);
-	    p += 4;
-	    /* stub section size.  */
-	    p += 4;
-	    /* Augmentation.  */
-	    p += 1;
-	    /* Pad.  */
-	    p += ((17 + align - 1) & -align) - 17;
+	    bfd_put_32 (dynobj, val, p + 8);
+	    p += stub_eh_frame_size (group, align);
 	  }
       if (htab->glink != NULL && htab->glink->size != 0)
 	{
-	  /* FDE length.  */
-	  p += 4;
-	  /* CIE pointer.  */
-	  p += 4;
 	  /* Offset to .glink.  */
 	  val = (htab->glink->output_section->vma
 		 + htab->glink->output_offset
 		 + 8);
 	  val -= (htab->glink_eh_frame->output_section->vma
 		  + htab->glink_eh_frame->output_offset
-		  + (p - htab->glink_eh_frame->contents));
+		  + (p + 8 - htab->glink_eh_frame->contents));
 	  if (val + 0x80000000 > 0xffffffff)
 	    {
 	      info->callbacks->einfo
@@ -15824,15 +15860,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 		 htab->glink->name);
 	      return FALSE;
 	    }
-	  bfd_put_32 (dynobj, val, p);
-	  p += 4;
-	  /* .glink size.  */
-	  p += 4;
-	  /* Augmentation.  */
-	  p += 1;
-	  /* Ops.  */
-	  p += 7;
-	  p += ((24 + align - 1) & -align) - 24;
+	  bfd_put_32 (dynobj, val, p + 8);
+	  p += (24 + align - 1) & -align;
 	}
 
       if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 9820c5a..81b3dc6 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,10 @@
+2017-07-25  Alan Modra  <amodra@gmail.com>
+
+	* testsuite/ld-powerpc/tlsopt5.s: Add cfi.
+	* testsuite/ld-powerpc/tlsopt5.d: Update.
+	* testsuite/ld-powerpc/tlsopt5.wf: New file.
+	* testsuite/ld-powerpc/powerpc.exp: Perform new tlsopt5 test.
+
 2017-07-14  Alan Modra  <amodra@gmail.com>
 
 	* testsuite/ld-powerpc/powerpc.exp: Add -shared to tlsop5 tests.
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 9816eff..6249ccb 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -211,7 +211,7 @@ set ppc64elftests {
     {"TLS DLL" "-shared -melf64ppc --version-script tlsdll.ver" "" "-a64" {tlsdll.s}
      {} "tlsdll.so"}
     {"TLS opt 5" "-melf64ppc -shared --gc-sections --no-plt-localentry tmpdir/tlsdll.so" "" "-a64"  {tlsopt5.s}
-     {{objdump -dr tlsopt5.d}}
+     {{objdump -dr tlsopt5.d} {readelf -wf tlsopt5.wf}}
       "tlsopt5"}
     {"sym@tocbase" "-shared -melf64ppc" "" "-a64" {symtocbase-1.s symtocbase-2.s}
 	{{objdump -dj.data symtocbase.d}} "symtocbase.so"}
diff --git a/ld/testsuite/ld-powerpc/tlsopt5.d b/ld/testsuite/ld-powerpc/tlsopt5.d
index 7a74679..3c85185 100644
--- a/ld/testsuite/ld-powerpc/tlsopt5.d
+++ b/ld/testsuite/ld-powerpc/tlsopt5.d
@@ -31,8 +31,8 @@ Disassembly of section \.text:
 .*:	(08 80 62 38|38 62 80 08) 	addi    r3,r2,-32760
 .*:	(b9 ff ff 4b|4b ff ff b9) 	bl      .*
 .*:	(00 00 00 60|60 00 00 00) 	nop
-.*:	(f8 01 01 00|00 00 00 00) 	.*
-.*:	(00 00 00 00|00 01 01 f8) 	.*
+.*:	(f8 02 01 00|00 00 00 00) 	.*
+.*:	(00 00 00 00|00 01 02 f8) 	.*
 
 0+318 <__glink_PLTresolve>:
 .*:	(a6 02 08 7c|7c 08 02 a6) 	mflr    r0
diff --git a/ld/testsuite/ld-powerpc/tlsopt5.s b/ld/testsuite/ld-powerpc/tlsopt5.s
index 598bbd9..70902ef 100644
--- a/ld/testsuite/ld-powerpc/tlsopt5.s
+++ b/ld/testsuite/ld-powerpc/tlsopt5.s
@@ -1,5 +1,7 @@
  .globl _start
 _start:
+ .cfi_startproc
  addi 3,2,gd@got@tlsgd
  bl __tls_get_addr(gd@tlsgd)
  nop
+ .cfi_endproc
diff --git a/ld/testsuite/ld-powerpc/tlsopt5.wf b/ld/testsuite/ld-powerpc/tlsopt5.wf
new file mode 100644
index 0000000..05ef7e0
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/tlsopt5.wf
@@ -0,0 +1,32 @@
+Contents of the \.eh_frame section:
+
+0+ 0+10 0+ CIE
+  Version:               1
+  Augmentation:          "zR"
+  Code alignment factor: 4
+  Data alignment factor: -8
+  Return address column: 65
+  Augmentation data:     1b
+
+  DW_CFA_def_cfa: r1 ofs 0
+
+0+14 0+14 0+18 FDE cie=0+ pc=0+2c0\.\.0+304
+  DW_CFA_advance_loc: 48 to 0+2f0
+  DW_CFA_offset_extended_sf: r65 at cfa\+8
+  DW_CFA_advance_loc: 16 to 0+300
+  DW_CFA_restore_extended: r65
+
+0+2c 0+18 0+30 FDE cie=0+ pc=0+318\.\.0+354
+  DW_CFA_advance_loc: 4 to 0+31c
+  DW_CFA_register: r65 in r0
+  DW_CFA_advance_loc: 28 to 0+338
+  DW_CFA_restore_extended: r65
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+0+48 0+10 0+4c FDE cie=0+ pc=0+304\.\.0+310
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]