2005-05-04 Paolo Bonzini <bonzini@gnu.org>
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 5a5e3a2c81d24c7d59a09bfef9d4062623a190cd..115610ac0d2994446191a8f970607ce5322f9cff 100644 (file)
@@ -19,7 +19,7 @@
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
-   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   59 Temple Place - Suite 330, Boston, MA 02110-1301, USA.  */
 
 /* The 64-bit PowerPC ELF ABI may be found at
    http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and
@@ -4688,9 +4688,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
                      sreloc = bfd_make_section (dynobj, name);
                      flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
+                              | SEC_IN_MEMORY | SEC_LINKER_CREATED
+                              | SEC_ALLOC | SEC_LOAD);
                      if (sreloc == NULL
                          || ! bfd_set_section_flags (dynobj, sreloc, flags)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 3))
@@ -5540,7 +5539,7 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
 
   if (htab->sfpr->size == 0)
-    _bfd_strip_section_from_output (info, htab->sfpr);
+    htab->sfpr->flags |= SEC_EXCLUDE;
 
   return TRUE;
 }
@@ -5952,6 +5951,125 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   return TRUE;
 }
 
+/* Handles decrementing dynamic reloc counts for the reloc specified by
+   R_INFO in section SEC.  If LOCAL_SYMS is NULL, then H and SYM_SEC
+   have already been determined.  */
+
+static bfd_boolean
+dec_dynrel_count (bfd_vma r_info,
+                 asection *sec,
+                 struct bfd_link_info *info,
+                 Elf_Internal_Sym **local_syms,
+                 struct elf_link_hash_entry *h,
+                 asection *sym_sec)
+{
+  enum elf_ppc64_reloc_type r_type;
+  struct ppc_dyn_relocs *p;
+  struct ppc_dyn_relocs **pp;
+
+  /* Can this reloc be dynamic?  This switch, and later tests here
+     should be kept in sync with the code in check_relocs.  */
+  r_type = ELF64_R_TYPE (r_info);
+  switch (r_type)
+    {
+    default:
+      return TRUE;
+
+    case R_PPC64_TPREL16:
+    case R_PPC64_TPREL16_LO:
+    case R_PPC64_TPREL16_HI:
+    case R_PPC64_TPREL16_HA:
+    case R_PPC64_TPREL16_DS:
+    case R_PPC64_TPREL16_LO_DS:
+    case R_PPC64_TPREL16_HIGHER:
+    case R_PPC64_TPREL16_HIGHERA:
+    case R_PPC64_TPREL16_HIGHEST:
+    case R_PPC64_TPREL16_HIGHESTA:
+      if (!info->shared)
+       return TRUE;
+
+    case R_PPC64_TPREL64:
+    case R_PPC64_DTPMOD64:
+    case R_PPC64_DTPREL64:
+    case R_PPC64_ADDR64:
+    case R_PPC64_REL30:
+    case R_PPC64_REL32:
+    case R_PPC64_REL64:
+    case R_PPC64_ADDR14:
+    case R_PPC64_ADDR14_BRNTAKEN:
+    case R_PPC64_ADDR14_BRTAKEN:
+    case R_PPC64_ADDR16:
+    case R_PPC64_ADDR16_DS:
+    case R_PPC64_ADDR16_HA:
+    case R_PPC64_ADDR16_HI:
+    case R_PPC64_ADDR16_HIGHER:
+    case R_PPC64_ADDR16_HIGHERA:
+    case R_PPC64_ADDR16_HIGHEST:
+    case R_PPC64_ADDR16_HIGHESTA:
+    case R_PPC64_ADDR16_LO:
+    case R_PPC64_ADDR16_LO_DS:
+    case R_PPC64_ADDR24:
+    case R_PPC64_ADDR32:
+    case R_PPC64_UADDR16:
+    case R_PPC64_UADDR32:
+    case R_PPC64_UADDR64:
+    case R_PPC64_TOC:
+      break;
+    }
+
+  if (local_syms != NULL)
+    {
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      bfd *ibfd = sec->owner;
+
+      r_symndx = ELF64_R_SYM (r_info);
+      if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
+       return FALSE;
+    }
+
+  if ((info->shared
+       && (MUST_BE_DYN_RELOC (r_type)
+          || (h != NULL
+              && (!info->symbolic
+                  || h->root.type == bfd_link_hash_defweak
+                  || !h->def_regular))))
+      || (ELIMINATE_COPY_RELOCS
+         && !info->shared
+         && h != NULL
+         && (h->root.type == bfd_link_hash_defweak
+             || !h->def_regular)))
+    ;
+  else
+    return TRUE;
+
+  if (h != NULL)
+    pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+  else if (sym_sec != NULL)
+    pp = (struct ppc_dyn_relocs **) &elf_section_data (sym_sec)->local_dynrel;
+  else
+    pp = (struct ppc_dyn_relocs **) &elf_section_data (sec)->local_dynrel;
+
+  while ((p = *pp) != NULL)
+    {
+      if (p->sec == sec)
+       {
+         if (!MUST_BE_DYN_RELOC (r_type))
+           p->pc_count -= 1;
+         p->count -= 1;
+         if (p->count == 0)
+           *pp = p->next;
+         return TRUE;
+       }
+      pp = &p->next;
+    }
+
+  (*_bfd_error_handler) (_("dynreloc miscount for %B, section %A"),
+                          sec->owner, sec);
+  bfd_set_error (bfd_error_bad_value);
+  return FALSE;
+}
+
 /* Remove unused Official Procedure Descriptor entries.  Currently we
    only remove those associated with functions in discarded link-once
    sections, or weakly defined functions that have been overridden.  It
@@ -6068,7 +6186,8 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
              if (h != NULL)
                sym_name = h->root.root.string;
              else
-               sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym);
+               sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
+                                            sym_sec);
 
              (*_bfd_error_handler)
                (_("%B: undefined sym `%s' in .opd section"),
@@ -6272,33 +6391,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
              if (skip)
                {
-                 BFD_ASSERT (MUST_BE_DYN_RELOC (ELF64_R_TYPE (rel->r_info)));
-                 if (info->shared)
-                   {
-                     /* We won't be needing dynamic relocs here.  */
-                     struct ppc_dyn_relocs **pp;
-                     struct ppc_dyn_relocs *p;
-
-                     if (h != NULL)
-                       pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
-                     else if (sym_sec != NULL)
-                       pp = ((struct ppc_dyn_relocs **)
-                             &elf_section_data (sym_sec)->local_dynrel);
-                     else
-                       pp = ((struct ppc_dyn_relocs **)
-                             &elf_section_data (sec)->local_dynrel);
-                     while ((p = *pp) != NULL)
-                       {
-                         if (p->sec == sec)
-                           {
-                             p->count -= 1;
-                             if (p->count == 0)
-                               *pp = p->next;
-                             break;
-                           }
-                         pp = &p->next;
-                       }
-                   }
+                 if (!dec_dynrel_count (rel->r_info, sec, info,
+                                        NULL, h, sym_sec))
+                   goto error_ret;
                }
              else
                {
@@ -6669,29 +6764,20 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                          ent->got.refcount -= 1;
                      }
                  }
