* gas/i860/dir-intel03-err.l: Update for junk at end line becoming
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 05f7c682b2f92c1e5137ba648e4046ad69ec71a9..e9bbd2be59ccb32249ca0b9ba5d264ed555fc656 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linker support.
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 /* ELF linker code.  */
 
-#include "safe-ctype.h"
-
-static bfd_boolean elf_link_add_object_symbols (bfd *, struct bfd_link_info *);
-static bfd_boolean elf_finalize_dynstr (bfd *, struct bfd_link_info *);
-static bfd_boolean elf_collect_hash_codes (struct elf_link_hash_entry *,
-                                          void *);
-static bfd_boolean elf_section_ignore_discarded_relocs (asection *);
-
-/* Given an ELF BFD, add symbols to the global hash table as
-   appropriate.  */
-
-bfd_boolean
-elf_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
-{
-  switch (bfd_get_format (abfd))
-    {
-    case bfd_object:
-      return elf_link_add_object_symbols (abfd, info);
-    case bfd_archive:
-      return _bfd_elf_link_add_archive_symbols (abfd, info);
-    default:
-      bfd_set_error (bfd_error_wrong_format);
-      return FALSE;
-    }
-}
-\f
-/* Sort symbol by value and section.  */
-static int
-sort_symbol (const void *arg1, const void *arg2)
-{
-  const struct elf_link_hash_entry *h1
-    = *(const struct elf_link_hash_entry **) arg1;
-  const struct elf_link_hash_entry *h2
-    = *(const struct elf_link_hash_entry **) arg2;
-  bfd_signed_vma vdiff = h1->root.u.def.value - h2->root.u.def.value;
-
-  if (vdiff)
-    return vdiff > 0 ? 1 : -1;
-  else
-    {
-      long sdiff = h1->root.u.def.section - h2->root.u.def.section;
-      if (sdiff)
-       return sdiff > 0 ? 1 : -1;
-      else
-       return 0;
-    }
-}
-
-/* Add symbols from an ELF object file to the linker hash table.  */
-
-static bfd_boolean
-elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
-{
-  bfd_boolean (*add_symbol_hook)
-    (bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
-     const char **, flagword *, asection **, bfd_vma *);
-  bfd_boolean (*check_relocs)
-    (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
-  bfd_boolean collect;
-  Elf_Internal_Shdr *hdr;
-  bfd_size_type symcount;
-  bfd_size_type extsymcount;
-  bfd_size_type extsymoff;
-  struct elf_link_hash_entry **sym_hash;
-  bfd_boolean dynamic;
-  Elf_External_Versym *extversym = NULL;
-  Elf_External_Versym *ever;
-  struct elf_link_hash_entry *weaks;
-  struct elf_link_hash_entry **nondeflt_vers = NULL;
-  bfd_size_type nondeflt_vers_cnt = 0;
-  Elf_Internal_Sym *isymbuf = NULL;
-  Elf_Internal_Sym *isym;
-  Elf_Internal_Sym *isymend;
-  const struct elf_backend_data *bed;
-  bfd_boolean dt_needed;
-  struct elf_link_hash_table * hash_table;
-  bfd_size_type amt;
-
-  hash_table = elf_hash_table (info);
-
-  bed = get_elf_backend_data (abfd);
-  add_symbol_hook = bed->elf_add_symbol_hook;
-  collect = bed->collect;
-
-  if ((abfd->flags & DYNAMIC) == 0)
-    dynamic = FALSE;
-  else
-    {
-      dynamic = TRUE;
-
-      /* You can't use -r against a dynamic object.  Also, there's no
-        hope of using a dynamic object which does not exactly match
-        the format of the output file.  */
-      if (info->relocatable
-         || !is_elf_hash_table (hash_table)
-         || hash_table->root.creator != abfd->xvec)
-       {
-         bfd_set_error (bfd_error_invalid_operation);
-         goto error_return;
-       }
-    }
-
-  /* As a GNU extension, any input sections which are named
-     .gnu.warning.SYMBOL are treated as warning symbols for the given
-     symbol.  This differs from .gnu.warning sections, which generate
-     warnings when they are included in an output file.  */
-  if (info->executable)
-    {
-      asection *s;
-
-      for (s = abfd->sections; s != NULL; s = s->next)
-       {
-         const char *name;
-
-         name = bfd_get_section_name (abfd, s);
-         if (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0)
-           {
-             char *msg;
-             bfd_size_type sz;
-             bfd_size_type prefix_len;
-             const char * gnu_warning_prefix = _("warning: ");
-
-             name += sizeof ".gnu.warning." - 1;
-
-             /* If this is a shared object, then look up the symbol
-                in the hash table.  If it is there, and it is already
-                been defined, then we will not be using the entry
-                from this shared object, so we don't need to warn.
-                FIXME: If we see the definition in a regular object
-                later on, we will warn, but we shouldn't.  The only
-                fix is to keep track of what warnings we are supposed
-                to emit, and then handle them all at the end of the
-                link.  */
-             if (dynamic)
-               {
-                 struct elf_link_hash_entry *h;
-
-                 h = elf_link_hash_lookup (hash_table, name,
-                                           FALSE, FALSE, TRUE);
-
-                 /* FIXME: What about bfd_link_hash_common?  */
-                 if (h != NULL
-                     && (h->root.type == bfd_link_hash_defined
-                         || h->root.type == bfd_link_hash_defweak))
-                   {
-                     /* We don't want to issue this warning.  Clobber
-                        the section size so that the warning does not
-                        get copied into the output file.  */
-                     s->_raw_size = 0;
-                     continue;
-                   }
-               }
-
-             sz = bfd_section_size (abfd, s);
-             prefix_len = strlen (gnu_warning_prefix);
-             msg = bfd_alloc (abfd, prefix_len + sz + 1);
-             if (msg == NULL)
-               goto error_return;
-
-             strcpy (msg, gnu_warning_prefix);
-             if (! bfd_get_section_contents (abfd, s, msg + prefix_len, 0, sz))
-               goto error_return;
-
-             msg[prefix_len + sz] = '\0';
-
-             if (! (_bfd_generic_link_add_one_symbol
-                    (info, abfd, name, BSF_WARNING, s, 0, msg,
-                     FALSE, collect, NULL)))
-               goto error_return;
-
-             if (! info->relocatable)
-               {
-                 /* Clobber the section size so that the warning does
-                    not get copied into the output file.  */
-                 s->_raw_size = 0;
-               }
-           }
-       }
-    }
-
-  dt_needed = FALSE;
-  if (! dynamic)
-    {
-      /* If we are creating a shared library, create all the dynamic
-        sections immediately.  We need to attach them to something,
-        so we attach them to this BFD, provided it is the right
-        format.  FIXME: If there are no input BFD's of the same
-        format as the output, we can't make a shared library.  */
-      if (info->shared
-         && is_elf_hash_table (hash_table)
-         && hash_table->root.creator == abfd->xvec
-         && ! hash_table->dynamic_sections_created)
-       {
-         if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
-           goto error_return;
-       }
-    }
-  else if (!is_elf_hash_table (hash_table))
-    goto error_return;
-  else
-    {
-      asection *s;
-      bfd_boolean add_needed;
-      const char *name;
-      bfd_size_type oldsize;
-      bfd_size_type strindex;
-      struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
-
-      /* ld --just-symbols and dynamic objects don't mix very well.
-        Test for --just-symbols by looking at info set up by
-        _bfd_elf_link_just_syms.  */
-      if ((s = abfd->sections) != NULL
-         && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
-       goto error_return;
-
-      /* Find the name to use in a DT_NEEDED entry that refers to this
-        object.  If the object has a DT_SONAME entry, we use it.
-        Otherwise, if the generic linker stuck something in
-        elf_dt_name, we use that.  Otherwise, we just use the file
-        name.  If the generic linker put a null string into
-        elf_dt_name, we don't make a DT_NEEDED entry at all, even if
-        there is a DT_SONAME entry.  */
-      add_needed = TRUE;
-      name = bfd_get_filename (abfd);
-      if (elf_dt_name (abfd) != NULL)
-       {
-         name = elf_dt_name (abfd);
-         if (*name == '\0')
-           {
-             if (elf_dt_soname (abfd) != NULL)
-               dt_needed = TRUE;
-
-             add_needed = FALSE;
-           }
-       }
-      s = bfd_get_section_by_name (abfd, ".dynamic");
-      if (s != NULL)
-       {
-         Elf_External_Dyn *dynbuf = NULL;
-         Elf_External_Dyn *extdyn;
-         Elf_External_Dyn *extdynend;
-         int elfsec;
-         unsigned long shlink;
-
-         dynbuf = bfd_malloc (s->_raw_size);
-         if (dynbuf == NULL)
-           goto error_return;
-
-         if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
-           goto error_free_dyn;
-
-         elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
-         if (elfsec == -1)
-           goto error_free_dyn;
-         shlink = elf_elfsections (abfd)[elfsec]->sh_link;
-
-         extdyn = dynbuf;
-         extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
-         for (; extdyn < extdynend; extdyn++)
-           {
-             Elf_Internal_Dyn dyn;
-
-             elf_swap_dyn_in (abfd, extdyn, &dyn);
-             if (dyn.d_tag == DT_SONAME)
-               {
-                 unsigned int tagv = dyn.d_un.d_val;
-                 name = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (name == NULL)
-                   goto error_free_dyn;
-               }
-             if (dyn.d_tag == DT_NEEDED)
-               {
-                 struct bfd_link_needed_list *n, **pn;
-                 char *fnm, *anm;
-                 unsigned int tagv = dyn.d_un.d_val;
-
-                 amt = sizeof (struct bfd_link_needed_list);
-                 n = bfd_alloc (abfd, amt);
-                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (n == NULL || fnm == NULL)
-                   goto error_free_dyn;
-                 amt = strlen (fnm) + 1;
-                 anm = bfd_alloc (abfd, amt);
-                 if (anm == NULL)
-                   goto error_free_dyn;
-                 memcpy (anm, fnm, amt);
-                 n->name = anm;
-                 n->by = abfd;
-                 n->next = NULL;
-                 for (pn = & hash_table->needed;
-                      *pn != NULL;
-                      pn = &(*pn)->next)
-                   ;
-                 *pn = n;
-               }
-             if (dyn.d_tag == DT_RUNPATH)
-               {
-                 struct bfd_link_needed_list *n, **pn;
-                 char *fnm, *anm;
-                 unsigned int tagv = dyn.d_un.d_val;
-
-                 amt = sizeof (struct bfd_link_needed_list);
-                 n = bfd_alloc (abfd, amt);
-                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (n == NULL || fnm == NULL)
-                   goto error_free_dyn;
-                 amt = strlen (fnm) + 1;
-                 anm = bfd_alloc (abfd, amt);
-                 if (anm == NULL)
-                   goto error_free_dyn;
-                 memcpy (anm, fnm, amt);
-                 n->name = anm;
-                 n->by = abfd;
-                 n->next = NULL;
-                 for (pn = & runpath;
-                      *pn != NULL;
-                      pn = &(*pn)->next)
-                   ;
-                 *pn = n;
-               }
-             /* Ignore DT_RPATH if we have seen DT_RUNPATH.  */
-             if (!runpath && dyn.d_tag == DT_RPATH)
-               {
-                 struct bfd_link_needed_list *n, **pn;
-                 char *fnm, *anm;
-                 unsigned int tagv = dyn.d_un.d_val;
-
-                 amt = sizeof (struct bfd_link_needed_list);
-                 n = bfd_alloc (abfd, amt);
-                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-                 if (n == NULL || fnm == NULL)
-                   goto error_free_dyn;
-                 amt = strlen (fnm) + 1;
-                 anm = bfd_alloc (abfd, amt);
-                 if (anm == NULL)
-                   {
-                   error_free_dyn:
-                     free (dynbuf);
-                     goto error_return;
-                   }
-                 memcpy (anm, fnm, amt);
-                 n->name = anm;
-                 n->by = abfd;
-                 n->next = NULL;
-                 for (pn = & rpath;
-                      *pn != NULL;
-                      pn = &(*pn)->next)
-                   ;
-                 *pn = n;
-               }
-           }
-
-         free (dynbuf);
-       }
-
-      /* DT_RUNPATH overrides DT_RPATH.  Do _NOT_ bfd_release, as that
-        frees all more recently bfd_alloc'd blocks as well.  */
-      if (runpath)
-       rpath = runpath;
-
-      if (rpath)
-       {
-         struct bfd_link_needed_list **pn;
-         for (pn = & hash_table->runpath;
-              *pn != NULL;
-              pn = &(*pn)->next)
-           ;
-         *pn = rpath;
-       }
-
-      /* We do not want to include any of the sections in a dynamic
-        object in the output file.  We hack by simply clobbering the
-        list of sections in the BFD.  This could be handled more
-        cleanly by, say, a new section flag; the existing
-        SEC_NEVER_LOAD flag is not the one we want, because that one
-        still implies that the section takes up space in the output
-        file.  */
-      bfd_section_list_clear (abfd);
-
-      /* If this is the first dynamic object found in the link, create
-        the special sections required for dynamic linking.  */
-      if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
-       goto error_return;
-
-      if (add_needed)
-       {
-         /* Add a DT_NEEDED entry for this dynamic object.  */
-         oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
-         strindex = _bfd_elf_strtab_add (hash_table->dynstr, name, FALSE);
-         if (strindex == (bfd_size_type) -1)
-           goto error_return;
-
-         if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
-           {
-             asection *sdyn;
-             Elf_External_Dyn *dyncon, *dynconend;
-
-             /* The hash table size did not change, which means that
-                the dynamic object name was already entered.  If we
-                have already included this dynamic object in the
-                link, just ignore it.  There is no reason to include
-                a particular dynamic object more than once.  */
-             sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
-             BFD_ASSERT (sdyn != NULL);
-
-             dyncon = (Elf_External_Dyn *) sdyn->contents;
-             dynconend = (Elf_External_Dyn *) (sdyn->contents +
-                                               sdyn->_raw_size);
-             for (; dyncon < dynconend; dyncon++)
-               {
-                 Elf_Internal_Dyn dyn;
-
-                 elf_swap_dyn_in (hash_table->dynobj, dyncon, & dyn);
-                 if (dyn.d_tag == DT_NEEDED
-                     && dyn.d_un.d_val == strindex)
-                   {
-                     _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
-                     return TRUE;
-                   }
-               }
-           }
-
-         if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
-           goto error_return;
-       }
-
-      /* Save the SONAME, if there is one, because sometimes the
-        linker emulation code will need to know it.  */
-      if (*name == '\0')
-       name = basename (bfd_get_filename (abfd));
-      elf_dt_name (abfd) = name;
-    }
-
-  /* If this is a dynamic object, we always link against the .dynsym
-     symbol table, not the .symtab symbol table.  The dynamic linker
-     will only see the .dynsym symbol table, so there is no reason to
-     look at .symtab for a dynamic object.  */
-
-  if (! dynamic || elf_dynsymtab (abfd) == 0)
-    hdr = &elf_tdata (abfd)->symtab_hdr;
-  else
-    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
-
-  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
-
-  /* The sh_info field of the symtab header tells us where the
-     external symbols start.  We don't care about the local symbols at
-     this point.  */
-  if (elf_bad_symtab (abfd))
-    {
-      extsymcount = symcount;
-      extsymoff = 0;
-    }
-  else
-    {
-      extsymcount = symcount - hdr->sh_info;
-      extsymoff = hdr->sh_info;
-    }
-
-  sym_hash = NULL;
-  if (extsymcount != 0)
-    {
-      isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
-                                     NULL, NULL, NULL);
-      if (isymbuf == NULL)
-       goto error_return;
-
-      /* We store a pointer to the hash table entry for each external
-        symbol.  */
-      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
-      sym_hash = bfd_alloc (abfd, amt);
-      if (sym_hash == NULL)
-       goto error_free_sym;
-      elf_sym_hashes (abfd) = sym_hash;
-    }
-
-  if (dynamic)
-    {
-      /* Read in any version definitions.  */
-      if (! _bfd_elf_slurp_version_tables (abfd))
-       goto error_free_sym;
-
-      /* Read in the symbol versions, but don't bother to convert them
-        to internal format.  */
-      if (elf_dynversym (abfd) != 0)
-       {
-         Elf_Internal_Shdr *versymhdr;
-
-         versymhdr = &elf_tdata (abfd)->dynversym_hdr;
-         extversym = bfd_malloc (versymhdr->sh_size);
-         if (extversym == NULL)
-           goto error_free_sym;
-         amt = versymhdr->sh_size;
-         if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread (extversym, amt, abfd) != amt)
-           goto error_free_vers;
-       }
-    }
-
-  weaks = NULL;
-
-  ever = extversym != NULL ? extversym + extsymoff : NULL;
-  for (isym = isymbuf, isymend = isymbuf + extsymcount;
-       isym < isymend;
-       isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
-    {
-      int bind;
-      bfd_vma value;
-      asection *sec;
-      flagword flags;
-      const char *name;
-      struct elf_link_hash_entry *h;
-      bfd_boolean definition;
-      bfd_boolean size_change_ok;
-      bfd_boolean type_change_ok;
-      bfd_boolean new_weakdef;
-      bfd_boolean override;
-      unsigned int old_alignment;
-      bfd *old_bfd;
-
-      override = FALSE;
-
-      flags = BSF_NO_FLAGS;
-      sec = NULL;
-      value = isym->st_value;
-      *sym_hash = NULL;
-
-      bind = ELF_ST_BIND (isym->st_info);
-      if (bind == STB_LOCAL)
-       {
-         /* This should be impossible, since ELF requires that all
-            global symbols follow all local symbols, and that sh_info
-            point to the first global symbol.  Unfortunately, Irix 5
-            screws this up.  */
-         continue;
-       }
-      else if (bind == STB_GLOBAL)
-       {
-         if (isym->st_shndx != SHN_UNDEF
-             && isym->st_shndx != SHN_COMMON)
-           flags = BSF_GLOBAL;
-       }
-      else if (bind == STB_WEAK)
-       flags = BSF_WEAK;
-      else
-       {
-         /* Leave it up to the processor backend.  */
-       }
-
-      if (isym->st_shndx == SHN_UNDEF)
-       sec = bfd_und_section_ptr;
-      else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
-       {
-         sec = section_from_elf_index (abfd, isym->st_shndx);
-         if (sec == NULL)
-           sec = bfd_abs_section_ptr;
-         else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
-           value -= sec->vma;
-       }
-      else if (isym->st_shndx == SHN_ABS)
-       sec = bfd_abs_section_ptr;
-      else if (isym->st_shndx == SHN_COMMON)
-       {
-         sec = bfd_com_section_ptr;
-         /* What ELF calls the size we call the value.  What ELF
-            calls the value we call the alignment.  */
-         value = isym->st_size;
-       }
-      else
-       {
-         /* Leave it up to the processor backend.  */
-       }
-
-      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                             isym->st_name);
-      if (name == NULL)
-       goto error_free_vers;
-
-      if (isym->st_shndx == SHN_COMMON
-         && ELF_ST_TYPE (isym->st_info) == STT_TLS)
-       {
-         asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon");
-
-         if (tcomm == NULL)
-           {
-             tcomm = bfd_make_section (abfd, ".tcommon");
-             if (tcomm == NULL
-                 || !bfd_set_section_flags (abfd, tcomm, (SEC_ALLOC
-                                                          | SEC_IS_COMMON
-                                                          | SEC_LINKER_CREATED
-                                                          | SEC_THREAD_LOCAL)))
-               goto error_free_vers;
-           }
-         sec = tcomm;
-       }
-      else if (add_symbol_hook)
-       {
-         if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec,
-                                   &value))
-           goto error_free_vers;
-
-         /* The hook function sets the name to NULL if this symbol
-            should be skipped for some reason.  */
-         if (name == NULL)
-           continue;
-       }
-
-      /* Sanity check that all possibilities were handled.  */
-      if (sec == NULL)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         goto error_free_vers;
-       }
-
-      if (bfd_is_und_section (sec)
-         || bfd_is_com_section (sec))
-       definition = FALSE;
-      else
-       definition = TRUE;
-
-      size_change_ok = FALSE;
-      type_change_ok = get_elf_backend_data (abfd)->type_change_ok;
-      old_alignment = 0;
-      old_bfd = NULL;
-
-      if (is_elf_hash_table (hash_table))
-       {
-         Elf_Internal_Versym iver;
-         unsigned int vernum = 0;
-         bfd_boolean skip;
-
-         if (ever != NULL)
-           {
-             _bfd_elf_swap_versym_in (abfd, ever, &iver);
-             vernum = iver.vs_vers & VERSYM_VERSION;
-
-             /* If this is a hidden symbol, or if it is not version
-                1, we append the version name to the symbol name.
-                However, we do not modify a non-hidden absolute
-                symbol, because it might be the version symbol
-                itself.  FIXME: What if it isn't?  */
-             if ((iver.vs_vers & VERSYM_HIDDEN) != 0
-                 || (vernum > 1 && ! bfd_is_abs_section (sec)))
-               {
-                 const char *verstr;
-                 size_t namelen, verlen, newlen;
-                 char *newname, *p;
-
-                 if (isym->st_shndx != SHN_UNDEF)
-                   {
-                     if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
-                       {
-                         (*_bfd_error_handler)
-                           (_("%s: %s: invalid version %u (max %d)"),
-                            bfd_archive_filename (abfd), name, vernum,
-                            elf_tdata (abfd)->dynverdef_hdr.sh_info);
-                         bfd_set_error (bfd_error_bad_value);
-                         goto error_free_vers;
-                       }
-                     else if (vernum > 1)
-                       verstr =
-                         elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
-                     else
-                       verstr = "";
-                   }
-                 else
-                   {
-                     /* We cannot simply test for the number of
-                        entries in the VERNEED section since the
-                        numbers for the needed versions do not start
-                        at 0.  */
-                     Elf_Internal_Verneed *t;
-
-                     verstr = NULL;
-                     for (t = elf_tdata (abfd)->verref;
-                          t != NULL;
-                          t = t->vn_nextref)
-                       {
-                         Elf_Internal_Vernaux *a;
-
-                         for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-                           {
-                             if (a->vna_other == vernum)
-                               {
-                                 verstr = a->vna_nodename;
-                                 break;
-                               }
-                           }
-                         if (a != NULL)
-                           break;
-                       }
-                     if (verstr == NULL)
-                       {
-                         (*_bfd_error_handler)
-                           (_("%s: %s: invalid needed version %d"),
-                            bfd_archive_filename (abfd), name, vernum);
-                         bfd_set_error (bfd_error_bad_value);
-                         goto error_free_vers;
-                       }
-                   }
-
-                 namelen = strlen (name);
-                 verlen = strlen (verstr);
-                 newlen = namelen + verlen + 2;
-                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0
-                     && isym->st_shndx != SHN_UNDEF)
-                   ++newlen;
-
-                 newname = bfd_alloc (abfd, newlen);
-                 if (newname == NULL)
-                   goto error_free_vers;
-                 memcpy (newname, name, namelen);
-                 p = newname + namelen;
-                 *p++ = ELF_VER_CHR;
-                 /* If this is a defined non-hidden version symbol,
-                    we add another @ to the name.  This indicates the
-                    default version of the symbol.  */
-                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0
-                     && isym->st_shndx != SHN_UNDEF)
-                   *p++ = ELF_VER_CHR;
-                 memcpy (p, verstr, verlen + 1);
-
-                 name = newname;
-               }
-           }
-
-         if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
-                                     sym_hash, &skip, &override,
-                                     &type_change_ok, &size_change_ok,
-                                     dt_needed))
-           goto error_free_vers;
-
-         if (skip)
-           continue;
-
-         if (override)
-           definition = FALSE;
-
-         h = *sym_hash;
-         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;
-
-         /* Remember the old alignment if this is a common symbol, so
-            that we don't reduce the alignment later on.  We can't
-            check later, because _bfd_generic_link_add_one_symbol
-            will set a default for the alignment which we want to
-            override. We also remember the old bfd where the existing
-            definition comes from.  */
-         switch (h->root.type)
-           {
-           default:
-             break;
-
-           case bfd_link_hash_defined:
-           case bfd_link_hash_defweak:
-             old_bfd = h->root.u.def.section->owner;
-             break;
-           
-           case bfd_link_hash_common:
-             old_bfd = h->root.u.c.p->section->owner;
-             old_alignment = h->root.u.c.p->alignment_power;
-             break;
-           }
-
-         if (elf_tdata (abfd)->verdef != NULL
-             && ! override
-             && vernum > 1
-             && definition)
-           h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
-       }
-
-      if (! (_bfd_generic_link_add_one_symbol
-            (info, abfd, name, flags, sec, value, NULL, FALSE, collect,
-             (struct bfd_link_hash_entry **) sym_hash)))
-       goto error_free_vers;
-
-      h = *sym_hash;
-      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;
-      *sym_hash = h;
-
-      new_weakdef = FALSE;
-      if (dynamic
-         && definition
-         && (flags & BSF_WEAK) != 0
-         && ELF_ST_TYPE (isym->st_info) != STT_FUNC
-         && is_elf_hash_table (hash_table)
-         && h->weakdef == NULL)
-       {
-         /* Keep a list of all weak defined non function symbols from
-            a dynamic object, using the weakdef field.  Later in this
-            function we will set the weakdef field to the correct
-            value.  We only put non-function symbols from dynamic
-            objects on this list, because that happens to be the only
-            time we need to know the normal symbol corresponding to a
-            weak symbol, and the information is time consuming to
-            figure out.  If the weakdef field is not already NULL,
-            then this symbol was already defined by some previous
-            dynamic object, and we will be using that previous
-            definition anyhow.  */
-
-         h->weakdef = weaks;
-         weaks = h;
-         new_weakdef = TRUE;
-       }
-
-      /* Set the alignment of a common symbol.  */
-      if (isym->st_shndx == SHN_COMMON
-         && h->root.type == bfd_link_hash_common)
-       {
-         unsigned int align;
-
-         align = bfd_log2 (isym->st_value);
-         if (align > old_alignment
-             /* Permit an alignment power of zero if an alignment of one
-                is specified and no other alignments have been specified.  */
-             || (isym->st_value == 1 && old_alignment == 0))
-           h->root.u.c.p->alignment_power = align;
-         else
-           h->root.u.c.p->alignment_power = old_alignment;
-       }
-
-      if (is_elf_hash_table (hash_table))
-       {
-         int old_flags;
-         bfd_boolean dynsym;
-         int new_flag;
-
-         /* Check the alignment when a common symbol is involved. This
-            can change when a common symbol is overridden by a normal
-            definition or a common symbol is ignored due to the old
-            normal definition. We need to make sure the maximum
-            alignment is maintained.  */
-         if ((old_alignment || isym->st_shndx == SHN_COMMON)
-             && h->root.type != bfd_link_hash_common)
-           {
-             unsigned int common_align;
-             unsigned int normal_align;
-             unsigned int symbol_align;
-             bfd *normal_bfd;
-             bfd *common_bfd;
-
-             symbol_align = ffs (h->root.u.def.value) - 1;
-             if (h->root.u.def.section->owner != NULL
-                 && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
-               {
-                 normal_align = h->root.u.def.section->alignment_power;
-                 if (normal_align > symbol_align)
-                   normal_align = symbol_align;
-               }
-             else
-               normal_align = symbol_align;
-
-             if (old_alignment)
-               {
-                 common_align = old_alignment;
-                 common_bfd = old_bfd;
-                 normal_bfd = abfd;
-               }
-             else
-               {
-                 common_align = bfd_log2 (isym->st_value);
-                 common_bfd = abfd;
-                 normal_bfd = old_bfd;
-               }
-
-             if (normal_align < common_align)
-               (*_bfd_error_handler)
-                 (_("Warning: alignment %u of symbol `%s' in %s is smaller than %u in %s"),
-                  1 << normal_align,
-                  name,
-                  bfd_archive_filename (normal_bfd),
-                  1 << common_align,
-                  bfd_archive_filename (common_bfd));
-           }
-
-         /* Remember the symbol size and type.  */
-         if (isym->st_size != 0
-             && (definition || h->size == 0))
-           {
-             if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
-               (*_bfd_error_handler)
-                 (_("Warning: size of symbol `%s' changed from %lu in %s to %lu in %s"),
-                  name, (unsigned long) h->size,
-                  bfd_archive_filename (old_bfd),
-                  (unsigned long) isym->st_size,
-                  bfd_archive_filename (abfd));
-
-             h->size = isym->st_size;
-           }
-
-         /* If this is a common symbol, then we always want H->SIZE
-            to be the size of the common symbol.  The code just above
-            won't fix the size if a common symbol becomes larger.  We
-            don't warn about a size change here, because that is
-            covered by --warn-common.  */
-         if (h->root.type == bfd_link_hash_common)
-           h->size = h->root.u.c.size;
-
-         if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
-             && (definition || h->type == STT_NOTYPE))
-           {
-             if (h->type != STT_NOTYPE
-                 && h->type != ELF_ST_TYPE (isym->st_info)
-                 && ! type_change_ok)
-               (*_bfd_error_handler)
-                 (_("Warning: type of symbol `%s' changed from %d to %d in %s"),
-                  name, h->type, ELF_ST_TYPE (isym->st_info),
-                  bfd_archive_filename (abfd));
-
-             h->type = ELF_ST_TYPE (isym->st_info);
-           }
-
-         /* If st_other has a processor-specific meaning, specific
-            code might be needed here. We never merge the visibility
-            attribute with the one from a dynamic object.  */
-         if (bed->elf_backend_merge_symbol_attribute)
-           (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
-                                                       dynamic);
-
-         if (isym->st_other != 0 && !dynamic)
-           {
-             unsigned char hvis, symvis, other, nvis;
-
-             /* Take the balance of OTHER from the definition.  */
-             other = (definition ? isym->st_other : h->other);
-             other &= ~ ELF_ST_VISIBILITY (-1);
-
-             /* Combine visibilities, using the most constraining one.  */
-             hvis   = ELF_ST_VISIBILITY (h->other);
-             symvis = ELF_ST_VISIBILITY (isym->st_other);
-             if (! hvis)
-               nvis = symvis;
-             else if (! symvis)
-               nvis = hvis;
-             else
-               nvis = hvis < symvis ? hvis : symvis;
-
-             h->other = other | nvis;
-           }
-
-         /* Set a flag in the hash table entry indicating the type of
-            reference or definition we just found.  Keep a count of
-            the number of dynamic symbols we find.  A dynamic symbol
-            is one which is referenced or defined by both a regular
-            object and a shared object.  */
-         old_flags = h->elf_link_hash_flags;
-         dynsym = FALSE;
-         if (! dynamic)
-           {
-             if (! definition)
-               {
-                 new_flag = ELF_LINK_HASH_REF_REGULAR;
-                 if (bind != STB_WEAK)
-                   new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
-               }
-             else
-               new_flag = ELF_LINK_HASH_DEF_REGULAR;
-             if (! info->executable
-                 || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC
-                                  | ELF_LINK_HASH_REF_DYNAMIC)) != 0)
-               dynsym = TRUE;
-           }
-         else
-           {
-             if (! definition)
-               new_flag = ELF_LINK_HASH_REF_DYNAMIC;
-             else
-               new_flag = ELF_LINK_HASH_DEF_DYNAMIC;
-             if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR
-                               | ELF_LINK_HASH_REF_REGULAR)) != 0
-                 || (h->weakdef != NULL
-                     && ! new_weakdef
-                     && h->weakdef->dynindx != -1))
-               dynsym = TRUE;
-           }
-
-         h->elf_link_hash_flags |= new_flag;
-
-         /* Check to see if we need to add an indirect symbol for
-            the default name.  */
-         if (definition || h->root.type == bfd_link_hash_common)
-           if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
-                                             &sec, &value, &dynsym,
-                                             override, dt_needed))
-             goto error_free_vers;
-
-         if (definition && !dynamic)
-           {
-             char *p = strchr (name, ELF_VER_CHR);
-             if (p != NULL && p[1] != ELF_VER_CHR)
-               {
-                 /* Queue non-default versions so that .symver x, x@FOO
-                    aliases can be checked.  */
-                 if (! nondeflt_vers)
-                   {
-                     amt = (isymend - isym + 1)
-                           * sizeof (struct elf_link_hash_entry *);
-                     nondeflt_vers = bfd_malloc (amt);
-                   }
-                 nondeflt_vers [nondeflt_vers_cnt++] = h;
-               }
-           }
-
-         if (dynsym && h->dynindx == -1)
-           {
-             if (! _bfd_elf_link_record_dynamic_symbol (info, h))
-               goto error_free_vers;
-             if (h->weakdef != NULL
-                 && ! new_weakdef
-                 && h->weakdef->dynindx == -1)
-               {
-                 if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef))
-                   goto error_free_vers;
-               }
-           }
-         else if (dynsym && h->dynindx != -1)
-           /* If the symbol already has a dynamic index, but
-              visibility says it should not be visible, turn it into
-              a local symbol.  */
-           switch (ELF_ST_VISIBILITY (h->other))
-             {
-             case STV_INTERNAL:
-             case STV_HIDDEN:
-               (*bed->elf_backend_hide_symbol) (info, h, TRUE);
-               break;
-             }
-
-         if (dt_needed && definition
-             && (h->elf_link_hash_flags
-                 & ELF_LINK_HASH_REF_REGULAR) != 0)
-           {
-             bfd_size_type oldsize;
-             bfd_size_type strindex;
-
-             /* The symbol from a DT_NEEDED object is referenced from
-                the regular object to create a dynamic executable. We
-                have to make sure there is a DT_NEEDED entry for it.  */
-
-             dt_needed = FALSE;
-             oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
-             strindex = _bfd_elf_strtab_add (hash_table->dynstr,
-                                             elf_dt_soname (abfd), FALSE);
-             if (strindex == (bfd_size_type) -1)
-               goto error_free_vers;
-
-             if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
-               {
-                 asection *sdyn;
-                 Elf_External_Dyn *dyncon, *dynconend;
-
-                 sdyn = bfd_get_section_by_name (hash_table->dynobj,
-                                                 ".dynamic");
-                 BFD_ASSERT (sdyn != NULL);
-
-                 dyncon = (Elf_External_Dyn *) sdyn->contents;
-                 dynconend = (Elf_External_Dyn *) (sdyn->contents +
-                                                   sdyn->_raw_size);
-                 for (; dyncon < dynconend; dyncon++)
-                   {
-                     Elf_Internal_Dyn dyn;
-
-                     elf_swap_dyn_in (hash_table->dynobj,
-                                      dyncon, &dyn);
-                     BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
-                                 dyn.d_un.d_val != strindex);
-                   }
-               }
-
-             if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
-               goto error_free_vers;
-           }
-       }
-    }
-
-  /* Now that all the symbols from this input file are created, handle
-     .symver foo, foo@BAR such that any relocs against foo become foo@BAR.  */
-  if (nondeflt_vers != NULL)
-    {
-      bfd_size_type cnt, symidx;
-
-      for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt)
-       {
-         struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi;
-         char *shortname, *p;
-
-         p = strchr (h->root.root.string, ELF_VER_CHR);
-         if (p == NULL
-             || (h->root.type != bfd_link_hash_defined
-                 && h->root.type != bfd_link_hash_defweak))
-           continue;
-
-         amt = p - h->root.root.string;
-         shortname = bfd_malloc (amt + 1);
-         memcpy (shortname, h->root.root.string, amt);
-         shortname[amt] = '\0';
-
-         hi = (struct elf_link_hash_entry *)
-              bfd_link_hash_lookup (&hash_table->root, shortname,
-                                    FALSE, FALSE, FALSE);
-         if (hi != NULL
-             && hi->root.type == h->root.type
-             && hi->root.u.def.value == h->root.u.def.value
-             && hi->root.u.def.section == h->root.u.def.section)
-           {
-             (*bed->elf_backend_hide_symbol) (info, hi, TRUE);
-             hi->root.type = bfd_link_hash_indirect;
-             hi->root.u.i.link = (struct bfd_link_hash_entry *) h;
-             (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi);
-             sym_hash = elf_sym_hashes (abfd);
-             if (sym_hash)
-               for (symidx = 0; symidx < extsymcount; ++symidx)
-                 if (sym_hash[symidx] == hi)
-                   {
-                     sym_hash[symidx] = h;
-                     break;
-                   }
-           }
-         free (shortname);
-       }
-      free (nondeflt_vers);
-      nondeflt_vers = NULL;
-    }
-
-  if (extversym != NULL)
-    {
-      free (extversym);
-      extversym = NULL;
-    }
-
-  if (isymbuf != NULL)
-    free (isymbuf);
-  isymbuf = NULL;
-
-  /* Now set the weakdefs field correctly for all the weak defined
-     symbols we found.  The only way to do this is to search all the
-     symbols.  Since we only need the information for non functions in
-     dynamic objects, that's the only time we actually put anything on
-     the list WEAKS.  We need this information so that if a regular
-     object refers to a symbol defined weakly in a dynamic object, the
-     real symbol in the dynamic object is also put in the dynamic
-     symbols; we also must arrange for both symbols to point to the
-     same memory location.  We could handle the general case of symbol
-     aliasing, but a general symbol alias can only be generated in
-     assembler code, handling it correctly would be very time
-     consuming, and other ELF linkers don't handle general aliasing
-     either.  */
-  if (weaks != NULL)
-    {
-      struct elf_link_hash_entry **hpp;
-      struct elf_link_hash_entry **hppend;
-      struct elf_link_hash_entry **sorted_sym_hash;
-      struct elf_link_hash_entry *h;
-      size_t sym_count;
-
-      /* Since we have to search the whole symbol list for each weak
-        defined symbol, search time for N weak defined symbols will be
-        O(N^2). Binary search will cut it down to O(NlogN).  */
-      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
-      sorted_sym_hash = bfd_malloc (amt);
-      if (sorted_sym_hash == NULL)
-       goto error_return;
-      sym_hash = sorted_sym_hash;
-      hpp = elf_sym_hashes (abfd);
-      hppend = hpp + extsymcount;
-      sym_count = 0;
-      for (; hpp < hppend; hpp++)
-       {
-         h = *hpp;
-         if (h != NULL
-             && h->root.type == bfd_link_hash_defined
-             && h->type != STT_FUNC)
-           {
-             *sym_hash = h;
-             sym_hash++;
-             sym_count++;
-           }
-       }
-
-      qsort (sorted_sym_hash, sym_count,
-            sizeof (struct elf_link_hash_entry *),
-            sort_symbol);
-
-      while (weaks != NULL)
-       {
-         struct elf_link_hash_entry *hlook;
-         asection *slook;
-         bfd_vma vlook;
-         long ilook;
-         size_t i, j, idx;
-
-         hlook = weaks;
-         weaks = hlook->weakdef;
-         hlook->weakdef = NULL;
-
-         BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
-                     || hlook->root.type == bfd_link_hash_defweak
-                     || hlook->root.type == bfd_link_hash_common
-                     || hlook->root.type == bfd_link_hash_indirect);
-         slook = hlook->root.u.def.section;
-         vlook = hlook->root.u.def.value;
-
-         ilook = -1;
-         i = 0;
-         j = sym_count;
-         while (i < j)
-           {
-             bfd_signed_vma vdiff;
-             idx = (i + j) / 2;
-             h = sorted_sym_hash [idx];
-             vdiff = vlook - h->root.u.def.value;
-             if (vdiff < 0)
-               j = idx;
-             else if (vdiff > 0)
-               i = idx + 1;
-             else
-               {
-                 long sdiff = slook - h->root.u.def.section;
-                 if (sdiff < 0)
-                   j = idx;
-                 else if (sdiff > 0)
-                   i = idx + 1;
-                 else
-                   {
-                     ilook = idx;
-                     break;
-                   }
-               }
-           }
-
-         /* We didn't find a value/section match.  */
-         if (ilook == -1)
-           continue;
-
-         for (i = ilook; i < sym_count; i++)
-           {
-             h = sorted_sym_hash [i];
-
-             /* Stop if value or section doesn't match.  */
-             if (h->root.u.def.value != vlook
-                 || h->root.u.def.section != slook)
-               break;
-             else if (h != hlook)
-               {
-                 hlook->weakdef = h;
-
-                 /* If the weak definition is in the list of dynamic
-                    symbols, make sure the real definition is put
-                    there as well.  */
-                 if (hlook->dynindx != -1 && h->dynindx == -1)
-                   {
-                     if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                                h))
-                       goto error_return;
-                   }
-
-                 /* If the real definition is in the list of dynamic
-                    symbols, make sure the weak definition is put
-                    there as well.  If we don't do this, then the
-                    dynamic loader might not merge the entries for the
-                    real definition and the weak definition.  */
-                 if (h->dynindx != -1 && hlook->dynindx == -1)
-                   {
-                     if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                                hlook))
-                       goto error_return;
-                   }
-                 break;
-               }
-           }
-       }
-
-      free (sorted_sym_hash);
-    }
-
-  /* If this object is the same format as the output object, and it is
-     not a shared library, then let the backend look through the
-     relocs.
-
-     This is required to build global offset table entries and to
-     arrange for dynamic relocs.  It is not required for the
-     particular common case of linking non PIC code, even when linking
-     against shared libraries, but unfortunately there is no way of
-     knowing whether an object file has been compiled PIC or not.
-     Looking through the relocs is not particularly time consuming.
-     The problem is that we must either (1) keep the relocs in memory,
-     which causes the linker to require additional runtime memory or
-     (2) read the relocs twice from the input file, which wastes time.
-     This would be a good case for using mmap.
-
-     I have no idea how to handle linking PIC code into a file of a
-     different format.  It probably can't be done.  */
-  check_relocs = get_elf_backend_data (abfd)->check_relocs;
-  if (! dynamic
-      && is_elf_hash_table (hash_table)
-      && hash_table->root.creator == abfd->xvec
-      && check_relocs != NULL)
-    {
-      asection *o;
-
-      for (o = abfd->sections; o != NULL; o = o->next)
-       {
-         Elf_Internal_Rela *internal_relocs;
-         bfd_boolean ok;
-
-         if ((o->flags & SEC_RELOC) == 0
-             || o->reloc_count == 0
-             || ((info->strip == strip_all || info->strip == strip_debugger)
-                 && (o->flags & SEC_DEBUGGING) != 0)
-             || bfd_is_abs_section (o->output_section))
-           continue;
-
-         internal_relocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
-                                                      info->keep_memory);
-         if (internal_relocs == NULL)
-           goto error_return;
-
-         ok = (*check_relocs) (abfd, info, o, internal_relocs);
-
-         if (elf_section_data (o)->relocs != internal_relocs)
-           free (internal_relocs);
-
-         if (! ok)
-           goto error_return;
-       }
-    }
-
-  /* If this is a non-traditional link, try to optimize the handling
-     of the .stab/.stabstr sections.  */
-  if (! dynamic
-      && ! info->traditional_format
-      && is_elf_hash_table (hash_table)
-      && (info->strip != strip_all && info->strip != strip_debugger))
-    {
-      asection *stabstr;
-      
-      stabstr = bfd_get_section_by_name (abfd, ".stabstr");
-      if (stabstr != NULL)
-       {
-         bfd_size_type string_offset = 0;
-         asection *stab;
-
-         for (stab = abfd->sections; stab; stab = stab->next)
-           if (strncmp (".stab", stab->name, 5) == 0
-               && (!stab->name[5] ||
-                   (stab->name[5] == '.' && ISDIGIT (stab->name[6])))
-               && (stab->flags & SEC_MERGE) == 0
-               && !bfd_is_abs_section (stab->output_section))
-             {
-               struct bfd_elf_section_data *secdata;
-               
-               secdata = elf_section_data (stab);
-               if (! _bfd_link_section_stabs (abfd,
-                                              & hash_table->stab_info,
-                                              stab, stabstr,
-                                              &secdata->sec_info,
-                                              &string_offset))
-                 goto error_return;
-               if (secdata->sec_info)
-                 stab->sec_info_type = ELF_INFO_TYPE_STABS;
-           }
-       }
-    }
-
-  if (! info->relocatable
-      && ! dynamic
-      && is_elf_hash_table (hash_table))
-    {
-      asection *s;
-
-      for (s = abfd->sections; s != NULL; s = s->next)
-       if ((s->flags & SEC_MERGE) != 0
-           && !bfd_is_abs_section (s->output_section))
-         {
-           struct bfd_elf_section_data *secdata;
-
-           secdata = elf_section_data (s);
-           if (! _bfd_merge_section (abfd,
-                                     & hash_table->merge_info,
-                                     s, &secdata->sec_info))
-             goto error_return;
-           else if (secdata->sec_info)
-             s->sec_info_type = ELF_INFO_TYPE_MERGE;
-         }
-    }
-
-  if (is_elf_hash_table (hash_table))
-    {
-      /* Add this bfd to the loaded list.  */
-      struct elf_link_loaded_list *n;
-
-      n = bfd_alloc (abfd, sizeof (struct elf_link_loaded_list));
-      if (n == NULL)
-       goto error_return;
-      n->abfd = abfd;
-      n->next = hash_table->loaded;
-      hash_table->loaded = n;
-    }
-
-  return TRUE;
-
- error_free_vers:
-  if (nondeflt_vers != NULL)
-    free (nondeflt_vers);
-  if (extversym != NULL)
-    free (extversym);
- error_free_sym:
-  if (isymbuf != NULL)
-    free (isymbuf);
- error_return:
-  return FALSE;
-}
-
-/* Add an entry to the .dynamic table.  */
-
-bfd_boolean
-elf_add_dynamic_entry (struct bfd_link_info *info, bfd_vma tag, bfd_vma val)
-{
-  Elf_Internal_Dyn dyn;
-  bfd *dynobj;
-  asection *s;
-  bfd_size_type newsize;
-  bfd_byte *newcontents;
-
-  if (! is_elf_hash_table (info->hash))
-    return FALSE;
-
-  dynobj = elf_hash_table (info)->dynobj;
-
-  s = bfd_get_section_by_name (dynobj, ".dynamic");
-  BFD_ASSERT (s != NULL);
-
-  newsize = s->_raw_size + sizeof (Elf_External_Dyn);
-  newcontents = bfd_realloc (s->contents, newsize);
-  if (newcontents == NULL)
-    return FALSE;
-
-  dyn.d_tag = tag;
-  dyn.d_un.d_val = val;
-  elf_swap_dyn_out (dynobj, &dyn,
-                   (Elf_External_Dyn *) (newcontents + s->_raw_size));
-
-  s->_raw_size = newsize;
-  s->contents = newcontents;
-
-  return TRUE;
-}
-\f
-/* Array used to determine the number of hash table buckets to use
-   based on the number of symbols there are.  If there are fewer than
-   3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets,
-   fewer than 37 we use 17 buckets, and so forth.  We never use more
-   than 32771 buckets.  */
-
-static const size_t elf_buckets[] =
-{
-  1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
-  16411, 32771, 0
-};
-
-/* Compute bucket count for hashing table.  We do not use a static set
-   of possible tables sizes anymore.  Instead we determine for all
-   possible reasonable sizes of the table the outcome (i.e., the
-   number of collisions etc) and choose the best solution.  The
-   weighting functions are not too simple to allow the table to grow
-   without bounds.  Instead one of the weighting factors is the size.
-   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)
-{
-  size_t dynsymcount = elf_hash_table (info)->dynsymcount;
-  size_t best_size = 0;
-  unsigned long int *hashcodes;
-  unsigned long int *hashcodesp;
-  unsigned long int i;
-  bfd_size_type amt;
-
-  /* Compute the hash values for all exported symbols.  At the same
-     time store the values in an array so that we could use them for
-     optimizations.  */
-  amt = dynsymcount;
-  amt *= sizeof (unsigned long int);
-  hashcodes = bfd_malloc (amt);
-  if (hashcodes == NULL)
-    return 0;
-  hashcodesp = hashcodes;
-
-  /* Put all hash values in HASHCODES.  */
-  elf_link_hash_traverse (elf_hash_table (info),
-                         elf_collect_hash_codes, &hashcodesp);
-
-  /* We have a problem here.  The following code to optimize the table
-     size requires an integer type with more the 32 bits.  If
-     BFD_HOST_U_64_BIT is set we know about such a type.  */
-#ifdef BFD_HOST_U_64_BIT
-  if (info->optimize)
-    {
-      unsigned long int nsyms = hashcodesp - hashcodes;
-      size_t minsize;
-      size_t maxsize;
-      BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0);
-      unsigned long int *counts ;
-
-      /* Possible optimization parameters: if we have NSYMS symbols we say
-        that the hashing table must at least have NSYMS/4 and at most
-        2*NSYMS buckets.  */
-      minsize = nsyms / 4;
-      if (minsize == 0)
-       minsize = 1;
-      best_size = maxsize = nsyms * 2;
-
-      /* Create array where we count the collisions in.  We must use bfd_malloc
-        since the size could be large.  */
-      amt = maxsize;
-      amt *= sizeof (unsigned long int);
-      counts = bfd_malloc (amt);
-      if (counts == NULL)
-       {
-         free (hashcodes);
-         return 0;
-       }
-
-      /* Compute the "optimal" size for the hash table.  The criteria is a
-        minimal chain length.  The minor criteria is (of course) the size
-        of the table.  */
-      for (i = minsize; i < maxsize; ++i)
-       {
-         /* Walk through the array of hashcodes and count the collisions.  */
-         BFD_HOST_U_64_BIT max;
-         unsigned long int j;
-         unsigned long int fact;
-
-         memset (counts, '\0', i * sizeof (unsigned long int));
-
-         /* Determine how often each hash bucket is used.  */
-         for (j = 0; j < nsyms; ++j)
-           ++counts[hashcodes[j] % i];
-
-         /* For the weight function we need some information about the
-            pagesize on the target.  This is information need not be 100%
-            accurate.  Since this information is not available (so far) we
-            define it here to a reasonable default value.  If it is crucial
-            to have a better value some day simply define this value.  */
-# ifndef BFD_TARGET_PAGESIZE
-#  define BFD_TARGET_PAGESIZE  (4096)
-# endif
-
-         /* We in any case need 2 + NSYMS entries for the size values and
-            the chains.  */
-         max = (2 + nsyms) * (ARCH_SIZE / 8);
-
-# if 1
-         /* Variant 1: optimize for short chains.  We add the squares
-            of all the chain lengths (which favors many small chain
-            over a few long chains).  */
-         for (j = 0; j < i; ++j)
-           max += counts[j] * counts[j];
-
-         /* This adds penalties for the overall size of the table.  */
-         fact = i / (BFD_TARGET_PAGESIZE / (ARCH_SIZE / 8)) + 1;
-         max *= fact * fact;
-# else
-         /* Variant 2: Optimize a lot more for small table.  Here we
-            also add squares of the size but we also add penalties for
-            empty slots (the +1 term).  */
-         for (j = 0; j < i; ++j)
-           max += (1 + counts[j]) * (1 + counts[j]);
-
-         /* The overall size of the table is considered, but not as
-            strong as in variant 1, where it is squared.  */
-         fact = i / (BFD_TARGET_PAGESIZE / (ARCH_SIZE / 8)) + 1;
-         max *= fact;
-# endif
-
-         /* Compare with current best results.  */
-         if (max < best_chlen)
-           {
-             best_chlen = max;
-             best_size = i;
-           }
-       }
-
-      free (counts);
-    }
-  else
-#endif /* defined (BFD_HOST_U_64_BIT) */
-    {
-      /* This is the fallback solution if no 64bit type is available or if we
-        are not supposed to spend much time on optimizations.  We select the
-        bucket count using a fixed set of numbers.  */
-      for (i = 0; elf_buckets[i] != 0; i++)
-       {
-         best_size = elf_buckets[i];
-         if (dynsymcount < elf_buckets[i + 1])
-           break;
-       }
-    }
-
-  /* Free the arrays we needed.  */
-  free (hashcodes);
-
-  return best_size;
-}
-
-/* Set up the sizes and contents of the ELF dynamic sections.  This is
-   called by the ELF linker emulation before_allocation routine.  We
-   must set the sizes of the sections before the linker sets the
-   addresses of the various sections.  */
-
-bfd_boolean
-NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
-                                    const char *soname,
-                                    const char *rpath,
-                                    const char *filter_shlib,
-                                    const char * const *auxiliary_filters,
-                                    struct bfd_link_info *info,
-                                    asection **sinterpptr,
-                                    struct bfd_elf_version_tree *verdefs)
-{
-  bfd_size_type soname_indx;
-  bfd *dynobj;
-  const struct elf_backend_data *bed;
-  struct elf_assign_sym_version_info asvinfo;
-
-  *sinterpptr = NULL;
-
-  soname_indx = (bfd_size_type) -1;
-
-  if (!is_elf_hash_table (info->hash))
-    return TRUE;
-
-  if (info->execstack)
-    elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
-  else if (info->noexecstack)
-    elf_tdata (output_bfd)->stack_flags = PF_R | PF_W;
-  else
-    {
-      bfd *inputobj;
-      asection *notesec = NULL;
-      int exec = 0;
-
-      for (inputobj = info->input_bfds;
-          inputobj;
-          inputobj = inputobj->link_next)
-       {
-         asection *s;
-
-         if (inputobj->flags & DYNAMIC)
-           continue;
-         s = bfd_get_section_by_name (inputobj, ".note.GNU-stack");
-         if (s)
-           {
-             if (s->flags & SEC_CODE)
-               exec = PF_X;
-             notesec = s;
-           }
-         else
-           exec = PF_X;
-       }
-      if (notesec)
-       {
-         elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | exec;
-         if (exec && info->relocatable
-             && notesec->output_section != bfd_abs_section_ptr)
-           notesec->output_section->flags |= SEC_CODE;
-       }
-    }
-
-  /* Any syms created from now on start with -1 in
-     got.refcount/offset and plt.refcount/offset.  */
-  elf_hash_table (info)->init_refcount = elf_hash_table (info)->init_offset;
-
-  /* The backend may have to create some sections regardless of whether
-     we're dynamic or not.  */
-  bed = get_elf_backend_data (output_bfd);
-  if (bed->elf_backend_always_size_sections
-      && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
-    return FALSE;
-
-  dynobj = elf_hash_table (info)->dynobj;
-
-  /* If there were no dynamic objects in the link, there is nothing to
-     do here.  */
-  if (dynobj == NULL)
-    return TRUE;
-
-  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
-    return FALSE;
-
-  if (elf_hash_table (info)->dynamic_sections_created)
-    {
-      struct elf_info_failed eif;
-      struct elf_link_hash_entry *h;
-      asection *dynstr;
-      struct bfd_elf_version_tree *t;
-      struct bfd_elf_version_expr *d;
-      bfd_boolean all_defined;
-
-      *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
-      BFD_ASSERT (*sinterpptr != NULL || !info->executable);
-
-      if (soname != NULL)
-       {
-         soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                            soname, TRUE);
-         if (soname_indx == (bfd_size_type) -1
-             || ! elf_add_dynamic_entry (info, DT_SONAME, soname_indx))
-           return FALSE;
-       }
-
-      if (info->symbolic)
-       {
-         if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
-           return FALSE;
-         info->flags |= DF_SYMBOLIC;
-       }
-
-      if (rpath != NULL)
-       {
-         bfd_size_type indx;
-
-         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
-                                     TRUE);
-         if (info->new_dtags)
-           _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx);
-         if (indx == (bfd_size_type) -1
-             || ! elf_add_dynamic_entry (info, DT_RPATH, indx)
-             || (info->new_dtags
-                 && ! elf_add_dynamic_entry (info, DT_RUNPATH, indx)))
-           return FALSE;
-       }
-
-      if (filter_shlib != NULL)
-       {
-         bfd_size_type indx;
-
-         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                     filter_shlib, TRUE);
-         if (indx == (bfd_size_type) -1
-             || ! elf_add_dynamic_entry (info, DT_FILTER, indx))
-           return FALSE;
-       }
-
-      if (auxiliary_filters != NULL)
-       {
-         const char * const *p;
-
-         for (p = auxiliary_filters; *p != NULL; p++)
-           {
-             bfd_size_type indx;
-
-             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                         *p, TRUE);
-             if (indx == (bfd_size_type) -1
-                 || ! elf_add_dynamic_entry (info, DT_AUXILIARY, indx))
-               return FALSE;
-           }
-       }
-
-      eif.info = info;
-      eif.verdefs = verdefs;
-      eif.failed = FALSE;
-
-      /* If we are supposed to export all symbols into the dynamic symbol
-        table (this is not the normal case), then do so.  */
-      if (info->export_dynamic)
-       {
-         elf_link_hash_traverse (elf_hash_table (info),
-                                 _bfd_elf_export_symbol,
-                                 &eif);
-         if (eif.failed)
-           return FALSE;
-       }
-
-      /* Make all global versions with definition.  */
-      for (t = verdefs; t != NULL; t = t->next)
-       for (d = t->globals.list; d != NULL; d = d->next)
-         if (!d->symver && d->symbol)
-           {
-             const char *verstr, *name;
-             size_t namelen, verlen, newlen;
-             char *newname, *p;
-             struct elf_link_hash_entry *newh;
-
-             name = d->symbol;
-             namelen = strlen (name);
-             verstr = t->name;
-             verlen = strlen (verstr);
-             newlen = namelen + verlen + 3;
-
-             newname = bfd_malloc (newlen);
-             if (newname == NULL)
-               return FALSE;
-             memcpy (newname, name, namelen);
-
-             /* Check the hidden versioned definition.  */
-             p = newname + namelen;
-             *p++ = ELF_VER_CHR;
-             memcpy (p, verstr, verlen + 1);
-             newh = elf_link_hash_lookup (elf_hash_table (info),
-                                          newname, FALSE, FALSE,
-                                          FALSE);
-             if (newh == NULL
-                 || (newh->root.type != bfd_link_hash_defined
-                     && newh->root.type != bfd_link_hash_defweak))
-               {
-                 /* Check the default versioned definition.  */
-                 *p++ = ELF_VER_CHR;
-                 memcpy (p, verstr, verlen + 1);
-                 newh = elf_link_hash_lookup (elf_hash_table (info),
-                                              newname, FALSE, FALSE,
-                                              FALSE);
-               }
-             free (newname);
-
-             /* Mark this version if there is a definition and it is
-                not defined in a shared object.  */
-             if (newh != NULL
-                 && ((newh->elf_link_hash_flags
-                      & ELF_LINK_HASH_DEF_DYNAMIC) == 0)
-                 && (newh->root.type == bfd_link_hash_defined
-                     || newh->root.type == bfd_link_hash_defweak))
-               d->symver = 1;
-           }
-
-      /* Attach all the symbols to their version information.  */
-      asvinfo.output_bfd = output_bfd;
-      asvinfo.info = info;
-      asvinfo.verdefs = verdefs;
-      asvinfo.failed = FALSE;
-
-      elf_link_hash_traverse (elf_hash_table (info),
-                             _bfd_elf_link_assign_sym_version,
-                             &asvinfo);
-      if (asvinfo.failed)
-       return FALSE;
-
-      if (!info->allow_undefined_version)
-       {
-         /* Check if all global versions have a definition.  */
-         all_defined = TRUE;
-         for (t = verdefs; t != NULL; t = t->next)
-           for (d = t->globals.list; d != NULL; d = d->next)
-             if (!d->symver && !d->script)
-               {
-                 (*_bfd_error_handler)
-                   (_("%s: undefined version: %s"),
-                    d->pattern, t->name);
-                 all_defined = FALSE;
-               }
-
-         if (!all_defined)
-           {
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
-       }
-
-      /* Find all symbols which were defined in a dynamic object and make
-        the backend pick a reasonable value for them.  */
-      elf_link_hash_traverse (elf_hash_table (info),
-                             _bfd_elf_adjust_dynamic_symbol,
-                             &eif);
-      if (eif.failed)
-       return FALSE;
-
-      /* Add some entries to the .dynamic section.  We fill in some of the
-        values later, in elf_bfd_final_link, but we must add the entries
-        now so that we know the final size of the .dynamic section.  */
-
-      /* If there are initialization and/or finalization functions to
-        call then add the corresponding DT_INIT/DT_FINI entries.  */
-      h = (info->init_function
-          ? elf_link_hash_lookup (elf_hash_table (info),
-                                  info->init_function, FALSE,
-                                  FALSE, FALSE)
-          : NULL);
-      if (h != NULL
-         && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
-                                       | ELF_LINK_HASH_DEF_REGULAR)) != 0)
-       {
-         if (! elf_add_dynamic_entry (info, DT_INIT, 0))
-           return FALSE;
-       }
-      h = (info->fini_function
-          ? elf_link_hash_lookup (elf_hash_table (info),
-                                  info->fini_function, FALSE,
-                                  FALSE, FALSE)
-          : NULL);
-      if (h != NULL
-         && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
-                                       | ELF_LINK_HASH_DEF_REGULAR)) != 0)
-       {
-         if (! elf_add_dynamic_entry (info, DT_FINI, 0))
-           return FALSE;
-       }
-
-      if (bfd_get_section_by_name (output_bfd, ".preinit_array") != NULL)
-       {
-         /* DT_PREINIT_ARRAY is not allowed in shared library.  */
-         if (! info->executable)
-           {
-             bfd *sub;
-             asection *o;
-
-             for (sub = info->input_bfds; sub != NULL;
-                  sub = sub->link_next)
-               for (o = sub->sections; o != NULL; o = o->next)
-                 if (elf_section_data (o)->this_hdr.sh_type
-                     == SHT_PREINIT_ARRAY)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%s: .preinit_array section is not allowed in DSO"),
-                        bfd_archive_filename (sub));
-                     break;
-                   }
-
-             bfd_set_error (bfd_error_nonrepresentable_section);
-             return FALSE;
-           }
-
-         if (!elf_add_dynamic_entry (info, DT_PREINIT_ARRAY, 0)
-             || !elf_add_dynamic_entry (info, DT_PREINIT_ARRAYSZ, 0))
-           return FALSE;
-       }
-      if (bfd_get_section_by_name (output_bfd, ".init_array") != NULL)
-       {
-         if (!elf_add_dynamic_entry (info, DT_INIT_ARRAY, 0)
-             || !elf_add_dynamic_entry (info, DT_INIT_ARRAYSZ, 0))
-           return FALSE;
-       }
-      if (bfd_get_section_by_name (output_bfd, ".fini_array") != NULL)
-       {
-         if (!elf_add_dynamic_entry (info, DT_FINI_ARRAY, 0)
-             || !elf_add_dynamic_entry (info, DT_FINI_ARRAYSZ, 0))
-           return FALSE;
-       }
-
-      dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
-      /* If .dynstr is excluded from the link, we don't want any of
-        these tags.  Strictly, we should be checking each section
-        individually;  This quick check covers for the case where
-        someone does a /DISCARD/ : { *(*) }.  */
-      if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr)
-       {
-         bfd_size_type strsize;
-
-         strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
-         if (! elf_add_dynamic_entry (info, DT_HASH, 0)
-             || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
-             || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
-             || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
-             || ! elf_add_dynamic_entry (info, DT_SYMENT,
-                                         sizeof (Elf_External_Sym)))
-           return FALSE;
-       }
-    }
-
-  /* The backend must work out the sizes of all the other dynamic
-     sections.  */
-  if (bed->elf_backend_size_dynamic_sections
-      && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
-    return FALSE;
-
-  if (elf_hash_table (info)->dynamic_sections_created)
-    {
-      bfd_size_type dynsymcount;
-      asection *s;
-      size_t bucketcount = 0;
-      size_t hash_entry_size;
-      unsigned int dtagcount;
-
-      /* Set up the version definition section.  */
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
-      BFD_ASSERT (s != NULL);
-
-      /* We may have created additional version definitions if we are
-        just linking a regular application.  */
-      verdefs = asvinfo.verdefs;
-
-      /* Skip anonymous version tag.  */
-      if (verdefs != NULL && verdefs->vernum == 0)
-       verdefs = verdefs->next;
-
-      if (verdefs == NULL)
-       _bfd_strip_section_from_output (info, s);
-      else
-       {
-         unsigned int cdefs;
-         bfd_size_type size;
-         struct bfd_elf_version_tree *t;
-         bfd_byte *p;
-         Elf_Internal_Verdef def;
-         Elf_Internal_Verdaux defaux;
-
-         cdefs = 0;
-         size = 0;
-
-         /* Make space for the base version.  */
-         size += sizeof (Elf_External_Verdef);
-         size += sizeof (Elf_External_Verdaux);
-         ++cdefs;
-
-         for (t = verdefs; t != NULL; t = t->next)
-           {
-             struct bfd_elf_version_deps *n;
-
-             size += sizeof (Elf_External_Verdef);
-             size += sizeof (Elf_External_Verdaux);
-             ++cdefs;
-
-             for (n = t->deps; n != NULL; n = n->next)
-               size += sizeof (Elf_External_Verdaux);
-           }
-
-         s->_raw_size = size;
-         s->contents = bfd_alloc (output_bfd, s->_raw_size);
-         if (s->contents == NULL && s->_raw_size != 0)
-           return FALSE;
-
-         /* Fill in the version definition section.  */
-
-         p = s->contents;
-
-         def.vd_version = VER_DEF_CURRENT;
-         def.vd_flags = VER_FLG_BASE;
-         def.vd_ndx = 1;
-         def.vd_cnt = 1;
-         def.vd_aux = sizeof (Elf_External_Verdef);
-         def.vd_next = (sizeof (Elf_External_Verdef)
-                        + sizeof (Elf_External_Verdaux));
-
-         if (soname_indx != (bfd_size_type) -1)
-           {
-             _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
-                                     soname_indx);
-             def.vd_hash = bfd_elf_hash (soname);
-             defaux.vda_name = soname_indx;
-           }
-         else
-           {
-             const char *name;
-             bfd_size_type indx;
-
-             name = basename (output_bfd->filename);
-             def.vd_hash = bfd_elf_hash (name);
-             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                         name, FALSE);
-             if (indx == (bfd_size_type) -1)
-               return FALSE;
-             defaux.vda_name = indx;
-           }
-         defaux.vda_next = 0;
-
-         _bfd_elf_swap_verdef_out (output_bfd, &def,
-                                   (Elf_External_Verdef *) p);
-         p += sizeof (Elf_External_Verdef);
-         _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
-                                    (Elf_External_Verdaux *) p);
-         p += sizeof (Elf_External_Verdaux);
-
-         for (t = verdefs; t != NULL; t = t->next)
-           {
-             unsigned int cdeps;
-             struct bfd_elf_version_deps *n;
-             struct elf_link_hash_entry *h;
-             struct bfd_link_hash_entry *bh;
-
-             cdeps = 0;
-             for (n = t->deps; n != NULL; n = n->next)
-               ++cdeps;
-
-             /* Add a symbol representing this version.  */
-             bh = NULL;
-             if (! (_bfd_generic_link_add_one_symbol
-                    (info, dynobj, t->name, BSF_GLOBAL, bfd_abs_section_ptr,
-                     0, NULL, FALSE,
-                     get_elf_backend_data (dynobj)->collect, &bh)))
-               return FALSE;
-             h = (struct elf_link_hash_entry *) bh;
-             h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
-             h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-             h->type = STT_OBJECT;
-             h->verinfo.vertree = t;
-
-             if (! _bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-
-             def.vd_version = VER_DEF_CURRENT;
-             def.vd_flags = 0;
-             if (t->globals.list == NULL && t->locals.list == NULL && ! t->used)
-               def.vd_flags |= VER_FLG_WEAK;
-             def.vd_ndx = t->vernum + 1;
-             def.vd_cnt = cdeps + 1;
-             def.vd_hash = bfd_elf_hash (t->name);
-             def.vd_aux = sizeof (Elf_External_Verdef);
-             if (t->next != NULL)
-               def.vd_next = (sizeof (Elf_External_Verdef)
-                              + (cdeps + 1) * sizeof (Elf_External_Verdaux));
-             else
-               def.vd_next = 0;
-
-             _bfd_elf_swap_verdef_out (output_bfd, &def,
-                                       (Elf_External_Verdef *) p);
-             p += sizeof (Elf_External_Verdef);
-
-             defaux.vda_name = h->dynstr_index;
-             _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
-                                     h->dynstr_index);
-             if (t->deps == NULL)
-               defaux.vda_next = 0;
-             else
-               defaux.vda_next = sizeof (Elf_External_Verdaux);
-             t->name_indx = defaux.vda_name;
-
-             _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
-                                        (Elf_External_Verdaux *) p);
-             p += sizeof (Elf_External_Verdaux);
-
-             for (n = t->deps; n != NULL; n = n->next)
-               {
-                 if (n->version_needed == NULL)
-                   {
-                     /* This can happen if there was an error in the
-                        version script.  */
-                     defaux.vda_name = 0;
-                   }
-                 else
-                   {
-                     defaux.vda_name = n->version_needed->name_indx;
-                     _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
-                                             defaux.vda_name);
-                   }
-                 if (n->next == NULL)
-                   defaux.vda_next = 0;
-                 else
-                   defaux.vda_next = sizeof (Elf_External_Verdaux);
-
-                 _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
-                                            (Elf_External_Verdaux *) p);
-                 p += sizeof (Elf_External_Verdaux);
-               }
-           }
-
-         if (! elf_add_dynamic_entry (info, DT_VERDEF, 0)
-             || ! elf_add_dynamic_entry (info, DT_VERDEFNUM, cdefs))
-           return FALSE;
-
-         elf_tdata (output_bfd)->cverdefs = cdefs;
-       }
-
-      if ((info->new_dtags && info->flags) || (info->flags & DF_STATIC_TLS))
-       {
-         if (! elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
-           return FALSE;
-       }
-      else if (info->flags & DF_BIND_NOW)
-       {
-         if (! elf_add_dynamic_entry (info, DT_BIND_NOW, 0))
-           return FALSE;
-       }
-
-      if (info->flags_1)
-       {
-         if (info->executable)
-           info->flags_1 &= ~ (DF_1_INITFIRST
-                               | DF_1_NODELETE
-                               | DF_1_NOOPEN);
-         if (! elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1))
-           return FALSE;
-       }
-
-      /* Work out the size of the version reference section.  */
-
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
-      BFD_ASSERT (s != NULL);
-      {
-       struct elf_find_verdep_info sinfo;
-
-       sinfo.output_bfd = output_bfd;
-       sinfo.info = info;
-       sinfo.vers = elf_tdata (output_bfd)->cverdefs;
-       if (sinfo.vers == 0)
-         sinfo.vers = 1;
-       sinfo.failed = FALSE;
-
-       elf_link_hash_traverse (elf_hash_table (info),
-                               _bfd_elf_link_find_version_dependencies,
-                               &sinfo);
-
-       if (elf_tdata (output_bfd)->verref == NULL)
-         _bfd_strip_section_from_output (info, s);
-       else
-         {
-           Elf_Internal_Verneed *t;
-           unsigned int size;
-           unsigned int crefs;
-           bfd_byte *p;
-
-           /* Build the version definition section.  */
-           size = 0;
-           crefs = 0;
-           for (t = elf_tdata (output_bfd)->verref;
-                t != NULL;
-                t = t->vn_nextref)
-             {
-               Elf_Internal_Vernaux *a;
-
-               size += sizeof (Elf_External_Verneed);
-               ++crefs;
-               for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-                 size += sizeof (Elf_External_Vernaux);
-             }
-
-           s->_raw_size = size;
-           s->contents = bfd_alloc (output_bfd, s->_raw_size);
-           if (s->contents == NULL)
-             return FALSE;
-
-           p = s->contents;
-           for (t = elf_tdata (output_bfd)->verref;
-                t != NULL;
-                t = t->vn_nextref)
-             {
-               unsigned int caux;
-               Elf_Internal_Vernaux *a;
-               bfd_size_type indx;
-
-               caux = 0;
-               for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-                 ++caux;
-
-               t->vn_version = VER_NEED_CURRENT;
-               t->vn_cnt = caux;
-               indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                           elf_dt_name (t->vn_bfd) != NULL
-                                           ? elf_dt_name (t->vn_bfd)
-                                           : basename (t->vn_bfd->filename),
-                                           FALSE);
-               if (indx == (bfd_size_type) -1)
-                 return FALSE;
-               t->vn_file = indx;
-               t->vn_aux = sizeof (Elf_External_Verneed);
-               if (t->vn_nextref == NULL)
-                 t->vn_next = 0;
-               else
-                 t->vn_next = (sizeof (Elf_External_Verneed)
-                               + caux * sizeof (Elf_External_Vernaux));
-
-               _bfd_elf_swap_verneed_out (output_bfd, t,
-                                          (Elf_External_Verneed *) p);
-               p += sizeof (Elf_External_Verneed);
-
-               for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-                 {
-                   a->vna_hash = bfd_elf_hash (a->vna_nodename);
-                   indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
-                                               a->vna_nodename, FALSE);
-                   if (indx == (bfd_size_type) -1)
-                     return FALSE;
-                   a->vna_name = indx;
-                   if (a->vna_nextptr == NULL)
-                     a->vna_next = 0;
-                   else
-                     a->vna_next = sizeof (Elf_External_Vernaux);
-
-                   _bfd_elf_swap_vernaux_out (output_bfd, a,
-                                              (Elf_External_Vernaux *) p);
-                   p += sizeof (Elf_External_Vernaux);
-                 }
-             }
-
-           if (! elf_add_dynamic_entry (info, DT_VERNEED, 0)
-               || ! elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs))
-             return FALSE;
-
-           elf_tdata (output_bfd)->cverrefs = crefs;
-         }
-      }
-
-      /* Assign dynsym indicies.  In a shared library we generate a
-        section symbol for each output section, which come first.
-        Next come all of the back-end allocated local dynamic syms,
-        followed by the rest of the global symbols.  */
-
-      dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
-
-      /* Work out the size of the symbol version section.  */
-      s = bfd_get_section_by_name (dynobj, ".gnu.version");
-      BFD_ASSERT (s != NULL);
-      if (dynsymcount == 0
-         || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
-       {
-         _bfd_strip_section_from_output (info, s);
-         /* The DYNSYMCOUNT might have changed if we were going to
-            output a dynamic symbol table entry for S.  */
-         dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
-       }
-      else
-       {
-         s->_raw_size = dynsymcount * sizeof (Elf_External_Versym);
-         s->contents = bfd_zalloc (output_bfd, s->_raw_size);
-         if (s->contents == NULL)
-           return FALSE;
-
-         if (! elf_add_dynamic_entry (info, DT_VERSYM, 0))
-           return FALSE;
-       }
-
-      /* Set the size of the .dynsym and .hash sections.  We counted
-        the number of dynamic symbols in elf_link_add_object_symbols.
-        We will build the contents of .dynsym and .hash when we build
-        the final symbol table, because until then we do not know the
-        correct value to give the symbols.  We built the .dynstr
-        section as we went along in elf_link_add_object_symbols.  */
-      s = bfd_get_section_by_name (dynobj, ".dynsym");
-      BFD_ASSERT (s != NULL);
-      s->_raw_size = dynsymcount * sizeof (Elf_External_Sym);
-      s->contents = bfd_alloc (output_bfd, s->_raw_size);
-      if (s->contents == NULL && s->_raw_size != 0)
-       return FALSE;
-
-      if (dynsymcount != 0)
-       {
-         Elf_Internal_Sym isym;
-
-         /* The first entry in .dynsym is a dummy symbol.  */
-         isym.st_value = 0;
-         isym.st_size = 0;
-         isym.st_name = 0;
-         isym.st_info = 0;
-         isym.st_other = 0;
-         isym.st_shndx = 0;
-         elf_swap_symbol_out (output_bfd, &isym, s->contents, 0);
-       }
-
-      /* Compute the size of the hashing table.  As a side effect this
-        computes the hash values for all the names we export.  */
-      bucketcount = compute_bucket_count (info);
-
-      s = bfd_get_section_by_name (dynobj, ".hash");
-      BFD_ASSERT (s != NULL);
-      hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
-      s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
-      s->contents = bfd_zalloc (output_bfd, s->_raw_size);
-      if (s->contents == NULL)
-       return FALSE;
-
-      bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
-      bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
-              s->contents + hash_entry_size);
-
-      elf_hash_table (info)->bucketcount = bucketcount;
-
-      s = bfd_get_section_by_name (dynobj, ".dynstr");
-      BFD_ASSERT (s != NULL);
-
-      elf_finalize_dynstr (output_bfd, info);
-
-      s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
-
-      for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
-       if (! elf_add_dynamic_entry (info, DT_NULL, 0))
-         return FALSE;
-    }
-
-  return TRUE;
-}
-\f
-/* This function is used to adjust offsets into .dynstr for
-   dynamic symbols.  This is called via elf_link_hash_traverse.  */
-
-static bfd_boolean
-elf_adjust_dynstr_offsets (struct elf_link_hash_entry *h, void *data)
-{
-  struct elf_strtab_hash *dynstr = data;
-
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if (h->dynindx != -1)
-    h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
-  return TRUE;
-}
-
-/* Assign string offsets in .dynstr, update all structures referencing
-   them.  */
-
-static bfd_boolean
-elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info)
-{
-  struct elf_link_local_dynamic_entry *entry;
-  struct elf_strtab_hash *dynstr = elf_hash_table (info)->dynstr;
-  bfd *dynobj = elf_hash_table (info)->dynobj;
-  asection *sdyn;
-  bfd_size_type size;
-  Elf_External_Dyn *dyncon, *dynconend;
-
-  _bfd_elf_strtab_finalize (dynstr);
-  size = _bfd_elf_strtab_size (dynstr);
-
-  /* Update all .dynamic entries referencing .dynstr strings.  */
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
-  BFD_ASSERT (sdyn != NULL);
-
-  dyncon = (Elf_External_Dyn *) sdyn->contents;
-  dynconend = (Elf_External_Dyn *) (sdyn->contents +
-                                   sdyn->_raw_size);
-  for (; dyncon < dynconend; dyncon++)
-    {
-      Elf_Internal_Dyn dyn;
-
-      elf_swap_dyn_in (dynobj, dyncon, & dyn);
-      switch (dyn.d_tag)
-       {
-       case DT_STRSZ:
-         dyn.d_un.d_val = size;
-         elf_swap_dyn_out (dynobj, & dyn, dyncon);
-         break;
-       case DT_NEEDED:
-       case DT_SONAME:
-       case DT_RPATH:
-       case DT_RUNPATH:
-       case DT_FILTER:
-       case DT_AUXILIARY:
-         dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val);
-         elf_swap_dyn_out (dynobj, & dyn, dyncon);
-         break;
-       default:
-         break;
-       }
-    }
-
-  /* Now update local dynamic symbols.  */
-  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
-    entry->isym.st_name = _bfd_elf_strtab_offset (dynstr,
-                                                 entry->isym.st_name);
-
-  /* And the rest of dynamic symbols.  */
-  elf_link_hash_traverse (elf_hash_table (info),
-                         elf_adjust_dynstr_offsets, dynstr);
-
-  /* Adjust version definitions.  */
-  if (elf_tdata (output_bfd)->cverdefs)
-    {
-      asection *s;
-      bfd_byte *p;
-      bfd_size_type i;
-      Elf_Internal_Verdef def;
-      Elf_Internal_Verdaux defaux;
-
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
-      p = (bfd_byte *) s->contents;
-      do
-       {
-         _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p,
-                                  &def);
-         p += sizeof (Elf_External_Verdef);
-         for (i = 0; i < def.vd_cnt; ++i)
-           {
-             _bfd_elf_swap_verdaux_in (output_bfd,
-                                       (Elf_External_Verdaux *) p, &defaux);
-             defaux.vda_name = _bfd_elf_strtab_offset (dynstr,
-                                                       defaux.vda_name);
-             _bfd_elf_swap_verdaux_out (output_bfd,
-                                        &defaux, (Elf_External_Verdaux *) p);
-             p += sizeof (Elf_External_Verdaux);
-           }
-       }
-      while (def.vd_next);
-    }
-
-  /* Adjust version references.  */
-  if (elf_tdata (output_bfd)->verref)
-    {
-      asection *s;
-      bfd_byte *p;
-      bfd_size_type i;
-      Elf_Internal_Verneed need;
-      Elf_Internal_Vernaux needaux;
-
-      s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
-      p = (bfd_byte *) s->contents;
-      do
-       {
-         _bfd_elf_swap_verneed_in (output_bfd, (Elf_External_Verneed *) p,
-                                   &need);
-         need.vn_file = _bfd_elf_strtab_offset (dynstr, need.vn_file);
-         _bfd_elf_swap_verneed_out (output_bfd, &need,
-                                    (Elf_External_Verneed *) p);
-         p += sizeof (Elf_External_Verneed);
-         for (i = 0; i < need.vn_cnt; ++i)
-           {
-             _bfd_elf_swap_vernaux_in (output_bfd,
-                                       (Elf_External_Vernaux *) p, &needaux);
-             needaux.vna_name = _bfd_elf_strtab_offset (dynstr,
-                                                        needaux.vna_name);
-             _bfd_elf_swap_vernaux_out (output_bfd,
-                                        &needaux,
-                                        (Elf_External_Vernaux *) p);
-             p += sizeof (Elf_External_Vernaux);
-           }
-       }
-      while (need.vn_next);
-    }
+static bfd_boolean elf_section_ignore_discarded_relocs (asection *);
 
