* merge.c (_bfd_merged_section_offset): Remove "addend" param.
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 90f9b221b903bff03ce9187fb2ea114864ef539d..980dcb9996b43abe637771299ea2c403ff51c884 100644 (file)
@@ -1,6 +1,6 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+   2004 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -70,6 +70,72 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
 #define DTP_OFFSET     0x8000
 
 \f
+/* Enumeration to specify the special section.  */
+enum elf_linker_section_enum
+{
+  LINKER_SECTION_SDATA,
+  LINKER_SECTION_SDATA2
+};
+
+/* Sections created by the linker.  */
+
+typedef struct elf_linker_section
+{
+  /* pointer to the section */
+  asection *section;
+  /* pointer to the relocations needed for this section */
+  asection *rel_section;
+  /* pointer to the created symbol hash value */
+  struct elf_link_hash_entry *sym_hash;
+  /* offset of symbol from beginning of section */
+  bfd_vma sym_offset;
+} elf_linker_section_t;
+
+/* Linked list of allocated pointer entries.  This hangs off of the
+   symbol lists, and provides allows us to return different pointers,
+   based on different addend's.  */
+
+typedef struct elf_linker_section_pointers
+{
+  /* next allocated pointer for this symbol */
+  struct elf_linker_section_pointers *next;
+  /* offset of pointer from beginning of section */
+  bfd_vma offset;
+  /* addend used */
+  bfd_vma addend;
+  /* which linker section this is */
+  elf_linker_section_t *lsect;
+  /* whether address was written yet */
+  bfd_boolean written_address_p;
+} elf_linker_section_pointers_t;
+
+struct ppc_elf_obj_tdata
+{
+  struct elf_obj_tdata elf;
+
+  /* A mapping from local symbols to offsets into the various linker
+     sections added.  This is index by the symbol index.  */
+  elf_linker_section_pointers_t **linker_section_pointers;
+};
+
+#define ppc_elf_tdata(bfd) \
+  ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any)
+
+#define elf_local_ptr_offsets(bfd) \
+  (ppc_elf_tdata (bfd)->linker_section_pointers)
+
+/* Override the generic function because we store some extras.  */
+
+static bfd_boolean
+ppc_elf_mkobject (bfd *abfd)
+{
+  bfd_size_type amt = sizeof (struct ppc_elf_obj_tdata);
+  abfd->tdata.any = bfd_zalloc (abfd, amt);
+  if (abfd->tdata.any == NULL)
+    return FALSE;
+  return TRUE;
+}
+
 /* The PPC linker needs to keep track of the number of relocs that it
    decides to copy as dynamic relocs in check_relocs for each symbol.
    This is so that it can later discard them if they are found to be
@@ -96,6 +162,11 @@ struct ppc_elf_link_hash_entry
 {
   struct elf_link_hash_entry elf;
 
+  /* If this symbol is used in the linker created sections, the processor
+     specific backend uses this field to map the field into the offset
+     from the beginning of the section.  */
+  elf_linker_section_pointers_t *linker_section_pointer;
+
   /* Track dynamic relocs copied for this symbol.  */
   struct ppc_elf_dyn_relocs *dyn_relocs;
 
@@ -132,9 +203,7 @@ struct ppc_elf_link_hash_table
   asection *relsbss;
   elf_linker_section_t *sdata;
   elf_linker_section_t *sdata2;
-
-  /* Short-cut to first output tls section.  */
-  asection *tls_sec;
+  asection *sbss;
 
   /* Shortcut to .__tls_get_addr.  */
   struct elf_link_hash_entry *tls_get_addr;
@@ -175,6 +244,7 @@ ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
   entry = _bfd_elf_link_hash_newfunc (entry, table, string);
   if (entry != NULL)
     {
+      ppc_elf_hash_entry (entry)->linker_section_pointer = NULL;
       ppc_elf_hash_entry (entry)->dyn_relocs = NULL;
       ppc_elf_hash_entry (entry)->tls_mask = 0;
     }
@@ -189,7 +259,7 @@ ppc_elf_link_hash_table_create (bfd *abfd)
 {
   struct ppc_elf_link_hash_table *ret;
 
-  ret = bfd_malloc (sizeof (struct ppc_elf_link_hash_table));
+  ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
     return NULL;
 
@@ -200,21 +270,6 @@ ppc_elf_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
-  ret->got = NULL;
-  ret->relgot = NULL;
-  ret->plt = NULL;
-  ret->relplt = NULL;
-  ret->dynbss = NULL;
-  ret->relbss = NULL;
-  ret->dynsbss = NULL;
-  ret->relsbss = NULL;
-  ret->sdata = NULL;
-  ret->sdata2 = NULL;
-  ret->tls_sec = NULL;
-  ret->tls_get_addr = NULL;
-  ret->tlsld_got.refcount = 0;
-  ret->sym_sec.abfd = NULL;
-
   return &ret->elf.root;
 }
 
@@ -227,7 +282,7 @@ ppc_elf_link_hash_table_create (bfd *abfd)
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
 
 static void
-ppc_elf_copy_indirect_symbol (struct elf_backend_data *bed,
+ppc_elf_copy_indirect_symbol (const struct elf_backend_data *bed,
                              struct elf_link_hash_entry *dir,
                              struct elf_link_hash_entry *ind)
 {
@@ -281,12 +336,13 @@ ppc_elf_copy_indirect_symbol (struct elf_backend_data *bed,
     dir->elf_link_hash_flags |=
       (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC
                                   | ELF_LINK_HASH_REF_REGULAR
-                                  | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+                                  | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                                  | ELF_LINK_HASH_NEEDS_PLT));
   else
     _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
 }
 \f
-static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max];
+static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
 
 static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
@@ -1476,6 +1532,35 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* Phony relocs to handle branch stubs.  */
+  HOWTO (R_PPC_RELAX32,                /* type */
+        0,                     /* rightshift */
+        0,                     /* size */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_RELAX32",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC_RELAX32PC,      /* type */
+        0,                     /* rightshift */
+        0,                     /* size */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_RELAX32PC",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
         0,                     /* rightshift */
@@ -1541,39 +1626,28 @@ ppc_elf_howto_init (void)
     }
 }
 \f
-/* This function handles relaxing for the PPC with option --mpc860c0[=<n>].
-
-   The MPC860, revision C0 or earlier contains a bug in the die.
-   If all of the following conditions are true, the next instruction
-   to be executed *may* be treated as a no-op.
-   1/ A forward branch is executed.
-   2/ The branch is predicted as not taken.
-   3/ The branch is taken.
-   4/ The branch is located in the last 5 words of a page.
-      (The EOP limit is 5 by default but may be specified as any value
-      from 1-10.)
-
-   Our software solution is to detect these problematic branches in a
-   linker pass and modify them as follows:
-   1/ Unconditional branches - Since these are always predicted taken,
-      there is no problem and no action is required.
-   2/ Conditional backward branches - No problem, no action required.
-   3/ Conditional forward branches - Ensure that the "inverse prediction
-      bit" is set (ensure it is predicted taken).
-   4/ Conditional register branches - Ensure that the "y bit" is set
-      (ensure it is predicted taken).  */
-
-/* Sort sections by address.  */
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
 
