PowerPC64 EH info for _notoc linkage stubs
authorAlan Modra <amodra@gmail.com>
Mon, 6 Aug 2018 12:13:51 +0000 (21:43 +0930)
committerAlan Modra <amodra@gmail.com>
Tue, 7 Aug 2018 09:13:55 +0000 (18:43 +0930)
This patch generates EH info for the new _notoc linkage stubs, to
support unwinding from asynchronous signal handlers.  Unwinding
through the __tls_get_addr_opt stub was already supported, but that
was just a single stub.  With multiple stubs the EH opcodes need to be
emitted and sized when iterating over stubs, so this is done when
emitting and sizing the stub code.  Emitting the CIEs and FDEs is done
when sizing the stubs, as we did before in order to have the linker
generated FDEs indexed in .eh_frame_hdr.  I moved the final tweaks to
FDEs from ppc64_elf_finish_dynamic_sections to ppc64_elf_build_stubs
simply because it's tidier to be done with them at that point.

bfd/
* elf64-ppc.c (struct map_stub): Delete tls_get_addr_opt_bctrl.
Add lr_restore, eh_size and eh_base.
(eh_advance, eh_advance_size): New functions.
(build_tls_get_addr_stub): Emit EH info for stub.
(ppc_build_one_stub): Likewise for _notoc stubs.
(ppc_size_one_stub): Size EH info for stub.
(group_sections): Init new map_stub fields.
(stub_eh_frame_size): Delete.
(ppc64_elf_size_stubs): Size EH info for stubs.  Set up dummy EH
program for stubs.
(ppc64_elf_build_stubs): Reinit new map_stub fields.  Set FDE
offset to stub section here..
(ppc64_elf_finish_dynamic_sections): ..rather than here.
ld/
* testsuite/ld-powerpc/notoc.s: Generate some cfi.
* testsuite/ld-powerpc/notoc.d: Adjust.
* testsuite/ld-powerpc/notoc.wf: New file.
* testsuite/ld-powerpc/powerpc.exp: Run "ext" and "notoc" tests
as run_ld_link_tests rather than run_dump_test.

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

index b8fd5be12eceff2927a5f55ac3402daee78dddbb..b16353f37325a7337db1da5bd024b3c48ad63761 100644 (file)
@@ -1,3 +1,19 @@
+2018-08-07  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (struct map_stub): Delete tls_get_addr_opt_bctrl.
+       Add lr_restore, eh_size and eh_base.
+       (eh_advance, eh_advance_size): New functions.
+       (build_tls_get_addr_stub): Emit EH info for stub.
+       (ppc_build_one_stub): Likewise for _notoc stubs.
+       (ppc_size_one_stub): Size EH info for stub.
+       (group_sections): Init new map_stub fields.
+       (stub_eh_frame_size): Delete.
+       (ppc64_elf_size_stubs): Size EH info for stubs.  Set up dummy EH
+       program for stubs.
+       (ppc64_elf_build_stubs): Reinit new map_stub fields.  Set FDE
+       offset to stub section here..
+       (ppc64_elf_finish_dynamic_sections): ..rather than here.
+
 2018-08-07  Alan Modra  <amodra@gmail.com>
 
        * elf64-ppc.c (ppc64_elf_relocate_section): Don't skip first
index 5e20bbd971a6551c7ad5f5612a7e18d5fa1b75ab..c9ac8e9aace7db5dfd2a61dc503bf2e97bb66e11 100644 (file)
@@ -4113,9 +4113,15 @@ 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;
+  /* Current offset within stubs after the insn restoring lr in a
+     _notoc or _both stub using bcl for pc-relative addressing, or
+     after the insn restoring lr in a __tls_get_addr_opt plt stub.  */
+  unsigned int lr_restore;
+  /* Accumulated size of EH info emitted to describe return address
+     if stubs modify lr.  Does not include 17 byte FDE header.  */
+  unsigned int eh_size;
+  /* Offset in glink_eh_frame to the start of EH info for this group.  */
+  unsigned int eh_base;
 };
 
 struct ppc_stub_hash_entry {
@@ -10965,6 +10971,52 @@ size_offset (bfd_vma off)
   return size;
 }
 