-  return TRUE;
-}
-\f
 /* Final phase of ELF linker.  */
 
 /* A structure we use to avoid passing large numbers of arguments.  */
@@ -2558,7 +48,7 @@ struct elf_final_link_info
   Elf_Internal_Rela *internal_relocs;
   /* Buffer large enough to hold external local symbols of any input
      BFD.  */
-  Elf_External_Sym *external_syms;
+  bfd_byte *external_syms;
   /* And a buffer for symbol section indices.  */
   Elf_External_Sym_Shndx *locsym_shndx;
   /* Buffer large enough to hold internal local symbols of any input
@@ -2571,7 +61,7 @@ struct elf_final_link_info
      symbol of any input BFD.  */
   asection **sections;
   /* Buffer to hold swapped out symbols.  */
-  Elf_External_Sym *symbuf;
+  bfd_byte *symbuf;
   /* And one for symbol section indices.  */
   Elf_External_Sym_Shndx *symshndxbuf;
   /* Number of swapped out symbols in buffer.  */
@@ -2586,7 +76,7 @@ static bfd_boolean elf_link_output_sym
   (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *,
    struct elf_link_hash_entry *);
 static bfd_boolean elf_link_flush_output_syms
-  (struct elf_final_link_info *);
+  (struct elf_final_link_info *, const struct elf_backend_data *);
 static bfd_boolean elf_link_output_extsym
   (struct elf_link_hash_entry *, void *);
 static bfd_boolean elf_link_input_bfd
