* MAINTAINERS: Change my e-mail address.
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 716ad705f1610b307e29818ac4ae4de2d130731a..3bffc70c7868575cba5f1f2a84b753047f8d6130 100644 (file)
@@ -109,9 +109,32 @@ typedef struct elf_linker_section_pointers
   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) \
-  ((elf_linker_section_pointers_t **) \
-   (elf_tdata (bfd)->linker_section_pointers))
+  (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.
@@ -262,7 +285,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)
 {
@@ -1511,6 +1534,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* Phony reloc 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 */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
         0,                     /* rightshift */
@@ -1576,286 +1614,423 @@ 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.  */
-
-static int
-ppc_elf_sort_rela (const void *arg1, const void *arg2)
+static bfd_reloc_status_type
+ppc_elf_install_value (bfd *abfd,
+                      bfd_byte *hit_addr,
+                      bfd_vma v,
+                      unsigned int r_type)
 {
-  const Elf_Internal_Rela * const *rela1 = arg1;
-  const Elf_Internal_Rela * const *rela2 = arg2;
+  bfd_vma t0, t1;
+#ifdef BFD_HOST_U_64_BIT
+  BFD_HOST_U_64_BIT val = (BFD_HOST_U_64_BIT) v;
+#else
+  bfd_vma val = v;
+#endif
+
+  switch (r_type)
+    {
+    case R_PPC_RELAX32:
+      /* Do stuff here.  */
+      t0 = bfd_get_32 (abfd, hit_addr);
+      t1 = bfd_get_32 (abfd, hit_addr + 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 */
+      t0 |= ((val + 0x8000) >> 16) & 0xffff;
+      t1 |= val & 0xffff;
+
+      bfd_put_32 (abfd, t0, hit_addr);
+      bfd_put_32 (abfd, t1, hit_addr + 4);
+      break;
+
+    case R_PPC_REL24:
+      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;
 
-  /* Sort by offset.  */
-  return ((*rela1)->r_offset - (*rela2)->r_offset);
+    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;
+
+    default:
+      return bfd_reloc_notsupported;
+    }
+
+  return bfd_reloc_ok;
 }
 
+static const bfd_byte shared_stub_entry[] =
+  {
+    0x48, 0x00, 0x00, 0x24, /* b .+36 */
+    0x7c, 0x08, 0x02, 0xa6, /* mflr 0 */
+    0x42, 0x9f, 0x00, 0x05, /* bcl 20, 31, .Lxxx */
+    0x7d, 0x68, 0x02, 0xa6, /* mflr 11 */
+    0x3d, 0x60, 0x00, 0x00, /* addis 11, 11, (xxx-.Lxxx)@ha */
+    0x39, 0x6b, 0x00, 0x18, /* addi 11, 11, (xxx-.Lxxx)@l */
+    0x7c, 0x08, 0x03, 0xa6, /* mtlr 0 */
+    0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */
+    0x4e, 0x80, 0x04, 0x20, /* bctr */
+  };
+
+static const bfd_byte stub_entry[] =
+  {
+    0x48, 0x00, 0x00, 0x14, /* b .+20 */
+    0x3d, 0x60, 0x00, 0x00, /* lis 11,xxx@ha */
+    0x39, 0x6b, 0x00, 0x00, /* addi 11,11,xxx@l */
+    0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */
+    0x4e, 0x80, 0x04, 0x20, /* bctr */
+  };
+
+
 static bfd_boolean
 ppc_elf_relax_section (bfd *abfd,
                       asection *isec,
                       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_contents = FALSE;
+  bfd_boolean changed_relocs = FALSE;
+  struct ppc_elf_link_hash_table *ppc_info;
 
-  /* We never have to do this more than once per input section.  */
   *again = FALSE;
 
+  /* Nothing to do if there are no relocations and no need for
+     the relax finalize pass.  */
+  if ((isec->flags & SEC_RELOC) == 0
+      || isec->reloc_count == 0
+      || link_info->relax_finalizing)
+    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)
+  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, trampoff, toff, roff;
+      asection *tsec;
+      bfd_size_type amt;
+      struct one_fixup *f;
+      size_t insn_offset = 0;
+      bfd_vma max_branch_offset;
+
+      switch (r_type)
        {
-         /* Go get them off disk.  */
-         contents = bfd_malloc (isec->_raw_size);
-         if (contents == NULL)
-           goto error_return;
-         free_contents = contents;
+       case R_PPC_REL24:
+       case R_PPC_LOCAL24PC:
+       case R_PPC_REL14:
+       case R_PPC_REL14_BRTAKEN:
+       case R_PPC_REL14_BRNTAKEN:
+       case R_PPC_PLTREL24:
+         break;
 
-         if (! bfd_get_section_contents (abfd, isec, contents,
-                                         (file_ptr) 0, isec->_raw_size))
-           goto error_return;
+       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;
-
-             /* 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;
-               }
            }
-         if (comb_count > 1)
-           qsort (rela_comb, (size_t) comb_count, sizeof (int),
-                  ppc_elf_sort_rela);
-       }
+         isym = isymbuf + ELF32_R_SYM (irel->r_info);
+         if (isym->st_shndx == SHN_UNDEF)
+           continue;   /* We can't do anthing 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);
 
-      /* 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)
+         toff = isym->st_value;
+       }
+      else
        {
-         /* Check each word in this EOP region.  */
-         for (; dot < end_page; dot += 4)
+         /* Need dynamic 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)
            {
-             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;
+             Elf_Internal_Sym *isym;
 
-                 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)
+             if (h->plt.offset == (bfd_vma) -1
+                 || ppc_info->plt == NULL)
                {
-                 /* 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))
+
+                 /* Read this BFD's local symbols.  */
+                 if (isymbuf == NULL)
                    {
-                     /* 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;
+                     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)
+                   /* We can't do anthing with undefined symbols.  */
+                   continue;
+                 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 = h->root.u.def.section;
+
+                 toff = h->root.u.def.value;
                }
-#undef BO0
-#undef BO2
-#undef BO4
-             if (modified)
+             else
                {
-                 bfd_put_32 (abfd, insn, contents + isec_offset);
-                 section_modified = TRUE;
+                 tsec = ppc_info->plt;
+                 toff = h->plt.offset;
                }
            }
+         else if (h->root.type == bfd_link_hash_undefined
+                  || h->root.type == bfd_link_hash_undefweak)
+           continue;
+
+         else
+           {
+             tsec = h->root.u.def.section;
+             toff = h->root.u.def.value;
+           }
        }
-      if (section_modified)
+
+      if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE)
+       toff = _bfd_merged_section_offset (abfd, &tsec,
+                                          elf_section_data (tsec)->sec_info,
+                                          toff + irel->r_addend, 0);
+      else
+       toff += irel->r_addend;
+
+      symaddr = tsec->output_section->vma + tsec->output_offset + toff;
+
+      roff = irel->r_offset;
+
+      reladdr = (isec->output_section->vma
+                + isec->output_offset
+                + roff) & (bfd_vma) -4;
+
+      /* If the branch is in range, no need to do anything.  */
+      max_branch_offset = 1 << 25;
+      if (r_type != R_PPC_REL24
+         && r_type != R_PPC_LOCAL24PC
+         && r_type != R_PPC_PLTREL24)
+       max_branch_offset = 1 << 15;
+
+      if ((bfd_vma) (symaddr - reladdr) + max_branch_offset
+         <= 2 * max_branch_offset)
+       continue;
+
+      /* If the branch and target are in the same section, you have
+        no hope.  We'll error out later.  */
+      if (tsec == isec)
+       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)
        {
-         elf_section_data (isec)->this_hdr.contents = contents;
-         free_contents = NULL;
+         size_t size;
+
+         if (link_info->shared
+             || tsec == ppc_info->plt
+             || r_type == R_PPC_LOCAL24PC)
+           {
+             size = sizeof (shared_stub_entry);
+             insn_offset = 16;
+           }
+         else
+           {
+             size = sizeof (stub_entry);
+             insn_offset = 4;
+           }
+
+         /* Resize the current section to make room for the new branch.  */
+         trampoff = (isec->_cooked_size + 3) & (bfd_vma) - 4;
+         amt = trampoff + size;
+         contents = bfd_realloc (contents, amt);
+         if (contents == NULL)
+           abort ();
+
+         isec->_cooked_size = amt;
+
+         if (link_info->shared
+             || tsec == ppc_info->plt
+             || r_type == R_PPC_LOCAL24PC)
+           memcpy (contents + trampoff, shared_stub_entry, size);
+         else
+           memcpy (contents + trampoff, stub_entry, size);
+
+         /* 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),
+                                      R_PPC_RELAX32);
+         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;
        }
+      else
+       {
+         /* 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.  Hope like
+        hell this doesn't overflow too.  */
+      if (ppc_elf_install_value (abfd, contents + roff,
+                                f->trampoff - (roff & (bfd_vma) -3) + 4,
+                                r_type) != bfd_reloc_ok)
+       abort ();
+
+      changed_contents = TRUE;
+      changed_relocs = TRUE;
     }
 
