Support the use of the STT_COMMON type. (In source and object files only at the...
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 3561d8be2de811ec093de015d887ee58b6fbd7d7..68804ad806c56b1063160638d122b79b103c10d5 100644 (file)
@@ -1,13 +1,13 @@
 /* PowerPC-specific support for 32-bit ELF
    Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-   2004, 2005, 2006 Free Software Foundation, Inc.
+   2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
    Boston, MA 02110-1301, USA.  */
 
+
 /* This file is based on a preliminary PowerPC ELF ABI.  The
    information may not match the final PowerPC ELF ABI.  It includes
    suggestions from the in-progress Embedded PowerPC ABI, and that
    information may also not match.  */
 
-#include "bfd.h"
 #include "sysdep.h"
+#include <stdarg.h>
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
@@ -1577,6 +1579,22 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return ppc_elf_howto_table[r];
 };
 
+static reloc_howto_type *
+ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                          const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
+       i++)
+    if (ppc_elf_howto_raw[i].name != NULL
+       && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0)
+      return &ppc_elf_howto_raw[i];
+
+  return NULL;
+}
+
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
@@ -1590,6 +1608,17 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
 
   BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
   cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)];
+
+  /* Just because the above assert didn't trigger doesn't mean that
+     ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation.  */
+  if (!cache_ptr->howto)
+    {
+      (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+                             abfd, ELF32_R_TYPE (dst->r_info));
+      bfd_set_error (bfd_error_bad_value);
+
+      cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
+    }
 }
 
 /* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs.  */
@@ -1695,6 +1724,10 @@ struct ppc_elf_obj_tdata
   /* A mapping from local symbols to offsets into the various linker
      sections added.  This is index by the symbol index.  */
   elf_linker_section_pointers_t **linker_section_pointers;
+
+  /* Flags used to auto-detect plt type.  */
+  unsigned int makes_plt_call : 1;
+  unsigned int has_rel16 : 1;
 };
 
 #define ppc_elf_tdata(bfd) \
@@ -1813,6 +1846,52 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   return TRUE;
 }
 
+static char *
+ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
+{
+  switch (note_type)
+    {
+    default:
+      return NULL;
+
+    case NT_PRPSINFO:
+      {
+       char data[128];
+       va_list ap;
+
+       va_start (ap, note_type);
+       memset (data, 0, 32);
+       strncpy (data + 32, va_arg (ap, const char *), 16);
+       strncpy (data + 48, va_arg (ap, const char *), 80);
+       va_end (ap);
+       return elfcore_write_note (abfd, buf, bufsiz,
+                                  "CORE", note_type, data, sizeof (data));
+      }
+
+    case NT_PRSTATUS:
+      {
+       char data[268];
+       va_list ap;
+       long pid;
+       int cursig;
+       const void *greg;
+
+       va_start (ap, note_type);
+       memset (data, 0, 72);
+       pid = va_arg (ap, long);
+       bfd_put_32 (abfd, pid, data + 24);
+       cursig = va_arg (ap, int);
+       bfd_put_16 (abfd, cursig, data + 12);
+       greg = va_arg (ap, const void *);
+       memcpy (data + 72, greg, 192);
+       memset (data + 264, 0, 4);
+       va_end (ap);
+       return elfcore_write_note (abfd, buf, bufsiz,
+                                  "CORE", note_type, data, sizeof (data));
+      }
+    }
+}
+
 /* Return address for Ith PLT stub in section PLT, for relocation REL
    or (bfd_vma) -1 if it should not be included.  */
 
@@ -2151,6 +2230,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
 
 static bfd_boolean
 ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED,