@@ -2619,13 +109,15 @@ elf_link_adjust_relocs (bfd *abfd,
   bfd_byte *erela;
   void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
+  bfd_vma r_type_mask;
+  int r_sym_shift;
 
-  if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+  if (rel_hdr->sh_entsize == bed->s->sizeof_rel)
     {
       swap_in = bed->s->swap_reloc_in;
       swap_out = bed->s->swap_reloc_out;
     }
-  else if (rel_hdr->sh_entsize == sizeof (Elf_External_Rela))
+  else if (rel_hdr->sh_entsize == bed->s->sizeof_rela)
     {
       swap_in = bed->s->swap_reloca_in;
       swap_out = bed->s->swap_reloca_out;
@@ -2636,6 +128,17 @@ elf_link_adjust_relocs (bfd *abfd,
   if (bed->s->int_rels_per_ext_rel > MAX_INT_RELS_PER_EXT_REL)
     abort ();
 
+  if (bed->s->arch_size == 32)
+    {
+      r_type_mask = 0xff;
+      r_sym_shift = 8;
+    }
+  else
+    {
+      r_type_mask = 0xffffffff;
+      r_sym_shift = 32;
+    }
+
   erela = rel_hdr->contents;
   for (i = 0; i < count; i++, rel_hash++, erela += rel_hdr->sh_entsize)
     {
@@ -2649,15 +152,18 @@ elf_link_adjust_relocs (bfd *abfd,
 
       (*swap_in) (abfd, erela, irela);
       for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
-       irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                     ELF_R_TYPE (irela[j].r_info));
+       irela[j].r_info = ((bfd_vma) (*rel_hash)->indx << r_sym_shift
+                          | (irela[j].r_info & r_type_mask));
       (*swap_out) (abfd, irela, erela);
     }
 }
 
 struct elf_link_sort_rela
 {
-  bfd_vma offset;
+  union {
+    bfd_vma offset;
+    bfd_vma sym_mask;
+  } u;
   enum elf_reloc_type_class type;
   /* We use this as an array of size int_rels_per_ext_rel.  */
   Elf_Internal_Rela rela[1];
@@ -2677,9 +183,9 @@ elf_link_sort_cmp1 (const void *A, const void *B)
     return 1;
   if (relativea > relativeb)
     return -1;
-  if (ELF_R_SYM (a->rela->r_info) < ELF_R_SYM (b->rela->r_info))
+  if ((a->rela->r_info & a->u.sym_mask) < (b->rela->r_info & b->u.sym_mask))
     return -1;
-  if (ELF_R_SYM (a->rela->r_info) > ELF_R_SYM (b->rela->r_info))
+  if ((a->rela->r_info & a->u.sym_mask) > (b->rela->r_info & b->u.sym_mask))
     return 1;
   if (a->rela->r_offset < b->rela->r_offset)
     return -1;
@@ -2695,9 +201,9 @@ elf_link_sort_cmp2 (const void *A, const void *B)
   const struct elf_link_sort_rela *b = B;
   int copya, copyb;
 
-  if (a->offset < b->offset)
+  if (a->u.offset < b->u.offset)
     return -1;
-  if (a->offset > b->offset)
+  if (a->u.offset > b->u.offset)
     return 1;
   copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt);
   copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt);
@@ -2725,6 +231,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *);
   void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *);
   struct bfd_link_order *lo;
