* elf.c (bfd_section_from_shdr): Make "name" const.
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 0d3f0d2264d25707c39680996abdbc1bac585f07..17c5d254a46d9d78968181e4dd9dfb9fcbb24283 100644 (file)
@@ -1,5 +1,6 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -32,27 +33,30 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define USE_RELA               /* we want RELA relocations, not REL */
 
-
 static reloc_howto_type *ppc_elf_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
 static void ppc_elf_info_to_howto
   PARAMS ((bfd *abfd, arelent *cache_ptr, Elf32_Internal_Rela *dst));
 static void ppc_elf_howto_init PARAMS ((void));
+static int ppc_elf_sort_rela PARAMS ((const PTR, const PTR));
+static boolean ppc_elf_relax_section
+  PARAMS ((bfd *, asection *, struct bfd_link_info *, boolean *));
 static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static boolean ppc_elf_set_private_flags PARAMS ((bfd *, flagword));
-static boolean ppc_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
 static boolean ppc_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
 
 static int ppc_elf_additional_program_headers PARAMS ((bfd *));
 static boolean ppc_elf_modify_segment_map PARAMS ((bfd *));
 
+static asection *ppc_elf_create_got
+  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean ppc_elf_create_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 
 static boolean ppc_elf_section_from_shdr PARAMS ((bfd *,
                                                  Elf32_Internal_Shdr *,
-                                                 char *));
+                                                 const char *));
 static boolean ppc_elf_fake_sections
   PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
 
@@ -80,8 +84,6 @@ static boolean ppc_elf_gc_sweep_hook PARAMS ((bfd *abfd,
 static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *,
                                                      struct elf_link_hash_entry *));
 