+                      struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
                       asection *asec,
                       bfd_byte *contents ATTRIBUTE_UNUSED)
 {
@@ -2317,13 +2397,6 @@ struct ppc_elf_link_hash_entry
 
 #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
 
-enum ppc_elf_plt_type {
-  PLT_UNSET,
-  PLT_OLD,
-  PLT_NEW,
-  PLT_VXWORKS
-};
-
 /* PPC ELF linker hash table.  */
 
 struct ppc_elf_link_hash_table
@@ -2343,9 +2416,18 @@ struct ppc_elf_link_hash_table
   elf_linker_section_t sdata[2];
   asection *sbss;
 
+  /* The (unloaded but important) .rela.plt.unloaded on VxWorks.  */
+  asection *srelplt2;
+
+  /* The .got.plt section (VxWorks only)*/
+  asection *sgotplt;
+
   /* Shortcut to .__tls_get_addr.  */
   struct elf_link_hash_entry *tls_get_addr;
 
+  /* The bfd that forced an old-style PLT.  */
+  bfd *old_bfd;
   /* TLS local dynamic got entry handling.  */
   union {
     bfd_signed_vma refcount;
@@ -2363,23 +2445,11 @@ struct ppc_elf_link_hash_table
   /* The type of PLT we have chosen to use.  */
   enum ppc_elf_plt_type plt_type;
 
-  /* Whether we can use the new PLT layout.  */
-  unsigned int can_use_new_plt:1;
-
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
-
-  /* The (unloaded but important) .rela.plt.unloaded on VxWorks.  */
-  asection *srelplt2;
-
-  /* The .got.plt section (VxWorks only)*/
-  asection *sgotplt;
-
   /* True if the target system is VxWorks.  */
-  int is_vxworks;
+  unsigned int is_vxworks:1;
 
   /* The size of PLT entries.  */
   int plt_entry_size;
@@ -2387,6 +2457,9 @@ struct ppc_elf_link_hash_table
   int plt_slot_size;
   /* The size of the first PLT entry.  */
   int plt_initial_entry_size;
+
+  /* Small local sym to section mapping cache.  */
+  struct sym_sec_cache sym_sec;
 };
 
 /* Get the PPC ELF linker hash table from a link_info structure.  */
@@ -2458,8 +2531,6 @@ ppc_elf_link_hash_table_create (bfd *abfd)
   ret->plt_entry_size = 12;
   ret->plt_slot_size = 8;
   ret->plt_initial_entry_size = 72;
-  
-  ret->is_vxworks = 0;
 
   return &ret->elf.root;
 }
