2008-03-07 Paul Brook <paul@codesourcery.com>
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 63a8c6592d3628741c28024719c5c6613854fc62..513979926b412408ed0a376674c1051843d7ecc5 100644 (file)
@@ -1,6 +1,6 @@
 /* ELF linking support for BFD.
    Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007 Free Software Foundation, Inc.
+   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -884,7 +884,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
 
   /* This code is for coping with dynamic objects, and is only useful
      if we are doing an ELF link.  */
-  if (info->hash->creator != abfd->xvec)
+  if (info->output_bfd->xvec != abfd->xvec)
     return TRUE;
 
   /* For merging, we only care about real symbols.  */
@@ -2321,7 +2321,7 @@ _bfd_elf_link_output_relocs (bfd *output_bfd,
       (*_bfd_error_handler)
        (_("%B: relocation size mismatch in %B section %A"),
         output_bfd, input_section->owner, input_section);
-      bfd_set_error (bfd_error_wrong_object_format);
+      bfd_set_error (bfd_error_wrong_format);
       return FALSE;
     }
 
@@ -2789,6 +2789,11 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   if (h == NULL)
     return TRUE;
 
+  /* STV_HIDDEN or STV_INTERNAL ones must be local.  */
+  if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
+      || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
+    return TRUE;
+
   /* Common symbols that become definitions don't get the DEF_REGULAR
      flag set, so test it first, and don't bail out.  */
   if (ELF_COMMON_DEF_P (h))
@@ -2817,10 +2822,6 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
   if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
     return FALSE;
 
-  /* However, STV_HIDDEN or STV_INTERNAL ones must be local.  */
-  if (ELF_ST_VISIBILITY (h->other) != STV_PROTECTED)
-    return TRUE;
-
   hash_table = elf_hash_table (info);
   if (!is_elf_hash_table (hash_table))
     return TRUE;
@@ -3336,7 +3337,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         the format of the output file.  */
       if (info->relocatable
          || !is_elf_hash_table (htab)
-         || htab->root.creator != abfd->xvec)
+         || info->output_bfd->xvec != abfd->xvec)
        {
          if (info->relocatable)
            bfd_set_error (bfd_error_invalid_operation);
@@ -3433,7 +3434,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         format as the output, we can't make a shared library.  */
       if (info->shared
          && is_elf_hash_table (htab)
-         && htab->root.creator == abfd->xvec
+         && info->output_bfd->xvec == abfd->xvec
          && !htab->dynamic_sections_created)
        {
          if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
@@ -4674,7 +4675,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   if (! dynamic
       && is_elf_hash_table (htab)
       && bed->check_relocs != NULL
-      && (*bed->relocs_compatible) (abfd->xvec, htab->root.creator))
+      && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec))
     {
       asection *o;
 
@@ -5234,13 +5235,13 @@ static const size_t elf_buckets[] =
    Therefore the result is always a good payoff between few collisions
    (= short chain lengths) and table size.  */
 static size_t
-compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes,
-                     unsigned long int nsyms, int gnu_hash)
+compute_bucket_count (struct bfd_link_info *info,
+                     unsigned long int *hashcodes ATTRIBUTE_UNUSED,
+                     unsigned long int nsyms,
+                     int gnu_hash)
 {
-  size_t dynsymcount = elf_hash_table (info)->dynsymcount;
   size_t best_size = 0;
   unsigned long int i;
-  bfd_size_type amt;
 
   /* We have a problem here.  The following code to optimize the table
      size requires an integer type with more the 32 bits.  If
@@ -5252,8 +5253,10 @@ compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes,
       size_t maxsize;
       BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
       bfd *dynobj = elf_hash_table (info)->dynobj;
+      size_t dynsymcount = elf_hash_table (info)->dynsymcount;
       const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
       unsigned long int *counts;
+      bfd_size_type amt;
 
       /* Possible optimization parameters: if we have NSYMS symbols we say
         that the hashing table must at least have NSYMS/4 and at most
@@ -6868,7 +6871,7 @@ elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
   Elf_Internal_Sym **ind, **indbufend, **indbuf;
   struct elf_symbuf_symbol *ssym;
   struct elf_symbuf_head *ssymbuf, *ssymhead;
-  bfd_size_type i, shndx_count;
+  bfd_size_type i, shndx_count, total_size;
 
   indbuf = bfd_malloc2 (symcount, sizeof (*indbuf));
   if (indbuf == NULL)
@@ -6888,15 +6891,16 @@ elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
       if (ind[0]->st_shndx != ind[1]->st_shndx)
        shndx_count++;
 
-  ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
-                       + (indbufend - indbuf) * sizeof (*ssymbuf));
+  total_size = ((shndx_count + 1) * sizeof (*ssymbuf)
+               + (indbufend - indbuf) * sizeof (*ssym));
+  ssymbuf = bfd_malloc (total_size);
   if (ssymbuf == NULL)
     {
       free (indbuf);
       return NULL;
     }
 
-  ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
+  ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count + 1);
   ssymbuf->ssym = NULL;
   ssymbuf->count = shndx_count;
   ssymbuf->st_shndx = 0;
@@ -6914,7 +6918,9 @@ elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
       ssym->st_other = (*ind)->st_other;
       ssymhead->count++;
     }
-  BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
+  BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count
+             && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf)
+                 == total_size));
 
   free (indbuf);
   return ssymbuf;
@@ -8178,9 +8184,10 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
          bfd_size_type amt;
 
          amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
-         finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2);
+         destshndx = bfd_realloc (destshndx, amt * 2);
          if (destshndx == NULL)
            return FALSE;
+         finfo->symshndxbuf = destshndx;
          memset ((char *) destshndx + amt, 0, amt);
          finfo->shndxbuf_size *= 2;
        }
@@ -8536,10 +8543,15 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
                sym.st_value += input_sec->output_section->vma;
                if (h->type == STT_TLS)
                  {
-                   /* STT_TLS symbols are relative to PT_TLS segment
-                      base.  */
-                   BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
-                   sym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
+                   asection *tls_sec = elf_hash_table (finfo->info)->tls_sec;
+                   if (tls_sec != NULL)
+                     sym.st_value -= tls_sec->vma;
+                   else
+                     {
+                       /* The TLS section may have been garbage collected.  */
+                       BFD_ASSERT (finfo->info->gc_sections
+                                   && !input_sec->gc_mark);
+                     }
                  }
              }
          }