-static boolean ppc_elf_adjust_dynindx PARAMS ((struct elf_link_hash_entry *, PTR));
-
 static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
 
 static boolean ppc_elf_relocate_section PARAMS ((bfd *,
@@ -107,6 +109,12 @@ static boolean ppc_elf_finish_dynamic_symbol PARAMS ((bfd *,
                                                      Elf_Internal_Sym *));
 
 static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
+static enum elf_reloc_type_class ppc_elf_reloc_type_class
+  PARAMS ((const Elf_Internal_Rela *));
+static boolean ppc_elf_grok_prstatus
+  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
+static boolean ppc_elf_grok_psinfo
+  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
 
 #define BRANCH_PREDICT_BIT 0x200000            /* branch prediction bit for branch taken relocs */
 #define RA_REGISTER_MASK 0x001f0000            /* mask to set RA in memory instructions */
@@ -117,17 +125,36 @@ static boolean ppc_elf_finish_dynamic_sections PARAMS ((bfd *, struct bfd_link_i
 
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
 
-/* The size in bytes of an entry in the procedure linkage table, and of the initial size
-   of the plt reserved for the dynamic linker.  */
-
+/* The size in bytes of an entry in the procedure linkage table.  */
 #define PLT_ENTRY_SIZE 12
+/* The initial size of the plt reserved for the dynamic linker.  */
 #define PLT_INITIAL_ENTRY_SIZE 72
-
+/* The size of the gap between entries in the PLT.  */
+#define PLT_SLOT_SIZE 8
+/* The number of single-slot PLT entries (the rest use two slots).  */
+#define PLT_NUM_SINGLE_ENTRIES 8192
+
+/* Will references to this symbol always reference the symbol
+   in this object?  */
+#define SYMBOL_REFERENCES_LOCAL(INFO, H)                               \
+  ((! INFO->shared                                                     \
+    || INFO->symbolic                                                  \
+    || H->dynindx == -1                                                        \
+    || ELF_ST_VISIBILITY (H->other) == STV_INTERNAL                    \
+    || ELF_ST_VISIBILITY (H->other) == STV_HIDDEN)                     \
+   && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+
+/* Will _calls_ to this symbol always call the version in this object?  */
+#define SYMBOL_CALLS_LOCAL(INFO, H)                            \
+  ((! INFO->shared                                                     \
+    || INFO->symbolic                                                  \
+    || H->dynindx == -1                                                        \
+    || ELF_ST_VISIBILITY (H->other) != STV_DEFAULT)                    \
+   && (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
 \f
-static reloc_howto_type *ppc_elf_howto_table[ (int)R_PPC_max ];
+static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max];
 
-static reloc_howto_type ppc_elf_howto_raw[] =
-{
+static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
   HOWTO (R_PPC_NONE,           /* type */
         0,                     /* rightshift */
@@ -220,7 +247,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         false),                /* pcrel_offset */
 
   /* The high order 16 bits of an address, plus 1 if the contents of
-     the low 16 bits, treated as a signed number, is negative. */
+     the low 16 bits, treated as a signed number, is negative.  */
   HOWTO (R_PPC_ADDR16_HA,      /* type */
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -253,7 +280,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
 
   /* An absolute 16 bit branch, for which bit 10 should be set to
      indicate that the branch is expected to be taken. The lower two
-     bits must be zero.         */
+     bits must be zero.  */
   HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -285,7 +312,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xfffc,                /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* A relative 26 bit branch; the lower two bits must be zero.         */
+  /* A relative 26 bit branch; the lower two bits must be zero.  */
   HOWTO (R_PPC_REL24,          /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -300,7 +327,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0x3fffffc,             /* dst_mask */
         true),                 /* pcrel_offset */
 
-  /* A relative 16 bit branch; the lower two bits must be zero.         */
+  /* A relative 16 bit branch; the lower two bits must be zero.  */
   HOWTO (R_PPC_REL14,          /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -315,7 +342,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xfffc,                /* dst_mask */
         true),                 /* pcrel_offset */
 
-  /* A relative 16 bit branch. Bit 10 should be set to indicate that
+  /* A relative 16 bit branch.  Bit 10 should be set to indicate that
      the branch is expected to be taken.  The lower two bits must be
      zero.  */
   HOWTO (R_PPC_REL14_BRTAKEN,  /* type */
@@ -332,7 +359,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xfffc,                /* dst_mask */
         true),                 /* pcrel_offset */
 
-  /* A relative 16 bit branch. Bit 10 should be set to indicate that
+  /* A relative 16 bit branch.  Bit 10 should be set to indicate that
      the branch is not expected to be taken.  The lower two bits must
      be zero.  */
   HOWTO (R_PPC_REL14_BRNTAKEN, /* type */
@@ -373,7 +400,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_GOT16_LO",      /* name */
         false,                 /* partial_inplace */
@@ -559,7 +586,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         true),                 /* pcrel_offset */
 
   /* 32-bit relocation to the symbol's procedure linkage table.
-     FIXME: not supported. */
+     FIXME: not supported.  */
   HOWTO (R_PPC_PLT32,          /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -575,7 +602,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         false),                /* pcrel_offset */
 
   /* 32-bit PC relative relocation to the symbol's procedure linkage table.
-     FIXME: not supported. */
+     FIXME: not supported.  */
   HOWTO (R_PPC_PLTREL32,       /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -598,7 +625,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_PLT16_LO",      /* name */
         false,                 /* partial_inplace */
@@ -623,15 +650,15 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         false),                 /* pcrel_offset */
 
   /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for
-     the symbol.  FIXME: Not supported.         */
+     the symbol.  */
   HOWTO (R_PPC_PLT16_HA,       /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_addr16_ha_reloc, /* special_function */
         "R_PPC_PLT16_HA",      /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -654,29 +681,29 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* 32-bit section relative relocation. */
+  /* 16-bit section relative relocation.  */
   HOWTO (R_PPC_SECTOFF,                /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        true,                  /* pc_relative */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_SECTOFF",       /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        true),                 /* pcrel_offset */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
 
-  /* 16-bit lower half section relative relocation. */
+  /* 16-bit lower half section relative relocation.  */
   HOWTO (R_PPC_SECTOFF_LO,       /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_SECTOFF_LO",    /* name */
         false,                 /* partial_inplace */
@@ -684,7 +711,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
-  /* 16-bit upper half section relative relocation. */
+  /* 16-bit upper half section relative relocation.  */
   HOWTO (R_PPC_SECTOFF_HI,     /* type */
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -699,15 +726,15 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xffff,                /* dst_mask */
         false),                 /* pcrel_offset */
 
-  /* 16-bit upper half adjusted section relative relocation. */
+  /* 16-bit upper half adjusted section relative relocation.  */
   HOWTO (R_PPC_SECTOFF_HA,     /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_addr16_ha_reloc, /* special_function */
         "R_PPC_SECTOFF_HA",    /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -787,7 +814,7 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_addr16_ha_reloc, /* special_function */
         "R_PPC_EMB_NADDR16_HA", /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -930,7 +957,6 @@ static reloc_howto_type ppc_elf_howto_raw[] =
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 };
-
 \f
 /* Initialize the ppc_elf_howto_table, so that linear accesses can be done.  */
 
@@ -942,27 +968,305 @@ ppc_elf_howto_init ()
   for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++)
     {
       type = ppc_elf_howto_raw[i].type;
-      BFD_ASSERT (type < sizeof(ppc_elf_howto_table) / sizeof(ppc_elf_howto_table[0]));
+      BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0]));
       ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
     }
 }
+\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 (arg1, arg2)
+     const PTR arg1;
+     const PTR arg2;
+{
+  const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1;
+  const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2;
+
+  /* Sort by offset.  */
+  return ((*rela1)->r_offset - (*rela2)->r_offset);
+}
+
+static boolean
+ppc_elf_relax_section (abfd, isec, link_info, again)
+     bfd *abfd;
+     asection *isec;
+     struct bfd_link_info *link_info;
+     boolean *again;
+{
+#define PAGESIZE 0x1000
+
+  bfd_byte *contents = NULL;
+  bfd_byte *free_contents = NULL;
+  Elf_Internal_Rela *internal_relocs = NULL;
+  Elf_Internal_Rela *free_relocs = NULL;
+  Elf_Internal_Rela **rela_comb = NULL;
+  int comb_curr, comb_count;
+
+  /* We never have to do this more than once per input section.  */
+  *again = false;
+
+  /* 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)
+    {
+      bfd_vma dot, end_page, end_section;
+      boolean section_modified;
+
+      /* 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
+       {
+         /* Go get them off disk.  */
+         contents = (bfd_byte *) 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;
+       }
+
+      comb_curr = 0;
+      comb_count = 0;
+      if (isec->reloc_count)
+       {
+          unsigned n;
+         bfd_size_type amt;
+
+          /* Get a copy of the native relocations.  */
+          internal_relocs = _bfd_elf32_link_read_relocs (
+           abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) 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 = (Elf_Internal_Rela**) bfd_malloc (amt);
+          if (rela_comb == NULL)
+              goto error_return;
+          for (n = 0; n < isec->reloc_count; ++n)
+            {
+              long r_type;
+
+              r_type = ELF32_R_TYPE (internal_relocs[n].r_info);
+              if (r_type < 0 || r_type >= (int) R_PPC_max)
+                  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:     /* absolute, predicted not taken */
+                case R_PPC_REL14:               /* relative cond. br.  */
+                case R_PPC_REL14_BRNTAKEN:      /* rel. cond. br., predicted not taken */
+                  /* 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);
+       }
+
+      /* 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;
+      if (dot < isec->vma)      /* Increment the start position if this section */
+          dot = isec->vma;      /* begins in the middle of its first EOP region.  */
+      for (;
+           dot < end_section;
+           dot += PAGESIZE, end_page += PAGESIZE)
+        {
+
+          /* Check each word in this EOP region.  */
+          for (; dot < end_page; dot += 4)
+            {
+              bfd_vma isec_offset;
+              unsigned long insn;
+              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;
+
+                  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;               /*extract*/
+                      target = (target ^ 0x8000) - 0x8000;      /*sign extend*/
+                      if ((insn & 0x00000002) == 0)
+                          target += dot;                        /*convert to abs*/
+                      if (target > dot)
+                        {
+                          insn |= 0x00200000;   /* set the prediction bit */
+                          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;   /* set the prediction bit */
+                      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;   /* set the prediction bit */
+                      modified = true;
+                   }
+                }
+#undef BO0
+#undef BO2
+#undef BO4
+              if (modified)
+               {
+                  bfd_put_32 (abfd, (bfd_vma) insn, contents + isec_offset);
+                 section_modified = true;
+               }
+            }
+        }
+      if (section_modified)
+       {
+         elf_section_data (isec)->this_hdr.contents = contents;
+         free_contents = NULL;
+       }
+    }
+
+  if (rela_comb != NULL)
+    {
+      free (rela_comb);
+      rela_comb = NULL;
+    }
+
+  if (free_relocs != NULL)
+    {
+      free (free_relocs);
+      free_relocs = NULL;
+    }
+
+  if (free_contents != NULL)
+    {
+      if (! link_info->keep_memory)
+       free (free_contents);
+      else
+       {
+         /* Cache the section contents for elf_link_input_bfd.  */
+         elf_section_data (isec)->this_hdr.contents = contents;
+       }
+      free_contents = NULL;
+    }
+
+  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);
+  return false;
+}
 \f
 static reloc_howto_type *
 ppc_elf_reloc_type_lookup (abfd, code)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      bfd_reloc_code_real_type code;
 {
   enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE;
 
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed */
+    /* Initialize howto table if needed */
     ppc_elf_howto_init ();
 
-  switch ((int)code)
+  switch ((int) code)
     {
     default:
-      return (reloc_howto_type *)NULL;
+      return (reloc_howto_type *) NULL;
 
     case BFD_RELOC_NONE:               ppc_reloc = R_PPC_NONE;                 break;
     case BFD_RELOC_32:                 ppc_reloc = R_PPC_ADDR32;               break;
@@ -993,7 +1297,7 @@ ppc_elf_reloc_type_lookup (abfd, code)
     case BFD_RELOC_HI16_PLTOFF:                ppc_reloc = R_PPC_PLT16_HI;             break;
     case BFD_RELOC_HI16_S_PLTOFF:      ppc_reloc = R_PPC_PLT16_HA;             break;
     case BFD_RELOC_GPREL16:            ppc_reloc = R_PPC_SDAREL16;             break;
-    case BFD_RELOC_32_BASEREL:         ppc_reloc = R_PPC_SECTOFF;              break;
+    case BFD_RELOC_16_BASEREL:         ppc_reloc = R_PPC_SECTOFF;              break;
     case BFD_RELOC_LO16_BASEREL:       ppc_reloc = R_PPC_SECTOFF_LO;           break;
     case BFD_RELOC_HI16_BASEREL:       ppc_reloc = R_PPC_SECTOFF_HI;           break;
     case BFD_RELOC_HI16_S_BASEREL:     ppc_reloc = R_PPC_SECTOFF_HA;           break;
@@ -1019,18 +1323,19 @@ ppc_elf_reloc_type_lookup (abfd, code)
     case BFD_RELOC_VTABLE_ENTRY:       ppc_reloc = R_PPC_GNU_VTENTRY;          break;
     }
 
-  return ppc_elf_howto_table[ (int)ppc_reloc ];
+  return ppc_elf_howto_table[(int) ppc_reloc];
 };
 
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
 ppc_elf_info_to_howto (abfd, cache_ptr, dst)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *cache_ptr;
      Elf32_Internal_Rela *dst;
 {
-  if (!ppc_elf_howto_table[ R_PPC_ADDR32 ])    /* Initialize howto table if needed */
+  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);
@@ -1042,13 +1347,13 @@ ppc_elf_info_to_howto (abfd, cache_ptr, dst)
 static bfd_reloc_status_type
 ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
                         output_bfd, error_message)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *reloc_entry;
      asymbol *symbol;
-     PTR data;
+     PTR data ATTRIBUTE_UNUSED;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   bfd_vma relocation;
 
@@ -1075,7 +1380,7 @@ ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
   return bfd_reloc_continue;
 }
 
-/* Function to set whether a module needs the -mrelocatable bit set. */
+/* Function to set whether a module needs the -mrelocatable bit set.  */
 
 static boolean
 ppc_elf_set_private_flags (abfd, flags)
@@ -1090,24 +1395,6 @@ ppc_elf_set_private_flags (abfd, flags)
   return true;
 }
 
-/* Copy backend specific data from one object module to another */
-static boolean
-ppc_elf_copy_private_bfd_data (ibfd, obfd)
-     bfd *ibfd;
-     bfd *obfd;
-{
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return true;
-
-  BFD_ASSERT (!elf_flags_init (obfd)
-             || elf_elfheader (obfd)->e_flags == elf_elfheader (ibfd)->e_flags);
-
-  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
-  elf_flags_init (obfd) = true;
-  return true;
-}
-
 /* Merge backend specific data from an object file to the output
    object file when linking */
 static boolean
@@ -1120,21 +1407,8 @@ ppc_elf_merge_private_bfd_data (ibfd, obfd)
   boolean error;
 
   /* Check if we have the same endianess */
-  if (ibfd->xvec->byteorder != obfd->xvec->byteorder
-      && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
-    {
-      const char *msg;
-
-      if (bfd_big_endian (ibfd))
-       msg = _("%s: compiled for a big endian system and target is little endian");
-      else
-       msg = _("%s: compiled for a little endian system and target is big endian");
-
-      (*_bfd_error_handler) (msg, bfd_get_filename (ibfd));
-
-      bfd_set_error (bfd_error_wrong_format);
-      return false;
-    }
+  if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
+    return false;
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
@@ -1162,7 +1436,7 @@ ppc_elf_merge_private_bfd_data (ibfd, obfd)
          error = true;
          (*_bfd_error_handler)
            (_("%s: compiled with -mrelocatable and linked with modules compiled normally"),
-            bfd_get_filename (ibfd));
+            bfd_archive_filename (ibfd));
        }
       else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
               && (old_flags & EF_PPC_RELOCATABLE) != 0)
@@ -1170,14 +1444,19 @@ ppc_elf_merge_private_bfd_data (ibfd, obfd)
          error = true;
          (*_bfd_error_handler)
            (_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
-            bfd_get_filename (ibfd));
+            bfd_archive_filename (ibfd));
        }
-      /* If -mrelocatable-lib is linked with an object without -mrelocatable-lib, turn off
-        the -mrelocatable-lib, since at least one module isn't relocatable.  */
-      else if ((old_flags & EF_PPC_RELOCATABLE_LIB) != 0
-              && (new_flags & EF_PPC_RELOCATABLE_LIB) == 0)
+
+      /* The output is -mrelocatable-lib iff both the input files are.  */
+      if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
        elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
 