+  bfd_vma r_sym_mask;
 
   reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
   if (reldyn == NULL || reldyn->_raw_size == 0)
@@ -2732,13 +239,13 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
       reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
       if (reldyn == NULL || reldyn->_raw_size == 0)
        return 0;
-      ext_size = sizeof (Elf_External_Rel);
+      ext_size = bed->s->sizeof_rel;
       swap_in = bed->s->swap_reloc_in;
       swap_out = bed->s->swap_reloc_out;
     }
   else
     {
-      ext_size = sizeof (Elf_External_Rela);
+      ext_size = bed->s->sizeof_rela;
       swap_in = bed->s->swap_reloca_in;
       swap_out = bed->s->swap_reloca_out;
     }
@@ -2765,6 +272,11 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
       return 0;
     }
 
+  if (bed->s->arch_size == 32)
+    r_sym_mask = ~(bfd_vma) 0xff;
+  else
+    r_sym_mask = ~(bfd_vma) 0xffffffff;
+
   for (lo = reldyn->link_order_head; lo != NULL; lo = lo->next)
     if (lo->type == bfd_indirect_link_order)
       {
@@ -2779,6 +291,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
            struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p;
            (*swap_in) (abfd, erel, s->rela);
            s->type = (*bed->elf_backend_reloc_type_class) (s->rela);
+           s->u.sym_mask = r_sym_mask;
            p += sort_elt;
            erel += ext_size;
          }