-  if (rela_comb != NULL)
+  /* Clean up.  */
+  while (fixups)
     {
-      free (rela_comb);
-      rela_comb = NULL;
+      struct one_fixup *f = fixups;
+      fixups = fixups->next;
+      free (f);
     }
-
-  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_contents && !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_relocs)
+       free (internal_relocs);
+      else
+       elf_section_data (isec)->relocs = internal_relocs;
+    }
+
+  *again = changed_contents || changed_relocs;
   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
@@ -2406,11 +2581,12 @@ elf_finish_pointer_linker_section (bfd *output_bfd,
              asection *srel = lsect->rel_section;
              Elf_Internal_Rela outrel[MAX_INT_RELS_PER_EXT_REL];
              bfd_byte *erel;
-             struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+             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
@@ -4542,6 +4718,7 @@ 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;
@@ -4552,44 +4729,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
        }
       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;
+         RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx,
+                                  symtab_hdr, relocation, sec,
+                                  unresolved_reloc, info,
+                                  warned);
+         
          sym_name = h->root.root.string;
-
-         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->executable
-                  && !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;
-           }
        }
 
       /* TLS optimizations.  Replace instruction sequences and relocs
@@ -5152,9 +5297,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 */
 
@@ -5184,8 +5328,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
@@ -5240,8 +5383,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);
@@ -5308,6 +5450,46 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
+       case R_PPC_RELAX32:
+         {
+           unsigned long r_symndx;
+           Elf_Internal_Sym *sym;
+           asection *sym_sec;
+           bfd_byte *hit_addr = 0;
+           bfd_vma value = 0;
+
+           r_symndx = ELF32_R_SYM (rel->r_info);
+
+           if (r_symndx < symtab_hdr->sh_info)
+             {
+               sym = local_syms + r_symndx;
+               sym_sec = local_sections[r_symndx];
+
+               value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel);
+             }
+           else
+             {
+               bfd_boolean warned;
+               bfd_boolean unresolved_reloc;
+
+               RELOC_FOR_GLOBAL_SYMBOL (h, elf_sym_hashes (input_bfd),
+                                        r_symndx, symtab_hdr,
+                                        value, sym_sec,
+                                        unresolved_reloc, info,
+                                        warned);
+               if (warned)
+                 continue;
+             }
+           hit_addr = contents + rel->r_offset;
+           value += rel->r_addend;
+
+           r = ppc_elf_install_value (output_bfd, hit_addr, value, r_type);
+           if (r != bfd_reloc_ok)
+             break;
+           else
+             continue;
+         }
+
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
          BFD_ASSERT (htab->sdata != NULL);
