bfd/
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 90f9b221b903bff03ce9187fb2ea114864ef539d..68d83e3014e4a5b9ac06edeedb9c811e6870b074 100644 (file)
@@ -286,7 +286,7 @@ ppc_elf_copy_indirect_symbol (struct elf_backend_data *bed,
     _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
 }
 \f
-static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max];
+static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
 
 static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
@@ -1830,8 +1830,8 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   enum elf_ppc_reloc_type r;
 
+  /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   switch (code)
@@ -1932,8 +1932,8 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
 {
+  /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
@@ -2169,6 +2169,360 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 \f
+/* Create a special linker section, or return a pointer to a linker
+   section already created */
+
+static elf_linker_section_t *
+elf_create_linker_section (bfd *abfd,
+                          struct bfd_link_info *info,
+                          enum elf_linker_section_enum which,
+                          elf_linker_section_t *defaults)
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  elf_linker_section_t *lsect;
+
+  /* Record the first bfd section that needs the special section */
+  if (!dynobj)
+    dynobj = elf_hash_table (info)->dynobj = abfd;
+
+  /* If this is the first time, create the section */
+  lsect = elf_linker_section (dynobj, which);
+  if (!lsect)
+    {
+      asection *s;
+      bfd_size_type amt = sizeof (elf_linker_section_t);
+
+      lsect = bfd_alloc (dynobj, amt);
+
+      *lsect = *defaults;
+      elf_linker_section (dynobj, which) = lsect;
+      lsect->which = which;
+      lsect->hole_written_p = FALSE;
+
+      /* See if the sections already exist */
+      lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name);
+      if (!s || (s->flags & defaults->flags) != defaults->flags)
+       {
+         lsect->section = s = bfd_make_section_anyway (dynobj, lsect->name);
+
+         if (s == NULL)
+           return NULL;
+
+         bfd_set_section_flags (dynobj, s, defaults->flags);
+         bfd_set_section_alignment (dynobj, s, lsect->alignment);
+       }
+      else if (bfd_get_section_alignment (dynobj, s) < lsect->alignment)
+       bfd_set_section_alignment (dynobj, s, lsect->alignment);
+
+      s->_raw_size = align_power (s->_raw_size, lsect->alignment);
+
+      /* Is there a hole we have to provide?  If so check whether the
+        segment is too big already */
+      if (lsect->hole_size)
+       {
+         lsect->hole_offset = s->_raw_size;
+         s->_raw_size += lsect->hole_size;
+         if (lsect->hole_offset > lsect->max_hole_offset)
+           {
+             (*_bfd_error_handler)
+               (_("%s: Section %s is too large to add hole of %ld bytes"),
+                bfd_get_filename (abfd),
+                lsect->name,
+                (long) lsect->hole_size);
+
+             bfd_set_error (bfd_error_bad_value);
+             return NULL;
+           }
+       }
+
+#ifdef DEBUG
+      fprintf (stderr, "Creating section %s, current size = %ld\n",
+              lsect->name, (long) s->_raw_size);
+#endif
+
+      if (lsect->sym_name)
+       {
+         struct elf_link_hash_entry *h;
+         struct bfd_link_hash_entry *bh;
+
+#ifdef DEBUG
+         fprintf (stderr, "Adding %s to section %s\n",
+                  lsect->sym_name,
+                  lsect->name);
+#endif
+         bh = bfd_link_hash_lookup (info->hash, lsect->sym_name,
+                                    FALSE, FALSE, FALSE);
+
+         if ((bh == NULL || bh->type == bfd_link_hash_undefined)
+             && !(_bfd_generic_link_add_one_symbol
+                  (info, abfd, lsect->sym_name, BSF_GLOBAL, s,
+                   (lsect->hole_size
+                    ? s->_raw_size - lsect->hole_size + lsect->sym_offset
+                    : lsect->sym_offset),
+                   NULL, FALSE,
+                   get_elf_backend_data (abfd)->collect, &bh)))
+           return NULL;
+         h = (struct elf_link_hash_entry *) bh;
+
+         if ((defaults->which != LINKER_SECTION_SDATA)
+             && (defaults->which != LINKER_SECTION_SDATA2))
+           h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC;
+
+         h->type = STT_OBJECT;
+         lsect->sym_hash = h;
+
+         if (info->shared
+             && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+           return NULL;
+       }
+    }
+
+  return lsect;
+}
+\f
+/* Find a linker generated pointer with a given addend and type.  */
+
+static elf_linker_section_pointers_t *
+elf_find_pointer_linker_section
+  (elf_linker_section_pointers_t *linker_pointers,
+   bfd_vma addend,
+   elf_linker_section_enum_t which)
+{
+  for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next)
+    if (which == linker_pointers->which && addend == linker_pointers->addend)
+      return linker_pointers;
+
+  return NULL;
+}
+\f
+/* Allocate a pointer to live in a linker created section.  */
+
+static bfd_boolean
+elf_create_pointer_linker_section (bfd *abfd,
+                                  struct bfd_link_info *info,
+                                  elf_linker_section_t *lsect,
+                                  struct elf_link_hash_entry *h,
+                                  const Elf_Internal_Rela *rel)
+{
+  elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
+  elf_linker_section_pointers_t *linker_section_ptr;
+  unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+  bfd_size_type amt;
+
+  BFD_ASSERT (lsect != NULL);
+
+  /* Is this a global symbol?  */
+  if (h != NULL)
+    {
+      /* Has this symbol already been allocated?  If so, our work is done.  */
+      if (elf_find_pointer_linker_section (h->linker_section_pointer,
+                                          rel->r_addend,
+                                          lsect->which))
+       return TRUE;
+
+      ptr_linker_section_ptr = &h->linker_section_pointer;
+      /* Make sure this symbol is output as a dynamic symbol.  */
+      if (h->dynindx == -1)
+       {
+         if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+           return FALSE;
+       }
+
+      if (lsect->rel_section)
+       lsect->rel_section->_raw_size += sizeof (Elf32_External_Rela);
+    }
+  else
+    {
+      /* Allocation of a pointer to a local symbol.  */
+      elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
+
+      /* Allocate a table to hold the local symbols if first time.  */
+      if (!ptr)
+       {
+         unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info;
+         register unsigned int i;
+
+         amt = num_symbols;
+         amt *= sizeof (elf_linker_section_pointers_t *);
+         ptr = bfd_alloc (abfd, amt);
+
+         if (!ptr)
+           return FALSE;
+
+         elf_local_ptr_offsets (abfd) = ptr;
+         for (i = 0; i < num_symbols; i++)
+           ptr[i] = NULL;
+       }
+
+      /* Has this symbol already been allocated?  If so, our work is done.  */
+      if (elf_find_pointer_linker_section (ptr[r_symndx],
+                                          rel->r_addend,
+                                          lsect->which))
+       return TRUE;
+
+      ptr_linker_section_ptr = &ptr[r_symndx];
+
+      if (info->shared)
+       {
+         /* If we are generating a shared object, we need to
+            output a R_<xxx>_RELATIVE reloc so that the
+            dynamic linker can adjust this GOT entry.  */
+         BFD_ASSERT (lsect->rel_section != NULL);
+         lsect->rel_section->_raw_size += sizeof (Elf32_External_Rela);
+       }
+    }
+
+  /* Allocate space for a pointer in the linker section, and allocate
+     a new pointer record from internal memory.  */
+  BFD_ASSERT (ptr_linker_section_ptr != NULL);
+  amt = sizeof (elf_linker_section_pointers_t);
+  linker_section_ptr = bfd_alloc (abfd, amt);
+
+  if (!linker_section_ptr)
+    return FALSE;
+
+  linker_section_ptr->next = *ptr_linker_section_ptr;
+  linker_section_ptr->addend = rel->r_addend;
+  linker_section_ptr->which = lsect->which;
+  linker_section_ptr->written_address_p = FALSE;
+  *ptr_linker_section_ptr = linker_section_ptr;
+
+  linker_section_ptr->offset = lsect->section->_raw_size;
+  lsect->section->_raw_size += 4;
+
+#ifdef DEBUG
+  fprintf (stderr,
+          "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
+          lsect->name, (long) linker_section_ptr->offset,
+          (long) lsect->section->_raw_size);
+#endif
+
+  return TRUE;
+}
+\f
+#define bfd_put_ptr(BFD, VAL, ADDR) bfd_put_32 (BFD, VAL, ADDR)
+
+/* Fill in the address for a pointer generated in a linker section.  */
+
+static bfd_vma
+elf_finish_pointer_linker_section (bfd *output_bfd,
+                                  bfd *input_bfd,
+                                  struct bfd_link_info *info,
+                                  elf_linker_section_t *lsect,
+                                  struct elf_link_hash_entry *h,
+                                  bfd_vma relocation,
+                                  const Elf_Internal_Rela *rel,
+                                  int relative_reloc)
+{
+  elf_linker_section_pointers_t *linker_section_ptr;
+
+  BFD_ASSERT (lsect != NULL);
+
+  if (h != NULL)
+    {
+      /* Handle global symbol.  */
+      linker_section_ptr
+       = elf_find_pointer_linker_section (h->linker_section_pointer,
+                                          rel->r_addend,
+                                          lsect->which);
+
+      BFD_ASSERT (linker_section_ptr != NULL);
+
+      if (! elf_hash_table (info)->dynamic_sections_created
+         || (info->shared
+             && info->symbolic
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+       {
+         /* This is actually a static link, or it is a
+            -Bsymbolic link and the symbol is defined
+            locally.  We must initialize this entry in the
+            global section.
+
+            When doing a dynamic link, we create a .rela.<xxx>
+            relocation entry to initialize the value.  This
+            is done in the finish_dynamic_symbol routine.  */
+         if (!linker_section_ptr->written_address_p)
+           {
+             linker_section_ptr->written_address_p = TRUE;
+             bfd_put_ptr (output_bfd,
+                          relocation + linker_section_ptr->addend,
+                          (lsect->section->contents
+                           + linker_section_ptr->offset));
+           }
+       }
+    }
+  else
+    {
+      /* Handle local symbol.  */
+      unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+      BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
+      BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL);
+      linker_section_ptr = (elf_find_pointer_linker_section
+                           (elf_local_ptr_offsets (input_bfd)[r_symndx],
+                            rel->r_addend,
+                            lsect->which));
+
+      BFD_ASSERT (linker_section_ptr != NULL);
+
+      /* Write out pointer if it hasn't been rewritten out before.  */
+      if (!linker_section_ptr->written_address_p)
+       {
+         linker_section_ptr->written_address_p = TRUE;
+         bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
+                      lsect->section->contents + linker_section_ptr->offset);
+
+         if (info->shared)
+           {
+             asection *srel = lsect->rel_section;
+             Elf_Internal_Rela outrel[MAX_INT_RELS_PER_EXT_REL];
+             bfd_byte *erel;
+             struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+             unsigned int i;
+
+             /* We need to generate a relative reloc for the dynamic
+                linker.  */
+             if (!srel)
+               {
+                 srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+                                                 lsect->rel_name);
+                 lsect->rel_section = srel;
+               }
+
+             BFD_ASSERT (srel != NULL);
+
+             for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+               {
+                 outrel[i].r_offset = (lsect->section->output_section->vma
+                                       + lsect->section->output_offset
+                                       + linker_section_ptr->offset);
+                 outrel[i].r_info = 0;
+                 outrel[i].r_addend = 0;
+               }
+             outrel[0].r_info = ELF32_R_INFO (0, relative_reloc);
+             erel = lsect->section->contents;
+             erel += (elf_section_data (lsect->section)->rel_count++
+                      * sizeof (Elf32_External_Rela));
+             bfd_elf32_swap_reloca_out (output_bfd, outrel, erel);
+           }
+       }
+    }
+
+  relocation = (lsect->section->output_offset
+               + linker_section_ptr->offset
+               - lsect->hole_offset
+               - lsect->sym_offset);
+
+#ifdef DEBUG
+  fprintf (stderr,
+          "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
+          lsect->name, (long) relocation, (long) relocation);
+#endif
+
+  /* Subtract out the addend, because it will get added back in by the normal
+     processing.  */
+  return relocation - linker_section_ptr->addend;
+}
+\f
 /* Create a special linker section */
 static elf_linker_section_t *
 ppc_elf_create_linker_section (bfd *abfd,
@@ -2233,7 +2587,7 @@ ppc_elf_create_linker_section (bfd *abfd,
          break;
        }
 
-      lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults);
+      lsect = elf_create_linker_section (abfd, info, which, &defaults);
     }
 
   return lsect;