-static int
-ppc_elf_sort_rela (const void *arg1, const void *arg2)
-{
-  const Elf_Internal_Rela * const *rela1 = arg1;
-  const Elf_Internal_Rela * const *rela2 = arg2;
+static const int shared_stub_entry[] =
+  {
+    0x7c0802a6, /* mflr 0 */
+    0x429f0005, /* bcl 20, 31, .Lxxx */
+    0x7d6802a6, /* mflr 11 */
+    0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */
+    0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */
+    0x7c0803a6, /* mtlr 0 */
+    0x7d6903a6, /* mtctr 11 */
+    0x4e800420, /* bctr */
+  };
+
+static const int stub_entry[] =
+  {
+    0x3d600000, /* lis 11,xxx@ha */
+    0x396b0000, /* addi 11,11,xxx@l */
+    0x7d6903a6, /* mtctr 11 */
+    0x4e800420, /* bctr */
+  };
 
-  /* Sort by offset.  */
-  return ((*rela1)->r_offset - (*rela2)->r_offset);
-}
 
 static bfd_boolean
 ppc_elf_relax_section (bfd *abfd,
@@ -1581,246 +1655,348 @@ ppc_elf_relax_section (bfd *abfd,
                       struct bfd_link_info *link_info,
                       bfd_boolean *again)
 {
-#define PAGESIZE 0x1000
+  struct one_fixup
+  {
+    struct one_fixup *next;
+    asection *tsec;
+    bfd_vma toff;
+    bfd_vma trampoff;
+  };
 
+  Elf_Internal_Shdr *symtab_hdr;
   bfd_byte *contents = NULL;
-  bfd_byte *free_contents = NULL;
+  Elf_Internal_Sym *isymbuf = NULL;
   Elf_Internal_Rela *internal_relocs = NULL;
-  Elf_Internal_Rela *free_relocs = NULL;
-  Elf_Internal_Rela **rela_comb = NULL;
-  int comb_curr, comb_count;
+  Elf_Internal_Rela *irel, *irelend;
+  struct one_fixup *fixups = NULL;
+  bfd_boolean changed;
+  struct ppc_elf_link_hash_table *ppc_info;
+  bfd_size_type trampoff;
 
-  /* We never have to do this more than once per input section.  */
   *again = FALSE;
 
+  /* Nothing to do if there are no relocations.  */
+  if ((isec->flags & SEC_RELOC) == 0 || isec->reloc_count == 0)
+    return TRUE;
+
   /* If needed, initialize this section's cooked size.  */
   if (isec->_cooked_size == 0)
     isec->_cooked_size = isec->_raw_size;
 
-  /* We're only interested in text sections which overlap the
-     troublesome area at the end of a page.  */
-  if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size)
+  trampoff = (isec->_cooked_size + 3) & (bfd_vma) -4;
+  /* Space for a branch around any trampolines.  */
+  trampoff += 4;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+  /* Get a copy of the native relocations.  */
+  internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
+                                              link_info->keep_memory);
+  if (internal_relocs == NULL)
+    goto error_return;
+
+  ppc_info = ppc_elf_hash_table (link_info);
+  irelend = internal_relocs + isec->reloc_count;
+
+  /* Get the section contents.  */
+  /* Get cached copy if it exists.  */
+  if (elf_section_data (isec)->this_hdr.contents != NULL)
+    contents = elf_section_data (isec)->this_hdr.contents;
+  else
     {
-      bfd_vma dot, end_page, end_section;
-      bfd_boolean section_modified;
+      /* Go get them off disk.  */
+      contents = bfd_malloc (isec->_raw_size);
+      if (contents == NULL)
+       goto error_return;
 
-      /* Get the section contents.  */
-      /* Get cached copy if it exists.  */
-      if (elf_section_data (isec)->this_hdr.contents != NULL)
-       contents = elf_section_data (isec)->this_hdr.contents;
-      else
+      if (!bfd_get_section_contents (abfd, isec, contents, 0, isec->_raw_size))
+       goto error_return;
+    }
+
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      unsigned long r_type = ELF32_R_TYPE (irel->r_info);
+      bfd_vma symaddr, reladdr, toff, roff;
+      asection *tsec;
+      struct one_fixup *f;
+      size_t insn_offset = 0;
+      bfd_vma max_branch_offset, val;
+      bfd_byte *hit_addr;
+      unsigned long t0;
+
+      switch (r_type)
        {
-         /* Go get them off disk.  */
-         contents = bfd_malloc (isec->_raw_size);
-         if (contents == NULL)
-           goto error_return;
-         free_contents = contents;
-
-         if (! bfd_get_section_contents (abfd, isec, contents,
-                                         (file_ptr) 0, isec->_raw_size))
-           goto error_return;
+       case R_PPC_REL24:
+       case R_PPC_LOCAL24PC:
+       case R_PPC_PLTREL24:
+         max_branch_offset = 1 << 25;
+         break;
+
+       case R_PPC_REL14:
+       case R_PPC_REL14_BRTAKEN:
+       case R_PPC_REL14_BRNTAKEN:
+         max_branch_offset = 1 << 15;
+         break;
+
+       default:
+         continue;
        }
 
-      comb_curr = 0;
-      comb_count = 0;
-      if (isec->reloc_count)
+      /* Get the value of the symbol referred to by the reloc.  */
+      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
-         unsigned n;
-         bfd_size_type amt;
-
-         /* Get a copy of the native relocations.  */
-         internal_relocs
-           = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
-                                        link_info->keep_memory);
-         if (internal_relocs == NULL)
-           goto error_return;
-         if (! link_info->keep_memory)
-           free_relocs = internal_relocs;
-
-         /* Setup a faster access method for the reloc info we need.  */
-         amt = isec->reloc_count;
-         amt *= sizeof (Elf_Internal_Rela*);
-         rela_comb = bfd_malloc (amt);
-         if (rela_comb == NULL)
-           goto error_return;
-         for (n = 0; n < isec->reloc_count; ++n)
-           {
-             enum elf_ppc_reloc_type r_type;
+         /* A local symbol.  */
+         Elf_Internal_Sym *isym;
 
-             r_type = ELF32_R_TYPE (internal_relocs[n].r_info);
-             if (r_type >= R_PPC_max)
+         /* Read this BFD's local symbols.  */
+         if (isymbuf == NULL)
+           {
+             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+             if (isymbuf == NULL)
+               isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                               symtab_hdr->sh_info, 0,
+                                               NULL, NULL, NULL);
+             if (isymbuf == 0)
                goto error_return;
+           }
+         isym = isymbuf + ELF32_R_SYM (irel->r_info);
+         if (isym->st_shndx == SHN_UNDEF)
+           continue;   /* We can't do anything with undefined symbols.  */
+         else if (isym->st_shndx == SHN_ABS)
+           tsec = bfd_abs_section_ptr;
+         else if (isym->st_shndx == SHN_COMMON)
+           tsec = bfd_com_section_ptr;
+         else
+           tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
-             /* Prologue constants are sometimes present in the ".text"
-                sections and they can be identified by their associated
-                relocation.  We don't want to process those words and
-                some others which can also be identified by their
-                relocations.  However, not all conditional branches will
-                have a relocation so we will only ignore words that
-                1) have a reloc, and 2) the reloc is not applicable to a
-                conditional branch.  The array rela_comb is built here
-                for use in the EOP scan loop.  */
-             switch (r_type)
-               {
-               case R_PPC_ADDR14_BRNTAKEN:
-               case R_PPC_REL14:
-               case R_PPC_REL14_BRNTAKEN:
-                 /* We should check the instruction.  */
-                 break;
-               default:
-                 /* The word is not a conditional branch - ignore it.  */
-                 rela_comb[comb_count++] = &internal_relocs[n];
-                 break;
-               }
+         toff = isym->st_value;
+       }
+      else
+       {
+         /* Global symbol handling.  */
+         unsigned long indx;
+         struct elf_link_hash_entry *h;
+
+         indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+         h = elf_sym_hashes (abfd)[indx];
+
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         if (r_type == R_PPC_PLTREL24
+             && ppc_info->plt != NULL
+             && h->plt.offset != (bfd_vma) -1)
+           {
+             tsec = ppc_info->plt;
+             toff = h->plt.offset;
+           }
+         else if (h->root.type == bfd_link_hash_defined
+                  || h->root.type == bfd_link_hash_defweak)
+           {
+             tsec = h->root.u.def.section;
+             toff = h->root.u.def.value;
            }
-         if (comb_count > 1)
-           qsort (rela_comb, (size_t) comb_count, sizeof (int),
-                  ppc_elf_sort_rela);
+         else
+           continue;
        }
 