@@ -2799,9 +312,9 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec)
   for (; i < count; i++, p += sort_elt)
     {
       struct elf_link_sort_rela *sp = (struct elf_link_sort_rela *) p;
-      if (ELF_R_SYM (sp->rela->r_info) != ELF_R_SYM (sq->rela->r_info))
+      if (((sp->rela->r_info ^ sq->rela->r_info) & r_sym_mask) != 0)
        sq = sp;
-      sp->offset = sq->rela->r_offset;
+      sp->u.offset = sq->rela->r_offset;
     }
 
   qsort (s_non_relative, count - ret, sort_elt, elf_link_sort_cmp2);
@@ -2874,7 +387,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
 
   finfo.info = info;
   finfo.output_bfd = abfd;
-  finfo.symstrtab = elf_stringtab_init ();
+  finfo.symstrtab = _bfd_elf_stringtab_init ();
   if (finfo.symstrtab == NULL)
     return FALSE;
 
@@ -2974,7 +487,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
 
                  if (elf_bad_symtab (sec->owner))
                    sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size
-                                / sizeof (Elf_External_Sym));
+                                / bed->s->sizeof_sym);
                  else
                    sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info;
 
@@ -3016,10 +529,9 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
              bfd_size_type entsize1;
 
              entsize1 = esdi->rel_hdr.sh_entsize;