-               else if (h != NULL)
+               else
                  {
-                   struct ppc_link_hash_entry * eh;
-                   struct ppc_dyn_relocs **pp;
-                   struct ppc_dyn_relocs *p;
-
-                   /* Adjust dynamic relocs.  */
-                   eh = (struct ppc_link_hash_entry *) h;
-                   for (pp = &eh->dyn_relocs;
-                        (p = *pp) != NULL;
-                        pp = &p->next)
-                     if (p->sec == sec)
-                       {
-                         /* If we got rid of a DTPMOD/DTPREL reloc
-                            pair then we'll lose one or two dyn
-                            relocs.  */
-                         if (tls_set == (TLS_EXPLICIT | TLS_GD))
-                           p->count -= 1;
-                         p->count -= 1;
-                         if (p->count == 0)
-                           *pp = p->next;
-                         break;
-                       }
+                   /* If we got rid of a DTPMOD/DTPREL reloc pair then
+                      we'll lose one or two dyn relocs.  */
+                   if (!dec_dynrel_count (rel->r_info, sec, info,
+                                          NULL, h, sym_sec))
+                     return FALSE;
+
+                   if (tls_set == (TLS_EXPLICIT | TLS_GD))
+                     {
+                       if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
+                                              NULL, h, sym_sec))
+                         return FALSE;
+                     }
                  }
 
                *tls_mask |= tls_set;
@@ -7057,6 +7143,10 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *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;
@@ -7132,7 +7222,8 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      {
                        (*_bfd_error_handler)
                          (_("%s defined in removed toc entry"),
-                          bfd_elf_sym_name (ibfd, symtab_hdr, sym));
+                          bfd_elf_sym_name (ibfd, symtab_hdr, sym,
+                                            NULL));
                        sym->st_value = 0;
                        sym->st_shndx = SHN_ABS;
                      }
@@ -7596,7 +7687,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       if (s->size == 0)
        {
-         _bfd_strip_section_from_output (info, s);
+         s->flags |= SEC_EXCLUDE;
          continue;
        }
 
@@ -7625,7 +7716,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (s != NULL && s != htab->got)
        {
          if (s->size == 0)
-           _bfd_strip_section_from_output (info, s);
+           s->flags |= SEC_EXCLUDE;
          else
            {
              s->contents = bfd_zalloc (ibfd, s->size);
@@ -7637,7 +7728,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       if (s != NULL)
        {
          if (s->size == 0)
-           _bfd_strip_section_from_output (info, s);
+           s->flags |= SEC_EXCLUDE;
          else
            {
              s->contents = bfd_zalloc (ibfd, s->size);
@@ -8245,7 +8336,7 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
 
   /* We can't use output_bfd->section_count here to find the top output
      section index as some sections may have been removed, and
-     _bfd_strip_section_from_output doesn't renumber the indices.  */
+     strip_excluded_output_sections doesn't renumber the indices.  */
   for (section = output_bfd->sections, top_index = 0;
        section != NULL;
        section = section->next)
@@ -9384,7 +9475,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
-         sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym);
+         sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
          sym_type = ELF64_ST_TYPE (sym->st_info);
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
          opd_adjust = get_opd_info (sec);
This page took 0.047182 seconds and 4 git commands to generate.