+      /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
+         but each input file is either -mrelocatable or -mrelocatable-lib.  */
+      if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
+         && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
+         && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
+       elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
 
       /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */
       elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
@@ -1191,7 +1470,7 @@ ppc_elf_merge_private_bfd_data (ibfd, obfd)
          error = true;
          (*_bfd_error_handler)
            (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
-            bfd_get_filename (ibfd), (long)new_flags, (long)old_flags);
+            bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags);
        }
 
       if (error)
@@ -1203,7 +1482,6 @@ ppc_elf_merge_private_bfd_data (ibfd, obfd)
 
   return true;
 }
-
 \f
 /* Handle a PowerPC specific section when reading an object file.  This
    is called when elfcode.h finds a section with an unknown type.  */
@@ -1212,7 +1490,7 @@ static boolean
 ppc_elf_section_from_shdr (abfd, hdr, name)
      bfd *abfd;
      Elf32_Internal_Shdr *hdr;
-     char *name;
+     const char *name;
 {
   asection *newsect;
   flagword flags;
@@ -1231,13 +1509,12 @@ ppc_elf_section_from_shdr (abfd, hdr, name)
   bfd_set_section_flags (abfd, newsect, flags);
   return true;
 }
-
 \f
 /* Set up any other section flags and such that may be necessary.  */
 
 static boolean
 ppc_elf_fake_sections (abfd, shdr, asect)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      Elf32_Internal_Shdr *shdr;
      asection *asect;
 {
@@ -1249,7 +1526,6 @@ ppc_elf_fake_sections (abfd, shdr, asect)
 
   return true;
 }
-
 \f
 /* Create a special linker section */
 static elf_linker_section_t *
@@ -1293,10 +1569,10 @@ ppc_elf_create_linker_section (abfd, info, which)
        default:
          (*_bfd_error_handler) (_("%s: Unknown special linker type %d"),
                                 bfd_get_filename (abfd),
-                                (int)which);
+                                (int) which);
 
          bfd_set_error (bfd_error_bad_value);
-         return (elf_linker_section_t *)0;
+         return (elf_linker_section_t *) 0;
 
        case LINKER_SECTION_SDATA:      /* .sdata/.sbss section */
          defaults.name           = ".sdata";
@@ -1321,10 +1597,9 @@ ppc_elf_create_linker_section (abfd, info, which)
 
   return lsect;
 }
-
 \f
-/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we need to bump up
-   the number of section headers.  */
+/* If we have a non-zero sized .sbss2 or .PPC.EMB.sbss0 sections, we
+   need to bump up the number of section headers.  */
 
 static int
 ppc_elf_additional_program_headers (abfd)
@@ -1350,15 +1625,39 @@ ppc_elf_additional_program_headers (abfd)
   return ret;
 }
 
-/* Modify the segment map if needed */
+/* Modify the segment map if needed */
 
 static boolean
 ppc_elf_modify_segment_map (abfd)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
 {
   return true;
 }
 \f
+/* The powerpc .got has a blrl instruction in it.  Mark it executable.  */
+
+static asection *
+ppc_elf_create_got (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  register asection *s;
+  flagword flags;
+
+  if (!_bfd_elf_create_got_section (abfd, info))
+    return NULL;
+
+  s = bfd_get_section_by_name (abfd, ".got");
+  if (s == NULL)
+    abort ();
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
+  if (!bfd_set_section_flags (abfd, s, flags))
+    return NULL;
+  return s;
+}
+
 /* We have to create .dynsbss and .rela.sbss here so that they get mapped
    to output sections (just like _bfd_elf_create_dynamic_sections has
    to create .dynbss and .rela.bss).  */
@@ -1371,7 +1670,10 @@ ppc_elf_create_dynamic_sections (abfd, info)
   register asection *s;
   flagword flags;
 
-  if (!_bfd_elf_create_dynamic_sections(abfd, info))
+  if (!ppc_elf_create_got (abfd, info))
+    return false;
+
+  if (!_bfd_elf_create_dynamic_sections (abfd, info))
     return false;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
@@ -1390,7 +1692,13 @@ ppc_elf_create_dynamic_sections (abfd, info)
          || ! bfd_set_section_alignment (abfd, s, 2))
        return false;
     }
-  return true;
+
+  s = bfd_get_section_by_name (abfd, ".plt");
+  if (s == NULL)
+    abort ();
+
+  flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED;
+  return bfd_set_section_flags (abfd, s, flags);
 }
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
@@ -1424,7 +1732,6 @@ ppc_elf_adjust_dynamic_symbol (info, h)
                      && (h->elf_link_hash_flags
                          & ELF_LINK_HASH_DEF_REGULAR) == 0)));
 
-
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later,
      when we know the address of the .got section.  */
@@ -1432,9 +1739,7 @@ ppc_elf_adjust_dynamic_symbol (info, h)
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
       if (! elf_hash_table (info)->dynamic_sections_created
-         || ((!info->shared || info->symbolic || h->dynindx == -1)
-             && (h->elf_link_hash_flags
-                 & ELF_LINK_HASH_DEF_REGULAR) != 0)
+         || SYMBOL_CALLS_LOCAL (info, h)
          || (info->shared && h->plt.refcount <= 0))
        {
          /* A PLT entry is not required/allowed when:
@@ -1442,9 +1747,8 @@ ppc_elf_adjust_dynamic_symbol (info, h)
             1. We are not using ld.so; because then the PLT entry
             can't be set up, so we can't use one.
 
-            2. We know for certain that a symbol is defined in
-            this object, because this object is the application,
-            is linked with -Bsymbolic, or because the symbol is local.
+            2. We know for certain that a call to this symbol
+            will go to this object.
 
             3. GC has rendered the entry unused.
             Note, however, that in an executable all references to the
@@ -1476,7 +1780,9 @@ ppc_elf_adjust_dynamic_symbol (info, h)
         is 2 words (for a load and a jump), and then there is a remaining
         word available at the end.  */
       plt_offset = (PLT_INITIAL_ENTRY_SIZE
-                   + 8 * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE));
+                   + (PLT_SLOT_SIZE
+                      * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE)
+                         / PLT_ENTRY_SIZE)));
 
       /* If this symbol is not defined in a regular file, and we are
         not generating a shared library, then set the symbol to this
@@ -1492,8 +1798,13 @@ ppc_elf_adjust_dynamic_symbol (info, h)
 
       h->plt.offset = plt_offset;
 
-      /* Make room for this entry.  */
-      s->_raw_size += PLT_ENTRY_SIZE;
+      /* Make room for this entry.  After the 8192nd entry, room
+         for two entries is allocated.  */
+      if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+         >= PLT_NUM_SINGLE_ENTRIES)
+       s->_raw_size += 2 * PLT_ENTRY_SIZE;
+      else
+       s->_raw_size += PLT_ENTRY_SIZE;
 
       /* We also need to make an entry in the .rela.plt section.  */
       s = bfd_get_section_by_name (dynobj, ".rela.plt");
@@ -1502,6 +1813,8 @@ ppc_elf_adjust_dynamic_symbol (info, h)
 
       return true;
     }
+  else
+    h->plt.offset = (bfd_vma) -1;
 
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
@@ -1586,41 +1899,18 @@ ppc_elf_adjust_dynamic_symbol (info, h)
 
   return true;
 }
-
-\f
-/* Increment the index of a dynamic symbol by a given amount.  Called
-   via elf_link_hash_traverse.  */
-
-static boolean
-ppc_elf_adjust_dynindx (h, cparg)
-     struct elf_link_hash_entry *h;
-     PTR cparg;
-{
-  int *cp = (int *) cparg;
-
-#ifdef DEBUG
-  fprintf (stderr, "ppc_elf_adjust_dynindx called, h->dynindx = %d, *cp = %d\n", h->dynindx, *cp);
-#endif
-
-  if (h->dynindx != -1)
-    h->dynindx += *cp;
-
-  return true;
-}
-
 \f
 /* Set the sizes of the dynamic sections.  */
 
 static boolean
 ppc_elf_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *dynobj;
   asection *s;
   boolean plt;
   boolean relocs;
-  boolean reltext;
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_size_dynamic_sections called\n");
@@ -1649,10 +1939,10 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
         stripped from the output file below.  */
       static char *rela_sections[] = { ".rela.got", ".rela.sdata",
                                       ".rela.sdata2", ".rela.sbss",
-                                      (char *)0 };
+                                      (char *) 0 };
       char **p;
 