@@ -9506,6 +9518,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
        default:
          {
            if (! (o->flags & SEC_EXCLUDE)
+               && ! (o->output_section->flags & SEC_NEVER_LOAD)
                && ! bfd_set_section_contents (output_bfd, o->output_section,
                                               contents,
                                               (file_ptr) o->output_offset,
@@ -10935,6 +10948,139 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   return FALSE;
 }
 \f
+/* Initialize COOKIE for input bfd ABFD.  */
+
+static bfd_boolean
+init_reloc_cookie (struct elf_reloc_cookie *cookie,
+                  struct bfd_link_info *info, bfd *abfd)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  const struct elf_backend_data *bed;
+
+  bed = get_elf_backend_data (abfd);
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+  cookie->abfd = abfd;
+  cookie->sym_hashes = elf_sym_hashes (abfd);
+  cookie->bad_symtab = elf_bad_symtab (abfd);
+  if (cookie->bad_symtab)
+    {
+      cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
+      cookie->extsymoff = 0;
+    }
+  else
+    {
+      cookie->locsymcount = symtab_hdr->sh_info;
+      cookie->extsymoff = symtab_hdr->sh_info;
+    }
+
+  if (bed->s->arch_size == 32)
+    cookie->r_sym_shift = 8;
+  else
+    cookie->r_sym_shift = 32;
+
+  cookie->locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+  if (cookie->locsyms == NULL && cookie->locsymcount != 0)
+    {
+      cookie->locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                             cookie->locsymcount, 0,
+                                             NULL, NULL, NULL);
+      if (cookie->locsyms == NULL)
+       {
+         info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
+         return FALSE;
+       }
+      if (info->keep_memory)
+       symtab_hdr->contents = (bfd_byte *) cookie->locsyms;
+    }
+  return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie, if appropriate.  */
+
+static void
+fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  if (cookie->locsyms != NULL
+      && symtab_hdr->contents != (unsigned char *) cookie->locsyms)
+    free (cookie->locsyms);
+}
+
+/* Initialize the relocation information in COOKIE for input section SEC
+   of input bfd ABFD.  */
+
+static bfd_boolean
+init_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+                       struct bfd_link_info *info, bfd *abfd,
+                       asection *sec)
+{
+  const struct elf_backend_data *bed;
+
+  if (sec->reloc_count == 0)
+    {
+      cookie->rels = NULL;
+      cookie->relend = NULL;
+    }
+  else
+    {
+      bed = get_elf_backend_data (abfd);
+
+      cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+                                               info->keep_memory);
+      if (cookie->rels == NULL)
+       return FALSE;
+      cookie->rel = cookie->rels;
+      cookie->relend = (cookie->rels
+                       + sec->reloc_count * bed->s->int_rels_per_ext_rel);
+    }
+  cookie->rel = cookie->rels;
+  return TRUE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_rels,
+   if appropriate.  */
+
+static void
+fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie,
+                       asection *sec)
+{
+  if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels)
+    free (cookie->rels);
+}
+
+/* Initialize the whole of COOKIE for input section SEC.  */
+
+static bfd_boolean
+init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+                              struct bfd_link_info *info,
+                              asection *sec)
+{
+  if (!init_reloc_cookie (cookie, info, sec->owner))
+    goto error1;
+  if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec))
+    goto error2;
+  return TRUE;
+
+ error2:
+  fini_reloc_cookie (cookie, sec->owner);
+ error1:
+  return FALSE;
+}
+
+/* Free the memory allocated by init_reloc_cookie_for_section,
+   if appropriate.  */
+
+static void
+fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie,
+                              asection *sec)
+{
+  fini_reloc_cookie_rels (cookie, sec);
+  fini_reloc_cookie (cookie, sec->owner);
+}
+\f
 /* Garbage collect unused sections.  */
 
 /* Default gc_mark_hook.  */