-             BFD_ASSERT (entsize1 == sizeof (Elf_External_Rel)
-                         || entsize1 == sizeof (Elf_External_Rela));
-             same_size = (!o->use_rela_p
-                          == (entsize1 == sizeof (Elf_External_Rel)));
+             BFD_ASSERT (entsize1 == bed->s->sizeof_rel
+                         || entsize1 == bed->s->sizeof_rela);
+             same_size = !o->use_rela_p == (entsize1 == bed->s->sizeof_rel);
 
              if (!same_size)
                rel_count1 = &esdo->rel_count2;
@@ -3031,8 +543,8 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
                  unsigned int *rel_count2;
 
                  BFD_ASSERT (entsize2 != entsize1
-                             && (entsize2 == sizeof (Elf_External_Rel)
-                                 || entsize2 == sizeof (Elf_External_Rela)));
+                             && (entsize2 == bed->s->sizeof_rel
+                                 || entsize2 == bed->s->sizeof_rela));
 
                  rel_count2 = &esdo->rel_count2;
                  if (!same_size)
@@ -3113,7 +625,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   /* sh_name is set in prep_headers.  */
   symtab_hdr->sh_type = SHT_SYMTAB;
   /* sh_flags, sh_addr and sh_size all start off zero.  */
-  symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
+  symtab_hdr->sh_entsize = bed->s->sizeof_sym;
   /* sh_link is set in assign_section_numbers.  */
   /* sh_info is set below.  */
   /* sh_offset is set just below.  */