-      for (p = rela_sections; *p != (char *)0; p++)
+      for (p = rela_sections; *p != (char *) 0; p++)
        {
          s = bfd_get_section_by_name (dynobj, *p);
          if (s != NULL)
@@ -1665,7 +1955,6 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
      memory for them.  */
   plt = false;
   relocs = false;
-  reltext = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
@@ -1711,22 +2000,9 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             asection *target;
-             const char *outname;
-
-             /* Remember whether there are any relocation sections. */
+             /* Remember whether there are any relocation sections.  */
              relocs = true;
 
-             /* If this relocation section applies to a read only
-                section, then we probably need a DT_TEXTREL entry.  */
-             outname = bfd_get_section_name (output_bfd,
-                                             s->output_section);
-             target = bfd_get_section_by_name (output_bfd, outname + 5);
-             if (target != NULL
-                 && (target->flags & SEC_READONLY) != 0
-                 && (target->flags & SEC_ALLOC) != 0)
-               reltext = true;
-
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
              s->reloc_count = 0;
@@ -1742,15 +2018,7 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
 
       if (strip)
        {
-         asection **spp;
-
-         for (spp = &s->output_section->owner->sections;
-              *spp != s->output_section;
-              spp = &(*spp)->next)
-           ;
-         *spp = s->output_section->next;
-         --s->output_section->owner->section_count;
-
+         _bfd_strip_section_from_output (info, s);
          continue;
        }
 
@@ -1767,77 +2035,43 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
         must add the entries now so that we get the correct size for
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
-      if (! info->shared)
+#define add_dynamic_entry(TAG, VAL) \
+  bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+      if (!info->shared)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+         if (!add_dynamic_entry (DT_DEBUG, 0))
            return false;
        }
 
       if (plt)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_JMPREL, 0))
+         if (!add_dynamic_entry (DT_PLTGOT, 0)
+             || !add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
            return false;
        }
 
       if (relocs)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_RELA, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_RELASZ, 0)
-             || ! bfd_elf32_add_dynamic_entry (info, DT_RELAENT,
-                                               sizeof (Elf32_External_Rela)))
+         if (!add_dynamic_entry (DT_RELA, 0)
+             || !add_dynamic_entry (DT_RELASZ, 0)
+             || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
            return false;
        }
 
-      if (reltext)
+      if ((info->flags & DF_TEXTREL) != 0)
        {
-         if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
            return false;
+         info->flags |= DF_TEXTREL;
        }
     }
-
-  /* If we are generating a shared library, we generate a section
-     symbol for each output section.  These are local symbols, which
-     means that they must come first in the dynamic symbol table.
-     That means we must increment the dynamic symbol index of every
-     other dynamic symbol.
-
-     FIXME: We assume that there will never be relocations to
-     locations in linker-created sections that do not have
-     externally-visible names. Instead, we should work out precisely
-     which sections relocations are targetted at.  */
-  if (info->shared)
-    {
-      int c;
-
-      for (c = 0, s = output_bfd->sections; s != NULL; s = s->next)
-       {
-         if ((s->flags & SEC_LINKER_CREATED) != 0
-             || (s->flags & SEC_ALLOC) == 0)
-           {
-             elf_section_data (s)->dynindx = -1;
-             continue;
-           }
-
-         /* These symbols will have no names, so we don't need to
-            fiddle with dynstr_index.  */
-
-         elf_section_data (s)->dynindx = c + 1;
-
-         c++;
-       }
-
-      elf_link_hash_traverse (elf_hash_table (info),
-                             ppc_elf_adjust_dynindx,
-                             (PTR) &c);
-      elf_hash_table (info)->dynsymcount += c;
-    }
+#undef add_dynamic_entry
 
   return true;
 }
-
 \f
 /* Look through the relocs for a section during the first phase, and
    allocate space in the global offset table or procedure linkage
@@ -1868,7 +2102,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_check_relocs called for section %s in %s\n",
           bfd_get_section_name (abfd, sec),
-          bfd_get_filename (abfd));
+          bfd_archive_filename (abfd));
 #endif
 
   /* Create the linker generated sections all the time so that the
@@ -1881,7 +2115,6 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
        return false;
     }
 
-
   if ((sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2)) == NULL)
     {
       sdata2 = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA2);
@@ -1894,7 +2127,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
   if (!elf_bad_symtab (abfd))
     sym_hashes_end -= symtab_hdr->sh_info;
 
@@ -1921,10 +2154,9 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
            {
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
-             if (! _bfd_elf_create_got_section (dynobj, info))
+             sgot = ppc_elf_create_got (dynobj, info);
+             if (sgot == NULL)
                return false;
-             sgot = bfd_get_section_by_name (dynobj, ".got");
-             BFD_ASSERT (sgot != NULL);
            }
        }
 
@@ -1941,10 +2173,9 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
            {
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
-             if (! _bfd_elf_create_got_section (dynobj, info))
+             sgot = ppc_elf_create_got (dynobj, info);
+             if (sgot == NULL)
                return false;
-             sgot = bfd_get_section_by_name (dynobj, ".got");
-             BFD_ASSERT (sgot != NULL);
            }
 
          if (srelgot == NULL
@@ -1969,7 +2200,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
 
          if (h != NULL)
            {
-             if (h->got.refcount == -1)
+             if (h->got.refcount == 0)
                {
                  /* Make sure this symbol is output as a dynamic symbol.  */
                  if (h->dynindx == -1)
@@ -1980,29 +2211,25 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
                  sgot->_raw_size += 4;
                  /* Allocate relocation space.  */
                  srelgot->_raw_size += sizeof (Elf32_External_Rela);
-
-                 h->got.refcount = 1;
                }
-             else
-               h->got.refcount++;
+             h->got.refcount++;
            }
          else
            {
              /* This is a global offset table entry for a local symbol.  */
              if (local_got_refcounts == NULL)
                {
-                 size_t size;
-                 register unsigned int i;
+                 bfd_size_type size;
 
-                 size = symtab_hdr->sh_info * sizeof (bfd_signed_vma);
-                 local_got_refcounts = (bfd_signed_vma *)
-                   bfd_alloc (abfd, size);
+                 size = symtab_hdr->sh_info;
+                 size *= sizeof (bfd_signed_vma);
+                 local_got_refcounts
+                   = (bfd_signed_vma *) bfd_zalloc (abfd, size);
                  if (local_got_refcounts == NULL)
                    return false;
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
-                 memset (local_got_refcounts, -1, size);
                }
-             if (local_got_refcounts[r_symndx] == -1)
+             if (local_got_refcounts[r_symndx] == 0)
                {
                  sgot->_raw_size += 4;
 
@@ -2011,11 +2238,8 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
                      dynamic linker can adjust this GOT entry.  */
                  if (info->shared)
                    srelgot->_raw_size += sizeof (Elf32_External_Rela);
-
-                 local_got_refcounts[r_symndx] = 1;
                }
-             else
-               local_got_refcounts[r_symndx]++;
+             local_got_refcounts[r_symndx]++;
            }
          break;
 
@@ -2025,8 +2249,8 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
            {
              ((*_bfd_error_handler)
               (_("%s: relocation %s cannot be used when making a shared object"),
-               bfd_get_filename (abfd), "R_PPC_EMB_SDAI16"));
-              return false;
+               bfd_archive_filename (abfd), "R_PPC_EMB_SDAI16"));
+             return false;
            }
 
          if (srelgot == NULL && (h != NULL || info->shared))
@@ -2059,7 +2283,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
            {
              ((*_bfd_error_handler)
               (_("%s: relocation %s cannot be used when making a shared object"),
-               bfd_get_filename (abfd), "R_PPC_EMB_SDA2I16"));
+               bfd_archive_filename (abfd), "R_PPC_EMB_SDA2I16"));
              return false;
            }
 
@@ -2094,8 +2318,8 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
            {
              ((*_bfd_error_handler)
               (_("%s: relocation %s cannot be used when making a shared object"),
-               bfd_get_filename (abfd),
-               ppc_elf_howto_table[(int)ELF32_R_TYPE (rel->r_info)]->name));
+               bfd_archive_filename (abfd),
+               ppc_elf_howto_table[(int) ELF32_R_TYPE (rel->r_info)]->name));
              return false;
            }
          break;
@@ -2128,13 +2352,8 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
              if (! bfd_elf32_link_record_dynamic_symbol (info, h))
                return false;
            }
-         if (h->plt.refcount == -1)
-           {
-             h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-             h->plt.refcount = 1;
-           }
-         else
-           h->plt.refcount++;
+         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+         h->plt.refcount++;
          break;
 
          /* The following relocations don't need to propagate the
@@ -2173,7 +2392,8 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
        case R_PPC_REL14_BRNTAKEN:
        case R_PPC_REL32:
          if (h == NULL
-             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+             || SYMBOL_REFERENCES_LOCAL (info, h))
            break;
          /* fall through */
 
@@ -2214,6 +2434,8 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf32_External_Rela);
@@ -2239,7 +2461,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
 static asection *
 ppc_elf_gc_mark_hook (abfd, info, rel, h, sym)
      bfd *abfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      Elf_Internal_Rela *rel;
      struct elf_link_hash_entry *h;
      Elf_Internal_Sym *sym;
@@ -2261,18 +2483,15 @@ ppc_elf_gc_mark_hook (abfd, info, rel, h, sym)
 
            case bfd_link_hash_common:
              return h->root.u.c.p->section;
+
+           default:
+             break;
            }
        }
     }
   else
     {
-      if (!(elf_bad_symtab (abfd)
-           && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
-         && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
-               && sym->st_shndx != SHN_COMMON))
-       {
-         return bfd_section_from_elf_index (abfd, sym->st_shndx);
-       }
+      return bfd_section_from_elf_index (abfd, sym->st_shndx);
     }
 
   return NULL;