@@ -3229,8 +3300,13 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          else
            {
-             bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0;
+             bfd_vma addend = 0;
 
+             if (r_type == R_PPC_PLTREL24)
+               {
+                 ppc_elf_tdata (abfd)->makes_plt_call = 1;
+                 addend = rel->r_addend;
+               }
              h->needs_plt = 1;
              if (!update_plt_info (abfd, h, got2, addend))
                return FALSE;
@@ -3255,7 +3331,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
-         htab->can_use_new_plt = 1;
+         ppc_elf_tdata (abfd)->has_rel16 = 1;
          break;
 
          /* These are just markers.  */
@@ -3284,7 +3360,10 @@ ppc_elf_check_relocs (bfd *abfd,
          /* This refers only to functions defined in the shared library.  */
        case R_PPC_LOCAL24PC:
          if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
-           htab->plt_type = PLT_OLD;
+           {
+             htab->plt_type = PLT_OLD;
+             htab->old_bfd = abfd;
+           }
          break;
 
          /* This relocation describes the C++ object vtable hierarchy.
@@ -3297,7 +3376,9 @@ ppc_elf_check_relocs (bfd *abfd,
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_PPC_GNU_VTENTRY:
-         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         BFD_ASSERT (h != NULL);
+         if (h != NULL
+             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
 
@@ -3338,7 +3419,10 @@ ppc_elf_check_relocs (bfd *abfd,
              s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
                                             r_symndx);
              if (s == got2)
-               htab->plt_type = PLT_OLD;
+               {
+                 htab->plt_type = PLT_OLD;
+                 htab->old_bfd = abfd;
+               }
            }
          if (h == NULL || h == htab->elf.hgot)
            break;
@@ -3353,7 +3437,10 @@ ppc_elf_check_relocs (bfd *abfd,
          if (h == htab->elf.hgot)
            {
              if (htab->plt_type == PLT_UNSET)
-               htab->plt_type = PLT_OLD;
+               {
+                 htab->plt_type = PLT_OLD;
+                 htab->old_bfd = abfd;
+               }
              break;
            }
          /* fall through */
@@ -3510,6 +3597,62 @@ ppc_elf_check_relocs (bfd *abfd,
   return TRUE;
 }
 \f
+
+/* Merge object attributes from IBFD into OBFD.  Raise an error if
+   there are conflicting attributes.  */
+static bfd_boolean
+ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+
+  if (!elf_known_obj_attributes_proc (obfd)[0].i)
+    {
+      /* This is the first object.  Copy the attributes.  */
+      _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+      /* Use the Tag_null value to indicate the attributes have been
+        initialized.  */
+      elf_known_obj_attributes_proc (obfd)[0].i = 1;
+
+      return TRUE;
+    }
+
+  /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
+     non-conflicting ones.  */
+  in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+  out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+  if (in_attr[Tag_GNU_Power_ABI_FP].i != out_attr[Tag_GNU_Power_ABI_FP].i)
+    {
+      out_attr[Tag_GNU_Power_ABI_FP].type = 1;
+      if (out_attr[Tag_GNU_Power_ABI_FP].i == 0)
+       out_attr[Tag_GNU_Power_ABI_FP].i = in_attr[Tag_GNU_Power_ABI_FP].i;
+      else if (in_attr[Tag_GNU_Power_ABI_FP].i == 0)
+       ;
+      else if (out_attr[Tag_GNU_Power_ABI_FP].i == 1
+              && in_attr[Tag_GNU_Power_ABI_FP].i == 2)
+       _bfd_error_handler
+         (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
+      else if (out_attr[Tag_GNU_Power_ABI_FP].i == 2
+              && in_attr[Tag_GNU_Power_ABI_FP].i == 1)
+       _bfd_error_handler
+         (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+      else if (in_attr[Tag_GNU_Power_ABI_FP].i > 2)
+       _bfd_error_handler
+         (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
+          in_attr[Tag_GNU_Power_ABI_FP].i);
+      else
+       _bfd_error_handler
+         (_("Warning: %B uses unknown floating point ABI %d"), obfd,
+          out_attr[Tag_GNU_Power_ABI_FP].i);
+    }
+
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  _bfd_elf_merge_object_attributes (ibfd, obfd);
+
+  return TRUE;
+}
+
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
@@ -3528,6 +3671,9 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   if (! _bfd_generic_verify_endian_match (ibfd, obfd))
     return FALSE;
 
+  if (!ppc_elf_merge_obj_attributes (ibfd, obfd))
+    return FALSE;
+
   new_flags = elf_elfheader (ibfd)->e_flags;
   old_flags = elf_elfheader (obfd)->e_flags;
   if (!elf_flags_init (obfd))
@@ -3607,7 +3753,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 int
 ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
                           struct bfd_link_info *info,
-                          int force_old_plt,
+                          enum ppc_elf_plt_type plt_style,
                           int emit_stub_syms)
 {
   struct ppc_elf_link_hash_table *htab;
@@ -3616,8 +3762,37 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
   htab = ppc_elf_hash_table (info);
 
   if (htab->plt_type == PLT_UNSET)
-    htab->plt_type = (force_old_plt || !htab->can_use_new_plt
-                     ? PLT_OLD : PLT_NEW);
+    {
+      if (plt_style == PLT_OLD)
+       htab->plt_type = PLT_OLD;
+      else
+       {
+         bfd *ibfd;
+         enum ppc_elf_plt_type plt_type = plt_style;
+
+         /* Look through the reloc flags left by ppc_elf_check_relocs.
+            Use the old style bss plt if a file makes plt calls
+            without using the new relocs, and if ld isn't given
+            --secure-plt and we never see REL16 relocs.  */
+         if (plt_type == PLT_UNSET)
+           plt_type = PLT_OLD;
+         for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+           if (is_ppc_elf_target (ibfd->xvec))
+             {
+               if (ppc_elf_tdata (ibfd)->has_rel16)
+                 plt_type = PLT_NEW;
+               else if (ppc_elf_tdata (ibfd)->makes_plt_call)
+                 {
+                   plt_type = PLT_OLD;
+                   htab->old_bfd = ibfd;
+                   break;
+                 }
+             }
+         htab->plt_type = plt_type;
+       }
+    }
+  if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
+    info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd);
 
   htab->emit_stub_syms = emit_stub_syms;
 
@@ -4034,7 +4209,6 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 {
   struct ppc_elf_link_hash_table *htab;
   asection *s;
-  unsigned int power_of_two;
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n",
@@ -4112,11 +4286,15 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (!h->non_got_ref)
     return TRUE;
 
-   /* If we didn't find any dynamic relocs in read-only sections, then we'll
-      be keeping the dynamic relocs and avoiding the copy reloc.  We can't
-      do this if there are any small data relocations.  */
+   /* If we didn't find any dynamic relocs in read-only sections, then
+      we'll be keeping the dynamic relocs and avoiding the copy reloc.
+      We can't do this if there are any small data relocations.  This
+      doesn't work on VxWorks, where we can not have dynamic
+      relocations (other than copy and jump slot relocations) in an
+      executable.  */
   if (ELIMINATE_COPY_RELOCS
-      && !ppc_elf_hash_entry (h)->has_sda_refs)
+      && !ppc_elf_hash_entry (h)->has_sda_refs
+      && !htab->is_vxworks)
     {
       struct ppc_elf_dyn_relocs *p;
       for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
@@ -4176,28 +4354,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
-  /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this.  */
-  power_of_two = bfd_log2 (h->size);
-  if (power_of_two > 4)
-    power_of_two = 4;
-
-  /* Apply the required alignment.  */
-  s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
-    {
-      if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
-       return FALSE;
-    }
-
-  /* Define the symbol as being at this point in the section.  */
-  h->root.u.def.section = s;
-  h->root.u.def.value = s->size;
-
-  /* Increment the section size to make room for the symbol.  */
-  s->size += h->size;
-
-  return TRUE;
+  return _bfd_elf_adjust_dynamic_copy (h, s);
 }
 \f
 /* Generate a symbol to mark plt call stubs.  For non-PIC code the sym is
@@ -4436,13 +4593,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              }
            else
              ent->plt.offset = (bfd_vma) -1;
-
-           if (!doneone)
-             {
-               h->plt.plist = NULL;
-               h->needs_plt = 0;
-             }
          }
+       else
+         ent->plt.offset = (bfd_vma) -1;
+
+      if (!doneone)
+       {
+         h->plt.plist = NULL;
+         h->needs_plt = 0;
+       }
     }
   else
     {
@@ -5516,29 +5675,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
   got2 = bfd_get_section_by_name (input_bfd, ".got2");
 
-  if (info->relocatable)
-    {
-      if (got2 == NULL)
-       return TRUE;
-
-      rel = relocs;
-      relend = relocs + input_section->reloc_count;
-      for (; rel < relend; rel++)
-       {
-         enum elf_ppc_reloc_type r_type;
-
-         r_type = ELF32_R_TYPE (rel->r_info);
-         if (r_type == R_PPC_PLTREL24
-             && rel->r_addend >= 32768)
-           {
-             /* R_PPC_PLTREL24 is rather special.  If non-zero, the
-                addend specifies the GOT pointer offset within .got2.  */
-             rel->r_addend += got2->output_offset;
-           }
-       }
-      return TRUE;
-    }
-
   /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
     ppc_elf_howto_init ();