@@ -2318,7 +2672,10 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   asection *s;
   flagword flags;
 
-  if (!ppc_elf_create_got (abfd, info))
+  htab = ppc_elf_hash_table (info);
+
+  if (htab->got == NULL
+      && !ppc_elf_create_got (abfd, info))
     return FALSE;
 
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
@@ -2327,7 +2684,6 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
 
-  htab = ppc_elf_hash_table (info);
   htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
   htab->dynsbss = s = bfd_make_section (abfd, ".dynsbss");
   if (s == NULL
@@ -3085,7 +3441,7 @@ ppc_elf_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
 #ifdef DEBUG
@@ -3094,9 +3450,12 @@ ppc_elf_check_relocs (bfd *abfd,
           bfd_archive_filename (abfd));
 #endif
 
+  /* Initialize howto table if not already done.  */
+  if (!ppc_elf_howto_table[R_PPC_ADDR32])
+    ppc_elf_howto_init ();
+
   /* Create the linker generated sections all the time so that the
      special symbols are created.  */
-
   htab = ppc_elf_hash_table (info);
   if (htab->sdata == NULL)
     {
@@ -3217,8 +3576,8 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (!bfd_elf32_create_pointer_linker_section (abfd, info,
-                                                       htab->sdata, h, rel))
+         if (!elf_create_pointer_linker_section (abfd, info,
+                                                 htab->sdata, h, rel))
            return FALSE;
          break;
 
@@ -3229,8 +3588,8 @@ ppc_elf_check_relocs (bfd *abfd,
              bad_shared_reloc (abfd, r_type);
              return FALSE;
            }
-         if (!bfd_elf32_create_pointer_linker_section (abfd, info,
-                                                       htab->sdata2, h, rel))
+         if (!elf_create_pointer_linker_section (abfd, info,
+                                                 htab->sdata2, h, rel))
            return FALSE;
          break;
 
@@ -3269,6 +3628,12 @@ ppc_elf_check_relocs (bfd *abfd,
            {
              /* It does not make sense to have a procedure linkage
                 table entry for a local symbol.  */
+             (*_bfd_error_handler) (_("%s(%s+0x%lx): %s reloc against "
+                                      "local symbol"),
+                                    bfd_archive_filename (abfd),
+                                    sec->name,
+                                    (long) rel->r_offset,
+                                    ppc_elf_howto_table[r_type]->name);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
            }
@@ -3710,7 +4075,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
   asection *sec;
   struct ppc_elf_link_hash_table *htab;
 
-  if (info->relocateable || info->shared)
+  if (info->relocatable || info->shared)
     return TRUE;
 
   htab = ppc_elf_hash_table (info);
@@ -3905,7 +4270,7 @@ ppc_elf_add_symbol_hook (bfd *abfd,
                         bfd_vma *valp)
 {
   if (sym->st_shndx == SHN_COMMON
-      && !info->relocateable
+      && !info->relocatable
       && sym->st_size <= elf_gp_size (abfd)
       && info->hash->creator->flavour == bfd_target_elf_flavour)
     {
@@ -4142,7 +4507,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
    This function is responsible for adjust the section contents as
    necessary, and (if using Rela relocs and generating a
-   relocateable output file) adjusting the reloc addend as
+   relocatable output file) adjusting the reloc addend as
    necessary.
 
    This function does not have to worry about setting the reloc
@@ -4156,7 +4521,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
    The global hash table entry for the global symbols can be found
    via elf_sym_hashes (input_bfd).
 
-   When generating relocateable output, this function must handle
+   When generating relocatable output, this function must handle
    STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
    going to be the section symbol corresponding to the output
    section, which means that the addend must be adjusted
@@ -4189,14 +4554,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
           bfd_archive_filename (input_bfd),
           bfd_section_name(input_bfd, input_section),
           (long) input_section->reloc_count,
-          (info->relocateable) ? " (relocatable)" : "");
+          (info->relocatable) ? " (relocatable)" : "");
 #endif
 
-  if (info->relocateable)
+  if (info->relocatable)
     return TRUE;
 
+  /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
-    /* Initialize howto table if needed.  */
     ppc_elf_howto_init ();
 
   htab = ppc_elf_hash_table (info);
@@ -4263,7 +4628,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          else if (h->root.type == bfd_link_hash_undefweak)
            ;
-         else if (info->shared
+         else if (!info->executable
                   && !info->no_undefined
                   && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
            ;
@@ -4999,20 +5364,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_EMB_SDAI16:
          BFD_ASSERT (htab->sdata != NULL);
          relocation
-           = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd,
-                                                      info, htab->sdata, h,
-                                                      relocation, rel,
-                                                      R_PPC_RELATIVE);
+           = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
+                                                htab->sdata, h, relocation,
+                                                rel, R_PPC_RELATIVE);
          break;
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
          BFD_ASSERT (htab->sdata2 != NULL);
          relocation
-           = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd,
-                                                      info, htab->sdata2, h,
-                                                      relocation, rel,
-                                                      R_PPC_RELATIVE);
+           = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
+                                                htab->sdata2, h, relocation,
+                                                rel, R_PPC_RELATIVE);
          break;
 
          /* Handle the TOC16 reloc.  We want to use the offset within the .got
This page took 0.032001 seconds and 4 git commands to generate.