ppc476 plt call stubs
authorAlan Modra <amodra@gmail.com>
Mon, 14 Apr 2014 02:18:06 +0000 (11:48 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 14 Apr 2014 08:47:13 +0000 (18:17 +0930)
Fuss over bctr in call stubs.

* elf32-ppc.c (BA): Define
(ppc_elf_link_hash_table_create): Correct default_params.
(write_glink_stub): Pad small plt call stub with "ba 0" rather
than "nop" for ppc476_workaround.
(ppc_elf_finish_dynamic_sections): Likewise for branch table
and __glink_PLTresolve.  Ensure plt call stub at end of page
doesn't allow fall-thru prefetch.

bfd/ChangeLog
bfd/elf32-ppc.c

index 7621c6f..9331477 100644 (file)
@@ -1,3 +1,13 @@
+2014-04-14  Alan Modra  <amodra@gmail.com>
+
+       * elf32-ppc.c (BA): Define
+       (ppc_elf_link_hash_table_create): Correct default_params.
+       (write_glink_stub): Pad small plt call stub with "ba 0" rather
+       than "nop" for ppc476_workaround.
+       (ppc_elf_finish_dynamic_sections): Likewise for branch table
+       and __glink_PLTresolve.  Ensure plt call stub at end of page
+       doesn't allow fall-thru prefetch.
+
 2014-04-11  Nick Clifton  <nickc@redhat.com>
 
        PR ld/16821
index 61e94a0..8492732 100644 (file)
@@ -147,6 +147,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
 #define ADD_3_12_2     0x7c6c1214
 #define ADD_11_0_11    0x7d605a14
 #define B              0x48000000
+#define BA             0x48000002
 #define BCL_20_31      0x429f0005
 #define BCTR           0x4e800420
 #define BEQLR          0x4d820020
@@ -3249,7 +3250,7 @@ static struct bfd_link_hash_table *
 ppc_elf_link_hash_table_create (bfd *abfd)
 {
   struct ppc_elf_link_hash_table *ret;
-  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 4096 };
+  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12 };
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
@@ -7336,7 +7337,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
          p += 4;
          bfd_put_32 (output_bfd, BCTR, p);
          p += 4;
-         bfd_put_32 (output_bfd, NOP, p);
+         bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
          p += 4;
        }
       else
@@ -10115,7 +10116,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       p += htab->glink_pltresolve;
       endp = htab->glink->contents;
       endp += htab->glink->size - GLINK_PLTRESOLVE;
-      while (p < endp - 8 * 4)
+      while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4))
        {
          bfd_put_32 (output_bfd, B + endp - p, p);
          p += 4;
@@ -10130,6 +10131,39 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
              + htab->glink->output_section->vma
              + htab->glink->output_offset);
 
+      if (htab->params->ppc476_workaround)
+       {
+         /* Ensure that a call stub at the end of a page doesn't
+            result in prefetch over the end of the page into the
+            glink branch table.  */
+         bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+         bfd_vma page_addr;
+         bfd_vma glink_start = (htab->glink->output_section->vma
+                                + htab->glink->output_offset);
+
+         for (page_addr = res0 & -pagesize;
+              page_addr > glink_start;
+              page_addr -= pagesize)
+           {
+             /* We have a plt call stub that may need fixing.  */
+             bfd_byte *loc;
+             unsigned int insn;
+
+             loc = htab->glink->contents + page_addr - 4 - glink_start;
+             insn = bfd_get_32 (output_bfd, loc);
+             if (insn == BCTR)
+               {
+                 /* By alignment, we know that there must be at least
+                    one other call stub before this one.  */
+                 insn = bfd_get_32 (output_bfd, loc - 16);
+                 if (insn == BCTR)
+                   bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc);
+                 else
+                   bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc);
+               }
+           }
+       }
+
       /* Last comes the PLTresolve stub.  */
       if (info->shared)
        {
@@ -10137,7 +10171,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
          for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
            {
-             bfd_put_32 (output_bfd, pic_plt_resolve[i], p);
+             unsigned int insn = pic_plt_resolve[i];
+
+             if (htab->params->ppc476_workaround && insn == NOP)
+               insn = BA + 0;
+             bfd_put_32 (output_bfd, insn, p);
              p += 4;
            }
          p -= 4 * ARRAY_SIZE (pic_plt_resolve);
@@ -10171,7 +10209,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        {
          for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
            {
-             bfd_put_32 (output_bfd, plt_resolve[i], p);
+             unsigned int insn = plt_resolve[i];
+
+             if (htab->params->ppc476_workaround && insn == NOP)
+               insn = BA + 0;
+             bfd_put_32 (output_bfd, insn, p);
              p += 4;
            }
          p -= 4 * ARRAY_SIZE (plt_resolve);