@@ -5996,6 +6178,35 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 
   apuinfo_list_finish ();
 }
+
+/* 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",           0,      NULL,   0,
+    SHT_ORDERED,       SHF_ALLOC },
+  { ".sdata",          0,      NULL,   0,
+    SHT_PROGBITS,      SHF_ALLOC + SHF_WRITE },
+  { ".sbss",           0,      NULL,   0,
+    SHT_NOBITS,                SHF_ALLOC + SHF_WRITE },
+  { ".sdata2",         0,      NULL,   0,
+    SHT_PROGBITS,      SHF_ALLOC },
+  { ".sbss2",          0,      NULL,   0,
+    SHT_PROGBITS,      SHF_ALLOC },
+  { ".PPC.EMB.apuinfo",        0,      NULL,   0,
+    SHT_NOTE,          0 },
+  { ".PPC.EMB.sdata0", 0,      NULL,   0,
+    SHT_PROGBITS,      SHF_ALLOC },
+  { ".PPC.EMB.sbss0",  0,      NULL,   0,
+    SHT_PROGBITS,      SHF_ALLOC },
+  { ".plt",            0,      NULL,   0,
+    SHT_NOBITS,                0 },
+  { NULL,              0,      NULL,   0,
+    0,                 0 }
+};
 \f
 #define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
 #define TARGET_LITTLE_NAME     "elf32-powerpcle"
@@ -6003,7 +6214,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
@@ -6022,6 +6237,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 #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
@@ -6050,5 +6266,6 @@ 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
 
 #include "elf32-target.h"
This page took 0.035629 seconds and 4 git commands to generate.