-      /* Enumerate each EOP region that overlaps this section.  */
-      end_section = isec->vma + isec->_cooked_size;
-      dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1;
-      dot -= link_info->mpc860c0;
-      section_modified = FALSE;
-      /* Increment the start position if this section begins in the
-        middle of its first EOP region.  */
-      if (dot < isec->vma)
-       dot = isec->vma;
-      for (;
-          dot < end_section;
-          dot += PAGESIZE, end_page += PAGESIZE)
+      /* If the branch and target are in the same section, you have
+        no hope of adding stubs.  We'll error out later should the
+        branch overflow.  */
+      if (tsec == isec)
+       continue;
+
+      toff += irel->r_addend;
+      if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE)
+       toff = _bfd_merged_section_offset (abfd, &tsec,
+                                          elf_section_data (tsec)->sec_info,
+                                          toff);
+
+      symaddr = tsec->output_section->vma + tsec->output_offset + toff;
+
+      roff = irel->r_offset;
+      reladdr = isec->output_section->vma + isec->output_offset + roff;
+
+      /* If the branch is in range, no need to do anything.  */
+      if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
+       continue;
+
+      /* Look for an existing fixup to this address.  */
+      for (f = fixups; f ; f = f->next)
+       if (f->tsec == tsec && f->toff == toff)
+         break;
+
+      if (f == NULL)
        {
-         /* Check each word in this EOP region.  */
-         for (; dot < end_page; dot += 4)
-           {
-             bfd_vma isec_offset;
-             unsigned long insn;
-             bfd_boolean skip, modified;
-
-             /* Don't process this word if there is a relocation for it
-                and the relocation indicates the word is not a
-                conditional branch.  */
-             skip = FALSE;
-             isec_offset = dot - isec->vma;
-             for (; comb_curr<comb_count; ++comb_curr)
-               {
-                 bfd_vma r_offset;
+         size_t size;
+         unsigned long stub_rtype;
 
-                 r_offset = rela_comb[comb_curr]->r_offset;
-                 if (r_offset >= isec_offset)
-                   {
-                     if (r_offset == isec_offset) skip = TRUE;
-                     break;
-                   }
-               }
-             if (skip) continue;
-
-             /* Check the current word for a problematic conditional
-                branch.  */
-#define BO0(insn) ((insn) & 0x02000000)
-#define BO2(insn) ((insn) & 0x00800000)
-#define BO4(insn) ((insn) & 0x00200000)
-             insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset);
-             modified = FALSE;
-             if ((insn & 0xFc000000) == 0x40000000)
-               {
-                 /* Instruction is BCx */
-                 if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
-                   {
-                     bfd_vma target;
-
-                     /* This branch is predicted as "normal".
-                        If this is a forward branch, it is problematic.  */
-                     target = insn & 0x0000Fffc;
-                     target = (target ^ 0x8000) - 0x8000;
-                     if ((insn & 0x00000002) == 0)
-                       /* Convert to abs.  */
-                       target += dot;
-                     if (target > dot)
-                       {
-                         /* Set the prediction bit.  */
-                         insn |= 0x00200000;
-                         modified = TRUE;
-                       }
-                   }
-               }
-             else if ((insn & 0xFc00Fffe) == 0x4c000420)
-               {
-                 /* Instruction is BCCTRx.  */
-                 if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
-                   {
-                     /* This branch is predicted as not-taken.
-                        If this is a forward branch, it is problematic.
-                        Since we can't tell statically if it will branch
-                        forward, always set the prediction bit.  */
-                     insn |= 0x00200000;
-                     modified = TRUE;
-                   }
-               }
-             else if ((insn & 0xFc00Fffe) == 0x4c000020)
-               {
-                 /* Instruction is BCLRx */
-                 if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
-                   {
-                     /* This branch is predicted as not-taken.
-                        If this is a forward branch, it is problematic.
-                        Since we can't tell statically if it will branch
-                        forward, always set the prediction bit.  */
-                     insn |= 0x00200000;
-                     modified = TRUE;
-                   }
-               }
-#undef BO0
-#undef BO2
-#undef BO4
-             if (modified)
-               {
-                 bfd_put_32 (abfd, insn, contents + isec_offset);
-                 section_modified = TRUE;
-               }
+         val = trampoff - roff;
+         if (val >= max_branch_offset)
+           /* Oh dear, we can't reach a trampoline.  Don't try to add
+              one.  We'll report an error later.  */
+           continue;
+
+         if (link_info->shared)
+           {
+             size = 4 * ARRAY_SIZE (shared_stub_entry);
+             insn_offset = 12;
+             stub_rtype = R_PPC_RELAX32PC;
            }
+         else
+           {
+             size = 4 * ARRAY_SIZE (stub_entry);
+             insn_offset = 0;
+             stub_rtype = R_PPC_RELAX32;
+           }
+
+         /* Hijack the old relocation.  Since we need two
+            relocations for this use a "composite" reloc.  */
+         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                      stub_rtype);
+         irel->r_offset = trampoff + insn_offset;
+
+         /* Record the fixup so we don't do it again this section.  */
+         f = bfd_malloc (sizeof (*f));
+         f->next = fixups;
+         f->tsec = tsec;
+         f->toff = toff;
+         f->trampoff = trampoff;
+         fixups = f;
+
+         trampoff += size;
        }
-      if (section_modified)
+      else
        {
-         elf_section_data (isec)->this_hdr.contents = contents;
-         free_contents = NULL;
+         val = f->trampoff - roff;
+         if (val >= max_branch_offset)
+           continue;
+
+         /* Nop out the reloc, since we're finalizing things here.  */
+         irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
+       }
+
+      /* Fix up the existing branch to hit the trampoline.  */
+      hit_addr = contents + roff;
+      switch (r_type)
+       {
+       case R_PPC_REL24:
+       case R_PPC_LOCAL24PC:
+       case R_PPC_PLTREL24:
+         t0 = bfd_get_32 (abfd, hit_addr);
+         t0 &= ~0x3fffffc;
+         t0 |= val & 0x3fffffc;
+         bfd_put_32 (abfd, t0, hit_addr);
+         break;
+
+       case R_PPC_REL14:
+       case R_PPC_REL14_BRTAKEN:
+       case R_PPC_REL14_BRNTAKEN:
+         t0 = bfd_get_32 (abfd, hit_addr);
+         t0 &= ~0xfffc;
+         t0 |= val & 0xfffc;
+         bfd_put_32 (abfd, t0, hit_addr);
+         break;
        }
     }
 