@@ -5592,6 +5728,33 @@ ppc_elf_relocate_section (bfd *output_bfd,
          sym_name = h->root.root.string;
        }
 
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         howto = NULL;
+         if (r_type < R_PPC_max)
+           howto = ppc_elf_howto_table[r_type];
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
+
+      if (info->relocatable)
+       {
+         if (got2 != NULL
+             && r_type == R_PPC_PLTREL24
+             && rel->r_addend >= 32768)
+           {
+             /* R_PPC_PLTREL24 is rather special.  If non-zero, the
+                addend specifies the GOT pointer offset within .got2.  */
+             rel->r_addend += got2->output_offset;
+           }
+         continue;
+       }
+
       /* TLS optimizations.  Replace instruction sequences and relocs
         based on information we collected in tls_optimize.  We edit
         RELOCS so that --emit-relocs will output something sensible
@@ -6177,17 +6340,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
-         /* r_symndx will be zero only for relocs against symbols
-            from removed linkonce sections, or sections discarded by
-            a linker script.  */
        dodyn:
-         if (r_symndx == 0)
-           {
-             _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-             break;
-           }
-         /* Fall thru.  */
-
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
          /* Fall thru.  */
@@ -7455,6 +7608,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define bfd_elf32_bfd_merge_private_bfd_data   ppc_elf_merge_private_bfd_data
 #define bfd_elf32_bfd_relax_section            ppc_elf_relax_section
 #define bfd_elf32_bfd_reloc_type_lookup                ppc_elf_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup        ppc_elf_reloc_name_lookup
 #define bfd_elf32_bfd_set_private_flags                ppc_elf_set_private_flags
 #define bfd_elf32_bfd_link_hash_table_create   ppc_elf_link_hash_table_create
 
@@ -7475,6 +7629,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_additional_program_headers ppc_elf_additional_program_headers
 #define elf_backend_grok_prstatus              ppc_elf_grok_prstatus
 #define elf_backend_grok_psinfo                        ppc_elf_grok_psinfo
+#define elf_backend_write_core_note            ppc_elf_write_core_note
 #define elf_backend_reloc_type_class           ppc_elf_reloc_type_class
 #define elf_backend_begin_write_processing     ppc_elf_begin_write_processing
 #define elf_backend_final_write_processing     ppc_elf_final_write_processing
This page took 0.176372 seconds and 4 git commands to generate.