@@ -2283,7 +2502,7 @@ ppc_elf_gc_mark_hook (abfd, info, rel, h, sym)
 static boolean
 ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
      bfd *abfd;
-     struct bfd_link_info *info;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
      asection *sec;
      const Elf_Internal_Rela *relocs;
 {
@@ -2313,7 +2532,7 @@ ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
            if (h->got.refcount > 0)
              h->got.refcount--;
          }
-       else
+       else if (local_got_refcounts != NULL)
          {
            if (local_got_refcounts[r_symndx] > 0)
              local_got_refcounts[r_symndx]--;
@@ -2344,20 +2563,20 @@ ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
 /* Hook called by the linker routine which adds symbols from an object
    file.  We use it to put .comm items in .sbss, and not .bss.  */
 
-/*ARGSUSED*/
 static boolean
 ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
      bfd *abfd;
      struct bfd_link_info *info;
      const Elf_Internal_Sym *sym;
-     const char **namep;
-     flagword *flagsp;
+     const char **namep ATTRIBUTE_UNUSED;
+     flagword *flagsp ATTRIBUTE_UNUSED;
      asection **secp;
      bfd_vma *valp;
 {
   if (sym->st_shndx == SHN_COMMON
       && !info->relocateable
-      && sym->st_size <= (bfd_vma) bfd_get_gp_size (abfd))
+      && sym->st_size <= elf_gp_size (abfd)
+      && info->hash->creator->flavour == bfd_target_elf_flavour)
     {
       /* Common symbols less than or equal to -G nn bytes are automatically
         put into .sdata.  */
@@ -2366,21 +2585,24 @@ ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 
       if (!sdata->bss_section)
        {
+         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.  */
-         sdata->bss_section = ((asection *)
-                               bfd_zalloc (abfd, sizeof (asection)));
+         amt = sizeof (asection);
+         sdata->bss_section = (asection *) 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;
-         sdata->bss_section->symbol =
-           (asymbol *) bfd_zalloc (abfd, sizeof (asymbol));
+         amt = sizeof (asymbol);
+         sdata->bss_section->symbol = (asymbol *) bfd_zalloc (abfd, amt);
+         amt = sizeof (asymbol *);
          sdata->bss_section->symbol_ptr_ptr =
-           (asymbol **) bfd_zalloc (abfd, sizeof (asymbol *));
+           (asymbol **) bfd_zalloc (abfd, amt);
          if (sdata->bss_section->symbol == NULL
              || sdata->bss_section->symbol_ptr_ptr == NULL)
            return false;
@@ -2396,7 +2618,6 @@ ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
 
   return true;
 }
-
 \f
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
@@ -2423,6 +2644,7 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
       asection *splt;
       asection *srela;
       Elf_Internal_Rela rela;
+      bfd_vma reloc_index;
 
 #ifdef DEBUG
       fprintf (stderr, ", plt_offset = %d", h->plt.offset);
@@ -2446,15 +2668,26 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
                       + h->plt.offset);
       rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
       rela.r_addend = 0;
+
+      reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE;
+      if (reloc_index > PLT_NUM_SINGLE_ENTRIES)
+       reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
       bfd_elf32_swap_reloca_out (output_bfd, &rela,
                                 ((Elf32_External_Rela *) srela->contents
-                                 + ((h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / 8)));
+                                 + reloc_index));
 
       if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
        {
          /* Mark the symbol as undefined, rather than as defined in
             the .plt section.  Leave the value alone.  */
          sym->st_shndx = SHN_UNDEF;
+         /* If the symbol is weak, we do need to clear the value.
+            Otherwise, the PLT entry would provide a definition for
+            the symbol even if the symbol wasn't defined anywhere,
+            and so the symbol would never be NULL.  */
+         if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
+             == 0)
+           sym->st_value = 0;
        }
     }
 
@@ -2473,15 +2706,14 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
       rela.r_offset = (sgot->output_section->vma
                       + sgot->output_offset
-                      + (h->got.offset &~ 1));
+                      + (h->got.offset &~ (bfd_vma) 1));
 
       /* If this is a -Bsymbolic link, and the symbol is defined
         locally, we just want to emit a RELATIVE reloc.  The entry in
         the global offset table will already have been initialized in
         the relocate_section function.  */
       if (info->shared
-         && (info->symbolic || h->dynindx == -1)
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+         && SYMBOL_REFERENCES_LOCAL (info, h))
        {
          rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
          rela.r_addend = (h->root.u.def.value
@@ -2490,7 +2722,7 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
        }
       else
        {
-         BFD_ASSERT((h->got.offset & 1) == 0);
+         BFD_ASSERT ((h->got.offset & 1) == 0);
          bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset);
          rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_GLOB_DAT);
          rela.r_addend = 0;
@@ -2546,7 +2778,6 @@ ppc_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
 
   return true;
 }
-
 \f
 /* Finish up the dynamic sections.  */
 
@@ -2620,7 +2851,7 @@ ppc_elf_finish_dynamic_sections (output_bfd, info)
   if (sgot)
     {
       unsigned char *contents = sgot->contents;
-      bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, contents);
+      bfd_put_32 (output_bfd, (bfd_vma) 0x4e800021 /* blrl */, contents);
 
       if (sdyn == NULL)
        bfd_put_32 (output_bfd, (bfd_vma) 0, contents+4);
@@ -2632,57 +2863,8 @@ ppc_elf_finish_dynamic_sections (output_bfd, info)
       elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
     }
 
-  if (info->shared)
-    {
-      asection *sdynsym;
-      asection *s;
-      Elf_Internal_Sym sym;
-      int maxdindx = 0;
-
-      /* Set up the section symbols for the output sections.  */
-
-      sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
-      BFD_ASSERT (sdynsym != NULL);
-
-      sym.st_size = 0;
-      sym.st_name = 0;
-      sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
-      sym.st_other = 0;
-
-      for (s = output_bfd->sections; s != NULL; s = s->next)
-       {
-         int indx, dindx;
-
-         sym.st_value = s->vma;
-
-         indx = elf_section_data (s)->this_idx;
-         dindx = elf_section_data (s)->dynindx;
-         if (dindx != -1)
-           {
-             BFD_ASSERT(indx > 0);
-             BFD_ASSERT(dindx > 0);
-
-             if (dindx > maxdindx)
-               maxdindx = dindx;
-
-             sym.st_shndx = indx;
-
-             bfd_elf32_swap_symbol_out (output_bfd, &sym,
-                                        (PTR) (((Elf32_External_Sym *)
-                                                sdynsym->contents)
-                                               + dindx));
-           }
-       }
-
-      /* Set the sh_info field of the output .dynsym section to the
-         index of the first global symbol.  */
-      elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
-       maxdindx + 1;
-    }
-
   return true;
 }
-
 \f
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
@@ -2741,13 +2923,17 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_relocate_section called for %s section %s, %ld relocations%s\n",
-          bfd_get_filename (input_bfd),
+          bfd_archive_filename (input_bfd),
           bfd_section_name(input_bfd, input_section),
-          (long)input_section->reloc_count,
+          (long) input_section->reloc_count,
           (info->relocateable) ? " (relocatable)" : "");
 #endif
 
-  if (!ppc_elf_howto_table[ R_PPC_ADDR32 ])    /* Initialize howto table if needed */
+  if (info->relocateable)
+    return true;
+
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   local_got_offsets = elf_local_got_offsets (input_bfd);
@@ -2765,66 +2951,41 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_vma offset                   = rel->r_offset;
       bfd_vma addend                   = rel->r_addend;
       bfd_reloc_status_type r          = bfd_reloc_other;
-      Elf_Internal_Sym *sym            = (Elf_Internal_Sym *)0;
-      asection *sec                    = (asection *)0;
-      struct elf_link_hash_entry *h    = (struct elf_link_hash_entry *)0;
-      const char *sym_name             = (const char *)0;
+      Elf_Internal_Sym *sym            = (Elf_Internal_Sym *) 0;
+      asection *sec                    = (asection *) 0;
+      struct elf_link_hash_entry *h    = (struct elf_link_hash_entry *) 0;
+      const char *sym_name             = (const char *) 0;
       reloc_howto_type *howto;
       unsigned long r_symndx;
       bfd_vma relocation;
+      int will_become_local;
 
       /* Unknown relocation handling */
-      if ((unsigned)r_type >= (unsigned)R_PPC_max || !ppc_elf_howto_table[(int)r_type])
+      if ((unsigned) r_type >= (unsigned) R_PPC_max
+         || !ppc_elf_howto_table[(int) r_type])
        {
          (*_bfd_error_handler) (_("%s: unknown relocation type %d"),
-                                bfd_get_filename (input_bfd),
-                                (int)r_type);
+                                bfd_archive_filename (input_bfd),
+                                (int) r_type);
 
          bfd_set_error (bfd_error_bad_value);
          ret = false;
          continue;
        }
 
-      howto = ppc_elf_howto_table[(int)r_type];
+      howto = ppc_elf_howto_table[(int) r_type];
       r_symndx = ELF32_R_SYM (rel->r_info);
 