-  if (rela_comb != NULL)
+  /* Write out the trampolines.  */
+  changed = fixups != NULL;
+  if (fixups != NULL)
     {
-      free (rela_comb);
-      rela_comb = NULL;
+      const int *stub;
+      bfd_byte *dest;
+      bfd_vma val;
+      int i, size;
+
+      do
+       {
+         struct one_fixup *f = fixups;
+         fixups = fixups->next;
+         free (f);
+       }
+      while (fixups);
+
+      contents = bfd_realloc (contents, trampoff);
+      if (contents == NULL)
+       goto error_return;
+
+      isec->_cooked_size = (isec->_cooked_size + 3) & (bfd_vma) -4;
+      /* Branch around the trampolines.  */
+      val = trampoff - isec->_cooked_size + 0x48000000;
+      dest = contents + isec->_cooked_size;
+      isec->_cooked_size = trampoff;
+      bfd_put_32 (abfd, val, dest);
+      dest += 4;
+
+      if (link_info->shared)
+       {
+         stub = shared_stub_entry;
+         size = ARRAY_SIZE (shared_stub_entry);
+       }
+      else
+       {
+         stub = stub_entry;
+         size = ARRAY_SIZE (stub_entry);
+       }
+
+      i = 0;
+      while (dest < contents + trampoff)
+       {
+         bfd_put_32 (abfd, stub[i], dest);
+         i++;
+         if (i == size)
+           i = 0;
+         dest += 4;
+       }
+      BFD_ASSERT (i == 0);
     }
 
-  if (free_relocs != NULL)
+  if (isymbuf != NULL
+      && symtab_hdr->contents != (unsigned char *) isymbuf)
     {
-      free (free_relocs);
-      free_relocs = NULL;
+      if (! link_info->keep_memory)
+       free (isymbuf);
+      else
+       {
+         /* Cache the symbols for elf_link_input_bfd.  */
+         symtab_hdr->contents = (unsigned char *) isymbuf;
+       }
     }
 
-  if (free_contents != NULL)
+  if (contents != NULL
+      && elf_section_data (isec)->this_hdr.contents != contents)
     {
-      if (! link_info->keep_memory)
-       free (free_contents);
+      if (!changed && !link_info->keep_memory)
+       free (contents);
       else
        {
          /* Cache the section contents for elf_link_input_bfd.  */
          elf_section_data (isec)->this_hdr.contents = contents;
        }
-      free_contents = NULL;
     }
 
+  if (elf_section_data (isec)->relocs != internal_relocs)
+    {
+      if (!changed)
+       free (internal_relocs);
+      else
+       elf_section_data (isec)->relocs = internal_relocs;
+    }
+
+  *again = changed;
   return TRUE;
 
  error_return:
-  if (rela_comb != NULL)
-    free (rela_comb);
-  if (free_relocs != NULL)
-    free (free_relocs);
-  if (free_contents != NULL)
-    free (free_contents);
+  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+    free (isymbuf);
+  if (contents != NULL
+      && elf_section_data (isec)->this_hdr.contents != contents)
+    free (contents);
+  if (internal_relocs != NULL
+      && elf_section_data (isec)->relocs != internal_relocs)
+    free (internal_relocs);
   return FALSE;
 }
 \f
@@ -1830,8 +2006,8 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   enum elf_ppc_reloc_type r;
 