+/* Emit .eh_frame opcode to advance pc by DELTA.  */
+
+static bfd_byte *
+eh_advance (bfd *abfd, bfd_byte *eh, unsigned int delta)
+{
+  delta /= 4;
+  if (delta < 64)
+    *eh++ = DW_CFA_advance_loc + delta;
+  else if (delta < 256)
+    {
+      *eh++ = DW_CFA_advance_loc1;
+      *eh++ = delta;
+    }
+  else if (delta < 65536)
+    {
+      *eh++ = DW_CFA_advance_loc2;
+      bfd_put_16 (abfd, delta, eh);
+      eh += 2;
+    }
+  else
+    {
+      *eh++ = DW_CFA_advance_loc4;
+      bfd_put_32 (abfd, delta, eh);
+      eh += 4;
+    }
+  return eh;
+}
+
+/* Size of required .eh_frame opcode to advance pc by DELTA.  */
+
+static unsigned int
+eh_advance_size (unsigned int delta)
+{
+  if (delta < 64 * 4)
+    /* DW_CFA_advance_loc+[1..63].  */
+    return 1;
+  if (delta < 256 * 4)
+    /* DW_CFA_advance_loc1, byte.  */
+    return 2;
+  if (delta < 65536 * 4)
+    /* DW_CFA_advance_loc2, 2 bytes.  */
+    return 3;
+  /* DW_CFA_advance_loc4, 4 bytes.  */
+  return 5;
+}
+
 /* With power7 weakly ordered memory model, it is possible for ld.so
    to update a plt entry in one thread and have another thread see a
    stale zero toc entry.  To avoid this we need some sort of acquire
@@ -11262,6 +11314,7 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
                         bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
   bfd *obfd = htab->params->stub_bfd;
+  bfd_byte *loc = p;
 
   bfd_put_32 (obfd, LD_R11_0R3 + 0, p),                p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),                p += 4;
@@ -11288,6 +11341,26 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   bfd_put_32 (obfd, MTLR_R11, p),              p += 4;
   bfd_put_32 (obfd, BLR, p),                   p += 4;
 
+  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 - 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;
+    }
   return p;
 }
 
@@ -11707,6 +11780,32 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          bfd_put_32 (htab->params->stub_bfd, BCTR, p);
        }
       p += 4;
+
+      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 + 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:
@@ -11920,15 +12019,45 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       off = targ - off;
       size = plt_stub_size (htab, stub_entry, off);
 
-      if (stub_entry->stub_type < ppc_stub_plt_call_notoc)
+      if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+       {
+         /* After the bcl, lr has been modified so we need to emit
+            .eh_frame info saying the return address is in r12.  */
+         unsigned int lr_used = stub_entry->stub_offset + 8;
+         unsigned int delta;
+         if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
+           lr_used += 4;
+         /* 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.  */
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+         stub_entry->group->lr_restore = lr_used + 8;
+       }
+      else
        {
          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
              && stub_entry->stub_type == ppc_stub_plt_call_r2save)
