2000-03-01 H.J. Lu <hjl@gnu.org>
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index a1ff1e1681e8937e95ed5f2339f8dbab28d035d1..242cfb730ab5f12fe792969c1f49ff10b5bf7958 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -80,8 +80,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 *,
@@ -117,11 +115,14 @@ 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
 
 \f
 static reloc_howto_type *ppc_elf_howto_table[ (int)R_PPC_max ];
@@ -373,7 +374,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 */
@@ -598,7 +599,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 +624,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 */
@@ -676,7 +677,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_SECTOFF_LO",    /* name */
         false,                 /* partial_inplace */
@@ -701,13 +702,13 @@ static reloc_howto_type ppc_elf_howto_raw[] =
 
   /* 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 +788,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 */
@@ -947,13 +948,291 @@ ppc_elf_howto_init ()
     }
 }
 
+\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 void *arg1;
+    const void *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;
+
+          /* 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. */
+          rela_comb = (Elf_Internal_Rela**)
+           bfd_malloc (isec->reloc_count*sizeof(Elf_Internal_Rela*));
+          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, 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 ppc_reloc_type ppc_reloc = R_PPC_NONE;
+  enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE;
 
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
     /* Initialize howto table if needed */
@@ -1026,7 +1305,7 @@ ppc_elf_reloc_type_lookup (abfd, code)
 
 static void
 ppc_elf_info_to_howto (abfd, cache_ptr, dst)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      arelent *cache_ptr;
      Elf32_Internal_Rela *dst;
 {
@@ -1042,13 +1321,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;
 
@@ -1172,12 +1451,17 @@ ppc_elf_merge_private_bfd_data (ibfd, obfd)
            (_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
             bfd_get_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);
@@ -1237,7 +1521,7 @@ ppc_elf_section_from_shdr (abfd, hdr, name)
 
 static boolean
 ppc_elf_fake_sections (abfd, shdr, asect)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      Elf32_Internal_Shdr *shdr;
      asection *asect;
 {
@@ -1354,7 +1638,7 @@ ppc_elf_additional_program_headers (abfd)
 
 static boolean
 ppc_elf_modify_segment_map (abfd)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
 {
   return true;
 }
@@ -1431,27 +1715,26 @@ ppc_elf_adjust_dynamic_symbol (info, h)
   if (h->type == STT_FUNC
       || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
     {
-      if (! info->shared
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 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)
+         || (info->shared && h->plt.refcount <= 0))
        {
-         /* This case can occur if we saw a PLT32 reloc in an input
-             file, but the symbol was never referred to by a dynamic
-             object.  In such a case, we don't actually need to build
-             a procedure linkage table, and we can just do a PC32
-             reloc instead.  */
-         BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
-         return true;
-       }
+         /* A PLT entry is not required/allowed when:
 
-      /* GC may have rendered this entry unused.  Note, however, that in
-        an executable all references to the symbol go to the PLT, so we
-        can't turn it off in that case.
-        ??? The correct thing to do here is to reference count all uses
-        of the symbol, not just those to the GOT or PLT.  */
+            1. We are not using ld.so; because then the PLT entry
+            can't be set up, so we can't use one.
 
-      if (h->plt.refcount <= 0 && info->shared)
-       {
+            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.
+
+            3. GC has rendered the entry unused.
+            Note, however, that in an executable all references to the
+            symbol go to the PLT, so we can't turn it off in that case.
+            ??? The correct thing to do here is to reference count
+            all uses of the symbol, not just those to the GOT or PLT.  */
          h->plt.offset = (bfd_vma) -1;
          h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
          return true;
@@ -1477,7 +1760,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
@@ -1493,8 +1778,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");
@@ -1588,27 +1878,6 @@ 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.  */
 
@@ -1743,15 +2012,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;
        }
 
@@ -1799,43 +2060,6 @@ ppc_elf_size_dynamic_sections (output_bfd, info)
        }
     }
 
-  /* 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;
-    }
-
   return true;
 }
 
@@ -1860,7 +2084,7 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
   elf_linker_section_t *sdata;
   elf_linker_section_t *sdata2;
   asection *sreloc;
-  asection *sgot;
+  asection *sgot = NULL;
   asection *srelgot = NULL;
 
   if (info->relocateable)
@@ -1913,6 +2137,22 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
       else
        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
+      /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
+        This shows up in particular in an R_PPC_ADDR32 in the eabi
+        startup code.  */
+      if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+       {
+         if (sgot == NULL)
+           {
+             if (dynobj == NULL)
+               elf_hash_table (info)->dynobj = dynobj = abfd;
+             if (! _bfd_elf_create_got_section (dynobj, info))
+               return false;
+             sgot = bfd_get_section_by_name (dynobj, ".got");
+             BFD_ASSERT (sgot != NULL);
+           }
+       }
+
       switch (ELF32_R_TYPE (rel->r_info))
        {
        /* GOT16 relocations */
@@ -1925,11 +2165,9 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
          if (sgot == NULL)
            {
              if (dynobj == NULL)
-               {
-                 elf_hash_table (info)->dynobj = dynobj = abfd;
-                 if (! _bfd_elf_create_got_section (dynobj, info))
-                   return false;
-               }
+               elf_hash_table (info)->dynobj = dynobj = abfd;
+             if (! _bfd_elf_create_got_section (dynobj, info))
+               return false;
              sgot = bfd_get_section_by_name (dynobj, ".got");
              BFD_ASSERT (sgot != NULL);
            }
@@ -1979,7 +2217,6 @@ ppc_elf_check_relocs (abfd, info, sec, relocs)
              if (local_got_refcounts == NULL)
                {
                  size_t size;
-                 register unsigned int i;
 
                  size = symtab_hdr->sh_info * sizeof (bfd_signed_vma);
                  local_got_refcounts = (bfd_signed_vma *)
@@ -2226,7 +2463,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;
@@ -2248,6 +2485,9 @@ ppc_elf_gc_mark_hook (abfd, info, rel, h, sym)
 
            case bfd_link_hash_common:
              return h->root.u.c.p->section;
+
+           default:
+             break;
            }
        }
     }