-      if (info->relocateable)
-       {
-         /* This is a relocateable link.  We don't have to change
-            anything, unless the reloc is against a section symbol,
-            in which case we have to adjust according to where the
-            section symbol winds up in the output section.  */
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             sym = local_syms + r_symndx;
-             if ((unsigned)ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-               {
-                 sec = local_sections[r_symndx];
-                 addend = rel->r_addend += sec->output_offset + sym->st_value;
-               }
-           }
-
-#ifdef DEBUG
-         fprintf (stderr, "\ttype = %s (%d), symbol index = %ld, offset = %ld, addend = %ld\n",
-                  howto->name,
-                  (int)r_type,
-                  r_symndx,
-                  (long)offset,
-                  (long)addend);
-#endif
-         continue;
-       }
-
-      /* This is a final link.  */
       if (r_symndx < symtab_hdr->sh_info)
        {
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
          sym_name = "<local symbol>";
 
-         relocation = (sec->output_section->vma
-                       + sec->output_offset
-                       + sym->st_value);
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+         addend = rel->r_addend;
+         /* Relocs to local symbols are always resolved.  */
+         will_become_local = 1;
        }
       else
        {
@@ -2833,11 +2994,17 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
          sym_name = h->root.root.string;
+
+         /* Can this relocation be resolved immediately?  */
+         will_become_local = SYMBOL_REFERENCES_LOCAL (info, h);
+
          if (h->root.type == bfd_link_hash_defined
              || h->root.type == bfd_link_hash_defweak)
            {
              sec = h->root.u.def.section;
-             if ((r_type == R_PPC_PLT32
+             if (((r_type == R_PPC_PLT32
+                   || r_type == R_PPC_PLTREL24)
+                  && splt != NULL
                   && h->plt.offset != (bfd_vma) -1)
                  || (r_type == R_PPC_LOCAL24PC
                      && sec->output_section == NULL)
@@ -2846,15 +3013,17 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                       || r_type == R_PPC_GOT16_HI
                       || r_type == R_PPC_GOT16_HA)
                      && elf_hash_table (info)->dynamic_sections_created
-                     && (! info->shared
-                         || (! info->symbolic && h->dynindx != -1)
-                         || (h->elf_link_hash_flags
-                             & ELF_LINK_HASH_DEF_REGULAR) == 0))
+                     && (! info->shared || ! will_become_local))
                  || (info->shared
-                     && ((! info->symbolic && h->dynindx != -1)
-                         || (h->elf_link_hash_flags
-                             & ELF_LINK_HASH_DEF_REGULAR) == 0)
-                     && (input_section->flags & SEC_ALLOC) != 0
+                     && ! will_become_local
+                     && ((input_section->flags & SEC_ALLOC) != 0
+                         /* Testing SEC_DEBUGGING here may be wrong.
+                             It's here to avoid a crash when
+                             generating a shared library with DWARF
+                             debugging information.  */
+                         || ((input_section->flags & SEC_DEBUGGING) != 0
+                             && (h->elf_link_hash_flags
+                                 & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
                      && (r_type == R_PPC_ADDR32
                          || r_type == R_PPC_ADDR24
                          || r_type == R_PPC_ADDR16
@@ -2864,7 +3033,6 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                          || r_type == R_PPC_ADDR14
                          || r_type == R_PPC_ADDR14_BRTAKEN
                          || r_type == R_PPC_ADDR14_BRNTAKEN
-                         || r_type == R_PPC_PLTREL24
                          || r_type == R_PPC_COPY
                          || r_type == R_PPC_GLOB_DAT
                          || r_type == R_PPC_JMP_SLOT
@@ -2897,6 +3065,14 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      obscure cases sec->output_section will be NULL.  */
                  relocation = 0;
                }
+             else if (sec->output_section == NULL)
+               {
+                  (*_bfd_error_handler)
+                    (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
+                     bfd_archive_filename (input_bfd), h->root.root.string,
+                     bfd_get_section_name (input_bfd, input_section));
+                 relocation = 0;
+               }
              else
                relocation = (h->root.u.def.value
                              + sec->output_section->vma
@@ -2904,33 +3080,42 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          else if (h->root.type == bfd_link_hash_undefweak)
            relocation = 0;
-         else if (info->shared)
+         else if (info->shared
+                  && (!info->symbolic || info->allow_shlib_undefined)
+                  && !info->no_undefined
+                  && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
            relocation = 0;
          else
            {
-             (*info->callbacks->undefined_symbol)(info,
-                                                  h->root.root.string,
-                                                  input_bfd,
-                                                  input_section,
-                                                  rel->r_offset);
-             ret = false;
-             continue;
+             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;
+             relocation = 0;
            }
        }
 
-      switch ((int)r_type)
+      switch ((int) r_type)
        {
        default:
          (*_bfd_error_handler) (_("%s: unknown relocation type %d for symbol %s"),
-                                bfd_get_filename (input_bfd),
-                                (int)r_type, sym_name);
+                                bfd_archive_filename (input_bfd),
+                                (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
          ret = false;
          continue;
 
+       case (int) R_PPC_NONE:
+         continue;
+
        /* Relocations that need no special processing.  */
-       case (int)R_PPC_LOCAL24PC:
+       case (int) R_PPC_LOCAL24PC:
          /* It makes no sense to point a local relocation
             at a symbol not in this object.  */
          if (h != NULL
@@ -2938,44 +3123,45 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  || h->root.type == bfd_link_hash_defweak)
              && sec->output_section == NULL)
            {
-             (*info->callbacks->undefined_symbol) (info,
-                                                   h->root.root.string,
-                                                   input_bfd,
-                                                   input_section,
-                                                   rel->r_offset);
-             ret = false;
+             if (! (*info->callbacks->undefined_symbol) (info,
+                                                         h->root.root.string,
+                                                         input_bfd,
+                                                         input_section,
+                                                         rel->r_offset,
+                                                         true))
+               return false;
              continue;
            }
          break;
 
        /* Relocations that may need to be propagated if this is a shared
            object.  */
-       case (int)R_PPC_REL24:
-       case (int)R_PPC_REL32:
-       case (int)R_PPC_REL14:
+       case (int) R_PPC_REL24:
+       case (int) R_PPC_REL32:
+       case (int) R_PPC_REL14:
          /* 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)
+             || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+             || SYMBOL_REFERENCES_LOCAL (info, h))
            break;
        /* fall through */
 
        /* Relocations that always need to be propagated if this is a shared
            object.  */
-       case (int)R_PPC_NONE:
-       case (int)R_PPC_ADDR32:
-       case (int)R_PPC_ADDR24:
-       case (int)R_PPC_ADDR16:
-       case (int)R_PPC_ADDR16_LO:
-       case (int)R_PPC_ADDR16_HI:
-       case (int)R_PPC_ADDR16_HA:
-       case (int)R_PPC_ADDR14:
-       case (int)R_PPC_UADDR32:
-       case (int)R_PPC_UADDR16:
-         if (info->shared)
+       case (int) R_PPC_ADDR32:
+       case (int) R_PPC_ADDR24:
+       case (int) R_PPC_ADDR16:
+       case (int) R_PPC_ADDR16_LO:
+       case (int) R_PPC_ADDR16_HI:
+       case (int) R_PPC_ADDR16_HA:
+       case (int) R_PPC_ADDR14:
+       case (int) R_PPC_UADDR32:
+       case (int) R_PPC_UADDR16:
+         if (info->shared && r_symndx != 0)
            {
              Elf_Internal_Rela outrel;
-             boolean skip;
+             int skip;
 
 #ifdef DEBUG
              fprintf (stderr, "ppc_elf_relocate_section need to create relocation for %s\n",
@@ -3006,24 +3192,14 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  BFD_ASSERT (sreloc != NULL);
                }
 
-             skip = false;
-
-             if (elf_section_data (input_section)->stab_info == NULL)
-               outrel.r_offset = rel->r_offset;
-             else
-               {
-                 bfd_vma off;
-
-                 off = (_bfd_stab_section_offset
-                        (output_bfd, &elf_hash_table (info)->stab_info,
-                         input_section,
-                         &elf_section_data (input_section)->stab_info,
-                         rel->r_offset));
-                 if (off == (bfd_vma) -1)
-                   skip = true;
-                 outrel.r_offset = off;
-               }
+             skip = 0;
 
+             outrel.r_offset =
+               _bfd_elf_section_offset (output_bfd, info, input_section,
+                                        rel->r_offset);
+             if (outrel.r_offset == (bfd_vma) -1
+                 || outrel.r_offset == (bfd_vma) -2)
+               skip = (int) outrel.r_offset;
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
 
@@ -3031,12 +3207,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                memset (&outrel, 0, sizeof outrel);
              /* h->dynindx may be -1 if this symbol was marked to
                  become local.  */
-             else if (h != NULL
-                      && ((! info->symbolic && h->dynindx != -1)
-                          || (h->elf_link_hash_flags
-                              & ELF_LINK_HASH_DEF_REGULAR) == 0))
+             else if (! will_become_local)
                {
-                 BFD_ASSERT (h->dynindx != -1);
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
                  outrel.r_addend = rel->r_addend;
                }
@@ -3073,11 +3245,11 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
                          osec = sec->output_section;
                          indx = elf_section_data (osec)->dynindx;
-                         BFD_ASSERT(indx > 0);
+                         BFD_ASSERT (indx > 0);
 #ifdef DEBUG
                          if (indx <= 0)
                            {
-                             printf("indx=%d section=%s flags=%08x name=%s\n",
+                             printf ("indx=%d section=%s flags=%08x name=%s\n",
                                     indx, osec->name, osec->flags,
                                     h->root.root.string);
                            }
@@ -3098,7 +3270,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              /* This reloc will be computed at runtime, so there's no
                  need to do anything now, unless this is a RELATIVE
                  reloc in an unallocated section.  */
-             if (skip
+             if (skip != -1
                  || (input_section->flags & SEC_ALLOC) != 0
                  || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)
                continue;
@@ -3118,32 +3290,32 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          break;
 
        /* branch taken prediction relocations */
-       case (int)R_PPC_ADDR14_BRTAKEN:
-       case (int)R_PPC_REL14_BRTAKEN:
+       case (int) R_PPC_ADDR14_BRTAKEN:
+       case (int) R_PPC_REL14_BRTAKEN:
          insn = bfd_get_32 (output_bfd, contents + offset);
          if ((relocation - offset) & 0x8000)
            insn &= ~BRANCH_PREDICT_BIT;
          else
            insn |= BRANCH_PREDICT_BIT;
-         bfd_put_32 (output_bfd, insn, contents + offset);
+         bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
          break;
 
        /* branch not taken predicition relocations */
-       case (int)R_PPC_ADDR14_BRNTAKEN:
-       case (int)R_PPC_REL14_BRNTAKEN:
+       case (int) R_PPC_ADDR14_BRNTAKEN:
+       case (int) R_PPC_REL14_BRNTAKEN:
          insn = bfd_get_32 (output_bfd, contents + offset);
          if ((relocation - offset) & 0x8000)
            insn |= BRANCH_PREDICT_BIT;
          else
            insn &= ~BRANCH_PREDICT_BIT;
-         bfd_put_32 (output_bfd, insn, contents + offset);
+         bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
          break;
 
        /* GOT16 relocations */
-       case (int)R_PPC_GOT16:
-       case (int)R_PPC_GOT16_LO:
-       case (int)R_PPC_GOT16_HI:
-       case (int)R_PPC_GOT16_HA:
+       case (int) R_PPC_GOT16:
+       case (int) R_PPC_GOT16_LO:
+       case (int) R_PPC_GOT16_HI:
+       case (int) R_PPC_GOT16_HA:
          /* Relocation is to the entry for this symbol in the global
              offset table.  */
          BFD_ASSERT (sgot != NULL);
@@ -3157,8 +3329,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              if (! elf_hash_table (info)->dynamic_sections_created
                  || (info->shared
-                     && (info->symbolic || h->dynindx == -1)
-                     && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+                     && SYMBOL_REFERENCES_LOCAL (info, h)))
                {
                  /* This is actually a static link, or it is a
                      -Bsymbolic link and the symbol is defined
@@ -3231,7 +3402,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          break;
 
        /* Indirect .sdata relocation */
-       case (int)R_PPC_EMB_SDAI16:
+       case (int) R_PPC_EMB_SDAI16:
          BFD_ASSERT (sdata != NULL);
          relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info,
                                                                sdata, h, relocation, rel,
@@ -3239,7 +3410,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          break;
 
        /* Indirect .sdata2 relocation */
-       case (int)R_PPC_EMB_SDA2I16:
+       case (int) R_PPC_EMB_SDA2I16:
          BFD_ASSERT (sdata2 != NULL);
          relocation = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd, info,
                                                                sdata2, h, relocation, rel,
@@ -3250,8 +3421,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
           section, not the actual VMA.  This is appropriate when generating
           an embedded ELF object, for which the .got section acts like the
           AIX .toc section.  */
-       case (int)R_PPC_TOC16:                  /* phony GOT16 relocations */
-         BFD_ASSERT (sec != (asection *)0);
+       case (int) R_PPC_TOC16:                 /* phony GOT16 relocations */
+         BFD_ASSERT (sec != (asection *) 0);
          BFD_ASSERT (bfd_is_und_section (sec)
                      || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
                      || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0)
@@ -3259,7 +3430,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          addend -= sec->output_section->vma + sec->output_offset + 0x8000;
          break;
 
-       case (int)R_PPC_PLTREL24:
+       case (int) R_PPC_PLTREL24:
          /* Relocation is to the entry for this symbol in the
              procedure linkage table.  */
          BFD_ASSERT (h != NULL);
@@ -3276,22 +3447,22 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          relocation = (splt->output_section->vma
                        + splt->output_offset
                        + h->plt.offset);
-         break;
+         break;
 
        /* relocate against _SDA_BASE_ */
-       case (int)R_PPC_SDAREL16:
+       case (int) R_PPC_SDAREL16:
          {
            const char *name;
 
-           BFD_ASSERT (sec != (asection *)0);
+           BFD_ASSERT (sec != (asection *) 0);
            name = bfd_get_section_name (abfd, sec->output_section);
            if (strcmp (name, ".sdata") != 0
                && strcmp (name, ".sbss") != 0)
              {
                (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
-                                      bfd_get_filename (input_bfd),
+                                      bfd_archive_filename (input_bfd),
                                       sym_name,
-                                      ppc_elf_howto_table[ (int)r_type ]->name,
+                                      ppc_elf_howto_table[(int) r_type]->name,
                                       name);
              }
            addend -= (sdata->sym_hash->root.u.def.value
@@ -3300,22 +3471,21 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          }
          break;
 
-
        /* relocate against _SDA2_BASE_ */
-       case (int)R_PPC_EMB_SDA2REL:
+       case (int) R_PPC_EMB_SDA2REL:
          {
            const char *name;
 
-           BFD_ASSERT (sec != (asection *)0);
+           BFD_ASSERT (sec != (asection *) 0);
            name = bfd_get_section_name (abfd, sec->output_section);
            if (strcmp (name, ".sdata2") != 0 && strcmp (name, ".sbss2") != 0)
              {
                (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
-                                      bfd_get_filename (input_bfd),
+                                      bfd_archive_filename (input_bfd),
                                       sym_name,
-                                      ppc_elf_howto_table[ (int)r_type ]->name,
+                                      ppc_elf_howto_table[(int) r_type]->name,
                                       name);
-               
+
                bfd_set_error (bfd_error_bad_value);
                ret = false;
                continue;
@@ -3326,15 +3496,14 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          }
          break;
 
-
        /* relocate against either _SDA_BASE_, _SDA2_BASE_, or 0 */
-       case (int)R_PPC_EMB_SDA21:
-       case (int)R_PPC_EMB_RELSDA:
+       case (int) R_PPC_EMB_SDA21:
+       case (int) R_PPC_EMB_RELSDA:
          {
            const char *name;
            int reg;
 
-           BFD_ASSERT (sec != (asection *)0);
+           BFD_ASSERT (sec != (asection *) 0);
            name = bfd_get_section_name (abfd, sec->output_section);
            if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0)
              {
@@ -3344,7 +3513,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                           + sdata->sym_hash->root.u.def.section->output_offset);
              }
 
-           else if (strcmp (name, ".sdata2") == 0 || strcmp (name, ".sbss2") == 0)
+           else if (strcmp (name, ".sdata2") == 0
+                    || strcmp (name, ".sbss2") == 0)
              {
                reg = 2;
                addend -= (sdata2->sym_hash->root.u.def.value
@@ -3352,7 +3522,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                           + sdata2->sym_hash->root.u.def.section->output_offset);
              }
 
-           else if (strcmp (name, ".PPC.EMB.sdata0") == 0 || strcmp (name, ".PPC.EMB.sbss0") == 0)
+           else if (strcmp (name, ".PPC.EMB.sdata0") == 0
+                    || strcmp (name, ".PPC.EMB.sbss0") == 0)
              {
                reg = 0;
              }
@@ -3360,9 +3531,9 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            else
              {
                (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
-                                      bfd_get_filename (input_bfd),
+                                      bfd_archive_filename (input_bfd),
                                       sym_name,
-                                      ppc_elf_howto_table[ (int)r_type ]->name,
+                                      ppc_elf_howto_table[(int) r_type]->name,
                                       name);
 
                bfd_set_error (bfd_error_bad_value);
@@ -3374,81 +3545,80 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              {                 /* fill in register field */
                insn = bfd_get_32 (output_bfd, contents + offset);
                insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
-               bfd_put_32 (output_bfd, insn, contents + offset);
+               bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
              }
          }
          break;
 
        /* Relocate against the beginning of the section */
-       case (int)R_PPC_SECTOFF:
-       case (int)R_PPC_SECTOFF_LO:
-       case (int)R_PPC_SECTOFF_HI:
-         BFD_ASSERT (sec != (asection *)0);
+       case (int) R_PPC_SECTOFF:
+       case (int) R_PPC_SECTOFF_LO:
+       case (int) R_PPC_SECTOFF_HI:
+         BFD_ASSERT (sec != (asection *) 0);
          addend -= sec->output_section->vma;
          break;
 
-       case (int)R_PPC_SECTOFF_HA:
-         BFD_ASSERT (sec != (asection *)0);
+       case (int) R_PPC_SECTOFF_HA:
+         BFD_ASSERT (sec != (asection *) 0);
          addend -= sec->output_section->vma;
          addend += ((relocation + addend) & 0x8000) << 1;
          break;
 
        /* Negative relocations */
-       case (int)R_PPC_EMB_NADDR32:
-       case (int)R_PPC_EMB_NADDR16:
-       case (int)R_PPC_EMB_NADDR16_LO:
-       case (int)R_PPC_EMB_NADDR16_HI:
-         addend -= 2*relocation;
+       case (int) R_PPC_EMB_NADDR32:
+       case (int) R_PPC_EMB_NADDR16:
+       case (int) R_PPC_EMB_NADDR16_LO:
+       case (int) R_PPC_EMB_NADDR16_HI:
+         addend -= 2 * relocation;
          break;
 
-       case (int)R_PPC_EMB_NADDR16_HA:
-         addend -= 2*relocation;
+       case (int) R_PPC_EMB_NADDR16_HA:
+         addend -= 2 * relocation;
          addend += ((relocation + addend) & 0x8000) << 1;
          break;
 
        /* NOP relocation that prevents garbage collecting linkers from omitting a
           reference.  */
-       case (int)R_PPC_EMB_MRKREF:
+       case (int) R_PPC_EMB_MRKREF:
          continue;
 
-       case (int)R_PPC_COPY:
-       case (int)R_PPC_GLOB_DAT:
-       case (int)R_PPC_JMP_SLOT:
-       case (int)R_PPC_RELATIVE:
-       case (int)R_PPC_PLT32:
-       case (int)R_PPC_PLTREL32:
-       case (int)R_PPC_PLT16_LO:
-       case (int)R_PPC_PLT16_HI:
-       case (int)R_PPC_PLT16_HA:
-       case (int)R_PPC_EMB_RELSEC16:
-       case (int)R_PPC_EMB_RELST_LO:
-       case (int)R_PPC_EMB_RELST_HI:
-       case (int)R_PPC_EMB_RELST_HA:
-       case (int)R_PPC_EMB_BIT_FLD:
+       case (int) R_PPC_COPY:
+       case (int) R_PPC_GLOB_DAT:
+       case (int) R_PPC_JMP_SLOT:
+       case (int) R_PPC_RELATIVE:
+       case (int) R_PPC_PLT32:
+       case (int) R_PPC_PLTREL32:
+       case (int) R_PPC_PLT16_LO:
+       case (int) R_PPC_PLT16_HI:
+       case (int) R_PPC_PLT16_HA:
+       case (int) R_PPC_EMB_RELSEC16:
+       case (int) R_PPC_EMB_RELST_LO:
+       case (int) R_PPC_EMB_RELST_HI:
+       case (int) R_PPC_EMB_RELST_HA:
+       case (int) R_PPC_EMB_BIT_FLD:
          (*_bfd_error_handler) (_("%s: Relocation %s is not yet supported for symbol %s."),
-                                bfd_get_filename (input_bfd),
-                                ppc_elf_howto_table[ (int)r_type ]->name,
+                                bfd_archive_filename (input_bfd),
+                                ppc_elf_howto_table[(int) r_type]->name,
                                 sym_name);
 
          bfd_set_error (bfd_error_invalid_operation);
          ret = false;
          continue;
 
-       case (int)R_PPC_GNU_VTINHERIT:
-       case (int)R_PPC_GNU_VTENTRY:
+       case (int) R_PPC_GNU_VTINHERIT:
+       case (int) R_PPC_GNU_VTENTRY:
          /* These are no-ops in the end.  */
          continue;
        }
 
-
 #ifdef DEBUG
       fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n",
               howto->name,
-              (int)r_type,
+              (int) r_type,
               sym_name,
               r_symndx,
-              (long)offset,
-              (long)addend);
+              (long) offset,
+              (long) addend);
 #endif
 
       r = _bfd_final_link_relocate (howto,
@@ -3459,47 +3629,52 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                    relocation,
                                    addend);
 
-      if (r != bfd_reloc_ok)
+      if (r == bfd_reloc_ok)
+       ;
+      else if (r == bfd_reloc_overflow)
        {
-         ret = false;
-         switch (r)
+         const char *name;
+
+         if (h != NULL)
            {
-           default:
-             break;
+             if (h->root.type == bfd_link_hash_undefweak
+                 && howto->pc_relative)
+               {
+                 /* Assume this is a call protected by other code that
+                    detect the symbol is undefined.  If this is the case,
+                    we can safely ignore the overflow.  If not, the
+                    program is hosed anyway, and a little warning isn't
+                    going to help.  */
 
-           case bfd_reloc_overflow:
-             {
-               const char *name;
-
-               if (h != NULL)
-                 name = h->root.root.string;
-               else
-                 {
-                   name = bfd_elf_string_from_elf_section (input_bfd,
-                                                           symtab_hdr->sh_link,
-                                                           sym->st_name);
-                   if (name == NULL)
-                     break;
-
-                   if (*name == '\0')
-                     name = bfd_section_name (input_bfd, sec);
-                 }
-
-               (*info->callbacks->reloc_overflow)(info,
+                 continue;
+               }
+
+             name = h->root.root.string;
+           }
+         else
+           {
+             name = bfd_elf_string_from_elf_section (input_bfd,
+                                                     symtab_hdr->sh_link,
+                                                     sym->st_name);
+             if (name == NULL)
+               continue;
+             if (*name == '\0')
+               name = bfd_section_name (input_bfd, sec);
+           }
+
+         if (! (*info->callbacks->reloc_overflow) (info,
                                                   name,
                                                   howto->name,
                                                   (bfd_vma) 0,
                                                   input_bfd,
                                                   input_section,
-                                                  offset);
-             }
-             break;
-
-           }
+                                                  offset))
+           return false;
        }
+      else
+       ret = false;
     }
 
-
 #ifdef DEBUG
   fprintf (stderr, "\n");
 #endif
@@ -3507,6 +3682,89 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   return ret;
 }
 
+static enum elf_reloc_type_class
+ppc_elf_reloc_type_class (rela)
+     const Elf_Internal_Rela *rela;
+{
+  switch ((int) ELF32_R_TYPE (rela->r_info))
+    {
+    case R_PPC_RELATIVE:
+      return reloc_class_relative;
+    case R_PPC_REL24:
+    case R_PPC_ADDR24:
+    case R_PPC_JMP_SLOT:
+      return reloc_class_plt;
+    case R_PPC_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
+\f
+/* Support for core dump NOTE sections */
+static boolean
+ppc_elf_grok_prstatus (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  int offset;
+  unsigned int raw_size;
+
+  switch (note->descsz)
+    {
+      default:
+       return false;
+
+      case 268:                /* Linux/PPC */
+       /* pr_cursig */
+       elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+       /* pr_pid */
+       elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+
+       /* pr_reg */
+       offset = 72;
+       raw_size = 192;
+
+       break;
+    }
+
+  /* Make a ".reg/999" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+                                         raw_size, note->descpos + offset);
+}
+
+static boolean
+ppc_elf_grok_psinfo (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  switch (note->descsz)
+    {
+      default:
+       return false;
+
+      case 128:                /* Linux/PPC elf_prpsinfo */
+       elf_tdata (abfd)->core_program
+        = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
+       elf_tdata (abfd)->core_command
+        = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
+    }
+
+  /* Note that for some reason, a spurious space is tacked
+     onto the end of the args in some (at least one anyway)
+     implementations, so strip it off if it exists.  */
+
+  {
+    char *command = elf_tdata (abfd)->core_command;
+    int n = strlen (command);
+
+    if (0 < n && command[n - 1] == ' ')
+      command[n - 1] = '\0';
+  }
+
+  return true;
+}
 \f
 #define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
 #define TARGET_LITTLE_NAME     "elf32-powerpcle"
@@ -3528,13 +3786,15 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 #define elf_backend_plt_not_loaded     1
 #define elf_backend_got_symbol_offset  4
 #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_bfd_copy_private_bfd_data    ppc_elf_copy_private_bfd_data
 #define bfd_elf32_bfd_merge_private_bfd_data   ppc_elf_merge_private_bfd_data
-#define bfd_elf32_bfd_set_private_flags                ppc_elf_set_private_flags
+#define bfd_elf32_bfd_relax_section             ppc_elf_relax_section
 #define bfd_elf32_bfd_reloc_type_lookup                ppc_elf_reloc_type_lookup
+#define bfd_elf32_bfd_set_private_flags                ppc_elf_set_private_flags
 #define bfd_elf32_bfd_final_link               _bfd_elf32_gc_common_final_link
 
 #define elf_backend_gc_mark_hook               ppc_elf_gc_mark_hook
@@ -3551,5 +3811,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 #define elf_backend_fake_sections              ppc_elf_fake_sections
 #define elf_backend_additional_program_headers ppc_elf_additional_program_headers
 #define elf_backend_modify_segment_map         ppc_elf_modify_segment_map
+#define elf_backend_grok_prstatus              ppc_elf_grok_prstatus
+#define elf_backend_grok_psinfo                        ppc_elf_grok_psinfo
+#define elf_backend_reloc_type_class           ppc_elf_reloc_type_class
 
 #include "elf32-target.h"
This page took 0.093982 seconds and 4 git commands to generate.