@@ -3133,7 +645,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   else
     finfo.symbuf_size = max_sym_count;
   amt = finfo.symbuf_size;
-  amt *= sizeof (Elf_External_Sym);
+  amt *= bed->s->sizeof_sym;
   finfo.symbuf = bfd_malloc (amt);
   if (finfo.symbuf == NULL)
     goto error_return;
@@ -3192,7 +704,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
       elfsym.st_other = 0;
       for (i = 1; i < elf_numsections (abfd); i++)
        {
-         o = section_from_elf_index (abfd, i);
+         o = bfd_section_from_elf_index (abfd, i);
          if (o != NULL)
            o->target_index = bfd_get_symcount (abfd);
          elfsym.st_shndx = i;
@@ -3234,7 +746,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
 
   if (max_sym_count != 0)
     {
-      amt = max_sym_count * sizeof (Elf_External_Sym);
+      amt = max_sym_count * bed->s->sizeof_sym;
       finfo.external_syms = bfd_malloc (amt);
       if (finfo.external_syms == NULL)
        goto error_return;
@@ -3367,8 +879,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
       && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
-      Elf_External_Sym *dynsym =
-       (Elf_External_Sym *) finfo.dynsym_sec->contents;
+      bfd_byte *dynsym = finfo.dynsym_sec->contents;
       long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
@@ -3384,14 +895,16 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
          for (s = abfd->sections; s != NULL; s = s->next)
            {
              int indx;
-             Elf_External_Sym *dest;
+             bfd_byte *dest;
+             long dynindx;
 
              indx = elf_section_data (s)->this_idx;
+             dynindx = elf_section_data (s)->dynindx;
              BFD_ASSERT (indx > 0);
              sym.st_shndx = indx;
              sym.st_value = s->vma;
-             dest = dynsym + elf_section_data (s)->dynindx;
-             elf_swap_symbol_out (abfd, &sym, dest, 0);
+             dest = dynsym + dynindx * bed->s->sizeof_sym;
+             bed->s->swap_symbol_out (abfd, &sym, dest, 0);
            }
 
          last_local = bfd_count_sections (abfd);
@@ -3404,7 +917,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
          for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
            {
              asection *s;
-             Elf_External_Sym *dest;
+             bfd_byte *dest;
 
              sym.st_size = e->isym.st_size;
              sym.st_other = e->isym.st_other;
@@ -3431,8 +944,8 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
              if (last_local < e->dynindx)
                last_local = e->dynindx;
 
-             dest = dynsym + e->dynindx;
-             elf_swap_symbol_out (abfd, &sym, dest, 0);
+             dest = dynsym + e->dynindx * bed->s->sizeof_sym;
+             bed->s->swap_symbol_out (abfd, &sym, dest, 0);
            }
        }
 
@@ -3463,7 +976,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
     }
 
   /* Flush all symbols to the file.  */
-  if (! elf_link_flush_output_syms (&finfo))
+  if (! elf_link_flush_output_syms (&finfo, bed))
     return FALSE;
 
   /* Now we know the size of the symtab section.  */
@@ -3538,43 +1051,41 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
      shared library, finish up the dynamic linking information.  */
   if (dynamic)
     {
-      Elf_External_Dyn *dyncon, *dynconend;
+      bfd_byte *dyncon, *dynconend;
 
       /* Fix up .dynamic entries.  */
       o = bfd_get_section_by_name (dynobj, ".dynamic");
       BFD_ASSERT (o != NULL);
 
-      dyncon = (Elf_External_Dyn *) o->contents;
-      dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size);
-      for (; dyncon < dynconend; dyncon++)
+      dyncon = o->contents;
+      dynconend = o->contents + o->_raw_size;
+      for (; dyncon < dynconend; dyncon += bed->s->sizeof_dyn)
        {
          Elf_Internal_Dyn dyn;
          const char *name;
          unsigned int type;
 
-         elf_swap_dyn_in (dynobj, dyncon, &dyn);
+         bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
 
          switch (dyn.d_tag)
            {
            default:
-             break;
+             continue;
            case DT_NULL:
-             if (relativecount > 0 && dyncon + 1 < dynconend)
+             if (relativecount > 0 && dyncon + bed->s->sizeof_dyn < dynconend)
                {
                  switch (elf_section_data (reldyn)->this_hdr.sh_type)
                    {
                    case SHT_REL: dyn.d_tag = DT_RELCOUNT; break;
                    case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break;
-                   default: break;
-                   }
-                 if (dyn.d_tag != DT_NULL)
-                   {
-                     dyn.d_un.d_val = relativecount;
-                     elf_swap_dyn_out (dynobj, &dyn, dyncon);
-                     relativecount = 0;
+                   default: continue;
                    }
+                 dyn.d_un.d_val = relativecount;
+                 relativecount = 0;
+                 break;
                }
-             break;
+             continue;
+
            case DT_INIT:
              name = info->init_function;
              goto get_sym;
@@ -3601,11 +1112,10 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
                           library and does not apply to this one.  */
                        dyn.d_un.d_val = 0;
                      }
-
-                   elf_swap_dyn_out (dynobj, &dyn, dyncon);
+                   break;
                  }
              }
-             break;
+             continue;
 
            case DT_PREINIT_ARRAYSZ:
              name = ".preinit_array";
@@ -3628,7 +1138,6 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
                (*_bfd_error_handler)
                  (_("warning: %s section has zero size"), name);
              dyn.d_un.d_val = o->_raw_size;
-             elf_swap_dyn_out (dynobj, &dyn, dyncon);
              break;
 
            case DT_PREINIT_ARRAY:
@@ -3668,7 +1177,6 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
                  goto error_return;
                }
              dyn.d_un.d_ptr = o->vma;
-             elf_swap_dyn_out (dynobj, &dyn, dyncon);
              break;
 
            case DT_REL:
@@ -3698,9 +1206,9 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
                        }
                    }
                }
-             elf_swap_dyn_out (dynobj, &dyn, dyncon);
              break;
            }
+         bed->s->swap_dyn_out (dynobj, &dyn, dyncon);
        }
     }
 
