* elf32-ppc.c (LWZU_0_X_11): Delete.
authorAlan Modra <amodra@gmail.com>
Thu, 12 May 2005 15:24:51 +0000 (15:24 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 12 May 2005 15:24:51 +0000 (15:24 +0000)
(B, LWZ_11_X_11, LWZ_11_X_30, MTCTR_11): Define.
(ppc_elf_select_plt_layout): Set .got flags too.  Formatting.
(ppc_elf_size_dynamic_sections): Allocate space for .glink branch
table.
(ppc_elf_finish_dynamic_symbol): Point .plt entries into the branch
table.
(ppc_elf_finish_dynamic_sections): Adjust DT_PPC_GLINK value.
Generate .glink branch table and updated stubs.

bfd/ChangeLog
bfd/elf32-ppc.c

index 07018d2b2e622db65a11cc77354247645f36848b..1bca5b852d5aec42f1a64b492048ab3a1a8a24bc 100644 (file)
@@ -1,3 +1,15 @@
+2005-05-12  Alan Modra  <amodra@bigpond.net.au>
+
+       * elf32-ppc.c (LWZU_0_X_11): Delete.
+       (B, LWZ_11_X_11, LWZ_11_X_30, MTCTR_11): Define.
+       (ppc_elf_select_plt_layout): Set .got flags too.  Formatting.
+       (ppc_elf_size_dynamic_sections): Allocate space for .glink branch
+       table.
+       (ppc_elf_finish_dynamic_symbol): Point .plt entries into the branch
+       table.
+       (ppc_elf_finish_dynamic_sections): Adjust DT_PPC_GLINK value.
+       Generate .glink branch table and updated stubs.
+
 2005-05-11  Alan Modra  <amodra@bigpond.net.au>
 
        * reloc.c (BFD_RELOC_HI16_PCREL): Define.
index dbc745eb62d17258338494b46960ab5891e8446d..bc19406c4467f0a40ac86a4b0435f1b17e9f9dc7 100644 (file)
@@ -67,6 +67,7 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
 
 /* Some instructions.  */
 #define NOP            0x60000000
+#define B              0x48000000
 #define ADDIS_11_11    0x3d6b0000
 #define ADDI_11_11     0x396b0000
 #define SUB_11_11_30   0x7d7e5850
@@ -77,7 +78,9 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
 #define LWZ_12_8_30    0x819e0008
 #define BCTR           0x4e800420
 #define ADDIS_11_30    0x3d7e0000
-#define LWZU_0_X_11    0x840b0000
+#define LWZ_11_X_11    0x816b0000
+#define LWZ_11_X_30    0x817e0000
+#define MTCTR_11       0x7d6903a6
 
 /* Offset of tp and dtp pointers from start of TLS block.  */
 #define TP_OFFSET      0x7000
@@ -3280,24 +3283,25 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   if (!htab->old_plt)
     {
-      /* The new PLT is a loaded section.  Fix its flags.  */
-      if (htab->plt != NULL)
-       {
-         flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                           | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-
-         if (!bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
-           return -1;
-       }
+      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+
+      /* The new PLT is a loaded section.  */
+      if (htab->plt != NULL
+         && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
+       return -1;
+
+      /* The new GOT is not executable.  */
+      if (htab->got != NULL
+         && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags))
+       return -1;
     }
   else
     {
       /* Stop an unused .glink section from affecting .text alignment.  */
-      if (htab->glink != NULL)
-       {
-         if (!bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0))
-           return -1;
-       }
+      if (htab->glink != NULL
+         && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0))
+       return -1;
     }
   return !htab->old_plt;
 }
@@ -4302,6 +4306,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (htab->glink != NULL && htab->glink->size != 0)
     {
       htab->glink_pltresolve = htab->glink->size;
+      /* Space for the branch table.  */
+      htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
+      /* Pad out to align the start of PLTresolve.  */
+      htab->glink->size += -htab->glink->size & 15;
       htab->glink->size += GLINK_PLTRESOLVE;
     }
 
