* elf64-ppc.c (is_static_defined): New function.
authorAlan Modra <amodra@gmail.com>
Fri, 25 Jun 2010 03:46:04 +0000 (03:46 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 25 Jun 2010 03:46:04 +0000 (03:46 +0000)
(get_tls_mask, ppc_type_of_stub): Use it here.
(ppc64_elf_edit_opd): Ensure we only attempt to edit ppc64 input.
(ppc64_elf_tls_setup): Typo fix.
(adjust_toc_syms): Correctly handle symbols defined past the end
of the toc.  Move syms on removed entries to next entry rather
than to start of toc.
(ppc64_elf_edit_toc): Likewise.  Ensure we only attempt to
edit ppc64 input.  Allocate one extra word in skip array.
Honour info->keep_memory when reading relocs if we can.
Adjust toc relocs after adjusting symbols.

bfd/ChangeLog
bfd/elf64-ppc.c

index 41b6cb9714b9f4c4fadb03a3905db716c13fce5e..f1365e553d0d527a84b282403268e2f0139fc10e 100644 (file)
@@ -1,3 +1,17 @@
+2010-06-25  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (is_static_defined): New function.
+       (get_tls_mask, ppc_type_of_stub): Use it here.
+       (ppc64_elf_edit_opd): Ensure we only attempt to edit ppc64 input.
+       (ppc64_elf_tls_setup): Typo fix.
+       (adjust_toc_syms): Correctly handle symbols defined past the end
+       of the toc.  Move syms on removed entries to next entry rather
+       than to start of toc.
+       (ppc64_elf_edit_toc): Likewise.  Ensure we only attempt to
+       edit ppc64 input.  Allocate one extra word in skip array.
+       Honour info->keep_memory when reading relocs if we can.
+       Adjust toc relocs after adjusting symbols.
+
 2010-06-23  Nathan Sidwell  <nathan@codesourcery.com>
 
        * archive64.c (bfd_elf64_archive_write_armap): Fix buffer overrun
 
        * pe-x86_64.c (TARGET_UNDERSCORE): Set value dependent
        to USE_MINGW64_LEADING_UNDERSCORES.
-        * pei-x86_64.c (TARGET_UNDERSCORE): Likewise.
+       * pei-x86_64.c (TARGET_UNDERSCORE): Likewise.
        * config.bfd: Change underscoring default for x64 mingw
        to false.
        * coffcode.h (coff_write_relocs): Add check that dereferenced
index 769b0a43612ad07f3374e6a313ebb34f3ce6d3ee..fbc76002e93657c0e5fb3c24fa7cd884bd2d12dc 100644 (file)
@@ -5566,6 +5566,17 @@ opd_entry_value (asection *opd_sec,
   return val;
 }
 
+/* Return true if symbol is defined in a regular object file.  */
+
+static bfd_boolean
+is_static_defined (struct elf_link_hash_entry *h)
+{
+  return ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section != NULL
+         && h->root.u.def.section->output_section != NULL);
+}
+
 /* If FDH is a function descriptor symbol, return the associated code
    entry symbol if it is defined.  Return NULL otherwise.  */
 
@@ -6704,10 +6715,7 @@ get_tls_mask (unsigned char **tls_maskp,
     *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
   if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
     return 0;
-  if ((h == NULL
-       || ((h->root.type == bfd_link_hash_defined
-           || h->root.type == bfd_link_hash_defweak)
-          && !h->def_dynamic))
+  if ((h == NULL || is_static_defined (h))
       && (next_r == -1 || next_r == -2))
     return 1 - next_r;
   return 1;
@@ -6924,6 +6932,9 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
       bfd_boolean need_edit, add_aux_fields;
       bfd_size_type cnt_16b = 0;
 
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
       sec = bfd_get_section_by_name (ibfd, ".opd");
       if (sec == NULL || sec->size == 0)
        continue;
@@ -7375,7 +7386,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
                      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
                                              opt_fd->dynstr_index);
                      if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
-                       return FALSE;
+                       return NULL;
                    }
                  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
                  tga = &htab->tls_get_addr->elf;