@@ -10967,6 +11113,59 @@ _bfd_elf_gc_mark_hook (asection *sec,
   return NULL;
 }
 
+/* COOKIE->rel describes a relocation against section SEC, which is
+   a section we've decided to keep.  Return the section that contains
+   the relocation symbol, or NULL if no section contains it.  */
+
+asection *
+_bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
+                      elf_gc_mark_hook_fn gc_mark_hook,
+                      struct elf_reloc_cookie *cookie)
+{
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+
+  r_symndx = cookie->rel->r_info >> cookie->r_sym_shift;
+  if (r_symndx == 0)
+    return NULL;
+
+  if (r_symndx >= cookie->locsymcount
+      || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
+    {
+      h = cookie->sym_hashes[r_symndx - cookie->extsymoff];
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
+    }
+
+  return (*gc_mark_hook) (sec, info, cookie->rel, NULL,
+                         &cookie->locsyms[r_symndx]);
+}
+
+/* COOKIE->rel describes a relocation against section SEC, which is
+   a section we've decided to keep.  Mark the section that contains
+   the relocation symbol.  */
+
+bfd_boolean
+_bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
+                       asection *sec,
+                       elf_gc_mark_hook_fn gc_mark_hook,
+                       struct elf_reloc_cookie *cookie)
+{
+  asection *rsec;
+
+  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+  if (rsec && !rsec->gc_mark)
+    {
+      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
+       rsec->gc_mark = 1;
+      else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+       return FALSE;
+    }
+  return TRUE;
+}
+
 /* The mark phase of garbage collection.  For a given section, mark
    it and any sections in this section's group, and all the sections
    which define symbols to which it refers.  */
