__tls_get_addr_opt stub eh_frame info
authorAlan Modra <amodra@gmail.com>
Tue, 25 Jul 2017 04:22:32 +0000 (13:52 +0930)
committerAlan Modra <amodra@gmail.com>
Tue, 25 Jul 2017 05:44:39 +0000 (15:14 +0930)
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.

bfd/ChangeLog
bfd/elf64-ppc.c
ld/ChangeLog
ld/testsuite/ld-powerpc/powerpc.exp
ld/testsuite/ld-powerpc/tlsopt5.d
ld/testsuite/ld-powerpc/tlsopt5.s
ld/testsuite/ld-powerpc/tlsopt5.wf [new file with mode: 0644]

index 9ae5da99ebe43f545a0ab359d2f0adbfe0144afc..d224022c2efe28744ec03bd2d158651180544eee 100644 (file)
@@ -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-07-24  Nick Clifton  <nickc@redhat.com>
 
        PR 21813
index f399e351e0b954772902e247bd9ebea2670e40bb..cc0e8ee996c26b0692c20ef4d3a8a57007e6e796 100644 (file)
@@ -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 {
@@ -11386,6 +11389,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)
@@ -12252,6 +12264,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
@@ -12302,6 +12315,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
@@ -12404,7 +12438,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;
 
@@ -12722,11 +12755,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.  */
@@ -12761,11 +12794,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)
@@ -12777,24 +12808,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;
@@ -12809,7 +12836,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)
@@ -12824,13 +12851,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;
@@ -12841,12 +12866,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)
        {
@@ -13115,10 +13172,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);
@@ -13300,18 +13355,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
@@ -13323,7 +13374,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))
     {
@@ -15743,55 +15794,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
@@ -15799,15 +15835,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
index 2d3b0ebc33cf11345fc36177203bbf21126d3565..c44bc33d6dd931d36dfc36d7e5484f3c2505a311 100644 (file)
@@ -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-24  Claudiu Zissulescu  <claziss@synopsys.com>
 
        * testsuite/ld-arc/jli-overflow.d: Force testing for little
index 9816eff33c51c11a9f52207298c82e628bd7b0d1..6249ccbdb9f86edf360544ff3073b3c7dc6f0448 100644 (file)
@@ -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"}
index 7a746790c3715df0bb945400cf26208b92d07fe5..3c8518503c468f2ab92216b3b26e7bee05de7bfe 100644 (file)
@@ -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
index 598bbd99b0e719d997b54d1add802e2e3027ea0a..70902ef96a89c0a1b81898b4316402bf7a3976ee 100644 (file)
@@ -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 (file)
index 0000000..05ef7e0
--- /dev/null
@@ -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