@@ -2270,7 +2510,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;
 {
@@ -2337,8 +2577,8 @@ 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;
 {
@@ -2410,6 +2650,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);
@@ -2433,9 +2674,13 @@ 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)
        {
@@ -2619,54 +2864,6 @@ 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;
 }
 
@@ -2720,8 +2917,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   Elf_Internal_Rela *rel                 = relocs;
   Elf_Internal_Rela *relend              = relocs + input_section->reloc_count;
   asection *sreloc                       = NULL;
-  asection *splt                          = NULL;
-  asection *sgot                          = NULL;
+  asection *splt;
+  asection *sgot;
   bfd_vma *local_got_offsets;
   boolean ret                            = true;
   long insn;
@@ -2739,9 +2936,16 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
+  splt = sgot = NULL;
+  if (dynobj != NULL)
+    {
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+    }
+
   for (; rel < relend; rel++)
     {
-      enum ppc_reloc_type r_type       = (enum ppc_reloc_type)ELF32_R_TYPE (rel->r_info);
+      enum elf_ppc_reloc_type r_type   = (enum elf_ppc_reloc_type)ELF32_R_TYPE (rel->r_info);
       bfd_vma offset                   = rel->r_offset;
       bfd_vma addend                   = rel->r_addend;
       bfd_reloc_status_type r          = bfd_reloc_other;
@@ -2834,7 +3038,12 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      && ((! info->symbolic && h->dynindx != -1)
                          || (h->elf_link_hash_flags
                              & ELF_LINK_HASH_DEF_REGULAR) == 0)
-                     && (input_section->flags & SEC_ALLOC) != 0
+                     && ((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)
                      && (r_type == R_PPC_ADDR32
                          || r_type == R_PPC_ADDR24
                          || r_type == R_PPC_ADDR16
@@ -2877,6 +3086,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_get_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
@@ -2884,17 +3101,19 @@ 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->no_undefined)
            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)))
+               return false;
+             relocation = 0;
            }
        }
 
@@ -2918,12 +3137,13 @@ 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;
@@ -3126,11 +3346,7 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case (int)R_PPC_GOT16_HA:
          /* Relocation is to the entry for this symbol in the global
              offset table.  */