@@ -10977,8 +11176,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
                  elf_gc_mark_hook_fn gc_mark_hook)
 {
   bfd_boolean ret;
-  bfd_boolean is_eh;
-  asection *group_sec;
+  asection *group_sec, *eh_frame;
 
   sec->gc_mark = 1;
 
@@ -10990,103 +11188,39 @@ _bfd_elf_gc_mark (struct bfd_link_info *info,
 
   /* Look through the section relocs.  */
   ret = TRUE;
-  is_eh = strcmp (sec->name, ".eh_frame") == 0;
-  if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
+  eh_frame = elf_eh_frame_section (sec->owner);
+  if ((sec->flags & SEC_RELOC) != 0
+      && sec->reloc_count > 0
+      && sec != eh_frame)
     {
-      Elf_Internal_Rela *relstart, *rel, *relend;
-      Elf_Internal_Shdr *symtab_hdr;
-      struct elf_link_hash_entry **sym_hashes;
-      size_t nlocsyms;
-      size_t extsymoff;
-      bfd *input_bfd = sec->owner;
-      const struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
-      Elf_Internal_Sym *isym = NULL;
-      int r_sym_shift;
-
-      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-      sym_hashes = elf_sym_hashes (input_bfd);
-
-      /* Read the local symbols.  */
-      if (elf_bad_symtab (input_bfd))
-       {
-         nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym;
-         extsymoff = 0;
-       }
-      else
-       extsymoff = nlocsyms = symtab_hdr->sh_info;
+      struct elf_reloc_cookie cookie;
 
-      isym = (Elf_Internal_Sym *) symtab_hdr->contents;
-      if (isym == NULL && nlocsyms != 0)
+      if (!init_reloc_cookie_for_section (&cookie, info, sec))
+       ret = FALSE;
+      else
        {
-         isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0,
-                                      NULL, NULL, NULL);
-         if (isym == NULL)
-           return FALSE;
+         for (; cookie.rel < cookie.relend; cookie.rel++)
+           if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
+             {
+               ret = FALSE;
+               break;
+             }
+         fini_reloc_cookie_for_section (&cookie, sec);
        }
+    }
 
-      /* Read the relocations.  */
-      relstart = _bfd_elf_link_read_relocs (input_bfd, sec, NULL, NULL,
-                                           info->keep_memory);
-      if (relstart == NULL)
-       {
-         ret = FALSE;
-         goto out1;
-       }
-      relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+  if (ret && eh_frame && elf_fde_list (sec))
+    {
+      struct elf_reloc_cookie cookie;
 
-      if (bed->s->arch_size == 32)
-       r_sym_shift = 8;
+      if (!init_reloc_cookie_for_section (&cookie, info, eh_frame))
+       ret = FALSE;
       else
-       r_sym_shift = 32;
-
-      for (rel = relstart; rel < relend; rel++)
        {
-         unsigned long r_symndx;
-         asection *rsec;
-         struct elf_link_hash_entry *h;
-
-         r_symndx = rel->r_info >> r_sym_shift;
-         if (r_symndx == 0)
-           continue;
-
-         if (r_symndx >= nlocsyms
-             || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL)
-           {
-             h = sym_hashes[r_symndx - extsymoff];
-             while (h->root.type == bfd_link_hash_indirect
-                    || h->root.type == bfd_link_hash_warning)
-               h = (struct elf_link_hash_entry *) h->root.u.i.link;
-             rsec = (*gc_mark_hook) (sec, info, rel, h, NULL);
-           }
-         else
-           {
-             rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]);
-           }
-
-         if (rsec && !rsec->gc_mark)
-           {
-             if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
-               rsec->gc_mark = 1;
-             else if (is_eh)
-               rsec->gc_mark_from_eh = 1;
-             else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
-               {
-                 ret = FALSE;
-                 goto out2;
-               }
-           }
-       }
-
-    out2:
-      if (elf_section_data (sec)->relocs != relstart)
-       free (relstart);
-    out1:
-      if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym)
-       {
-         if (! info->keep_memory)
-           free (isym);
-         else
-           symtab_hdr->contents = (unsigned char *) isym;
+         if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame,
+                                     gc_mark_hook, &cookie))
+           ret = FALSE;
+         fini_reloc_cookie_for_section (&cookie, eh_frame);
        }
     }
 