-           stub_entry->group->tls_get_addr_opt_bctrl
-             = stub_entry->stub_offset + size - 5 * 4;
+           {
+             /* 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 put the EH info specifying
+                that the return address is on the stack *at* the
+                call rather than after it, because the EH info for a
+                call needs to be specified by that point.
+                See libgcc/unwind-dw2.c execute_cfa_program.  */
+             unsigned int lr_used = stub_entry->stub_offset + size - 20;
+             unsigned int delta;
+             /* The eh_frame info will consist of a DW_CFA_advance_loc
+                or variant, DW_CFA_offset_externed_sf, 65, -stackoff,
+                DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65.  */
+             delta = lr_used - stub_entry->group->lr_restore;
+             stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+             stub_entry->group->lr_restore = size - 4;
+           }
 
          if (info->emitrelocations)
            {
@@ -11988,6 +12117,19 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (stub_entry->stub_type >= ppc_stub_long_branch_notoc)
        {
+         /* After the bcl, lr has been modified so we need to emit
+            .eh_frame info saying the return address is in r12.  */
+         unsigned int lr_used = stub_entry->stub_offset + 8;
+         unsigned int delta;
+         if (stub_entry->stub_type > ppc_stub_long_branch_notoc)
+           lr_used += 4;
+         /* 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.  */
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+         stub_entry->group->lr_restore = lr_used + 8;
+
          if (off + (1 << 25) >= (bfd_vma) (1 << 26))
            {
              stub_entry->stub_type += (ppc_stub_plt_branch_notoc
@@ -12821,7 +12963,9 @@ 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->lr_restore = 0;
+         group->eh_size = 0;
+         group->eh_base = 0;
          group->next = htab->group;
          htab->group = group;
          do
@@ -12872,27 +13016,6 @@ 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
@@ -13394,18 +13517,22 @@ 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 (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.  */
-             stub_sec->rawsize = stub_sec->size;
-           stub_sec->size = 0;
-           stub_sec->reloc_count = 0;
-           stub_sec->flags &= ~SEC_RELOC;
-         }
+       {
+         group->lr_restore = 0;
+         group->eh_size = 0;
+         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.  */
+               stub_sec->rawsize = stub_sec->size;
+             stub_sec->size = 0;
+             stub_sec->reloc_count = 0;
+             stub_sec->flags &= ~SEC_RELOC;
+           }
+       }
 
       if (htab->stub_iteration <= STUB_SHRINK_ITER
          || htab->brlt->rawsize < htab->brlt->size)
@@ -13436,8 +13563,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          size_t size = 0, align = 4;
 
          for (group = htab->group; group != NULL; group = group->next)
-           if (group->stub_sec != NULL)
-             size += stub_eh_frame_size (group, align);
+           if (group->eh_size != 0)
+             size += (group->eh_size + 17 + align - 1) & -align;
          if (htab->glink != NULL && htab->glink->size != 0)
            size += (24 + align - 1) & -align;
          if (size != 0)
@@ -13484,6 +13611,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       size_t last_fde_len, size, align, pad;
       struct map_stub *group;
 
+      /* It is necessary to at least have a rough outline of the
+        linker generated CIEs and FDEs written before
+        bfd_elf_discard_info is run, in order for these FDEs to be
+        indexed in .eh_frame_hdr.  */
       p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
       if (p == NULL)
        return FALSE;
@@ -13498,10 +13629,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       p += last_fde_len + 4;
 
       for (group = htab->group; group != NULL; group = group->next)
-       if (group->stub_sec != NULL)
+       if (group->eh_size != 0)
          {
+           group->eh_base = p - htab->glink_eh_frame->contents;
            last_fde = p;
-           last_fde_len = stub_eh_frame_size (group, align) - 4;
+           last_fde_len = ((group->eh_size + 17 + align - 1) & -align) - 4;
            /* FDE length.  */
            bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
            p += 4;
@@ -13516,39 +13648,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
            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.  */
+           /* Make sure we don't have all nops.  This is enough for
+              elf-eh-frame.c to detect the last non-nop opcode.  */
+           p[group->eh_size - 1] = DW_CFA_advance_loc + 1;
            p = last_fde + last_fde_len + 4;
          }
       if (htab->glink != NULL && htab->glink->size != 0)
@@ -14023,14 +14125,19 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
 
   /* Allocate memory to hold the linker stubs.  */
   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);
-       if (stub_sec->contents == NULL)
-         return FALSE;
-       stub_sec->size = 0;
-      }
+    {
+      group->eh_size = 0;
+      group->lr_restore = 0;
+      if ((stub_sec = group->stub_sec) != NULL
+         && stub_sec->size != 0)
+       {
+         stub_sec->contents = bfd_zalloc (htab->params->stub_bfd,
+                                          stub_sec->size);
+         if (stub_sec->contents == NULL)
+           return FALSE;
+         stub_sec->size = 0;
+       }
+    }
 
   if (htab->glink != NULL && htab->glink->size != 0)
     {
@@ -14213,6 +14320,55 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
          }
       }
 
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0)
+    {
+      bfd_vma val;
+      size_t align = 4;
+
+      p = htab->glink_eh_frame->contents;
+      p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
+
+      for (group = htab->group; group != NULL; group = group->next)
+       if (group->eh_size != 0)
+         {
+           /* Offset to stub section.  */
+           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 + 8 - htab->glink_eh_frame->contents));
+           if (val + 0x80000000 > 0xffffffff)
+             {
+               _bfd_error_handler
+                 (_("%s offset too large for .eh_frame sdata4 encoding"),
+                  group->stub_sec->name);
+               return FALSE;
+             }
+           bfd_put_32 (htab->elf.dynobj, val, p + 8);
+           p += (group->eh_size + 17 + 3) & -4;
+         }
+      if (htab->glink != NULL && htab->glink->size != 0)
+       {
+         /* 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 + 8 - htab->glink_eh_frame->contents));
+         if (val + 0x80000000 > 0xffffffff)
+           {
+             _bfd_error_handler
+               (_("%s offset too large for .eh_frame sdata4 encoding"),
+                htab->glink->name);
+             return FALSE;
+           }
+         bfd_put_32 (htab->elf.dynobj, val, p + 8);
+         p += (24 + align - 1) & -align;
+       }
+    }
+
   for (group = htab->group; group != NULL; group = group->next)
     if ((stub_sec = group->stub_sec) != NULL)
       {
@@ -16745,62 +16901,14 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
                                       NULL))
     return FALSE;
 
-  if (htab->glink_eh_frame != NULL
-      && htab->glink_eh_frame->size != 0)
-    {
-      bfd_vma val;
-      bfd_byte *p;
-      struct map_stub *group;
-      size_t align = 4;
-
-      p = htab->glink_eh_frame->contents;
-      p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
-
-      for (group = htab->group; group != NULL; group = group->next)
-       if (group->stub_sec != NULL)
-         {
-           /* Offset to stub section.  */
-           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 + 8 - htab->glink_eh_frame->contents));
-           if (val + 0x80000000 > 0xffffffff)
-             {
-               _bfd_error_handler
-                 (_("%s offset too large for .eh_frame sdata4 encoding"),
-                  group->stub_sec->name);
-               return FALSE;
-             }
-           bfd_put_32 (dynobj, val, p + 8);
-           p += stub_eh_frame_size (group, align);
-         }
-      if (htab->glink != NULL && htab->glink->size != 0)
-       {
-         /* 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 + 8 - htab->glink_eh_frame->contents));
-         if (val + 0x80000000 > 0xffffffff)
-           {
-             _bfd_error_handler
-               (_("%s offset too large for .eh_frame sdata4 encoding"),
-                htab->glink->name);
-             return FALSE;
-           }
-         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
-         && !_bfd_elf_write_section_eh_frame (output_bfd, info,
-                                              htab->glink_eh_frame,
-                                              htab->glink_eh_frame->contents))
-       return FALSE;
-    }
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0
+      && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
+      && !_bfd_elf_write_section_eh_frame (output_bfd, info,
+                                          htab->glink_eh_frame,
+                                          htab->glink_eh_frame->contents))
+    return FALSE;
 
   /* We need to handle writing out multiple GOT sections ourselves,
      since we didn't add them to DYNOBJ.  We know dynobj is the first
index 98af46881209d257b05cdc204ca409387734f547..6171d466b11ba7dc139611dfd4baea5b85a9c8e0 100644 (file)
@@ -1,3 +1,11 @@
+2018-08-07  Alan Modra  <amodra@gmail.com>
+
+       * testsuite/ld-powerpc/notoc.s: Generate some cfi.
+       * testsuite/ld-powerpc/notoc.d: Adjust.
+       * testsuite/ld-powerpc/notoc.wf: New file.
+       * testsuite/ld-powerpc/powerpc.exp: Run "ext" and "notoc" tests
+       as run_ld_link_tests rather than run_dump_test.
+
 2018-08-07  Martin Storsjo  <martin@martin.st>
 
        * scripttempl/pe.sc: Improve the comment about overriding
index 97e7274beef55e965a874c5ef416f0165b7452d8..eaafd01390526a5d722f45dfcd1c1fb4cf24e7fb 100644 (file)
@@ -1,7 +1,7 @@
 #source: notoc.s
 #as: -a64
 #ld: --no-plt-localentry -T ext.lnk
-#objdump: -dr
+#objdump: -d
 #target: powerpc64*-*-*
 
 .*
@@ -63,8 +63,8 @@ Disassembly of section \.text:
 .*:    (20 00 80 4e|4e 80 00 20)       blr
 
 .* <f2>:
-.*:    (02 10 40 3c|3c 40 10 02)       lis     r2,4098
-.*:    (00 90 42 38|38 42 90 00)       addi    r2,r2,-28672
+.*:    (01 10 40 3c|3c 40 10 01)       lis     r2,4097
+.*:    (00 80 42 38|38 42 80 00)       addi    r2,r2,-32768
 .*:    (4d ff ff 4b|4b ff ff 4d)       bl      .* <.*\.long_branch\.f1>
 .*:    (18 00 41 e8|e8 41 00 18)       ld      r2,24\(r1\)
 .*:    (f9 ff ff 4b|4b ff ff f9)       bl      .* <f2\+0x8>
@@ -78,8 +78,8 @@ Disassembly of section \.text:
 .*:    (20 00 80 4e|4e 80 00 20)       blr
 
 .* <g2>:
-.*:    (02 10 40 3c|3c 40 10 02)       lis     r2,4098
-.*:    (00 90 42 38|38 42 90 00)       addi    r2,r2,-28672
+.*:    (01 10 40 3c|3c 40 10 01)       lis     r2,4097
+.*:    (00 80 42 38|38 42 80 00)       addi    r2,r2,-32768
 .*:    (cd ff ff 4b|4b ff ff cd)       bl      .* <f2\+0x8>
 .*:    (00 00 00 60|60 00 00 00)       nop
 .*:    (11 ff ff 4b|4b ff ff 11)       bl      .* <.*\.long_branch\.f1>
@@ -96,7 +96,7 @@ Disassembly of section \.text:
 Disassembly of section \.text\.ext:
 
 8000000000000000 <ext>:
-8000000000000000:      (02 10 40 3c|3c 40 10 02)       lis     r2,4098
-8000000000000004:      (00 90 42 38|38 42 90 00)       addi    r2,r2,-28672
+8000000000000000:      (01 10 40 3c|3c 40 10 01)       lis     r2,4097
+8000000000000004:      (00 80 42 38|38 42 80 00)       addi    r2,r2,-32768
 8000000000000008:      (00 00 00 60|60 00 00 00)       nop
 800000000000000c:      (20 00 80 4e|4e 80 00 20)       blr
index 8c620df3b411bb2a0d1509a4f992fb6e8bfc7cc2..eb881c865e2bf068e4e6163c673335dccd0b782f 100644 (file)
@@ -53,4 +53,6 @@ g2:
  blr
 
 _start:
+ .cfi_startproc
  b _start
+ .cfi_endproc
diff --git a/ld/testsuite/ld-powerpc/notoc.wf b/ld/testsuite/ld-powerpc/notoc.wf
new file mode 100644 (file)
index 0000000..208d676
--- /dev/null
@@ -0,0 +1,33 @@
+Contents of the \.eh_frame section:
+
+
+00000000 0000000000000010 00000000 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
+
+00000014 0000000000000024 00000018 FDE cie=00000000 pc=00000000100000c0\.\.0000000010000140
+  DW_CFA_advance_loc: 24 to 00000000100000d8
+  DW_CFA_register: r65 in r12
+  DW_CFA_advance_loc: 8 to 00000000100000e0
+  DW_CFA_restore_extended: r65
+  DW_CFA_advance_loc: 40 to 0000000010000108
+  DW_CFA_register: r65 in r12
+  DW_CFA_advance_loc: 8 to 0000000010000110
+  DW_CFA_restore_extended: r65
+  DW_CFA_advance_loc: 16 to 0000000010000120
+  DW_CFA_register: r65 in r12
+  DW_CFA_advance_loc: 8 to 0000000010000128
+  DW_CFA_restore_extended: r65
+  DW_CFA_nop
+  DW_CFA_nop
+
+0000003c 0000000000000010 00000040 FDE cie=00000000 pc=00000000100001cc\.\.00000000100001d0
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
index c4ab3decb87c13165274ff1b16d31fc14d52259c..12590f18177aed71d90e2d932fbac910093683a9 100644 (file)
@@ -257,6 +257,9 @@ set ppc64elftests {
        {{objdump -dr tocsave2a.d}} "tocsave2a"}
     {"ambig shared v1" "-shared -melf64ppc" "" "-a64" {funv1.s} {} "funv1.so"}
     {"ambig shared v2" "-shared -melf64ppc" "" "-a64" {funv2.s} {} "funv2.so"}
+    {"notoc ext" "" "" "-a64" {ext.s} {} ""}
+    {"notoc" "-melf64ppc --no-plt-localentry -T ext.lnk" "" "-a64" {notoc.s}
+       {{objdump -d notoc.d} {readelf {-wf -W} notoc.wf}} "notoc"}
 }
 
 set ppceabitests {
@@ -331,8 +334,6 @@ if [ supports_ppc64 ] then {
     run_dump_test "dotsym2"
     run_dump_test "dotsym3"
     run_dump_test "dotsym4"
-    run_dump_test "ext"
-    run_dump_test "notoc"
 }
 
 run_dump_test "tlsld32"