-         if (sgot == NULL)
-           {
-             sgot = bfd_get_section_by_name (dynobj, ".got");
-             BFD_ASSERT (sgot != NULL);
-           }
+         BFD_ASSERT (sgot != NULL);
 
          if (h != NULL)
            {
@@ -3248,7 +3464,8 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              procedure linkage table.  */
          BFD_ASSERT (h != NULL);
 
-         if (h->plt.offset == (bfd_vma) -1)
+         if (h->plt.offset == (bfd_vma) -1
+             || splt == NULL)
            {
              /* We didn't make a PLT entry for this symbol.  This
                  happens when statically linking PIC code, or when
@@ -3256,12 +3473,6 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              break;
            }
 
-         if (splt == NULL)
-           {
-             splt = bfd_get_section_by_name (dynobj, ".plt");
-             BFD_ASSERT (splt != NULL);
-           }
-
          relocation = (splt->output_section->vma
                        + splt->output_offset
                        + h->plt.offset);
@@ -3269,46 +3480,50 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
        /* relocate against _SDA_BASE_ */
        case (int)R_PPC_SDAREL16:
-         BFD_ASSERT (sec != (asection *)0);
-         if (strcmp (bfd_get_section_name (abfd, sec), ".sdata") != 0
-             && strcmp (bfd_get_section_name (abfd, sec), ".dynsbss") != 0
-             && strcmp (bfd_get_section_name (abfd, sec), ".sbss") != 0)
-           {
-             (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong section (%s)"),
-                                    bfd_get_filename (input_bfd),
-                                    sym_name,
-                                    ppc_elf_howto_table[ (int)r_type ]->name,
-                                    bfd_get_section_name (abfd, sec));
+         {
+           const char *name;
 
-             bfd_set_error (bfd_error_bad_value);
-             ret = false;
-             continue;
-           }
-         addend -= (sdata->sym_hash->root.u.def.value
-                    + sdata->sym_hash->root.u.def.section->output_section->vma
-                    + sdata->sym_hash->root.u.def.section->output_offset);
+           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),
+                                      sym_name,
+                                      ppc_elf_howto_table[ (int)r_type ]->name,
+                                      name);
+             }
+           addend -= (sdata->sym_hash->root.u.def.value
+                      + sdata->sym_hash->root.u.def.section->output_section->vma
+                      + sdata->sym_hash->root.u.def.section->output_offset);
+         }
          break;
 
 
        /* relocate against _SDA2_BASE_ */
        case (int)R_PPC_EMB_SDA2REL:
-         BFD_ASSERT (sec != (asection *)0);
-         if (strcmp (bfd_get_section_name (abfd, sec), ".sdata2") != 0
-             && strcmp (bfd_get_section_name (abfd, sec), ".sbss2") != 0)
-           {
-             (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong section (%s)"),
-                                    bfd_get_filename (input_bfd),
-                                    sym_name,
-                                    ppc_elf_howto_table[ (int)r_type ]->name,
-                                    bfd_get_section_name (abfd, sec));
+         {
+           const char *name;
 
-             bfd_set_error (bfd_error_bad_value);
-             ret = false;
-             continue;
-           }
-         addend -= (sdata2->sym_hash->root.u.def.value
-                    + sdata2->sym_hash->root.u.def.section->output_section->vma
-                    + sdata2->sym_hash->root.u.def.section->output_offset);
+           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),
+                                      sym_name,
+                                      ppc_elf_howto_table[ (int)r_type ]->name,
+                                      name);
+               
+               bfd_set_error (bfd_error_bad_value);
+               ret = false;
+               continue;
+             }
+           addend -= (sdata2->sym_hash->root.u.def.value
+                      + sdata2->sym_hash->root.u.def.section->output_section->vma
+                      + sdata2->sym_hash->root.u.def.section->output_offset);
+         }
          break;
 
 
@@ -3316,10 +3531,11 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case (int)R_PPC_EMB_SDA21:
        case (int)R_PPC_EMB_RELSDA:
          {
-           const char *name = bfd_get_section_name (abfd, sec);
+           const char *name;
            int reg;
 
            BFD_ASSERT (sec != (asection *)0);
+           name = bfd_get_section_name (abfd, sec->output_section);
            if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0)
              {
                reg = 13;
@@ -3343,11 +3559,11 @@ 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 section (%s)"),
+               (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
                                       bfd_get_filename (input_bfd),
                                       sym_name,
                                       ppc_elf_howto_table[ (int)r_type ]->name,
-                                      bfd_get_section_name (abfd, sec));
+                                      name);
 
                bfd_set_error (bfd_error_bad_value);
                ret = false;
@@ -3443,47 +3659,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
@@ -3517,8 +3738,9 @@ ppc_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
 #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
This page took 0.038162 seconds and 4 git commands to generate.