@@ -11336,6 +11470,29 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+/* Keep all sections containing symbols undefined on the command-line,
+   and the section containing the entry symbol.  */
+
+void
+_bfd_elf_gc_keep (struct bfd_link_info *info)
+{
+  struct bfd_sym_chain *sym;
+
+  for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
+    {
+      struct elf_link_hash_entry *h;
+
+      h = elf_link_hash_lookup (elf_hash_table (info), sym->name,
+                               FALSE, FALSE, FALSE);
+
+      if (h != NULL
+         && (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+         && !bfd_is_abs_section (h->root.u.def.section))
+       h->root.u.def.section->flags |= SEC_KEEP;
+    }
+}
+
 /* Do mark and sweep of unused sections.  */
 
 bfd_boolean
@@ -11347,14 +11504,33 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (!bed->can_gc_sections
-      || info->relocatable
-      || info->emitrelocations
       || !is_elf_hash_table (info->hash))
     {
       (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
       return TRUE;
     }
 
+  bed->gc_keep (info);
+
+  /* Try to parse each bfd's .eh_frame section.  Point elf_eh_frame_section
+     at the .eh_frame section if we can mark the FDEs individually.  */
+  _bfd_elf_begin_eh_frame_parsing (info);
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *sec;
+      struct elf_reloc_cookie cookie;
+
+      sec = bfd_get_section_by_name (sub, ".eh_frame");
+      if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+       {
+         _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
+         if (elf_section_data (sec)->sec_info)
+           elf_eh_frame_section (sub) = sec;
+         fini_reloc_cookie_for_section (&cookie, sec);
+       }
+    }
+  _bfd_elf_end_eh_frame_parsing (info);
+
   /* Apply transitive closure to the vtable entry usage info.  */
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_gc_propagate_vtable_entries_used,
@@ -11392,69 +11568,7 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 
   /* Allow the backend to mark additional target specific sections.  */
   if (bed->gc_mark_extra_sections)
-    bed->gc_mark_extra_sections(info, gc_mark_hook);
-
-  /* ... again for sections marked from eh_frame.  */
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
-    {
-      asection *o;
-
-      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
-       continue;
-
-      /* Keep .gcc_except_table.* if the associated .text.* (or the
-        associated .gnu.linkonce.t.* if .text.* doesn't exist) is
-        marked.  This isn't very nice, but the proper solution,
-        splitting .eh_frame up and using comdat doesn't pan out
-        easily due to needing special relocs to handle the
-        difference of two symbols in separate sections.
-        Don't keep code sections referenced by .eh_frame.  */
-#define TEXT_PREFIX                    ".text."
-#define TEXT_PREFIX2                   ".gnu.linkonce.t."
-#define GCC_EXCEPT_TABLE_PREFIX                ".gcc_except_table."
-      for (o = sub->sections; o != NULL; o = o->next)
-       if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
-         {
-           if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX))
-             {
-               char *fn_name;
-               const char *sec_name;
-               asection *fn_text;
-               unsigned o_name_prefix_len , fn_name_prefix_len, tmp;
-
-               o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
-               sec_name = o->name + o_name_prefix_len;
-               fn_name_prefix_len = strlen (TEXT_PREFIX);
-               tmp = strlen (TEXT_PREFIX2);
-               if (tmp > fn_name_prefix_len)
-                 fn_name_prefix_len = tmp;
-               fn_name
-                 = bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1);
-               if (fn_name == NULL)
-                 return FALSE;
-
-               /* Try the first prefix.  */
-               sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
-               fn_text = bfd_get_section_by_name (sub, fn_name);
-
-               /* Try the second prefix.  */
-               if (fn_text == NULL)
-                 {
-                   sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name);
-                   fn_text = bfd_get_section_by_name (sub, fn_name);
-                 }
-
-               free (fn_name);
-               if (fn_text == NULL || !fn_text->gc_mark)
-                 continue;
-             }
-
-           /* If not using specially named exception table section,
-              then keep whatever we are using.  */
-           if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-             return FALSE;
-         }
-    }
+    bed->gc_mark_extra_sections (info, gc_mark_hook);
 
   /* ... and mark SEC_EXCLUDE for those that go.  */
   return elf_gc_sweep (abfd, info);