@@ -3842,14 +1350,15 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
                     asection *input_sec,
                     struct elf_link_hash_entry *h)
 {
-  Elf_External_Sym *dest;
+  bfd_byte *dest;
   Elf_External_Sym_Shndx *destshndx;
   bfd_boolean (*output_symbol_hook)
     (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
      struct elf_link_hash_entry *);
+  const struct elf_backend_data *bed;
 
-  output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
-    elf_backend_link_output_symbol_hook;
+  bed = get_elf_backend_data (finfo->output_bfd);
+  output_symbol_hook = bed->elf_backend_link_output_symbol_hook;
   if (output_symbol_hook != NULL)
     {
       if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
@@ -3870,11 +1379,11 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
 
   if (finfo->symbuf_count >= finfo->symbuf_size)
     {
-      if (! elf_link_flush_output_syms (finfo))
+      if (! elf_link_flush_output_syms (finfo, bed))
        return FALSE;
     }
 
-  dest = finfo->symbuf + finfo->symbuf_count;
+  dest = finfo->symbuf + finfo->symbuf_count * bed->s->sizeof_sym;
   destshndx = finfo->symshndxbuf;
   if (destshndx != NULL)
     {
@@ -3892,7 +1401,7 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
       destshndx += bfd_get_symcount (finfo->output_bfd);
     }
 
-  elf_swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx);
+  bed->s->swap_symbol_out (finfo->output_bfd, elfsym, dest, destshndx);
   finfo->symbuf_count += 1;
   bfd_get_symcount (finfo->output_bfd) += 1;
 
@@ -3902,7 +1411,8 @@ elf_link_output_sym (struct elf_final_link_info *finfo,
 /* Flush the output symbols to the file.  */
 
 static bfd_boolean
-elf_link_flush_output_syms (struct elf_final_link_info *finfo)
+elf_link_flush_output_syms (struct elf_final_link_info *finfo,
+                           const struct elf_backend_data *bed)
 {
   if (finfo->symbuf_count > 0)
     {
@@ -3912,7 +1422,7 @@ elf_link_flush_output_syms (struct elf_final_link_info *finfo)
 
       hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr;
       pos = hdr->sh_offset + hdr->sh_size;
-      amt = finfo->symbuf_count * sizeof (Elf_External_Sym);
+      amt = finfo->symbuf_count * bed->s->sizeof_sym;
       if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
          || bfd_bwrite (finfo->symbuf, amt, finfo->output_bfd) != amt)
        return FALSE;
@@ -3932,6 +1442,7 @@ elf_link_flush_output_syms (struct elf_final_link_info *finfo)
 
 static bfd_boolean
 elf_link_check_versioned_symbol (struct bfd_link_info *info,
+                                const struct elf_backend_data *bed,
                                 struct elf_link_hash_entry *h)
 {
   bfd *abfd;
@@ -3949,7 +1460,8 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
     case bfd_link_hash_undefined:
     case bfd_link_hash_undefweak:
       abfd = h->root.u.undef.abfd;
-      if ((abfd->flags & DYNAMIC) == 0 || elf_dt_soname (abfd) == NULL)
+      if ((abfd->flags & DYNAMIC) == 0
+         || elf_dyn_lib_class (abfd) != DYN_DT_NEEDED)
        return FALSE;
       break;
 
@@ -3990,7 +1502,7 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
 
       hdr = &elf_tdata (input)->dynsymtab_hdr;
 
-      symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+      symcount = hdr->sh_size / bed->s->sizeof_sym;
       if (elf_bad_symtab (input))
        {
          extsymcount = symcount;
@@ -4085,6 +1597,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   bfd_boolean strip;
   Elf_Internal_Sym sym;
   asection *input_sec;
+  const struct elf_backend_data *bed;
 
   if (h->root.type == bfd_link_hash_warning)
     {
@@ -4105,6 +1618,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
        return TRUE;
     }
 
+  bed = get_elf_backend_data (finfo->output_bfd);
+
   /* If we have an undefined symbol reference here then it must have
      come from a shared library that is being linked in.  (Undefined
      references in regular files have already been handled).  If we
@@ -4112,7 +1627,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
   if (h->root.type == bfd_link_hash_undefined
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0
-      && ! elf_link_check_versioned_symbol (finfo->info, h)
+      && ! elf_link_check_versioned_symbol (finfo->info, bed, h)
       && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE)
     {
       if (! ((*finfo->info->callbacks->undefined_symbol)
@@ -4131,7 +1646,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
       && (h->elf_link_hash_flags
          & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK))
         == (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC)
-      && ! elf_link_check_versioned_symbol (finfo->info, h))
+      && ! elf_link_check_versioned_symbol (finfo->info, bed, h))
     {
       (*_bfd_error_handler)
        (_("%s: %s symbol `%s' in %s is referenced by DSO"),
@@ -4277,9 +1792,6 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
          || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
       && elf_hash_table (finfo->info)->dynamic_sections_created)
     {
-      const struct elf_backend_data *bed;
-
-      bed = get_elf_backend_data (finfo->output_bfd);
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
             (finfo->output_bfd, finfo->info, h, &sym)))
        {
@@ -4339,11 +1851,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
       size_t hash_entry_size;
       bfd_byte *bucketpos;
       bfd_vma chain;
-      Elf_External_Sym *esym;
+      bfd_byte *esym;
 
       sym.st_name = h->dynstr_index;
-      esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx;
-      elf_swap_symbol_out (finfo->output_bfd, &sym, esym, 0);
+      esym = finfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
+      bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0);
 
       bucketcount = elf_hash_table (finfo->info)->bucketcount;
       bucket = h->elf_hash_value % bucketcount;
@@ -4444,7 +1956,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   if (elf_bad_symtab (input_bfd))
     {
-      locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+      locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
       extsymoff = 0;
     }
   else
@@ -4493,7 +2005,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
       else if (isym->st_shndx < SHN_LORESERVE
               || isym->st_shndx > SHN_HIRESERVE)
        {
-         isec = section_from_elf_index (input_bfd, isym->st_shndx);
+         isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
          if (isec
              && isec->sec_info_type == ELF_INFO_TYPE_MERGE
              && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
@@ -4642,6 +2154,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
       if ((o->flags & SEC_RELOC) != 0)
        {
          Elf_Internal_Rela *internal_relocs;
+         bfd_vma r_type_mask;
+         int r_sym_shift;
 
          /* Get the swapped relocs.  */
          internal_relocs
@@ -4651,6 +2165,17 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              && o->reloc_count > 0)
            return FALSE;
 
+         if (bed->s->arch_size == 32)
+           {
+             r_type_mask = 0xff;
+             r_sym_shift = 8;
+           }
+         else
+           {
+             r_type_mask = 0xffffffff;
+             r_sym_shift = 32;
+           }
+
          /* Run through the relocs looking for any against symbols
             from discarded sections and section symbols from
             removed link-once sections.  Complain about relocs
@@ -4665,7 +2190,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
              for ( ; rel < relend; rel++)
                {
-                 unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+                 unsigned long r_symndx = rel->r_info >> r_sym_shift;
                  asection *sec;
 
                  if (r_symndx >= locsymcount
@@ -4726,8 +2251,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                                  = sec->kept_section;
                              else
                                {
-                                 rel->r_info
-                                   = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
+                                 rel->r_info &= r_type_mask;
                                  rel->r_addend = 0;
                                }
                            }
@@ -4796,7 +2320,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
              input_rel_hdr = &elf_section_data (o)->rel_hdr;
              rela_normal = (bed->rela_normal
                             && (input_rel_hdr->sh_entsize
-                                == sizeof (Elf_External_Rela)));
+                                == bed->s->sizeof_rela));
 
              /* Adjust the reloc addresses and symbol indices.  */
 
@@ -4844,7 +2368,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
 
                  last_offset = irela->r_offset;
 
-                 r_symndx = ELF_R_SYM (irela->r_info);
+                 r_symndx = irela->r_info >> r_sym_shift;
                  if (r_symndx == STN_UNDEF)
                    continue;
 
@@ -4968,8 +2492,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                      r_symndx = finfo->indices[r_symndx];
                    }
 
-                 irela->r_info = ELF_R_INFO (r_symndx,
-                                             ELF_R_TYPE (irela->r_info));
+                 irela->r_info = ((bfd_vma) r_symndx << r_sym_shift
+                                  | (irela->r_info & r_type_mask));
                }
 
              /* Swap out the relocs.  */
@@ -5183,21 +2707,24 @@ elf_reloc_link_order (bfd *output_bfd,
       irel[i].r_info = 0;
       irel[i].r_addend = 0;
     }
-  irel[0].r_info = ELF_R_INFO (indx, howto->type);
+  if (bed->s->arch_size == 32)
+    irel[0].r_info = ELF32_R_INFO (indx, howto->type);
+  else
+    irel[0].r_info = ELF64_R_INFO (indx, howto->type);
 
   rel_hdr = &elf_section_data (output_section)->rel_hdr;
   erel = rel_hdr->contents;
   if (rel_hdr->sh_type == SHT_REL)
     {
       erel += (elf_section_data (output_section)->rel_count
-              * sizeof (Elf_External_Rel));
+              * bed->s->sizeof_rel);
       (*bed->s->swap_reloc_out) (output_bfd, irel, erel);
     }
   else
     {
       irel[0].r_addend = addend;
       erel += (elf_section_data (output_section)->rel_count
-              * sizeof (Elf_External_Rela));
+              * bed->s->sizeof_rela);
       (*bed->s->swap_reloca_out) (output_bfd, irel, erel);
     }
 
@@ -5250,6 +2777,7 @@ elf_gc_mark (struct bfd_link_info *info,
       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);
@@ -5257,7 +2785,7 @@ elf_gc_mark (struct bfd_link_info *info,
       /* Read the local symbols.  */
       if (elf_bad_symtab (input_bfd))
        {
-         nlocsyms = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+         nlocsyms = symtab_hdr->sh_size / bed->s->sizeof_sym;
          extsymoff = 0;
        }
       else
@@ -5282,13 +2810,18 @@ elf_gc_mark (struct bfd_link_info *info,
        }
       relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
+      if (bed->s->arch_size == 32)
+       r_sym_shift = 8;
+      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 = ELF_R_SYM (rel->r_info);
+         r_symndx = rel->r_info >> r_sym_shift;
          if (r_symndx == 0)
            continue;
 
@@ -5606,11 +3139,12 @@ elf_gc_record_vtinherit (bfd *abfd,
   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
   struct elf_link_hash_entry **search, *child;
   bfd_size_type extsymcount;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   /* The sh_info field of the symtab header tells us where the
      external symbols start.  We don't care about the local symbols at
      this point.  */
-  extsymcount = elf_tdata (abfd)->symtab_hdr.sh_size/sizeof (Elf_External_Sym);
+  extsymcount = elf_tdata (abfd)->symtab_hdr.sh_size / bed->s->sizeof_sym;
   if (!elf_bad_symtab (abfd))
     extsymcount -= elf_tdata (abfd)->symtab_hdr.sh_info;
 
@@ -5717,6 +3251,11 @@ elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+struct alloc_got_off_arg {
+  bfd_vma gotoff;
+  unsigned int got_elt_size;
+};
+
 /* And an accompanying bit to work out final got entry offsets once
    we're done.  Should be called from final_link.  */
 
@@ -5727,6 +3266,8 @@ elf_gc_common_finalize_got_offsets (bfd *abfd,
   bfd *i;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   bfd_vma gotoff;
+  unsigned int got_elt_size = bed->s->arch_size / 8;
+  struct alloc_got_off_arg gofarg;
 
   if (! is_elf_hash_table (info->hash))
     return FALSE;
@@ -5754,7 +3295,7 @@ elf_gc_common_finalize_got_offsets (bfd *abfd,
 
       symtab_hdr = &elf_tdata (i)->symtab_hdr;
       if (elf_bad_symtab (i))
-       locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+       locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
       else
        locsymcount = symtab_hdr->sh_info;
 
@@ -5763,7 +3304,7 @@ elf_gc_common_finalize_got_offsets (bfd *abfd,
          if (local_got[j] > 0)
            {
              local_got[j] = gotoff;
-             gotoff += ARCH_SIZE / 8;
+             gotoff += got_elt_size;
            }
          else
            local_got[j] = (bfd_vma) -1;
@@ -5772,9 +3313,11 @@ elf_gc_common_finalize_got_offsets (bfd *abfd,
 
   /* Then the global .got entries.  .plt refcounts are handled by
      adjust_dynamic_symbol  */
+  gofarg.gotoff = gotoff;
+  gofarg.got_elt_size = got_elt_size;
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_gc_allocate_got_offsets,
-                         &gotoff);
+                         &gofarg);
   return TRUE;
 }
 
@@ -5782,17 +3325,17 @@ elf_gc_common_finalize_got_offsets (bfd *abfd,
    to real got offsets.  */
 
 static bfd_boolean
-elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *offarg)
+elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
 {
-  bfd_vma *off = offarg;
+  struct alloc_got_off_arg *gofarg = arg;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
   if (h->got.refcount > 0)
     {
-      h->got.offset = off[0];
-      off[0] += ARCH_SIZE / 8;
+      h->got.offset = gofarg->gotoff;
+      gofarg->gotoff += gofarg->got_elt_size;
     }
   else
     h->got.offset = (bfd_vma) -1;
@@ -5813,51 +3356,6 @@ elf_gc_common_final_link (bfd *abfd, struct bfd_link_info *info)
   return elf_bfd_final_link (abfd, info);
 }
 
-/* This function will be called though elf_link_hash_traverse to store
-   all hash value of the exported symbols in an array.  */
-
-static bfd_boolean
-elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data)
-{
-  unsigned long **valuep = data;
-  const char *name;
-  char *p;
-  unsigned long ha;
-  char *alc = NULL;
-
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  /* Ignore indirect symbols.  These are added by the versioning code.  */
-  if (h->dynindx == -1)
-    return TRUE;
-
-  name = h->root.root.string;
-  p = strchr (name, ELF_VER_CHR);
-  if (p != NULL)
-    {
-      alc = bfd_malloc (p - name + 1);
-      memcpy (alc, name, p - name);
-      alc[p - name] = '\0';
-      name = alc;
-    }
-
-  /* Compute the hash value.  */
-  ha = bfd_elf_hash (name);
-
-  /* Store the found hash value in the array given as the argument.  */
-  *(*valuep)++ = ha;
-
-  /* And store it in the struct so that we can put it in the hash table
-     later.  */
-  h->elf_hash_value = ha;
-
-  if (alc != NULL)
-    free (alc);
-
-  return TRUE;
-}
-
 bfd_boolean
 elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
 {
@@ -5876,7 +3374,7 @@ elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
       if (rcookie->rel->r_offset != offset)
        continue;
 
-      r_symndx = ELF_R_SYM (rcookie->rel->r_info);
+      r_symndx = rcookie->rel->r_info >> rcookie->r_sym_shift;
       if (r_symndx == SHN_UNDEF)
        return TRUE;
 
@@ -5910,7 +3408,7 @@ elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie)
          isym = &rcookie->locsyms[r_symndx];
          if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
            {
-             isec = section_from_elf_index (rcookie->abfd, isym->st_shndx);
+             isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx);
              if (isec != NULL && elf_discarded_section (isec))
                return TRUE;
            }
@@ -5975,7 +3473,7 @@ elf_bfd_discard_info (bfd *output_bfd, struct bfd_link_info *info)
       cookie.bad_symtab = elf_bad_symtab (abfd);
       if (cookie.bad_symtab)
        {
-         cookie.locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+         cookie.locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym;
          cookie.extsymoff = 0;
        }
       else
@@ -5984,6 +3482,11 @@ elf_bfd_discard_info (bfd *output_bfd, struct bfd_link_info *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)
        {
This page took 0.061603 seconds and 4 git commands to generate.