@@ -7840,6 +7851,7 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 {
   struct ppc_link_hash_entry *eh;
   struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
+  unsigned long i;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
@@ -7857,16 +7869,22 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 
   if (eh->elf.root.u.def.section == toc_inf->toc)
     {
-      unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3];
-      if (skip != (unsigned long) -1)
-       eh->elf.root.u.def.value -= skip;
+      if (eh->elf.root.u.def.value > toc_inf->toc->rawsize)
+       i = toc_inf->toc->rawsize >> 3;
       else
+       i = eh->elf.root.u.def.value >> 3;
+
+      if (toc_inf->skip[i] == (unsigned long) -1)
        {
          (*_bfd_error_handler)
-           (_("%s defined in removed toc entry"), eh->elf.root.root.string);
-         eh->elf.root.u.def.section = &bfd_abs_section;
-         eh->elf.root.u.def.value = 0;
+           (_("%s defined on removed toc entry"), eh->elf.root.root.string);
+         do
+           ++i;
+         while (toc_inf->skip[i] == (unsigned long) -1);
+         eh->elf.root.u.def.value = (bfd_vma) i << 3;
        }
+
+      eh->elf.root.u.def.value -= toc_inf->skip[i];
       eh->adjust_done = 1;
     }
   else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
@@ -7898,6 +7916,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
       unsigned char *used;
       unsigned char *keep, last, some_unused;
 
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
       toc = bfd_get_section_by_name (ibfd, ".toc");
       if (toc == NULL
          || toc->size == 0
@@ -7975,7 +7996,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 
              if (skip == NULL)
                {
-                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
                  if (skip == NULL)
                    goto error_ret;
                }
@@ -8025,7 +8046,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
              || (sec->flags & SEC_DEBUGGING) != 0)
            continue;
 
-         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                               info->keep_memory);
          if (relstart == NULL)
            goto error_ret;
 
@@ -8091,6 +8113,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                used[val >> 3] = 1;
              }
          while (repeat);
+
+         if (elf_section_data (sec)->relocs != relstart)
+           free (relstart);
        }
 
       /* Merge the used and skip arrays.  Assume that TOC
@@ -8143,40 +8168,10 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  memcpy (src - off, src, 8);
                }
            }
+         *drop = off;
          toc->rawsize = toc->size;
          toc->size = src - contents - off;
 
-         if (toc->reloc_count != 0)
-           {
-             Elf_Internal_Rela *wrel;
-             bfd_size_type sz;
-
-             /* Read toc relocs.  */
-             relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
-                                                   TRUE);
-             if (relstart == NULL)
-               goto error_ret;
-
-             /* Remove unused toc relocs, and adjust those we keep.  */
-             wrel = relstart;
-             for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
-               if (skip[rel->r_offset >> 3] != (unsigned long) -1)
-                 {
-                   wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
-                   wrel->r_info = rel->r_info;
-                   wrel->r_addend = rel->r_addend;
-                   ++wrel;
-                 }
-               else if (!dec_dynrel_count (rel->r_info, toc, info,
-                                           &local_syms, NULL, NULL))
-                 goto error_ret;
-
-             toc->reloc_count = wrel - relstart;
-             sz = elf_section_data (toc)->rel_hdr.sh_entsize;
-             elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
-             BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
-           }
-
          /* Adjust addends for relocs against the toc section sym.  */
          for (sec = ibfd->sections; sec != NULL; sec = sec->next)
            {
@@ -8185,7 +8180,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                continue;
 
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
-                                                   TRUE);
+                                                   info->keep_memory);
              if (relstart == NULL)
                goto error_ret;
 
@@ -8196,6 +8191,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  asection *sym_sec;
                  struct elf_link_hash_entry *h;
                  Elf_Internal_Sym *sym;