@@ -11772,16 +11886,15 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 {
   struct elf_reloc_cookie cookie;
   asection *stab, *eh;
-  Elf_Internal_Shdr *symtab_hdr;
   const struct elf_backend_data *bed;
   bfd *abfd;
-  unsigned int count;
   bfd_boolean ret = FALSE;
 
   if (info->traditional_format
       || !is_elf_hash_table (info->hash))
     return FALSE;
 
+  _bfd_elf_begin_eh_frame_parsing (info);
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
     {
       if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
@@ -11814,96 +11927,39 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
          && bed->elf_backend_discard_info == NULL)
        continue;
 
-      symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-      cookie.abfd = abfd;
-      cookie.sym_hashes = elf_sym_hashes (abfd);
-      cookie.bad_symtab = elf_bad_symtab (abfd);
-      if (cookie.bad_symtab)
-       {
-         cookie.locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
-         cookie.extsymoff = 0;
-       }
-      else
-       {
-         cookie.locsymcount = symtab_hdr->sh_info;
-         cookie.extsymoff = symtab_hdr->sh_info;
-       }
-
-      if (bed->s->arch_size == 32)
-       cookie.r_sym_shift = 8;
-      else
-       cookie.r_sym_shift = 32;
-
-      cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
-      if (cookie.locsyms == NULL && cookie.locsymcount != 0)
-       {
-         cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-                                                cookie.locsymcount, 0,
-                                                NULL, NULL, NULL);
-         if (cookie.locsyms == NULL)
-           {
-             info->callbacks->einfo (_("%P%X: can not read symbols: %E\n"));
-             return FALSE;
-           }
-       }
+      if (!init_reloc_cookie (&cookie, info, abfd))
+       return FALSE;
 
-      if (stab != NULL)
+      if (stab != NULL
+         && stab->reloc_count > 0
+         && init_reloc_cookie_rels (&cookie, info, abfd, stab))
        {
-         cookie.rels = NULL;
-         count = stab->reloc_count;
-         if (count != 0)
-           cookie.rels = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL,
-                                                    info->keep_memory);
-         if (cookie.rels != NULL)
-           {
-             cookie.rel = cookie.rels;
-             cookie.relend = cookie.rels;
-             cookie.relend += count * bed->s->int_rels_per_ext_rel;
-             if (_bfd_discard_section_stabs (abfd, stab,
-                                             elf_section_data (stab)->sec_info,
-                                             bfd_elf_reloc_symbol_deleted_p,
-                                             &cookie))
-               ret = TRUE;
-             if (elf_section_data (stab)->relocs != cookie.rels)
-               free (cookie.rels);
-           }
+         if (_bfd_discard_section_stabs (abfd, stab,
+                                         elf_section_data (stab)->sec_info,
+                                         bfd_elf_reloc_symbol_deleted_p,
+                                         &cookie))
+           ret = TRUE;
+         fini_reloc_cookie_rels (&cookie, stab);
        }
 
-      if (eh != NULL)
+      if (eh != NULL
+         && init_reloc_cookie_rels (&cookie, info, abfd, eh))
        {
-         cookie.rels = NULL;
-         count = eh->reloc_count;
-         if (count != 0)
-           cookie.rels = _bfd_elf_link_read_relocs (abfd, eh, NULL, NULL,
-                                                    info->keep_memory);
-         cookie.rel = cookie.rels;
-         cookie.relend = cookie.rels;
-         if (cookie.rels != NULL)
-           cookie.relend += count * bed->s->int_rels_per_ext_rel;
-
+         _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
          if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
                                                 bfd_elf_reloc_symbol_deleted_p,
                                                 &cookie))
            ret = TRUE;
-
-         if (cookie.rels != NULL
-             && elf_section_data (eh)->relocs != cookie.rels)
-           free (cookie.rels);
+         fini_reloc_cookie_rels (&cookie, eh);
        }
 
       if (bed->elf_backend_discard_info != NULL
          && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
        ret = TRUE;
 
-      if (cookie.locsyms != NULL
-         && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
-       {
-         if (! info->keep_memory)
-           free (cookie.locsyms);
-         else
-           symtab_hdr->contents = (unsigned char *) cookie.locsyms;
-       }
+      fini_reloc_cookie (&cookie, abfd);
     }
+  _bfd_elf_end_eh_frame_parsing (info);
 
   if (info->eh_frame_hdr
       && !info->relocatable
This page took 0.033123 seconds and 4 git commands to generate.