@@ -6197,6 +6205,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
       else
        {
          bfd_vma val = (htab->glink_pltresolve
+                        + h->plt.offset
                         + htab->glink->output_section->vma
                         + htab->glink->output_offset);
          bfd_put_32 (output_bfd, val, htab->plt->contents + h->plt.offset);
@@ -6345,7 +6354,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
            case DT_PPC_GLINK:
              s = htab->glink;
-             dyn.d_un.d_ptr = (htab->glink_pltresolve
+             dyn.d_un.d_ptr = (s->size - GLINK_PLTRESOLVE
                                + s->output_section->vma + s->output_offset);
              break;
 
@@ -6380,7 +6389,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
     {
       unsigned char *p;
       unsigned char *endp;
-      bfd_vma pltgot;
+      bfd_vma got, pltgot;
       unsigned int i;
       static const unsigned int plt_resolve[] =
        {
@@ -6400,17 +6409,67 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define PPC_HI(v) (((v) >> 16) & 0xffff)
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
+      got = (htab->elf.hgot->root.u.def.value
+            + htab->elf.hgot->root.u.def.section->output_section->vma
+            + htab->elf.hgot->root.u.def.section->output_offset);
+
       pltgot = (htab->plt->output_section->vma
                + htab->plt->output_offset
-               - htab->elf.hgot->root.u.def.value
-               - htab->elf.hgot->root.u.def.section->output_section->vma
-               - htab->elf.hgot->root.u.def.section->output_offset);
+               - got);
 
+      /* Write the plt call stubs.  */
       p = htab->glink->contents;
-      p += htab->glink_pltresolve;
-      bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (-pltgot), p);
+      endp = p + htab->glink_pltresolve;
+      while (p < endp)
+       {
+         if (pltgot < 0x8000)
+           {
+             bfd_put_32 (output_bfd, LWZ_11_X_30 + pltgot, p);
+             p += 4;
+             bfd_put_32 (output_bfd, MTCTR_11, p);
+             p += 4;
+             bfd_put_32 (output_bfd, BCTR, p);
+             p += 4;
+             bfd_put_32 (output_bfd, NOP, p);
+             p += 4;
+           }
+         else
+           {
+             bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (pltgot), p);
+             p += 4;
+             bfd_put_32 (output_bfd, LWZ_11_X_11 + PPC_LO (pltgot), p);
+             p += 4;
+             bfd_put_32 (output_bfd, MTCTR_11, p);
+             p += 4;
+             bfd_put_32 (output_bfd, BCTR, p);
+             p += 4;
+           }
+         pltgot += 4;
+       }
+
+      /* Now build the branch table, one for each plt entry (less one),
+        and perhaps some padding.  */
+      endp = htab->glink->contents;
+      endp += htab->glink->size - GLINK_PLTRESOLVE;
+      while (p < endp - 8 * 4)
+       {
+         bfd_put_32 (output_bfd, B + endp - p, p);
+         p += 4;
+       }
+      while (p < endp)
+       {
+         bfd_put_32 (output_bfd, NOP, p);
+         p += 4;
+       }
+
+      got -= (htab->glink_pltresolve
+             + htab->glink->output_section->vma
+             + htab->glink->output_offset);
+
+      /* Last comes the PLTresolve stub.  */
+      bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (got), p);
       p += 4;
-      bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (-pltgot), p);
+      bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (got), p);
       p += 4;
 
       for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
@@ -6420,21 +6479,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
       if (ARRAY_SIZE (plt_resolve) + 2 != GLINK_PLTRESOLVE / 4)
        abort ();
-
-      p = htab->glink->contents;
-      endp = p + htab->glink_pltresolve;
-      while (p < endp)
-       {
-         bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (pltgot), p);
-         p += 4;
-         bfd_put_32 (output_bfd, LWZU_0_X_11 + PPC_LO (pltgot), p);
-         p += 4;
-         bfd_put_32 (output_bfd, MTCTR_0, p);
-         p += 4;
-         bfd_put_32 (output_bfd, BCTR, p);
-         p += 4;
-         pltgot += 4;
-       }
     }
 
   return TRUE;