+                 bfd_vma val;
 
                  r_type = ELF64_R_TYPE (rel->r_info);
                  switch (r_type)
@@ -8221,8 +8217,17 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  if (sym_sec != toc || h != NULL || sym->st_value != 0)
                    continue;
 
-                 rel->r_addend -= skip[rel->r_addend >> 3];
+                 val = rel->r_addend;
+
+                 if (val > toc->rawsize)
+                   val = toc->rawsize;
+
+                 rel->r_addend -= skip[val >> 3];
+                 elf_section_data (sec)->relocs = relstart;
                }
+
+             if (elf_section_data (sec)->relocs != relstart)
+               free (relstart);
            }
 
          /* We shouldn't have local or global symbols defined in the TOC,
@@ -8237,22 +8242,30 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                if (sym->st_value != 0
                    && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
                  {
-                   if (skip[sym->st_value >> 3] != (unsigned long) -1)
-                     sym->st_value -= skip[sym->st_value >> 3];
+                   unsigned long i;
+
+                   if (sym->st_value > toc->rawsize)
+                     i = toc->rawsize >> 3;
                    else
+                     i = sym->st_value >> 3;
+
+                   if (skip[sym->st_value >> 3] == (unsigned long) -1)
                      {
                        (*_bfd_error_handler)
-                         (_("%s defined in removed toc entry"),
-                          bfd_elf_sym_name (ibfd, symtab_hdr, sym,
-                                            NULL));
-                       sym->st_value = 0;
-                       sym->st_shndx = SHN_ABS;
+                         (_("%s defined on removed toc entry"),
+                          bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+                       do
+                         ++i;
+                       while (skip[i] == (unsigned long) -1);
+                       sym->st_value = (bfd_vma) i << 3;
                      }
+
+                   sym->st_value -= skip[i];
                    symtab_hdr->contents = (unsigned char *) local_syms;
                  }
            }
 
-         /* Finally, adjust any global syms defined in the toc.  */
+         /* Adjust any global syms defined in this toc input section.  */
          if (toc_inf.global_toc_syms)
            {
              toc_inf.toc = toc;
@@ -8261,6 +8274,37 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
              elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
                                      &toc_inf);
            }
+
+         if (toc->reloc_count != 0)
+           {
+             Elf_Internal_Rela *wrel;
+             bfd_size_type sz;
+
+             /* Read toc relocs.  */
+             relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+                                                   TRUE);
+             if (relstart == NULL)
+               goto error_ret;
+
+             /* Remove unused toc relocs, and adjust those we keep.  */
+             wrel = relstart;
+             for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
+               if (skip[rel->r_offset >> 3] != (unsigned long) -1)
+                 {
+                   wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+                   wrel->r_info = rel->r_info;
+                   wrel->r_addend = rel->r_addend;
+                   ++wrel;
+                 }
+               else if (!dec_dynrel_count (rel->r_info, toc, info,
+                                           &local_syms, NULL, NULL))
+                 goto error_ret;
+
+             toc->reloc_count = wrel - relstart;
+             sz = elf_section_data (toc)->rel_hdr.sh_entsize;
+             elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
+             BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
+           }
        }
 
       if (local_syms != NULL
@@ -9007,12 +9051,8 @@ ppc_type_of_stub (asection *input_sec,
         either a defined function descriptor or a defined entry symbol
         in a regular object file, then it is pointless trying to make
         any other type of stub.  */
-      if (!((fdh->elf.root.type == bfd_link_hash_defined
-           || fdh->elf.root.type == bfd_link_hash_defweak)
-           && fdh->elf.root.u.def.section->output_section != NULL)
-         && !((h->elf.root.type == bfd_link_hash_defined
-               || h->elf.root.type == bfd_link_hash_defweak)
-              && h->elf.root.u.def.section->output_section != NULL))
+      if (!is_static_defined (&fdh->elf)
+         && !is_static_defined (&h->elf))
        return ppc_stub_none;
     }
   else if (elf_local_got_ents (input_sec->owner) != NULL)