+  /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   switch (code)
@@ -1932,8 +2108,8 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
 {
+  /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
@@ -2169,71 +2345,360 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 \f
+/* Find a linker generated pointer with a given addend and type.  */
+
+static elf_linker_section_pointers_t *
+elf_find_pointer_linker_section
+  (elf_linker_section_pointers_t *linker_pointers,
+   bfd_vma addend,
+   elf_linker_section_t *lsect)
+{
+  for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next)
+    if (lsect == linker_pointers->lsect && addend == linker_pointers->addend)
+      return linker_pointers;
+
+  return NULL;
+}
+\f
+/* Allocate a pointer to live in a linker created section.  */
+
+static bfd_boolean
+elf_create_pointer_linker_section (bfd *abfd,
+                                  struct bfd_link_info *info,
+                                  elf_linker_section_t *lsect,
+                                  struct elf_link_hash_entry *h,
+                                  const Elf_Internal_Rela *rel)
+{
+  elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
+  elf_linker_section_pointers_t *linker_section_ptr;
+  unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+  bfd_size_type amt;
+
+  BFD_ASSERT (lsect != NULL);
+
+  /* Is this a global symbol?  */
+  if (h != NULL)
+    {
+      struct ppc_elf_link_hash_entry *eh;
+
+      /* Has this symbol already been allocated?  If so, our work is done.  */
+      eh = (struct ppc_elf_link_hash_entry *) h;
+      if (elf_find_pointer_linker_section (eh->linker_section_pointer,
+                                          rel->r_addend,
+                                          lsect))
+       return TRUE;
+
+      ptr_linker_section_ptr = &eh->linker_section_pointer;
+      /* Make sure this symbol is output as a dynamic symbol.  */
+      if (h->dynindx == -1)
+       {
+         if (! bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+       }
+
+      if (lsect->rel_section)
+       lsect->rel_section->_raw_size += sizeof (Elf32_External_Rela);
+    }
+  else
+    {
+      /* Allocation of a pointer to a local symbol.  */
+      elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
+
+      /* Allocate a table to hold the local symbols if first time.  */
+      if (!ptr)
+       {
+         unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info;
+
+         amt = num_symbols;
+         amt *= sizeof (elf_linker_section_pointers_t *);
+         ptr = bfd_zalloc (abfd, amt);
+
+         if (!ptr)
+           return FALSE;
+
+         elf_local_ptr_offsets (abfd) = ptr;
+       }
+
+      /* Has this symbol already been allocated?  If so, our work is done.  */
+      if (elf_find_pointer_linker_section (ptr[r_symndx],
+                                          rel->r_addend,
+                                          lsect))
+       return TRUE;
+
+      ptr_linker_section_ptr = &ptr[r_symndx];
+
+      if (info->shared)
+       {
+         /* If we are generating a shared object, we need to
+            output a R_<xxx>_RELATIVE reloc so that the
+            dynamic linker can adjust this GOT entry.  */
+         BFD_ASSERT (lsect->rel_section != NULL);
+         lsect->rel_section->_raw_size += sizeof (Elf32_External_Rela);
+       }
+    }
+
+  /* Allocate space for a pointer in the linker section, and allocate
+     a new pointer record from internal memory.  */
+  BFD_ASSERT (ptr_linker_section_ptr != NULL);
+  amt = sizeof (elf_linker_section_pointers_t);
+  linker_section_ptr = bfd_alloc (abfd, amt);
+
+  if (!linker_section_ptr)
+    return FALSE;
+
+  linker_section_ptr->next = *ptr_linker_section_ptr;
+  linker_section_ptr->addend = rel->r_addend;
+  linker_section_ptr->lsect = lsect;
+  linker_section_ptr->written_address_p = FALSE;
+  *ptr_linker_section_ptr = linker_section_ptr;
+
+  linker_section_ptr->offset = lsect->section->_raw_size;
+  lsect->section->_raw_size += 4;
+
+#ifdef DEBUG
+  fprintf (stderr,
+          "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
+          lsect->name, (long) linker_section_ptr->offset,
+          (long) lsect->section->_raw_size);
+#endif
+
+  return TRUE;
+}
+\f
+#define bfd_put_ptr(BFD, VAL, ADDR) bfd_put_32 (BFD, VAL, ADDR)
+
+/* Fill in the address for a pointer generated in a linker section.  */
+
+static bfd_vma
+elf_finish_pointer_linker_section (bfd *output_bfd,
+                                  bfd *input_bfd,
+                                  struct bfd_link_info *info,
+                                  elf_linker_section_t *lsect,
+                                  struct elf_link_hash_entry *h,
+                                  bfd_vma relocation,
+                                  const Elf_Internal_Rela *rel,
+                                  int relative_reloc)
+{
+  elf_linker_section_pointers_t *linker_section_ptr;
+
+  BFD_ASSERT (lsect != NULL);
+
+  if (h != NULL)
+    {
+      /* Handle global symbol.  */
+      struct ppc_elf_link_hash_entry *eh;
+
+      eh = (struct ppc_elf_link_hash_entry *) h;
+      linker_section_ptr
+       = elf_find_pointer_linker_section (eh->linker_section_pointer,
+                                          rel->r_addend,
+                                          lsect);
+
+      BFD_ASSERT (linker_section_ptr != NULL);
+
+      if (! elf_hash_table (info)->dynamic_sections_created
+         || (info->shared
+             && info->symbolic
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+       {
+         /* This is actually a static link, or it is a
+            -Bsymbolic link and the symbol is defined
+            locally.  We must initialize this entry in the
+            global section.
+
+            When doing a dynamic link, we create a .rela.<xxx>
+            relocation entry to initialize the value.  This
+            is done in the finish_dynamic_symbol routine.  */
+         if (!linker_section_ptr->written_address_p)
+           {
+             linker_section_ptr->written_address_p = TRUE;
+             bfd_put_ptr (output_bfd,
+                          relocation + linker_section_ptr->addend,
+                          (lsect->section->contents
+                           + linker_section_ptr->offset));
+           }
+       }
+    }
+  else
+    {
+      /* Handle local symbol.  */
+      unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+      BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
+      BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL);
+      linker_section_ptr = (elf_find_pointer_linker_section
+                           (elf_local_ptr_offsets (input_bfd)[r_symndx],
+                            rel->r_addend,
+                            lsect));
+
+      BFD_ASSERT (linker_section_ptr != NULL);
+
+      /* Write out pointer if it hasn't been rewritten out before.  */
+      if (!linker_section_ptr->written_address_p)
+       {
+         linker_section_ptr->written_address_p = TRUE;
+         bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
+                      lsect->section->contents + linker_section_ptr->offset);
+
+         if (info->shared)
+           {
+             /* We need to generate a relative reloc for the dynamic
+                linker.  */
+
+             asection *srel = lsect->rel_section;
+             Elf_Internal_Rela outrel[MAX_INT_RELS_PER_EXT_REL];
+             bfd_byte *erel;
+             const struct elf_backend_data *bed;
+             unsigned int i;
+
+             BFD_ASSERT (srel != NULL);
+
+             bed = get_elf_backend_data (output_bfd);
+             for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+               {
+                 outrel[i].r_offset = (lsect->section->output_section->vma
+                                       + lsect->section->output_offset
+                                       + linker_section_ptr->offset);
+                 outrel[i].r_info = 0;
+                 outrel[i].r_addend = 0;
+               }
+             outrel[0].r_info = ELF32_R_INFO (0, relative_reloc);
+             erel = lsect->section->contents;
+             erel += (elf_section_data (lsect->section)->rel_count++
+                      * sizeof (Elf32_External_Rela));
+             bfd_elf32_swap_reloca_out (output_bfd, outrel, erel);
+           }
+       }
+    }
+
+  relocation = (lsect->section->output_offset
+               + linker_section_ptr->offset
+               - lsect->sym_offset);
+
+#ifdef DEBUG
+  fprintf (stderr,
+          "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
+          lsect->name, (long) relocation, (long) relocation);
+#endif
+
+  /* Subtract out the addend, because it will get added back in by the normal
+     processing.  */
+  return relocation - linker_section_ptr->addend;
+}
+\f
 /* Create a special linker section */
 static elf_linker_section_t *
 ppc_elf_create_linker_section (bfd *abfd,
                               struct bfd_link_info *info,
                               enum elf_linker_section_enum which)
 {
-  bfd *dynobj = elf_hash_table (info)->dynobj;
   elf_linker_section_t *lsect;
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  asection *s;
+  bfd_size_type amt;
+  flagword flags;
+  const char *name;
+  const char *rel_name;
+  const char *sym_name;
+  bfd_vma sym_offset;
+
+  /* Both of these sections are (technically) created by the user
+     putting data in them, so they shouldn't be marked
+     SEC_LINKER_CREATED.
+
+     The linker creates them so it has somewhere to attach their
+     respective symbols. In fact, if they were empty it would
+     be OK to leave the symbol set to 0 (or any random number), because
+     the appropriate register should never be used.  */
+  flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+  sym_offset = 32768;
+
+  switch (which)
+    {
+    default:
+      abort ();
+      return NULL;
 
-  /* Record the first bfd section that needs the special section.  */
-  if (!dynobj)
-    dynobj = elf_hash_table (info)->dynobj = abfd;
+    case LINKER_SECTION_SDATA: /* .sdata/.sbss section */
+      name     = ".sdata";
+      rel_name = ".rela.sdata";
+      sym_name = "_SDA_BASE_";
+      break;
 
-  /* If this is the first time, create the section.  */
-  lsect = elf_linker_section (dynobj, which);
-  if (!lsect)
+    case LINKER_SECTION_SDATA2:        /* .sdata2/.sbss2 section */
+      name     = ".sdata2";
+      rel_name = ".rela.sdata2";
+      sym_name = "_SDA2_BASE_";
+      flags    |= SEC_READONLY;
+      break;
+    }
+
+  /* Record the first bfd that needs the special sections.  */
+  if (!htab->elf.dynobj)
+    htab->elf.dynobj = abfd;
+
+  amt = sizeof (elf_linker_section_t);
+  lsect = bfd_zalloc (htab->elf.dynobj, amt);
+
+  lsect->sym_offset = sym_offset;
+
+  /* See if the sections already exist.  */
+  s = bfd_get_section_by_name (htab->elf.dynobj, name);
+  if (s == NULL || (s->flags & flags) != flags)
     {
-      elf_linker_section_t defaults;
-      static elf_linker_section_t zero_section;
-
-      defaults = zero_section;
-      defaults.which = which;
-      defaults.hole_written_p = FALSE;
-      defaults.alignment = 2;
-
-      /* Both of these sections are (technically) created by the user
-        putting data in them, so they shouldn't be marked
-        SEC_LINKER_CREATED.
-
-        The linker creates them so it has somewhere to attach their
-        respective symbols. In fact, if they were empty it would
-        be OK to leave the symbol set to 0 (or any random number), because
-        the appropriate register should never be used.  */
-      defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                       | SEC_IN_MEMORY);
-
-      switch (which)
-       {
-       default:
-         (*_bfd_error_handler) (_("%s: unknown special linker type %d"),
-                                bfd_get_filename (abfd),
-                                (int) which);
+      s = bfd_make_section_anyway (htab->elf.dynobj, name);
+      if (s == NULL
+         || !bfd_set_section_flags (htab->elf.dynobj, s, flags))
+       return NULL;
+    }
+  lsect->section = s;
 
-         bfd_set_error (bfd_error_bad_value);
-         return NULL;
-
-       case LINKER_SECTION_SDATA:      /* .sdata/.sbss section */
-         defaults.name           = ".sdata";
-         defaults.rel_name       = ".rela.sdata";
-         defaults.bss_name       = ".sbss";
-         defaults.sym_name       = "_SDA_BASE_";
-         defaults.sym_offset     = 32768;
-         break;
+  if (bfd_get_section_alignment (htab->elf.dynobj, s) < 2
+      && !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
+    return NULL;
 
-       case LINKER_SECTION_SDATA2:     /* .sdata2/.sbss2 section */
-         defaults.name           = ".sdata2";
-         defaults.rel_name       = ".rela.sdata2";
-         defaults.bss_name       = ".sbss2";
-         defaults.sym_name       = "_SDA2_BASE_";
-         defaults.sym_offset     = 32768;
-         defaults.flags         |= SEC_READONLY;
-         break;
-       }
+  s->_raw_size = align_power (s->_raw_size, 2);
+
+#ifdef DEBUG
+  fprintf (stderr, "Creating section %s, current size = %ld\n",
+          name, (long) s->_raw_size);
+#endif
+
+  if (sym_name)
+    {
+      struct elf_link_hash_entry *h;
+      struct bfd_link_hash_entry *bh;
+
+#ifdef DEBUG
+      fprintf (stderr, "Adding %s to section %s\n", sym_name, name);
+#endif
+      bh = bfd_link_hash_lookup (info->hash, sym_name,
+                                FALSE, FALSE, FALSE);
+
+      if ((bh == NULL || bh->type == bfd_link_hash_undefined)
+         && !(_bfd_generic_link_add_one_symbol
+              (info, abfd, sym_name, BSF_GLOBAL, s, sym_offset, NULL,
+               FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+       return NULL;
+      h = (struct elf_link_hash_entry *) bh;
 
-      lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults);
+      h->type = STT_OBJECT;
+      lsect->sym_hash = h;
+
+      if (info->shared
+         && ! bfd_elf_link_record_dynamic_symbol (info, h))
+       return NULL;
+    }
+
+  if (info->shared)
+    {
+      s = bfd_make_section_anyway (htab->elf.dynobj, rel_name);
+      lsect->rel_section = s;
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+              | SEC_LINKER_CREATED | SEC_READONLY);
+      if (s == NULL
+         || ! bfd_set_section_flags (htab->elf.dynobj, s, flags)
+         || ! bfd_set_section_alignment (htab->elf.dynobj, s, 2))
+       return NULL;
     }
 
   return lsect;
@@ -2268,7 +2733,8 @@ ppc_elf_additional_program_headers (bfd *abfd)
 /* Modify the segment map if needed.  */
 
 static bfd_boolean
-ppc_elf_modify_segment_map (bfd *abfd ATTRIBUTE_UNUSED)
+ppc_elf_modify_segment_map (bfd *abfd ATTRIBUTE_UNUSED,
+                           struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   return TRUE;
 }
@@ -2318,7 +2784,10 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   asection *s;
   flagword flags;
 
-  if (!ppc_elf_create_got (abfd, info))
+  htab = ppc_elf_hash_table (info);
+
+  if (htab->got == NULL
+      && !ppc_elf_create_got (abfd, info))
     return FALSE;
 
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
@@ -2327,7 +2796,6 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
 
-  htab = ppc_elf_hash_table (info);
   htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
   htab->dynsbss = s = bfd_make_section (abfd, ".dynsbss");
   if (s == NULL
@@ -2525,17 +2993,6 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   return TRUE;
 }
 \f
-/* This is the condition under which finish_dynamic_symbol will be
-   called from elflink.h.  If elflink.h doesn't call our
-   finish_dynamic_symbol routine, we'll need to do something about
-   initializing any .plt and .got entries in relocate_section.  */
-#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \
-  ((DYN)                                                               \
-   && ((SHARED)                                                                \
-       || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)     \
-   && ((H)->dynindx != -1                                              \
-       || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
-
 /* Of those relocs that might be copied as dynamic relocs, this macro
    selects those that must be copied when linking a shared library,
    even when the symbol is local.  */
@@ -2574,7 +3031,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       if (h->dynindx == -1
          && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
        {
-         if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+         if (! bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
        }
 
@@ -2637,7 +3094,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       if (eh->elf.dynindx == -1
          && (eh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
        {
-         if (!bfd_elf32_link_record_dynamic_symbol (info, &eh->elf))
+         if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
            return FALSE;
        }
 
@@ -2718,6 +3175,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
          && h->root.type == bfd_link_hash_undefweak)
        eh->dyn_relocs = NULL;
+
+      /* Make sure undefined weak symbols are output as a dynamic symbol
+        in PIEs.  */
+      if (info->pie
+         && eh->dyn_relocs != NULL
+         && h->dynindx == -1
+         && h->root.type == bfd_link_hash_undefweak
+         && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+       {
+         if (! bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+       }
     }
   else if (ELIMINATE_COPY_RELOCS)
     {
@@ -2734,7 +3203,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
          if (h->dynindx == -1
              && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
            {
-             if (! bfd_elf64_link_record_dynamic_symbol (info, h))
+             if (! bfd_elf_link_record_dynamic_symbol (info, h))
                return FALSE;
            }
 
@@ -2990,7 +3459,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
 #define add_dynamic_entry(TAG, VAL) \
-  bfd_elf32_add_dynamic_entry (info, (TAG), (VAL))
+  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
       if (info->executable)
        {
@@ -3085,7 +3554,7 @@ ppc_elf_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
 #ifdef DEBUG
@@ -3094,26 +3563,25 @@ ppc_elf_check_relocs (bfd *abfd,
           bfd_archive_filename (abfd));
 #endif
 
+  /* Initialize howto table if not already done.  */
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    ppc_elf_howto_init ();
+
   /* Create the linker generated sections all the time so that the
      special symbols are created.  */
-
   htab = ppc_elf_hash_table (info);
   if (htab->sdata == NULL)
     {
-      htab->sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA);
-      if (htab->sdata == NULL)
-       htab->sdata = ppc_elf_create_linker_section (abfd, info,
-                                                    LINKER_SECTION_SDATA);
+      htab->sdata = ppc_elf_create_linker_section (abfd, info,
+                                                  LINKER_SECTION_SDATA);
       if (htab->sdata == NULL)
        return FALSE;
     }
 
   if (htab->sdata2 == NULL)
     {
-      htab->sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2);
-      if (htab->sdata2 == NULL)
-       htab->sdata2 = ppc_elf_create_linker_section (abfd, info,
-                                                     LINKER_SECTION_SDATA2);
+      htab->sdata2 = ppc_elf_create_linker_section (abfd, info,
+                                                   LINKER_SECTION_SDATA2);
       if (htab->sdata2 == NULL)
        return FALSE;
     }
@@ -3217,8 +3685,8 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (!bfd_elf32_create_pointer_linker_section (abfd, info,
-                                                       htab->sdata, h, rel))
+         if (!elf_create_pointer_linker_section (abfd, info,
+                                                 htab->sdata, h, rel))
            return FALSE;
          break;
 
@@ -3229,8 +3697,8 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (!bfd_elf32_create_pointer_linker_section (abfd, info,
-                                                       htab->sdata2, h, rel))
+         if (!elf_create_pointer_linker_section (abfd, info,
+                                                 htab->sdata2, h, rel))
            return FALSE;
          break;
 
@@ -3269,6 +3737,12 @@ ppc_elf_check_relocs (bfd *abfd,
            {
              /* It does not make sense to have a procedure linkage
                 table entry for a local symbol.  */
+             (*_bfd_error_handler) (_("%s(%s+0x%lx): %s reloc against "
+                                      "local symbol"),
+                                    bfd_archive_filename (abfd),
+                                    sec->name,
+                                    (long) rel->r_offset,
+                                    ppc_elf_howto_table[r_type]->name);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
@@ -3321,14 +3795,14 @@ ppc_elf_check_relocs (bfd *abfd,
          /* This relocation describes the C++ object vtable hierarchy.
             Reconstruct it for later use during GC.  */
        case R_PPC_GNU_VTINHERIT:
-         if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+         if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
            return FALSE;
          break;
 
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_PPC_GNU_VTENTRY:
-         if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
 
@@ -3678,25 +4152,18 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
   return TRUE;
 }
 
-/* Set htab->tls_sec and htab->tls_get_addr.  */
+/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
-bfd_boolean
+asection *
 ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
 {
-  asection *tls;
   struct ppc_elf_link_hash_table *htab;
 
   htab = ppc_elf_hash_table (info);
   htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
                                             FALSE, FALSE, TRUE);
 
-  for (tls = obfd->sections; tls != NULL; tls = tls->next)
-    if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
-       == (SEC_THREAD_LOCAL | SEC_LOAD))
-      break;
-  htab->tls_sec = tls;
-
-  return tls != NULL;
+  return _bfd_elf_tls_setup (obfd, info);
 }
 
 /* Run through all the TLS relocs looking for optimization
@@ -3710,7 +4177,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
   asection *sec;
   struct ppc_elf_link_hash_table *htab;
 
-  if (info->relocateable || info->shared)
+  if (info->relocatable || info->shared)
     return TRUE;
 
   htab = ppc_elf_hash_table (info);
@@ -3898,51 +4365,34 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
 static bfd_boolean
 ppc_elf_add_symbol_hook (bfd *abfd,
                         struct bfd_link_info *info,
-                        const Elf_Internal_Sym *sym,
+                        Elf_Internal_Sym *sym,
                         const char **namep ATTRIBUTE_UNUSED,
                         flagword *flagsp ATTRIBUTE_UNUSED,
                         asection **secp,
                         bfd_vma *valp)
 {
   if (sym->st_shndx == SHN_COMMON
-      && !info->relocateable
+      && !info->relocatable
       && sym->st_size <= elf_gp_size (abfd)
-      && info->hash->creator->flavour == bfd_target_elf_flavour)
+      && (info->hash->creator == abfd->xvec
+         || info->hash->creator == abfd->xvec->alternative_target))
     {
       /* Common symbols less than or equal to -G nn bytes are automatically
-        put into .sdata.  */
-      elf_linker_section_t *sdata
-       = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+        put into .sbss.  */
+      struct ppc_elf_link_hash_table *htab;
 
-      if (!sdata->bss_section)
+      htab = ppc_elf_hash_table (info);
+      if (htab->sbss == NULL)
        {
-         bfd_size_type amt;
-
-         /* We don't go through bfd_make_section, because we don't
-            want to attach this common section to DYNOBJ.  The linker
-            will move the symbols to the appropriate output section
-            when it defines common symbols.  */
-         amt = sizeof (asection);
-         sdata->bss_section = bfd_zalloc (abfd, amt);
-         if (sdata->bss_section == NULL)
-           return FALSE;
-         sdata->bss_section->name = sdata->bss_name;
-         sdata->bss_section->flags = SEC_IS_COMMON;
-         sdata->bss_section->output_section = sdata->bss_section;
-         amt = sizeof (asymbol);
-         sdata->bss_section->symbol = bfd_zalloc (abfd, amt);
-         amt = sizeof (asymbol *);
-         sdata->bss_section->symbol_ptr_ptr = bfd_zalloc (abfd, amt);
-         if (sdata->bss_section->symbol == NULL
-             || sdata->bss_section->symbol_ptr_ptr == NULL)
+         flagword flags = SEC_IS_COMMON;
+
+         htab->sbss = bfd_make_section_anyway (abfd, ".sbss");
+         if (htab->sbss == NULL
+             || ! bfd_set_section_flags (abfd, htab->sbss, flags))
            return FALSE;
-         sdata->bss_section->symbol->name = sdata->bss_name;
-         sdata->bss_section->symbol->flags = BSF_SECTION_SYM;
-         sdata->bss_section->symbol->section = sdata->bss_section;
-         *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol;
        }
 
-      *secp = sdata->bss_section;
+      *secp = htab->sbss;
       *valp = sym->st_size;
     }
 
@@ -4142,7 +4592,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
    This function is responsible for adjust the section contents as
    necessary, and (if using Rela relocs and generating a
-   relocateable output file) adjusting the reloc addend as
+   relocatable output file) adjusting the reloc addend as
    necessary.
 
    This function does not have to worry about setting the reloc
@@ -4156,7 +4606,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
    The global hash table entry for the global symbols can be found
    via elf_sym_hashes (input_bfd).
 
-   When generating relocateable output, this function must handle
+   When generating relocatable output, this function must handle
    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    going to be the section symbol corresponding to the output
    section, which means that the addend must be adjusted
@@ -4189,14 +4639,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
           bfd_archive_filename (input_bfd),
           bfd_section_name(input_bfd, input_section),
           (long) input_section->reloc_count,
-          (info->relocateable) ? " (relocatable)" : "");
+          (info->relocatable) ? " (relocatable)" : "");
 #endif
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
+  /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   htab = ppc_elf_hash_table (info);
@@ -4229,54 +4679,23 @@ ppc_elf_relocate_section (bfd *output_bfd,
       unresolved_reloc = FALSE;
       warned = FALSE;
       r_symndx = ELF32_R_SYM (rel->r_info);
+
       if (r_symndx < symtab_hdr->sh_info)
        {
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
          sym_name = bfd_elf_local_sym_name (input_bfd, sym);
 
-         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
        }
       else
        {
-         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-         sym_name = h->root.root.string;
+         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+                                  r_symndx, symtab_hdr, sym_hashes,
+                                  h, sec, relocation,
+                                  unresolved_reloc, warned);
 
-         relocation = 0;
-         if (h->root.type == bfd_link_hash_defined
-             || h->root.type == bfd_link_hash_defweak)
-           {
-             sec = h->root.u.def.section;
-             /* Set a flag that will be cleared later if we find a
-                relocation value for this symbol.  output_section
-                is typically NULL for symbols satisfied by a shared
-                library.  */
-             if (sec->output_section == NULL)
-               unresolved_reloc = TRUE;
-             else
-               relocation = (h->root.u.def.value
-                             + sec->output_section->vma
-                             + sec->output_offset);
-           }
-         else if (h->root.type == bfd_link_hash_undefweak)
-           ;
-         else if (info->shared
-                  && !info->no_undefined
-                  && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
-           ;
-         else
-           {
-             if (! ((*info->callbacks->undefined_symbol)
-                    (info, h->root.root.string, input_bfd, input_section,
-                     rel->r_offset, (!info->shared
-                                     || info->no_undefined
-                                     || ELF_ST_VISIBILITY (h->other)))))
-               return FALSE;
-             warned = TRUE;
-           }
+         sym_name = h->root.root.string;
        }
 
       /* TLS optimizations.  Replace instruction sequences and relocs
@@ -4459,8 +4878,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                        {
                          /* Was an LD reloc.  */
                          r_symndx = 0;
-                         rel->r_addend = htab->tls_sec->vma + DTP_OFFSET;
-                         rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET;
+                         rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+                         rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
                        }
                      r_type = R_PPC_TPREL16_HA;
                      rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -4495,7 +4914,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          branch_bit = BRANCH_PREDICT_BIT;
          /* Fall thru */
 
-         /* Branch not taken predicition relocations.  */
+         /* Branch not taken prediction relocations.  */
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_REL14_BRNTAKEN:
          insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
@@ -4698,7 +5117,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          {
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
-                             outrel.r_addend -= htab->tls_sec->vma;
+                             outrel.r_addend -= htab->elf.tls_sec->vma;
                          }
                        loc = htab->relgot->contents;
                        loc += (htab->relgot->reloc_count++
@@ -4716,7 +5135,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          value = 1;
                        else if (tls_ty != 0)
                          {
-                           value -= htab->tls_sec->vma + DTP_OFFSET;
+                           value -= htab->elf.tls_sec->vma + DTP_OFFSET;
                            if (tls_ty == (TLS_TLS | TLS_TPREL))
                              value += DTP_OFFSET - TP_OFFSET;
 
@@ -4804,7 +5223,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_DTPREL16_LO:
        case R_PPC_DTPREL16_HI:
        case R_PPC_DTPREL16_HA:
-         addend -= htab->tls_sec->vma + DTP_OFFSET;
+         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          break;
 
          /* Relocations that may need to be propagated if this is a shared
@@ -4813,18 +5232,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
-         addend -= htab->tls_sec->vma + TP_OFFSET;
+         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          /* The TPREL16 relocs shouldn't really be used in shared
             libs as they will result in DT_TEXTREL being set, but
             support them anyway.  */
          goto dodyn;
 
        case R_PPC_TPREL32:
-         addend -= htab->tls_sec->vma + TP_OFFSET;
+         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          goto dodyn;
 
        case R_PPC_DTPREL32:
-         addend -= htab->tls_sec->vma + DTP_OFFSET;
+         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          goto dodyn;
 
        case R_PPC_DTPMOD32:
@@ -4839,9 +5258,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_REL14_BRNTAKEN:
          /* If these relocations are not to a named symbol, they can be
             handled right here, no need to bother the dynamic linker.  */
-         if (h == NULL
-             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
-             || SYMBOL_REFERENCES_LOCAL (info, h))
+         if (SYMBOL_REFERENCES_LOCAL (info, h)
+             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
            break;
          /* fall through */
 
@@ -4871,8 +5289,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                   || h->root.type != bfd_link_hash_undefweak)
               && (MUST_BE_DYN_RELOC (r_type)
-                  || (h != NULL
-                      && !SYMBOL_CALLS_LOCAL (info, h))))
+                  || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && (input_section->flags & SEC_ALLOC) != 0
@@ -4927,8 +5344,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (h != NULL
-                      && !SYMBOL_REFERENCES_LOCAL (info, h))
+             else if (!SYMBOL_REFERENCES_LOCAL (info, h))
                {
                  unresolved_reloc = FALSE;
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
@@ -4995,24 +5411,50 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
+       case R_PPC_RELAX32PC:
+         relocation -= (input_section->output_section->vma
+                        + input_section->output_offset
+                        + rel->r_offset - 4);
+         /* Fall thru */
+       case R_PPC_RELAX32:
+         {
+           unsigned long t0;
+           unsigned long t1;
+
+           t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
+           t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4);
+
+           /* We're clearing the bits for R_PPC_ADDR16_HA
+              and R_PPC_ADDR16_LO here.  */
+           t0 &= ~0xffff;
+           t1 &= ~0xffff;
+
+           /* t0 is HA, t1 is LO */
+           relocation += addend;
+           t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
+           t1 |= relocation & 0xffff;
+
+           bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
+           bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
+         }
+         continue;
+
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
          BFD_ASSERT (htab->sdata != NULL);
          relocation
-           = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd,
-                                                      info, htab->sdata, h,
-                                                      relocation, rel,
-                                                      R_PPC_RELATIVE);
+           = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
+                                                htab->sdata, h, relocation,
+                                                rel, R_PPC_RELATIVE);
          break;
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
          BFD_ASSERT (htab->sdata2 != NULL);
          relocation
-           = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd,
-                                                      info, htab->sdata2, h,
-                                                      relocation, rel,
-                                                      R_PPC_RELATIVE);
+           = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
+                                                htab->sdata2, h, relocation,
+                                                rel, R_PPC_RELATIVE);
          break;
 
          /* Handle the TOC16 reloc.  We want to use the offset within the .got
@@ -5685,6 +6127,36 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 
   apuinfo_list_finish ();
 }
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+   or (bfd_vma) -1 if it should not be included.  */
+
+static bfd_vma
+ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED,
+                    const asection *plt ATTRIBUTE_UNUSED,
+                    const arelent *rel)
+{
+  return rel->address;
+}
+
+/* Add extra PPC sections -- Note, for now, make .sbss2 and
+   .PPC.EMB.sbss0 a normal section, and not a bss section so
+   that the linker doesn't crater when trying to make more than
+   2 sections.  */
+
+static struct bfd_elf_special_section const ppc_elf_special_sections[]=
+{
+  { ".tags",             5,  0, SHT_ORDERED,  SHF_ALLOC },
+  { ".sdata",            6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { ".sbss",             5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
+  { ".sdata2",           7, -2, SHT_PROGBITS, SHF_ALLOC },
+  { ".sbss2",            6, -2, SHT_PROGBITS, SHF_ALLOC },
+  { ".PPC.EMB.apuinfo", 16,  0, SHT_NOTE,     0 },
+  { ".PPC.EMB.sdata0",  15,  0, SHT_PROGBITS, SHF_ALLOC },
+  { ".PPC.EMB.sbss0",   14,  0, SHT_PROGBITS, SHF_ALLOC },
+  { ".plt",              4,  0, SHT_NOBITS,   SHF_ALLOC + SHF_EXECINSTR },
+  { NULL,                0,  0, 0,            0 }
+};
 \f
 #define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
 #define TARGET_LITTLE_NAME     "elf32-powerpcle"
@@ -5692,7 +6164,11 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 #define TARGET_BIG_NAME                "elf32-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
 #define ELF_MACHINE_CODE       EM_PPC
+#ifdef __QNXTARGET__
+#define ELF_MAXPAGESIZE                0x1000
+#else
 #define ELF_MAXPAGESIZE                0x10000
+#endif
 #define elf_info_to_howto      ppc_elf_info_to_howto
 
 #ifdef  EM_CYGNUS_POWERPC
@@ -5708,9 +6184,9 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 #define elf_backend_can_gc_sections    1
 #define elf_backend_can_refcount       1
 #define elf_backend_got_header_size    12
-#define elf_backend_plt_header_size    PLT_INITIAL_ENTRY_SIZE
 #define elf_backend_rela_normal                1
 
+#define bfd_elf32_mkobject                     ppc_elf_mkobject
 #define bfd_elf32_bfd_merge_private_bfd_data   ppc_elf_merge_private_bfd_data
 #define bfd_elf32_bfd_relax_section            ppc_elf_relax_section
 #define bfd_elf32_bfd_reloc_type_lookup                ppc_elf_reloc_type_lookup
@@ -5739,5 +6215,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 #define elf_backend_begin_write_processing     ppc_elf_begin_write_processing
 #define elf_backend_final_write_processing     ppc_elf_final_write_processing
 #define elf_backend_write_section              ppc_elf_write_section
+#define elf_backend_special_sections           ppc_elf_special_sections
+#define elf_backend_plt_sym_val                        ppc_elf_plt_sym_val
 
 #include "elf32-target.h"
This page took 0.048214 seconds and 4 git commands to generate.