* elf32-arm.h (elf32_arm_final_link_relocate): Don't copy STN_UNDEF
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 43a44dace023876139ca6a7702bd98c0f6b1ebbf..a4fb88d5be5a2e692a8d9d436a15a14e07a555fe 100644 (file)
@@ -1,5 +1,6 @@
 /* ELF linker support.
-   Copyright 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -26,8 +27,13 @@ struct elf_info_failed
 {
   boolean failed;
   struct bfd_link_info *info;
+  struct bfd_elf_version_tree *verdefs;
 };
 
+static boolean is_global_data_symbol_definition
+  PARAMS ((bfd *, Elf_Internal_Sym *));
+static boolean elf_link_is_defined_archive_symbol
+  PARAMS ((bfd *, carsym *));
 static boolean elf_link_add_object_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_link_add_archive_symbols
@@ -35,9 +41,11 @@ static boolean elf_link_add_archive_symbols
 static boolean elf_merge_symbol
   PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
           asection **, bfd_vma *, struct elf_link_hash_entry **,
-          boolean *, boolean *, boolean *));
+          boolean *, boolean *, boolean *, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_finalize_dynstr
+  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_fix_symbol_flags
   PARAMS ((struct elf_link_hash_entry *, struct elf_info_failed *));
 static boolean elf_adjust_dynamic_symbol
@@ -50,15 +58,23 @@ static boolean elf_link_assign_sym_version
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_collect_hash_codes
   PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean elf_link_read_relocs_from_section 
+static boolean elf_link_read_relocs_from_section
   PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
+static size_t compute_bucket_count
+  PARAMS ((struct bfd_link_info *));
 static void elf_link_output_relocs
   PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
 static boolean elf_link_size_reloc_section
   PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
-static void elf_link_adjust_relocs 
-  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, 
+static void elf_link_adjust_relocs
+  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
           struct elf_link_hash_entry **));
+static int elf_link_sort_cmp1
+  PARAMS ((const void *, const void *));
+static int elf_link_sort_cmp2
+  PARAMS ((const void *, const void *));
+static size_t elf_link_sort_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -80,7 +96,141 @@ elf_bfd_link_add_symbols (abfd, info)
     }
 }
 \f
+/* Return true iff this is a non-common, definition of a non-function symbol.  */
+static boolean
+is_global_data_symbol_definition (abfd, sym)
+     bfd * abfd ATTRIBUTE_UNUSED;
+     Elf_Internal_Sym * sym;
+{
+  /* Local symbols do not count, but target specific ones might.  */
+  if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+      && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+    return false;
+
+  /* Function symbols do not count.  */
+  if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+    return false;
+
+  /* If the section is undefined, then so is the symbol.  */
+  if (sym->st_shndx == SHN_UNDEF)
+    return false;
+
+  /* If the symbol is defined in the common section, then
+     it is a common definition and so does not count.  */
+  if (sym->st_shndx == SHN_COMMON)
+    return false;
+
+  /* If the symbol is in a target specific section then we
+     must rely upon the backend to tell us what it is.  */
+  if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS)
+    /* FIXME - this function is not coded yet:
+
+       return _bfd_is_global_symbol_definition (abfd, sym);
+
+       Instead for now assume that the definition is not global,
+       Even if this is wrong, at least the linker will behave
+       in the same way that it used to do.  */
+    return false;
+
+  return true;
+}
+
+/* Search the symbol table of the archive element of the archive ABFD
+   whose archive map contains a mention of SYMDEF, and determine if
+   the symbol is defined in this element.  */
+static boolean
+elf_link_is_defined_archive_symbol (abfd, symdef)
+     bfd * abfd;
+     carsym * symdef;
+{
+  Elf_Internal_Shdr * hdr;
+  Elf_External_Sym *  esym;
+  Elf_External_Sym *  esymend;
+  Elf_External_Sym *  buf = NULL;
+  bfd_size_type symcount;
+  bfd_size_type extsymcount;
+  bfd_size_type extsymoff;
+  boolean result = false;
+  file_ptr pos;
+  bfd_size_type amt;
+
+  abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+  if (abfd == (bfd *) NULL)
+    return false;
+
+  if (! bfd_check_format (abfd, bfd_object))
+    return false;
+
+  /* If we have already included the element containing this symbol in the
+     link then we do not need to include it again.  Just claim that any symbol
+     it contains is not a definition, so that our caller will not decide to
+     (re)include this element.  */
+  if (abfd->archive_pass)
+    return false;
+
+  /* Select the appropriate symbol table.  */
+  if ((abfd->flags & DYNAMIC) == 0 || 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.  */
+  if (elf_bad_symtab (abfd))
+    {
+      extsymcount = symcount;
+      extsymoff = 0;
+    }
+  else
+    {
+      extsymcount = symcount - hdr->sh_info;
+      extsymoff = hdr->sh_info;
+    }
+
+  amt = extsymcount * sizeof (Elf_External_Sym);
+  buf = (Elf_External_Sym *) bfd_malloc (amt);
+  if (buf == NULL && extsymcount != 0)
+    return false;
+
+  /* Read in the symbol table.
+     FIXME:  This ought to be cached somewhere.  */
+  pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread ((PTR) buf, amt, abfd) != amt)
+    {
+      free (buf);
+      return false;
+    }
+
+  /* Scan the symbol table looking for SYMDEF.  */
+  esymend = buf + extsymcount;
+  for (esym = buf;
+       esym < esymend;
+       esym++)
+    {
+      Elf_Internal_Sym sym;
+      const char * name;
+
+      elf_swap_symbol_in (abfd, esym, & sym);
+
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+      if (name == (const char *) NULL)
+       break;
 
+      if (strcmp (name, symdef->name) == 0)
+       {
+         result = is_global_data_symbol_definition (abfd, & sym);
+         break;
+       }
+    }
+
+  free (buf);
+
+  return result;
+}
+\f
 /* Add symbols from an ELF archive file to the linker hash table.  We
    don't use _bfd_generic_link_add_archive_symbols because of a
    problem which arises on UnixWare.  The UnixWare libc.so is an
@@ -116,6 +266,7 @@ elf_link_add_archive_symbols (abfd, info)
   boolean *included = NULL;
   carsym *symdefs;
   boolean loop;
+  bfd_size_type amt;
 
   if (! bfd_has_map (abfd))
     {
@@ -132,12 +283,14 @@ elf_link_add_archive_symbols (abfd, info)
   c = bfd_ardata (abfd)->symdef_count;
   if (c == 0)
     return true;
-  defined = (boolean *) bfd_malloc (c * sizeof (boolean));
-  included = (boolean *) bfd_malloc (c * sizeof (boolean));
+  amt = c;
+  amt *= sizeof (boolean);
+  defined = (boolean *) bfd_malloc (amt);
+  included = (boolean *) bfd_malloc (amt);
   if (defined == (boolean *) NULL || included == (boolean *) NULL)
     goto error_return;
-  memset (defined, 0, c * sizeof (boolean));
-  memset (included, 0, c * sizeof (boolean));
+  memset (defined, 0, (size_t) amt);
+  memset (included, 0, (size_t) amt);
 
   symdefs = bfd_ardata (abfd)->symdefs;
 
@@ -185,10 +338,10 @@ elf_link_add_archive_symbols (abfd, info)
              if (p == NULL || p[1] != ELF_VER_CHR)
                continue;
 
-             copy = bfd_alloc (abfd, p - symdef->name + 1);
+             copy = bfd_alloc (abfd, (bfd_size_type) (p - symdef->name + 1));
              if (copy == NULL)
                goto error_return;
-             memcpy (copy, symdef->name, p - symdef->name);
+             memcpy (copy, symdef->name, (size_t) (p - symdef->name));
              copy[p - symdef->name] = '\0';
 
              h = elf_link_hash_lookup (elf_hash_table (info), copy,
@@ -200,7 +353,24 @@ elf_link_add_archive_symbols (abfd, info)
          if (h == NULL)
            continue;
 
-         if (h->root.type != bfd_link_hash_undefined)
+         if (h->root.type == bfd_link_hash_common)
+           {
+             /* We currently have a common symbol.  The archive map contains
+                a reference to this symbol, so we may want to include it.  We
+                only want to include it however, if this archive element
+                contains a definition of the symbol, not just another common
+                declaration of it.
+
+                Unfortunately some archivers (including GNU ar) will put
+                declarations of common symbols into their archive maps, as
+                well as real definitions, so we cannot just go by the archive
+                map alone.  Instead we must read in the element's symbol
+                table and check that to see what kind of symbol definition
+                this is.  */
+             if (! elf_link_is_defined_archive_symbol (abfd, symdef))
+               continue;
+           }
+         else if (h->root.type != bfd_link_hash_undefined)
            {
              if (h->root.type != bfd_link_hash_undefweak)
                defined[i] = true;
@@ -208,7 +378,6 @@ elf_link_add_archive_symbols (abfd, info)
            }
 
          /* We need to include this archive member.  */
-
          element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
          if (element == (bfd *) NULL)
            goto error_return;
@@ -285,11 +454,12 @@ elf_link_add_archive_symbols (abfd, info)
    TYPE_CHANGE_OK if it is OK for the type to change.  We set
    SIZE_CHANGE_OK if it is OK for the size to change.  By OK to
    change, we mean that we shouldn't warn if the type or size does
-   change.  */
+   change. DT_NEEDED indicates if it comes from a DT_NEEDED entry of
+   a shared object.  */
 
 static boolean
 elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
-                 override, type_change_ok, size_change_ok)
+                 override, type_change_ok, size_change_ok, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
      const char *name;
@@ -300,6 +470,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      boolean *override;
      boolean *type_change_ok;
      boolean *size_change_ok;
+     boolean dt_needed;
 {
   asection *sec;
   struct elf_link_hash_entry *h;
@@ -476,9 +647,11 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
     olddyncommon = false;
 
   /* It's OK to change the type if either the existing symbol or the
-     new symbol is weak.  */
+     new symbol is weak unless it comes from a DT_NEEDED entry of
+     a shared object, in which case, the DT_NEEDED entry may not be
+     required at the run time.  */
 
-  if (h->root.type == bfd_link_hash_defweak
+  if ((! dt_needed && h->root.type == bfd_link_hash_defweak)
       || h->root.type == bfd_link_hash_undefweak
       || bind == STB_WEAK)
     *type_change_ok = true;
@@ -530,7 +703,9 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      object to override a weak symbol in a shared object.
 
      We prefer a non-weak definition in a shared library to a weak
-     definition in the executable.  */
+     definition in the executable unless it comes from a DT_NEEDED
+     entry of a shared object, in which case, the DT_NEEDED entry
+     may not be required at the run time.  */
 
   if (newdyn
       && newdef
@@ -539,6 +714,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
              && (bind == STB_WEAK
                  || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
       && (h->root.type != bfd_link_hash_defweak
+         || dt_needed
          || bind == STB_WEAK))
     {
       *override = true;
@@ -673,8 +849,11 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
 
   /* Handle the special case of a weak definition in a regular object
      followed by a non-weak definition in a shared object.  In this
-     case, we prefer the definition in the shared object.  */
+     case, we prefer the definition in the shared object unless it
+     comes from a DT_NEEDED entry of a shared object, in which case,
+     the DT_NEEDED entry may not be required at the run time.  */
   if (olddef
+      && ! dt_needed
       && h->root.type == bfd_link_hash_defweak
       && newdef
       && newdyn
@@ -683,8 +862,12 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
       /* To make this work we have to frob the flags so that the rest
          of the code does not think we are using the regular
          definition.  */
-      h->elf_link_hash_flags &= ~ ELF_LINK_HASH_DEF_REGULAR;
-      h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+       h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+      else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+       h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+      h->elf_link_hash_flags &= ~ (ELF_LINK_HASH_DEF_REGULAR
+                                  | ELF_LINK_HASH_DEF_DYNAMIC);
 
       /* If H is the target of an indirection, we want the caller to
          use H rather than the indirect symbol.  Otherwise if we are
@@ -724,22 +907,29 @@ elf_link_add_object_symbols (abfd, info)
                                   asection *, const Elf_Internal_Rela *));
   boolean collect;
   Elf_Internal_Shdr *hdr;
-  size_t symcount;
-  size_t extsymcount;
-  size_t extsymoff;
+  bfd_size_type symcount;
+  bfd_size_type extsymcount;
+  bfd_size_type extsymoff;
   Elf_External_Sym *buf = NULL;
   struct elf_link_hash_entry **sym_hash;
   boolean dynamic;
-  bfd_byte *dynver = NULL;
   Elf_External_Versym *extversym = NULL;
   Elf_External_Versym *ever;
   Elf_External_Dyn *dynbuf = NULL;
   struct elf_link_hash_entry *weaks;
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
+  struct elf_backend_data *bed;
+  boolean dt_needed;
+  struct elf_link_hash_table * hash_table;
+  file_ptr pos;
+  bfd_size_type amt;
 
-  add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook;
-  collect = get_elf_backend_data (abfd)->collect;
+  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;
@@ -790,7 +980,7 @@ elf_link_add_object_symbols (abfd, info)
                {
                  struct elf_link_hash_entry *h;
 
-                 h = elf_link_hash_lookup (elf_hash_table (info), name,
+                 h = elf_link_hash_lookup (hash_table, name,
                                            false, false, true);
 
                  /* FIXME: What about bfd_link_hash_common?  */
@@ -855,12 +1045,12 @@ elf_link_add_object_symbols (abfd, info)
          Elf_Internal_Shdr *versymhdr;
 
          versymhdr = &elf_tdata (abfd)->dynversym_hdr;
-         extversym = (Elf_External_Versym *) bfd_malloc (hdr->sh_size);
+         extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
          if (extversym == NULL)
            goto error_return;
+         amt = versymhdr->sh_size;
          if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
-             || (bfd_read ((PTR) extversym, 1, versymhdr->sh_size, abfd)
-                 != versymhdr->sh_size))
+             || bfd_bread ((PTR) extversym, amt, abfd) != amt)
            goto error_return;
        }
     }
@@ -881,20 +1071,21 @@ elf_link_add_object_symbols (abfd, info)
       extsymoff = hdr->sh_info;
     }
 
-  buf = ((Elf_External_Sym *)
-        bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+  amt = extsymcount * sizeof (Elf_External_Sym);
+  buf = (Elf_External_Sym *) bfd_malloc (amt);
   if (buf == NULL && extsymcount != 0)
     goto error_return;
 
   /* We store a pointer to the hash table entry for each external
      symbol.  */
-  sym_hash = ((struct elf_link_hash_entry **)
-             bfd_alloc (abfd,
-                        extsymcount * sizeof (struct elf_link_hash_entry *)));
+  amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+  sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt);
   if (sym_hash == NULL)
     goto error_return;
   elf_sym_hashes (abfd) = sym_hash;
 
+  dt_needed = false;
+
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -903,13 +1094,16 @@ elf_link_add_object_symbols (abfd, info)
          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
-         && ! elf_hash_table (info)->dynamic_sections_created
+         && is_elf_hash_table (info)
+         && ! hash_table->dynamic_sections_created
          && abfd->xvec == info->hash->creator)
        {
          if (! elf_link_create_dynamic_sections (abfd, info))
            goto error_return;
        }
     }
+  else if (! is_elf_hash_table (info))
+    goto error_return;
   else
     {
       asection *s;
@@ -931,7 +1125,12 @@ elf_link_add_object_symbols (abfd, info)
        {
          name = elf_dt_name (abfd);
          if (*name == '\0')
-           add_needed = false;
+           {
+             if (elf_dt_soname (abfd) != NULL)
+               dt_needed = true;
+
+             add_needed = false;
+           }
        }
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
@@ -939,9 +1138,11 @@ elf_link_add_object_symbols (abfd, info)
          Elf_External_Dyn *extdyn;
          Elf_External_Dyn *extdynend;
          int elfsec;
-         unsigned long link;
+         unsigned long shlink;
+         int rpath;
+         int runpath;
 
-         dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size);
+         dynbuf = (Elf_External_Dyn *) bfd_malloc (s->_raw_size);
          if (dynbuf == NULL)
            goto error_return;
 
@@ -952,27 +1153,29 @@ elf_link_add_object_symbols (abfd, info)
          elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
          if (elfsec == -1)
            goto error_return;
-         link = elf_elfsections (abfd)[elfsec]->sh_link;
+         shlink = elf_elfsections (abfd)[elfsec]->sh_link;
 
          {
            /* The shared libraries distributed with hpux11 have a bogus
               sh_link field for the ".dynamic" section.  This code detects
-              when LINK refers to a section that is not a string table and
-              tries to find the string table for the ".dynsym" section
+              when SHLINK refers to a section that is not a string table
+              and tries to find the string table for the ".dynsym" section
               instead.  */
-           Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[link];
-           if (hdr->sh_type != SHT_STRTAB)
+           Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[shlink];
+           if (shdr->sh_type != SHT_STRTAB)
              {
-               asection *s = bfd_get_section_by_name (abfd, ".dynsym");
-               int elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
-               if (elfsec == -1)
+               asection *ds = bfd_get_section_by_name (abfd, ".dynsym");
+               int elfdsec = _bfd_elf_section_from_bfd_section (abfd, ds);
+               if (elfdsec == -1)
                  goto error_return;
-               link = elf_elfsections (abfd)[elfsec]->sh_link;
+               shlink = elf_elfsections (abfd)[elfdsec]->sh_link;
              }
          }
 
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+         rpath = 0;
+         runpath = 0;
          for (; extdyn < extdynend; extdyn++)
            {
              Elf_Internal_Dyn dyn;
@@ -980,8 +1183,8 @@ elf_link_add_object_symbols (abfd, info)
              elf_swap_dyn_in (abfd, extdyn, &dyn);
              if (dyn.d_tag == DT_SONAME)
                {
-                 name = bfd_elf_string_from_elf_section (abfd, link,
-                                                         dyn.d_un.d_val);
+                 unsigned int tagv = dyn.d_un.d_val;
+                 name = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (name == NULL)
                    goto error_return;
                }
@@ -989,25 +1192,84 @@ elf_link_add_object_symbols (abfd, info)
                {
                  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 = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
+                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+                 if (n == NULL || fnm == NULL)
+                   goto error_return;
+                 anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+                 if (anm == NULL)
+                   goto error_return;
+                 strcpy (anm, fnm);
+                 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;
+
+                 /* When we see DT_RPATH before DT_RUNPATH, we have
+                    to clear runpath.  Do _NOT_ bfd_release, as that
+                    frees all more recently bfd_alloc'd blocks as
+                    well.  */
+                 if (rpath && hash_table->runpath)
+                   hash_table->runpath = NULL;
+
+                 amt = sizeof (struct bfd_link_needed_list);
+                 n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
+                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
+                 if (n == NULL || fnm == NULL)
+                   goto error_return;
+                 anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
+                 if (anm == NULL)
+                   goto error_return;
+                 strcpy (anm, fnm);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = & hash_table->runpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+                 runpath = 1;
+                 rpath = 0;
+               }
+             /* 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;
 
-                 n = ((struct bfd_link_needed_list *)
-                      bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
-                 fnm = bfd_elf_string_from_elf_section (abfd, link,
-                                                        dyn.d_un.d_val);
+                 amt = sizeof (struct bfd_link_needed_list);
+                 n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
+                 fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
                  if (n == NULL || fnm == NULL)
                    goto error_return;
-                 anm = bfd_alloc (abfd, strlen (fnm) + 1);
+                 anm = bfd_alloc (abfd, (bfd_size_type) strlen (fnm) + 1);
                  if (anm == NULL)
                    goto error_return;
                  strcpy (anm, fnm);
                  n->name = anm;
                  n->by = abfd;
                  n->next = NULL;
-                 for (pn = &elf_hash_table (info)->needed;
+                 for (pn = & hash_table->runpath;
                       *pn != NULL;
                       pn = &(*pn)->next)
                    ;
                  *pn = n;
+                 rpath = 1;
                }
            }
 
@@ -1027,22 +1289,19 @@ elf_link_add_object_symbols (abfd, info)
 
       /* If this is the first dynamic object found in the link, create
         the special sections required for dynamic linking.  */
-      if (! elf_hash_table (info)->dynamic_sections_created)
-       {
-         if (! elf_link_create_dynamic_sections (abfd, info))
-           goto error_return;
-       }
+      if (! hash_table->dynamic_sections_created)
+       if (! elf_link_create_dynamic_sections (abfd, info))
+         goto error_return;
 
       if (add_needed)
        {
          /* Add a DT_NEEDED entry for this dynamic object.  */
-         oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
-         strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr, name,
-                                        true, false);
+         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_stringtab_size (elf_hash_table (info)->dynstr))
+         if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
            {
              asection *sdyn;
              Elf_External_Dyn *dyncon, *dynconend;
@@ -1052,8 +1311,7 @@ elf_link_add_object_symbols (abfd, info)
                 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 (elf_hash_table (info)->dynobj,
-                                             ".dynamic");
+             sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic");
              BFD_ASSERT (sdyn != NULL);
 
              dyncon = (Elf_External_Dyn *) sdyn->contents;
@@ -1063,8 +1321,7 @@ elf_link_add_object_symbols (abfd, info)
                {
                  Elf_Internal_Dyn dyn;
 
-                 elf_swap_dyn_in (elf_hash_table (info)->dynobj, dyncon,
-                                  &dyn);
+                 elf_swap_dyn_in (hash_table->dynobj, dyncon, & dyn);
                  if (dyn.d_tag == DT_NEEDED
                      && dyn.d_un.d_val == strindex)
                    {
@@ -1072,27 +1329,27 @@ elf_link_add_object_symbols (abfd, info)
                        free (buf);
                      if (extversym != NULL)
                        free (extversym);
+                     _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
                      return true;
                    }
                }
            }
 
-         if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+         if (! elf_add_dynamic_entry (info, (bfd_vma) 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 = bfd_get_filename (abfd);
+       name = basename (bfd_get_filename (abfd));
       elf_dt_name (abfd) = name;
     }
 
-  if (bfd_seek (abfd,
-               hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
-               SEEK_SET) != 0
-      || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
-         != extsymcount * sizeof (Elf_External_Sym)))
+  pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
+  amt = extsymcount * sizeof (Elf_External_Sym);
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread ((PTR) buf, amt, abfd) != amt)
     goto error_return;
 
   weaks = NULL;
@@ -1136,8 +1393,6 @@ elf_link_add_object_symbols (abfd, info)
          if (sym.st_shndx != SHN_UNDEF
              && sym.st_shndx != SHN_COMMON)
            flags = BSF_GLOBAL;
-         else
-           flags = 0;
        }
       else if (bind == STB_WEAK)
        flags = BSF_WEAK;
@@ -1222,7 +1477,8 @@ elf_link_add_object_symbols (abfd, info)
                  || (vernum > 1 && ! bfd_is_abs_section (sec)))
                {
                  const char *verstr;
-                 int namelen, newlen;
+                 unsigned int namelen;
+                 bfd_size_type newlen;
                  char *newname, *p;
 
                  if (sym.st_shndx != SHN_UNDEF)
@@ -1231,7 +1487,7 @@ elf_link_add_object_symbols (abfd, info)
                        {
                          (*_bfd_error_handler)
                            (_("%s: %s: invalid version %u (max %d)"),
-                            bfd_get_filename (abfd), name, vernum,
+                            bfd_archive_filename (abfd), name, vernum,
                             elf_tdata (abfd)->dynverdef_hdr.sh_info);
                          bfd_set_error (bfd_error_bad_value);
                          goto error_return;
@@ -1272,7 +1528,7 @@ elf_link_add_object_symbols (abfd, info)
                        {
                          (*_bfd_error_handler)
                            (_("%s: %s: invalid needed version %d"),
-                            bfd_get_filename (abfd), name, vernum);
+                            bfd_archive_filename (abfd), name, vernum);
                          bfd_set_error (bfd_error_bad_value);
                          goto error_return;
                        }
@@ -1289,7 +1545,11 @@ elf_link_add_object_symbols (abfd, info)
                  strcpy (newname, name);
                  p = newname + namelen;
                  *p++ = ELF_VER_CHR;
-                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+                 /* 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
+                     && sym.st_shndx != SHN_UNDEF)
                    *p++ = ELF_VER_CHR;
                  strcpy (p, verstr);
 
@@ -1299,7 +1559,7 @@ elf_link_add_object_symbols (abfd, info)
 
          if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
                                  sym_hash, &override, &type_change_ok,
-                                 &size_change_ok))
+                                 &size_change_ok, dt_needed))
            goto error_return;
 
          if (override)
@@ -1368,7 +1628,10 @@ elf_link_add_object_symbols (abfd, info)
          unsigned int align;
 
          align = bfd_log2 (sym.st_value);
-         if (align > old_alignment)
+         if (align > old_alignment
+             /* Permit an alignment power of zero if an alignment of one
+                is specified and no other alignments have been specified.  */
+             || (sym.st_value == 1 && old_alignment == 0))
            h->root.u.c.p->alignment_power = align;
        }
 
@@ -1386,7 +1649,7 @@ elf_link_add_object_symbols (abfd, info)
                (*_bfd_error_handler)
                  (_("Warning: size of symbol `%s' changed from %lu to %lu in %s"),
                   name, (unsigned long) h->size, (unsigned long) sym.st_size,
-                  bfd_get_filename (abfd));
+                  bfd_archive_filename (abfd));
 
              h->size = sym.st_size;
            }
@@ -1408,14 +1671,29 @@ elf_link_add_object_symbols (abfd, info)
                (*_bfd_error_handler)
                  (_("Warning: type of symbol `%s' changed from %d to %d in %s"),
                   name, h->type, ELF_ST_TYPE (sym.st_info),
-                  bfd_get_filename (abfd));
+                  bfd_archive_filename (abfd));
 
              h->type = ELF_ST_TYPE (sym.st_info);
            }
 
-         if (sym.st_other != 0
-             && (definition || h->other == 0))
-           h->other = sym.st_other;
+         /* If st_other has a processor-specific meaning, specific code
+            might be needed here.  */
+         if (sym.st_other != 0)
+           {
+             /* Combine visibilities, using the most constraining one.  */
+             unsigned char hvis   = ELF_ST_VISIBILITY (h->other);
+             unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+
+             if (symvis && (hvis > symvis || hvis == 0))
+               h->other = sym.st_other;
+
+             /* If neither has visibility, use the st_other of the
+                definition.  This is an arbitrary choice, since the
+                other bits have no general meaning.  */
+             if (!symvis && !hvis
+                 && (definition || h->other == 0))
+               h->other = sym.st_other;
+           }
 
          /* Set a flag in the hash table entry indicating the type of
             reference or definition we just found.  Keep a count of
@@ -1460,7 +1738,7 @@ elf_link_add_object_symbols (abfd, info)
              name to the fully decorated name.  This will cause
              external references which do not specify a version to be
              bound to this version of the symbol.  */
-         if (definition)
+         if (definition || h->root.type == bfd_link_hash_common)
            {
              char *p;
 
@@ -1472,10 +1750,10 @@ elf_link_add_object_symbols (abfd, info)
                  boolean override;
 
                  shortname = bfd_hash_allocate (&info->hash->table,
-                                                p - name + 1);
+                                                (size_t) (p - name + 1));
                  if (shortname == NULL)
                    goto error_return;
-                 strncpy (shortname, name, p - name);
+                 strncpy (shortname, name, (size_t) (p - name));
                  shortname[p - name] = '\0';
 
                  /* We are going to create a new symbol.  Merge it
@@ -1487,7 +1765,8 @@ elf_link_add_object_symbols (abfd, info)
                  size_change_ok = false;
                  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
                                          &value, &hi, &override,
-                                         &type_change_ok, &size_change_ok))
+                                         &type_change_ok,
+                                         &size_change_ok, dt_needed))
                    goto error_return;
 
                  if (! override)
@@ -1566,44 +1845,7 @@ elf_link_add_object_symbols (abfd, info)
                                  == 0);
 
                      ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-
-                     /* Copy down any references that we may have
-                        already seen to the symbol which just became
-                        indirect.  */
-                     ht->elf_link_hash_flags |=
-                       (hi->elf_link_hash_flags
-                        & (ELF_LINK_HASH_REF_DYNAMIC
-                           | ELF_LINK_HASH_REF_REGULAR
-                           | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
-
-                     /* Copy over the global and procedure linkage table
-                        offset entries.  These may have been already set
-                        up by a check_relocs routine.  */
-                     if (ht->got.offset == (bfd_vma) -1)
-                       {
-                         ht->got.offset = hi->got.offset;
-                         hi->got.offset = (bfd_vma) -1;
-                       }
-                     BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
-                     if (ht->plt.offset == (bfd_vma) -1)
-                       {
-                         ht->plt.offset = hi->plt.offset;
-                         hi->plt.offset = (bfd_vma) -1;
-                       }
-                     BFD_ASSERT (hi->plt.offset == (bfd_vma) -1);
-
-                     if (ht->dynindx == -1)
-                       {
-                         ht->dynindx = hi->dynindx;
-                         ht->dynstr_index = hi->dynstr_index;
-                         hi->dynindx = -1;
-                         hi->dynstr_index = 0;
-                       }
-                     BFD_ASSERT (hi->dynindx == -1);
-
-                     /* FIXME: There may be other information to copy
-                        over for particular targets.  */
+                     (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
 
                      /* See if the new flags lead us to realize that
                         the symbol must be dynamic.  */
@@ -1633,7 +1875,7 @@ elf_link_add_object_symbols (abfd, info)
                                                 strlen (name));
                  if (shortname == NULL)
                    goto error_return;
-                 strncpy (shortname, name, p - name);
+                 strncpy (shortname, name, (size_t) (p - name));
                  strcpy (shortname + (p - name), p + 1);
 
                  /* Once again, merge with any existing symbol.  */
@@ -1641,7 +1883,8 @@ elf_link_add_object_symbols (abfd, info)
                  size_change_ok = false;
                  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
                                          &value, &hi, &override,
-                                         &type_change_ok, &size_change_ok))
+                                         &type_change_ok,
+                                         &size_change_ok, dt_needed))
                    goto error_return;
 
                  if (override)
@@ -1651,7 +1894,7 @@ elf_link_add_object_symbols (abfd, info)
                          do in the case above.  */
                      (*_bfd_error_handler)
                        (_("%s: warning: unexpected redefinition of `%s'"),
-                        bfd_get_filename (abfd), shortname);
+                        bfd_archive_filename (abfd), shortname);
                    }
                  else
                    {
@@ -1676,43 +1919,7 @@ elf_link_add_object_symbols (abfd, info)
                                          | ELF_LINK_HASH_DEF_REGULAR))
                                      == 0);
 
-                         /* Copy down any references that we may have
-                             already seen to the symbol which just
-                             became indirect.  */
-                         h->elf_link_hash_flags |=
-                           (hi->elf_link_hash_flags
-                            & (ELF_LINK_HASH_REF_DYNAMIC
-                               | ELF_LINK_HASH_REF_REGULAR
-                               | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
-
-                         /* Copy over the global and procedure linkage
-                             table offset entries.  These may have been
-                             already set up by a check_relocs routine.  */
-                         if (h->got.offset == (bfd_vma) -1)
-                           {
-                             h->got.offset = hi->got.offset;
-                             hi->got.offset = (bfd_vma) -1;
-                           }
-                         BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
-                         if (h->plt.offset == (bfd_vma) -1)
-                           {
-                             h->plt.offset = hi->plt.offset;
-                             hi->plt.offset = (bfd_vma) -1;
-                           }
-                         BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
-                         if (h->dynindx == -1)
-                           {
-                             h->dynindx = hi->dynindx;
-                             h->dynstr_index = hi->dynstr_index;
-                             hi->dynindx = -1;
-                             hi->dynstr_index = 0;
-                           }
-                         BFD_ASSERT (hi->dynindx == -1);
-
-                         /* FIXME: There may be other information to
-                             copy over for particular targets.  */
+                         (*bed->elf_backend_copy_indirect_symbol) (h, hi);
 
                          /* See if the new flags lead us to realize
                              that the symbol must be dynamic.  */
@@ -1746,11 +1953,72 @@ elf_link_add_object_symbols (abfd, info)
                  && ! new_weakdef
                  && h->weakdef->dynindx == -1)
                {
-                 if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                            h->weakdef))
+                 if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef))
                    goto error_return;
                }
            }
+         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:
+               h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+               (*bed->elf_backend_hide_symbol) (info, h);
+               _bfd_elf_strtab_delref (hash_table->dynstr,
+                                       h->dynstr_index);
+               break;
+             }
+
+         if (dt_needed && definition
+             && (h->elf_link_hash_flags
+                 & ELF_LINK_HASH_REF_REGULAR) != 0)
+           {
+             bfd_size_type oldsize;
+             bfd_size_type strindex;
+
+             if (! is_elf_hash_table (info))
+               goto error_return;
+
+             /* 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_return;
+
+             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, (bfd_vma) DT_NEEDED, strindex))
+               goto error_return;
+           }
        }
     }
 
@@ -1898,6 +2166,7 @@ elf_link_add_object_symbols (abfd, info)
       && ! info->relocateable
       && ! info->traditional_format
       && info->hash->creator->flavour == bfd_target_elf_flavour
+      && is_elf_hash_table (info)
       && (info->strip != strip_all && info->strip != strip_debugger))
     {
       asection *stab, *stabstr;
@@ -1913,7 +2182,7 @@ elf_link_add_object_symbols (abfd, info)
 
              secdata = elf_section_data (stab);
              if (! _bfd_link_section_stabs (abfd,
-                                            &elf_hash_table (info)->stab_info,
+                                            & hash_table->stab_info,
                                             stab, stabstr,
                                             &secdata->stab_info))
                goto error_return;
@@ -1921,6 +2190,18 @@ elf_link_add_object_symbols (abfd, info)
        }
     }
 
+  if (! info->relocateable && ! dynamic
+      && is_elf_hash_table (info))
+    {
+      asection *s;
+
+      for (s = abfd->sections; s != NULL; s = s->next)
+       if ((s->flags & SEC_MERGE)
+           && ! _bfd_merge_section (abfd, & hash_table->merge_info, s,
+                                    & elf_section_data (s)->merge_info))
+         goto error_return;
+    }
+
   return true;
 
  error_return:
@@ -1928,8 +2209,6 @@ elf_link_add_object_symbols (abfd, info)
     free (buf);
   if (dynbuf != NULL)
     free (dynbuf);
-  if (dynver != NULL)
-    free (dynver);
   if (extversym != NULL)
     free (extversym);
   return false;
@@ -1952,6 +2231,9 @@ elf_link_create_dynamic_sections (abfd, info)
   struct elf_link_hash_entry *h;
   struct elf_backend_data *bed;
 
+  if (! is_elf_hash_table (info))
+    return false;
+
   if (elf_hash_table (info)->dynamic_sections_created)
     return true;
 
@@ -2010,7 +2292,7 @@ elf_link_create_dynamic_sections (abfd, info)
   /* Create a strtab to hold the dynamic symbol names.  */
   if (elf_hash_table (info)->dynstr == NULL)
     {
-      elf_hash_table (info)->dynstr = elf_stringtab_init ();
+      elf_hash_table (info)->dynstr = _bfd_elf_strtab_init ();
       if (elf_hash_table (info)->dynstr == NULL)
        return false;
     }
@@ -2073,9 +2355,12 @@ elf_add_dynamic_entry (info, tag, val)
   Elf_Internal_Dyn dyn;
   bfd *dynobj;
   asection *s;
-  size_t newsize;
+  bfd_size_type newsize;
   bfd_byte *newcontents;
 
+  if (! is_elf_hash_table (info))
+    return false;
+
   dynobj = elf_hash_table (info)->dynobj;
 
   s = bfd_get_section_by_name (dynobj, ".dynamic");
@@ -2107,10 +2392,15 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
 {
   struct elf_link_local_dynamic_entry *entry;
   struct elf_link_hash_table *eht;
-  struct bfd_strtab_hash *dynstr;
+  struct elf_strtab_hash *dynstr;
   Elf_External_Sym esym;
   unsigned long dynstr_index;
   char *name;
+  file_ptr pos;
+  bfd_size_type amt;
+
+  if (! is_elf_hash_table (info))
+    return false;
 
   /* See if the entry exists already.  */
   for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
@@ -2118,17 +2408,15 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
       return true;
 
   entry = (struct elf_link_local_dynamic_entry *)
-    bfd_alloc (input_bfd, sizeof (*entry));
+    bfd_alloc (input_bfd, (bfd_size_type) sizeof (*entry));
   if (entry == NULL)
     return false;
 
   /* Go find the symbol, so that we can find it's name.  */
-  if (bfd_seek (input_bfd,
-               (elf_tdata (input_bfd)->symtab_hdr.sh_offset
-                + input_indx * sizeof (Elf_External_Sym)),
-               SEEK_SET) != 0
-      || (bfd_read (&esym, sizeof (Elf_External_Sym), 1, input_bfd)
-         != sizeof (Elf_External_Sym)))
+  amt = sizeof (Elf_External_Sym);
+  pos = elf_tdata (input_bfd)->symtab_hdr.sh_offset + input_indx * amt;
+  if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
+      || bfd_bread (&esym, amt, input_bfd) != amt)
     return false;
   elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
 
@@ -2140,12 +2428,12 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
   if (dynstr == NULL)
     {
       /* Create a strtab to hold the dynamic symbol names.  */
-      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
       if (dynstr == NULL)
        return false;
     }
 
-  dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+  dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
   if (dynstr_index == (unsigned long) -1)
     return false;
   entry->isym.st_name = dynstr_index;
@@ -2167,7 +2455,6 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
   return true;
 }
 \f
-
 /* Read and swap the relocs from the section indicated by SHDR.  This
    may be either a REL or a RELA section.  The relocations are
    translated into RELA relocations and stored in INTERNAL_RELOCS,
@@ -2186,6 +2473,7 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
      Elf_Internal_Rela *internal_relocs;
 {
   struct elf_backend_data *bed;
+  bfd_size_type amt;
 
   /* If there aren't any relocations, that's OK.  */
   if (!shdr)
@@ -2196,8 +2484,7 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
     return false;
 
   /* Read the relocations.  */
-  if (bfd_read (external_relocs, 1, shdr->sh_size, abfd)
-      != shdr->sh_size)
+  if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size)
     return false;
 
   bed = get_elf_backend_data (abfd);
@@ -2211,13 +2498,13 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
       Elf_Internal_Rel *irel;
 
       erel = (Elf_External_Rel *) external_relocs;
-      erelend = erel + shdr->sh_size / shdr->sh_entsize;
+      erelend = erel + NUM_SHDR_ENTRIES (shdr);
       irela = internal_relocs;
-      irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel
-                              * sizeof (Elf_Internal_Rel)));
+      amt = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel);
+      irel = bfd_alloc (abfd, amt);
       for (; erel < erelend; erel++, irela += bed->s->int_rels_per_ext_rel)
        {
-         unsigned char i;
+         unsigned int i;
 
          if (bed->s->swap_reloc_in)
            (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel);
@@ -2241,7 +2528,7 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
       BFD_ASSERT (shdr->sh_entsize == sizeof (Elf_External_Rela));
 
       erela = (Elf_External_Rela *) external_relocs;
-      erelaend = erela + shdr->sh_size / shdr->sh_entsize;
+      erelaend = erela + NUM_SHDR_ENTRIES (shdr);
       irela = internal_relocs;
       for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel)
        {
@@ -2289,10 +2576,10 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
 
   if (internal_relocs == NULL)
     {
-      size_t size;
+      bfd_size_type size;
 
-      size = (o->reloc_count * bed->s->int_rels_per_ext_rel 
-             * sizeof (Elf_Internal_Rela));
+      size = o->reloc_count;
+      size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
       if (keep_memory)
        internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
       else
@@ -2303,10 +2590,10 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
 
   if (external_relocs == NULL)
     {
-      size_t size = (size_t) rel_hdr->sh_size;
+      bfd_size_type size = rel_hdr->sh_size;
 
       if (elf_section_data (o)->rel_hdr2)
-       size += (size_t) elf_section_data (o)->rel_hdr2->sh_size;
+       size += elf_section_data (o)->rel_hdr2->sh_size;
       alloc1 = (PTR) bfd_malloc (size);
       if (alloc1 == NULL)
        goto error_return;
@@ -2317,11 +2604,11 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
                                          external_relocs,
                                          internal_relocs))
     goto error_return;
-  if (!elf_link_read_relocs_from_section 
-      (abfd, 
+  if (!elf_link_read_relocs_from_section
+      (abfd,
        elf_section_data (o)->rel_hdr2,
        ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
-       internal_relocs + (rel_hdr->sh_size / rel_hdr->sh_entsize
+       internal_relocs + (NUM_SHDR_ENTRIES (rel_hdr)
                          * bed->s->int_rels_per_ext_rel)))
     goto error_return;
 
@@ -2345,11 +2632,9 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
   return NULL;
 }
 \f
-
 /* Record an assignment to a symbol made by a linker script.  We need
    this in case some dynamic object refers to this symbol.  */
 
-/*ARGSUSED*/
 boolean
 NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
      bfd *output_bfd ATTRIBUTE_UNUSED;
@@ -2367,7 +2652,7 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
     return false;
 
   if (h->root.type == bfd_link_hash_new)
-    h->elf_link_hash_flags &=ELF_LINK_NON_ELF;
+    h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
 
   /* If this symbol is being provided by the linker script, and it is
      currently defined by a dynamic object, but not by a regular
@@ -2389,7 +2674,7 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
 
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
 
-  /* When possible, keep the original type of the symbol */
+  /* When possible, keep the original type of the symbol */
   if (h->type == STT_NOTYPE)
     h->type = STT_OBJECT;
 
@@ -2426,8 +2711,6 @@ struct elf_assign_sym_version_info
   struct bfd_link_info *info;
   /* Version tree.  */
   struct bfd_elf_version_tree *verdefs;
-  /* Whether we are exporting all dynamic symbols.  */
-  boolean export_dynamic;
   /* Whether we had a failure.  */
   boolean failed;
 };
@@ -2476,12 +2759,14 @@ compute_bucket_count (info)
   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.  */
-  hashcodes = (unsigned long int *) bfd_malloc (dynsymcount
-                                               * sizeof (unsigned long int));
+  amt = dynsymcount;
+  amt *= sizeof (unsigned long int);
+  hashcodes = (unsigned long int *) bfd_malloc (amt);
   if (hashcodes == NULL)
     return 0;
   hashcodesp = hashcodes;
@@ -2512,8 +2797,9 @@ compute_bucket_count (info)
 
       /* Create array where we count the collisions in.  We must use bfd_malloc
         since the size could be large.  */
-      counts = (unsigned long int *) bfd_malloc (maxsize
-                                                * sizeof (unsigned long int));
+      amt = maxsize;
+      amt *= sizeof (unsigned long int);
+      counts = (unsigned long int *) bfd_malloc (amt);
       if (counts == NULL)
        {
          free (hashcodes);
@@ -2609,13 +2895,12 @@ compute_bucket_count (info)
 
 boolean
 NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
-                                    export_dynamic, filter_shlib,
+                                    filter_shlib,
                                     auxiliary_filters, info, sinterpptr,
                                     verdefs)
      bfd *output_bfd;
      const char *soname;
      const char *rpath;
-     boolean export_dynamic;
      const char *filter_shlib;
      const char * const *auxiliary_filters;
      struct bfd_link_info *info;
@@ -2634,6 +2919,13 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   if (info->hash->creator->flavour != bfd_target_elf_flavour)
     return true;
 
+  if (! is_elf_hash_table (info))
+    return false;
+
+  /* Any syms created from now on start with -1 in
+     got.refcount/offset and plt.refcount/offset.  */
+  elf_hash_table (info)->init_refcount = -1;
+
   /* The backend may have to create some sections regardless of whether
      we're dynamic or not.  */
   bed = get_elf_backend_data (output_bfd);
@@ -2648,52 +2940,46 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   if (dynobj == NULL)
     return true;
 
-  /* If we are supposed to export all symbols into the dynamic symbol
-     table (this is not the normal case), then do so.  */
-  if (export_dynamic)
-    {
-      struct elf_info_failed eif;
-
-      eif.failed = false;
-      eif.info = info;
-      elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
-                             (PTR) &eif);
-      if (eif.failed)
-       return false;
-    }
-
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
-      bfd_size_type strsize;
+      asection *dynstr;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || info->shared);
 
       if (soname != NULL)
        {
-         soname_indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                           soname, true, true);
+         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))
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SONAME,
+                                         soname_indx))
            return false;
        }
 
       if (info->symbolic)
        {
-         if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
+         if (! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMBOLIC,
+                                      (bfd_vma) 0))
            return false;
+         info->flags |= DF_SYMBOLIC;
        }
 
       if (rpath != NULL)
        {
          bfd_size_type indx;
 
-         indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
-                                    true, true);
+         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))
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_RPATH, indx)
+             || (info->new_dtags
+                 && ! elf_add_dynamic_entry (info, (bfd_vma) DT_RUNPATH,
+                                             indx)))
            return false;
        }
 
@@ -2701,10 +2987,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          bfd_size_type indx;
 
-         indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                    filter_shlib, true, true);
+         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))
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_FILTER, indx))
            return false;
        }
 
@@ -2716,19 +3002,33 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            {
              bfd_size_type indx;
 
-             indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                        *p, true, true);
+             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))
+                 || ! elf_add_dynamic_entry (info, (bfd_vma) 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), elf_export_symbol,
+                                 (PTR) &eif);
+         if (eif.failed)
+           return false;
+       }
+
       /* Attach all the symbols to their version information.  */
       asvinfo.output_bfd = output_bfd;
       asvinfo.info = info;
       asvinfo.verdefs = verdefs;
-      asvinfo.export_dynamic = export_dynamic;
       asvinfo.failed = false;
 
       elf_link_hash_traverse (elf_hash_table (info),
@@ -2739,8 +3039,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
       /* Find all symbols which were defined in a dynamic object and make
         the backend pick a reasonable value for them.  */
-      eif.failed = false;
-      eif.info = info;
       elf_link_hash_traverse (elf_hash_table (info),
                              elf_adjust_dynamic_symbol,
                              (PTR) &eif);
@@ -2754,7 +3052,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       /* 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), 
+          ? elf_link_hash_lookup (elf_hash_table (info),
                                   info->init_function, false,
                                   false, false)
           : NULL);
@@ -2762,11 +3060,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          && (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))
+         if (! elf_add_dynamic_entry (info, (bfd_vma) DT_INIT, (bfd_vma) 0))
            return false;
        }
       h = (info->fini_function
-          ? elf_link_hash_lookup (elf_hash_table (info), 
+          ? elf_link_hash_lookup (elf_hash_table (info),
                                   info->fini_function, false,
                                   false, false)
           : NULL);
@@ -2774,18 +3072,28 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          && (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))
+         if (! elf_add_dynamic_entry (info, (bfd_vma) DT_FINI, (bfd_vma) 0))
            return false;
        }
 
-      strsize = _bfd_stringtab_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;
+      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, (bfd_vma) DT_HASH, (bfd_vma) 0)
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRTAB, (bfd_vma) 0)
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMTAB, (bfd_vma) 0)
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRSZ, strsize)
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMENT,
+                                         (bfd_vma) sizeof (Elf_External_Sym)))
+           return false;
+       }
     }
 
   /* The backend must work out the sizes of all the other dynamic
@@ -2796,11 +3104,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      size_t dynsymcount;
+      bfd_size_type dynsymcount;
       asection *s;
       size_t bucketcount = 0;
-      Elf_Internal_Sym isym;
       size_t hash_entry_size;
+      unsigned int dtagcount;
 
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -2811,7 +3119,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       verdefs = asvinfo.verdefs;
 
       if (verdefs == NULL)
-       _bfd_strip_section_from_output (s);
+       _bfd_strip_section_from_output (info, s);
       else
        {
          unsigned int cdefs;
@@ -2860,6 +3168,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
          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;
            }
@@ -2868,10 +3178,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              const char *name;
              bfd_size_type indx;
 
-             name = output_bfd->filename;
+             name = basename (output_bfd->filename);
              def.vd_hash = bfd_elf_hash (name);
-             indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                           name, true, false);
+             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                         name, false);
              if (indx == (bfd_size_type) -1)
                return false;
              defaux.vda_name = indx;
@@ -2879,7 +3189,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          defaux.vda_next = 0;
 
          _bfd_elf_swap_verdef_out (output_bfd, &def,
-                                   (Elf_External_Verdef *)p);
+                                   (Elf_External_Verdef *) p);
          p += sizeof (Elf_External_Verdef);
          _bfd_elf_swap_verdaux_out (output_bfd, &defaux,
                                     (Elf_External_Verdaux *) p);
@@ -2930,6 +3240,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              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
@@ -2949,7 +3261,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                      defaux.vda_name = 0;
                    }
                  else
-                   defaux.vda_name = n->version_needed->name_indx;
+                   {
+                     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
@@ -2961,13 +3277,31 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                }
            }
 
-         if (! elf_add_dynamic_entry (info, DT_VERDEF, 0)
-             || ! elf_add_dynamic_entry (info, DT_VERDEFNUM, cdefs))
+         if (! elf_add_dynamic_entry (info, (bfd_vma) DT_VERDEF, (bfd_vma) 0)
+             || ! elf_add_dynamic_entry (info, (bfd_vma) DT_VERDEFNUM,
+                                         (bfd_vma) cdefs))
            return false;
 
          elf_tdata (output_bfd)->cverdefs = cdefs;
        }
 
+      if (info->new_dtags && info->flags)
+       {
+         if (! elf_add_dynamic_entry (info, (bfd_vma) DT_FLAGS, info->flags))
+           return false;
+       }
+
+      if (info->flags_1)
+       {
+         if (! info->shared)
+           info->flags_1 &= ~ (DF_1_INITFIRST
+                               | DF_1_NODELETE
+                               | DF_1_NOOPEN);
+         if (! elf_add_dynamic_entry (info, (bfd_vma) 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");
@@ -2987,7 +3321,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                                (PTR) &sinfo);
 
        if (elf_tdata (output_bfd)->verref == NULL)
-         _bfd_strip_section_from_output (s);
+         _bfd_strip_section_from_output (info, s);
        else
          {
            Elf_Internal_Verneed *t;
@@ -3011,7 +3345,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              }
 
            s->_raw_size = size;
-           s->contents = (bfd_byte *) bfd_alloc (output_bfd, size);
+           s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
            if (s->contents == NULL)
              return false;
 
@@ -3030,13 +3364,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
                t->vn_version = VER_NEED_CURRENT;
                t->vn_cnt = caux;
-               if (elf_dt_name (t->vn_bfd) != NULL)
-                 indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                            elf_dt_name (t->vn_bfd),
-                                            true, false);
-               else
-                 indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                            t->vn_bfd->filename, true, false);
+               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;
@@ -3054,8 +3386,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
                  {
                    a->vna_hash = bfd_elf_hash (a->vna_nodename);
-                   indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                              a->vna_nodename, true, false);
+                   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;
@@ -3070,15 +3402,17 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                  }
              }
 
-           if (! elf_add_dynamic_entry (info, DT_VERNEED, 0)
-               || ! elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs))
+           if (! elf_add_dynamic_entry (info, (bfd_vma) DT_VERNEED,
+                                        (bfd_vma) 0)
+               || ! elf_add_dynamic_entry (info, (bfd_vma) DT_VERNEEDNUM,
+                                           (bfd_vma) crefs))
              return false;
 
            elf_tdata (output_bfd)->cverrefs = crefs;
          }
       }
 
-      /* Assign dynsym indicies.  In a shared library we generate a 
+      /* 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.  */
@@ -3091,7 +3425,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (dynsymcount == 0
          || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
        {
-         _bfd_strip_section_from_output (s);
+         _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);
@@ -3103,7 +3437,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          if (s->contents == NULL)
            return false;
 
-         if (! elf_add_dynamic_entry (info, DT_VERSYM, 0))
+         if (! elf_add_dynamic_entry (info, (bfd_vma) DT_VERSYM, (bfd_vma) 0))
            return false;
        }
 
@@ -3120,15 +3454,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (s->contents == NULL && s->_raw_size != 0)
        return false;
 
-      /* 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,
-                          (PTR) (Elf_External_Sym *) s->contents);
+      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,
+                              (PTR) (Elf_External_Sym *) s->contents);
+       }
 
       /* Compute the size of the hashing table.  As a side effect this
         computes the hash values for all the names we export.  */
@@ -3143,44 +3482,196 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        return false;
       memset (s->contents, 0, (size_t) s->_raw_size);
 
-      bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
-      bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, 
+      bfd_put (8 * hash_entry_size, output_bfd, (bfd_vma) bucketcount,
+              s->contents);
+      bfd_put (8 * hash_entry_size, output_bfd, (bfd_vma) dynsymcount,
               s->contents + hash_entry_size);
 
       elf_hash_table (info)->bucketcount = bucketcount;
 
       s = bfd_get_section_by_name (dynobj, ".dynstr");
       BFD_ASSERT (s != NULL);
-      s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
 
-      if (! elf_add_dynamic_entry (info, DT_NULL, 0))
-       return false;
+      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, (bfd_vma) DT_NULL, (bfd_vma) 0))
+         return false;
     }
 
   return true;
 }
 \f
-/* Fix up the flags for a symbol.  This handles various cases which
-   can only be fixed after all the input files are seen.  This is
-   currently called by both adjust_dynamic_symbol and
-   assign_sym_version, which is unnecessary but perhaps more robust in
-   the face of future changes.  */
-
+/* This function is used to adjust offsets into .dynstr for
+   dynamic symbols.  This is called via elf_link_hash_traverse.  */
+      
+static boolean elf_adjust_dynstr_offsets
+PARAMS ((struct elf_link_hash_entry *, PTR));
+        
 static boolean
-elf_fix_symbol_flags (h, eif)
+elf_adjust_dynstr_offsets (h, data)
      struct elf_link_hash_entry *h;
-     struct elf_info_failed *eif;
+     PTR data;
 {
-  /* If this symbol was mentioned in a non-ELF file, try to set
-     DEF_REGULAR and REF_REGULAR correctly.  This is the only way to
-     permit a non-ELF file to correctly refer to a symbol defined in
-     an ELF dynamic object.  */
-  if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
+  struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
+
+  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 boolean
+elf_finalize_dynstr (output_bfd, info)
+     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++)
     {
-      if (h->root.type != bfd_link_hash_defined
-         && h->root.type != bfd_link_hash_defweak)
-       h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
-                                  | ELF_LINK_HASH_REF_REGULAR_NONWEAK);
+      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);
+    }
+
+  return true;
+}
+
+/* Fix up the flags for a symbol.  This handles various cases which
+   can only be fixed after all the input files are seen.  This is
+   currently called by both adjust_dynamic_symbol and
+   assign_sym_version, which is unnecessary but perhaps more robust in
+   the face of future changes.  */
+
+static boolean
+elf_fix_symbol_flags (h, eif)
+     struct elf_link_hash_entry *h;
+     struct elf_info_failed *eif;
+{
+  /* If this symbol was mentioned in a non-ELF file, try to set
+     DEF_REGULAR and REF_REGULAR correctly.  This is the only way to
+     permit a non-ELF file to correctly refer to a symbol defined in
+     an ELF dynamic object.  */
+  if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
+    {
+      while (h->root.type == bfd_link_hash_indirect)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+      if (h->root.type != bfd_link_hash_defined
+         && h->root.type != bfd_link_hash_defweak)
+       h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
+                                  | ELF_LINK_HASH_REF_REGULAR_NONWEAK);
       else
        {
          if (h->root.u.def.section->owner != NULL
@@ -3238,14 +3729,58 @@ elf_fix_symbol_flags (h, eif)
   /* If -Bsymbolic was used (which means to bind references to global
      symbols to the definition within the shared object), and this
      symbol was defined in a regular object, then it actually doesn't
-     need a PLT entry.  */
+     need a PLT entry, and we can accomplish that by forcing it local.
+     Likewise, if the symbol has hidden or internal visibility.
+     FIXME: It might be that we also do not need a PLT for other
+     non-hidden visibilities, but we would have to tell that to the
+     backend specifically; we can't just clear PLT-related data here.  */
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
       && eif->info->shared
-      && eif->info->symbolic
+      && is_elf_hash_table (eif->info)
+      && (eif->info->symbolic
+         || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+         || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
     {
-      h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
-      h->plt.offset = (bfd_vma) -1;
+      struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
+      if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+         || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
+       {
+         h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+         _bfd_elf_strtab_delref (elf_hash_table (eif->info)->dynstr,
+                                 h->dynstr_index);
+       }
+      (*bed->elf_backend_hide_symbol) (eif->info, h);
+    }
+
+  /* If this is a weak defined symbol in a dynamic object, and we know
+     the real definition in the dynamic object, copy interesting flags
+     over to the real definition.  */
+  if (h->weakdef != NULL)
+    {
+      struct elf_link_hash_entry *weakdef;
+
+      BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak);
+      weakdef = h->weakdef;
+      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
+                 || weakdef->root.type == bfd_link_hash_defweak);
+      BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
+
+      /* If the real definition is defined by a regular object file,
+        don't do anything special.  See the longer description in
+        elf_adjust_dynamic_symbol, below.  */
+      if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+       h->weakdef = NULL;
+      else
+       {
+         struct elf_backend_data *bed;
+
+         bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
+         (*bed->elf_backend_copy_indirect_symbol) (weakdef, h);
+       }
     }
 
   return true;
@@ -3268,6 +3803,9 @@ elf_adjust_dynamic_symbol (h, data)
   if (h->root.type == bfd_link_hash_indirect)
     return true;
 
+  if (! is_elf_hash_table (eif->info))
+    return false;
+
   /* Fix the symbol flags.  */
   if (! elf_fix_symbol_flags (h, eif))
     return false;
@@ -3330,33 +3868,14 @@ elf_adjust_dynamic_symbol (h, data)
 
   if (h->weakdef != NULL)
     {
-      struct elf_link_hash_entry *weakdef;
+      /* If we get to this point, we know there is an implicit
+        reference by a regular object file via the weak symbol H.
+        FIXME: Is this really true?  What if the traversal finds
+        H->WEAKDEF before it finds H?  */
+      h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
 
-      BFD_ASSERT (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak);
-      weakdef = h->weakdef;
-      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
-                 || weakdef->root.type == bfd_link_hash_defweak);
-      BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
-      if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
-       {
-         /* This symbol is defined by a regular object file, so we
-            will not do anything special.  Clear weakdef for the
-            convenience of the processor backend.  */
-         h->weakdef = NULL;
-       }
-      else
-       {
-         /* There is an implicit reference by a regular object file
-            via the weak symbol.  */
-         weakdef->elf_link_hash_flags |=
-           (ELF_LINK_HASH_REF_REGULAR
-            | (h->elf_link_hash_flags
-               & (ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                  | ELF_LINK_NON_GOT_REF)));
-         if (! elf_adjust_dynamic_symbol (weakdef, (PTR) eif))
-           return false;
-       }
+      if (! elf_adjust_dynamic_symbol (h->weakdef, (PTR) eif))
+       return false;
     }
 
   /* If a symbol has no type and no size and does not require a PLT
@@ -3400,11 +3919,39 @@ elf_export_symbol (h, data)
       && (h->elf_link_hash_flags
          & (ELF_LINK_HASH_DEF_REGULAR | ELF_LINK_HASH_REF_REGULAR)) != 0)
     {
-      if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h))
+      struct bfd_elf_version_tree *t;
+      struct bfd_elf_version_expr *d;
+
+      for (t = eif->verdefs; t != NULL; t = t->next)
        {
-         eif->failed = true;
-         return false;
+         if (t->globals != NULL)
+           {
+             for (d = t->globals; d != NULL; d = d->next)
+               {
+                 if ((*d->match) (d, h->root.root.string))
+                   goto doit;
+               }
+           }
+
+         if (t->locals != NULL)
+           {
+             for (d = t->locals ; d != NULL; d = d->next)
+               {
+                 if ((*d->match) (d, h->root.root.string))
+                   return true;
+               }
+           }
        }
+
+      if (!eif->verdefs)
+        {
+doit:
+         if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h))
+           {
+             eif->failed = true;
+             return false;
+           }
+        }
     }
 
   return true;
@@ -3423,6 +3970,7 @@ elf_link_find_version_dependencies (h, data)
   struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data;
   Elf_Internal_Verneed *t;
   Elf_Internal_Vernaux *a;
+  bfd_size_type amt;
 
   /* We only care about symbols defined in shared objects with version
      information.  */
@@ -3449,7 +3997,8 @@ elf_link_find_version_dependencies (h, data)
 
   if (t == NULL)
     {
-      t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->output_bfd, sizeof *t);
+      amt = sizeof *t;
+      t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->output_bfd, amt);
       if (t == NULL)
        {
          rinfo->failed = true;
@@ -3461,7 +4010,8 @@ elf_link_find_version_dependencies (h, data)
       elf_tdata (rinfo->output_bfd)->verref = t;
     }
 
-  a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->output_bfd, sizeof *a);
+  amt = sizeof *a;
+  a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->output_bfd, amt);
 
   /* Note that we are copying a string pointer here, and testing it
      above.  If bfd_elf_string_from_elf_section is ever changed to
@@ -3492,11 +4042,15 @@ elf_link_assign_sym_version (h, data)
      struct elf_link_hash_entry *h;
      PTR data;
 {
-  struct elf_assign_sym_version_info *sinfo =
-    (struct elf_assign_sym_version_info *) data;
-  struct bfd_link_info *info = sinfo->info;
+  struct elf_assign_sym_version_info *sinfo;
+  struct bfd_link_info *info;
+  struct elf_backend_data *bed;
   struct elf_info_failed eif;
   char *p;
+  bfd_size_type amt;
+
+  sinfo = (struct elf_assign_sym_version_info *) data;
+  info = sinfo->info;
 
   /* Fix the symbol flags.  */
   eif.failed = false;
@@ -3513,6 +4067,7 @@ elf_link_assign_sym_version (h, data)
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
     return true;
 
+  bed = get_elf_backend_data (sinfo->output_bfd);
   p = strchr (h->root.root.string, ELF_VER_CHR);
   if (p != NULL && h->verinfo.vertree == NULL)
     {
@@ -3543,12 +4098,12 @@ elf_link_assign_sym_version (h, data)
        {
          if (strcmp (t->name, p) == 0)
            {
-             int len;
+             size_t len;
              char *alc;
              struct bfd_elf_version_expr *d;
 
              len = p - h->root.root.string;
-             alc = bfd_alloc (sinfo->output_bfd, len);
+             alc = bfd_alloc (sinfo->output_bfd, (bfd_size_type) len);
              if (alc == NULL)
                return false;
              strncpy (alc, h->root.root.string, len - 1);
@@ -3577,16 +4132,12 @@ elf_link_assign_sym_version (h, data)
                        {
                          if (h->dynindx != -1
                              && info->shared
-                             && ! sinfo->export_dynamic)
+                             && ! info->export_dynamic)
                            {
                              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                             h->elf_link_hash_flags &=~
-                               ELF_LINK_HASH_NEEDS_PLT;
-                             h->dynindx = -1;
-                             h->plt.offset = (bfd_vma) -1;
-                             /* FIXME: The name of the symbol has
-                                already been recorded in the dynamic
-                                string table section.  */
+                             (*bed->elf_backend_hide_symbol) (info, h);
+                             _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                                     h->dynstr_index);
                            }
 
                          break;
@@ -3607,12 +4158,13 @@ elf_link_assign_sym_version (h, data)
          int version_index;
 
          /* If we aren't going to export this symbol, we don't need
-             to worry about it. */
+             to worry about it.  */
          if (h->dynindx == -1)
            return true;
 
+         amt = sizeof *t;
          t = ((struct bfd_elf_version_tree *)
-              bfd_alloc (sinfo->output_bfd, sizeof *t));
+              bfd_alloc (sinfo->output_bfd, amt));
          if (t == NULL)
            {
              sinfo->failed = true;
@@ -3692,15 +4244,12 @@ elf_link_assign_sym_version (h, data)
                      h->verinfo.vertree = t;
                      if (h->dynindx != -1
                          && info->shared
-                         && ! sinfo->export_dynamic)
+                         && ! info->export_dynamic)
                        {
                          h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                         h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
-                         h->dynindx = -1;
-                         h->plt.offset = (bfd_vma) -1;
-                         /* FIXME: The name of the symbol has already
-                            been recorded in the dynamic string table
-                            section.  */
+                         (*bed->elf_backend_hide_symbol) (info, h);
+                         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                                 h->dynstr_index);
                        }
                      break;
                    }
@@ -3716,14 +4265,12 @@ elf_link_assign_sym_version (h, data)
          h->verinfo.vertree = deflt;
          if (h->dynindx != -1
              && info->shared
-             && ! sinfo->export_dynamic)
+             && ! info->export_dynamic)
            {
              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-             h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
-             h->dynindx = -1;
-             h->plt.offset = (bfd_vma) -1;
-             /* FIXME: The name of the symbol has already been
-                recorded in the dynamic string table section.  */
+             (*bed->elf_backend_hide_symbol) (info, h);
+             _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                     h->dynstr_index);
            }
        }
     }
@@ -3782,6 +4329,8 @@ static boolean elf_link_flush_output_syms
   PARAMS ((struct elf_final_link_info *));
 static boolean elf_link_output_extsym
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_sec_merge_syms
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_link_input_bfd
   PARAMS ((struct elf_final_link_info *, bfd *));
 static boolean elf_reloc_link_order
@@ -3806,8 +4355,8 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
      Elf_Internal_Shdr *rel_hdr;
      asection *o;
 {
-  register struct elf_link_hash_entry **p, **pend;
-  unsigned reloc_count;
+  bfd_size_type reloc_count;
+  bfd_size_type num_rel_hashes;
 
   /* Figure out how many relocations there will be.  */
   if (rel_hdr == &elf_section_data (o)->rel_hdr)
@@ -3815,29 +4364,35 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
   else
     reloc_count = elf_section_data (o)->rel_count2;
 
+  num_rel_hashes = o->reloc_count;
+  if (num_rel_hashes < reloc_count)
+    num_rel_hashes = reloc_count;
+
   /* That allows us to calculate the size of the section.  */
   rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
 
   /* The contents field must last into write_object_contents, so we
-     allocate it with bfd_alloc rather than malloc.  */
-  rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+     allocate it with bfd_alloc rather than malloc.  Also since we
+     cannot be sure that the contents will actually be filled in,
+     we zero the allocated space.  */
+  rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size);
   if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
     return false;
-  
+
   /* We only allocate one set of hash entries, so we only do it the
      first time we are called.  */
-  if (elf_section_data (o)->rel_hashes == NULL)
+  if (elf_section_data (o)->rel_hashes == NULL
+      && num_rel_hashes)
     {
+      struct elf_link_hash_entry **p;
+
       p = ((struct elf_link_hash_entry **)
-          bfd_malloc (o->reloc_count
-                      * sizeof (struct elf_link_hash_entry *)));
-      if (p == NULL && o->reloc_count != 0)
+          bfd_zmalloc (num_rel_hashes
+                       * sizeof (struct elf_link_hash_entry *)));
+      if (p == NULL)
        return false;
 
       elf_section_data (o)->rel_hashes = p;
-      pend = p + o->reloc_count;
-      for (; p < pend; p++)
-       *p = NULL;
     }
 
   return true;
@@ -3856,6 +4411,25 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
      struct elf_link_hash_entry **rel_hash;
 {
   unsigned int i;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  Elf_Internal_Rel *irel;
+  Elf_Internal_Rela *irela;
+  bfd_size_type amt = sizeof (Elf_Internal_Rel) * bed->s->int_rels_per_ext_rel;
+
+  irel = (Elf_Internal_Rel *) bfd_zmalloc (amt);
+  if (irel == NULL)
+    {
+      (*_bfd_error_handler) (_("Error: out of memory"));
+      abort ();
+    }
+
+  amt = sizeof (Elf_Internal_Rela) * bed->s->int_rels_per_ext_rel;
+  irela = (Elf_Internal_Rela *) bfd_zmalloc (amt);
+  if (irela == NULL)
+    {
+      (*_bfd_error_handler) (_("Error: out of memory"));
+      abort ();
+    }
 
   for (i = 0; i < count; i++, rel_hash++)
     {
@@ -3867,29 +4441,258 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
       if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
        {
          Elf_External_Rel *erel;
-         Elf_Internal_Rel irel;
-         
+         unsigned int j;
+
          erel = (Elf_External_Rel *) rel_hdr->contents + i;
-         elf_swap_reloc_in (abfd, erel, &irel);
-         irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                   ELF_R_TYPE (irel.r_info));
-         elf_swap_reloc_out (abfd, &irel, erel);
+         if (bed->s->swap_reloc_in)
+           (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel);
+         else
+           elf_swap_reloc_in (abfd, erel, irel);
+
+         for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
+           irel[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
+                                        ELF_R_TYPE (irel[j].r_info));
+
+         if (bed->s->swap_reloc_out)
+           (*bed->s->swap_reloc_out) (abfd, irel, (bfd_byte *) erel);
+         else
+           elf_swap_reloc_out (abfd, irel, erel);
        }
       else
        {
          Elf_External_Rela *erela;
-         Elf_Internal_Rela irela;
-         
+         unsigned int j;
+
          BFD_ASSERT (rel_hdr->sh_entsize
                      == sizeof (Elf_External_Rela));
-         
+
          erela = (Elf_External_Rela *) rel_hdr->contents + i;
-         elf_swap_reloca_in (abfd, erela, &irela);
-         irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                    ELF_R_TYPE (irela.r_info));
-         elf_swap_reloca_out (abfd, &irela, erela);
+         if (bed->s->swap_reloca_in)
+           (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela);
+         else
+           elf_swap_reloca_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));
+
+         if (bed->s->swap_reloca_out)
+           (*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela);
+         else
+           elf_swap_reloca_out (abfd, irela, erela);
        }
     }
+
+  free (irel);
+  free (irela);
+}
+
+struct elf_link_sort_rela {
+  bfd_vma offset;
+  enum elf_reloc_type_class type;
+  union {
+    Elf_Internal_Rel rel;
+    Elf_Internal_Rela rela;
+  } u;
+};
+
+static int
+elf_link_sort_cmp1 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B;
+  int relativea, relativeb;
+
+  relativea = a->type == reloc_class_relative;
+  relativeb = b->type == reloc_class_relative;
+
+  if (relativea < relativeb)
+    return 1;
+  if (relativea > relativeb)
+    return -1;
+  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+    return -1;
+  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static int
+elf_link_sort_cmp2 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B;
+  int copya, copyb;
+
+  if (a->offset < b->offset)
+    return -1;
+  if (a->offset > b->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);
+  if (copya < copyb)
+    return -1;
+  if (copya > copyb)
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static size_t
+elf_link_sort_relocs (abfd, info, psec)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection **psec;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *reldyn, *o;
+  boolean rel = false;
+  bfd_size_type count, size;
+  size_t i, j, ret;
+  struct elf_link_sort_rela *rela;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
+  if (reldyn == NULL || reldyn->_raw_size == 0)
+    {
+      reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
+      if (reldyn == NULL || reldyn->_raw_size == 0)
+       return 0;
+      rel = true;
+      count = reldyn->_raw_size / sizeof (Elf_External_Rel);
+    }
+  else
+    count = reldyn->_raw_size / sizeof (Elf_External_Rela);
+
+  size = 0;
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+       == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+       && o->output_section == reldyn)
+      size += o->_raw_size;
+
+  if (size != reldyn->_raw_size)
+    return 0;
+
+  rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count);
+  if (rela == NULL)
+    {
+      (*info->callbacks->warning)
+       (info, _("Not enough memory to sort relocations"), 0, abfd, 0,
+        (bfd_vma) 0);
+      return 0;
+    }
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+       == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+       && o->output_section == reldyn)
+      {
+       if (rel)
+         {
+           Elf_External_Rel *erel, *erelend;
+           struct elf_link_sort_rela *s;
+
+           erel = (Elf_External_Rel *) o->contents;
+           erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rel);
+           for (; erel < erelend; erel++, s++)
+             {
+               if (bed->s->swap_reloc_in)
+                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+               else
+                 elf_swap_reloc_in (abfd, erel, &s->u.rel);
+
+               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+             }
+         }
+       else
+         {
+           Elf_External_Rela *erela, *erelaend;
+           struct elf_link_sort_rela *s;
+
+           erela = (Elf_External_Rela *) o->contents;
+           erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rela);
+           for (; erela < erelaend; erela++, s++)
+             {
+               if (bed->s->swap_reloca_in)
+                 (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela,
+                                            &s->u.rela);
+               else
+                 elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+
+               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+             }
+         }
+      }
+
+  qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
+  for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
+    ;
+  for (i = ret, j = ret; i < count; i++)
+    {
+      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+       j = i;
+      rela[i].offset = rela[j].u.rel.r_offset;
+    }
+  qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+       == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+       && o->output_section == reldyn)
+      {
+       if (rel)
+         {
+           Elf_External_Rel *erel, *erelend;
+           struct elf_link_sort_rela *s;
+
+           erel = (Elf_External_Rel *) o->contents;
+           erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rel);
+           for (; erel < erelend; erel++, s++)
+             {
+               if (bed->s->swap_reloc_out)
+                 (*bed->s->swap_reloc_out) (abfd, &s->u.rel,
+                                            (bfd_byte *) erel);
+               else
+                 elf_swap_reloc_out (abfd, &s->u.rel, erel);
+             }
+         }
+       else
+         {
+           Elf_External_Rela *erela, *erelaend;
+           struct elf_link_sort_rela *s;
+
+           erela = (Elf_External_Rela *) o->contents;
+           erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rela);
+           for (; erela < erelaend; erela++, s++)
+             {
+               if (bed->s->swap_reloca_out)
+                 (*bed->s->swap_reloca_out) (dynobj, &s->u.rela,
+                                             (bfd_byte *) erela);
+               else
+                 elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+             }
+         }
+      }
+
+  free (rela);
+  *psec = reldyn;
+  return ret;
 }
 
 /* Do the final step of an ELF link.  */
@@ -3900,15 +4703,16 @@ elf_bfd_final_link (abfd, info)
      struct bfd_link_info *info;
 {
   boolean dynamic;
+  boolean emit_relocs;
   bfd *dynobj;
   struct elf_final_link_info finfo;
   register asection *o;
   register struct bfd_link_order *p;
   register bfd *sub;
-  size_t max_contents_size;
-  size_t max_external_reloc_size;
-  size_t max_internal_reloc_count;
-  size_t max_sym_count;
+  bfd_size_type max_contents_size;
+  bfd_size_type max_external_reloc_size;
+  bfd_size_type max_internal_reloc_count;
+  bfd_size_type max_sym_count;
   file_ptr off;
   Elf_Internal_Sym elfsym;
   unsigned int i;
@@ -3916,6 +4720,13 @@ elf_bfd_final_link (abfd, info)
   Elf_Internal_Shdr *symstrtab_hdr;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
+  boolean merged;
+  size_t relativecount = 0;
+  asection *reldyn = 0;
+  bfd_size_type amt;
+
+  if (! is_elf_hash_table (info))
+    return false;
 
   if (info->shared)
     abfd->flags |= DYNAMIC;
@@ -3923,6 +4734,10 @@ elf_bfd_final_link (abfd, info)
   dynamic = elf_hash_table (info)->dynamic_sections_created;
   dynobj = elf_hash_table (info)->dynobj;
 
+  emit_relocs = (info->relocateable
+                 || info->emitrelocations
+                 || bed->elf_backend_emit_relocs);
+
   finfo.info = info;
   finfo.output_bfd = abfd;
   finfo.symstrtab = elf_stringtab_init ();
@@ -3961,6 +4776,7 @@ elf_bfd_final_link (abfd, info)
   max_external_reloc_size = 0;
   max_internal_reloc_count = 0;
   max_sym_count = 0;
+  merged = false;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     {
       o->reloc_count = 0;
@@ -3982,8 +4798,25 @@ elf_bfd_final_link (abfd, info)
                 the linker has decided to not include.  */
              sec->linker_mark = true;
 
-             if (info->relocateable)
+             if (sec->flags & SEC_MERGE)
+               merged = true;
+
+             if (info->relocateable || info->emitrelocations)
                o->reloc_count += sec->reloc_count;
+              else if (bed->elf_backend_count_relocs)
+               {
+                 Elf_Internal_Rela * relocs;
+
+                 relocs = (NAME(_bfd_elf,link_read_relocs)
+                           (abfd, sec, (PTR) NULL,
+                            (Elf_Internal_Rela *) NULL, info->keep_memory));
+
+                 o->reloc_count += (*bed->elf_backend_count_relocs)
+                                     (sec, relocs);
+
+                 if (!info->keep_memory)
+                   free (relocs);
+               }
 
              if (sec->_raw_size > max_contents_size)
                max_contents_size = sec->_raw_size;
@@ -4039,6 +4872,10 @@ elf_bfd_final_link (abfd, info)
        o->vma = 0;
     }
 
+  if (! info->relocateable && merged)
+    elf_link_hash_traverse (elf_hash_table (info),
+                           elf_link_sec_merge_syms, (PTR) abfd);
+
   /* Figure out the file positions for everything but the symbol table
      and the relocs.  We set symcount to force assign_section_numbers
      to create a symbol table.  */
@@ -4050,7 +4887,7 @@ elf_bfd_final_link (abfd, info)
   /* Figure out how many relocations we will have in each section.
      Just using RELOC_COUNT isn't good enough since that doesn't
      maintain a separate value for REL vs. RELA relocations.  */
-  if (info->relocateable)
+  if (emit_relocs)
     for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
       for (o = sub->sections; o != NULL; o = o->next)
        {
@@ -4067,9 +4904,9 @@ elf_bfd_final_link (abfd, info)
          if (output_section != NULL
              && (o->flags & SEC_RELOC) != 0)
            {
-             struct bfd_elf_section_data *esdi 
+             struct bfd_elf_section_data *esdi
                = elf_section_data (o);
-             struct bfd_elf_section_data *esdo 
+             struct bfd_elf_section_data *esdo
                = elf_section_data (output_section);
              unsigned int *rel_count;
              unsigned int *rel_count2;
@@ -4086,12 +4923,11 @@ elf_bfd_final_link (abfd, info)
                  rel_count = &esdo->rel_count2;
                  rel_count2 = &esdo->rel_count;
                }
-             
-             *rel_count += (esdi->rel_hdr.sh_size 
-                            / esdi->rel_hdr.sh_entsize);
+
+             *rel_count += NUM_SHDR_ENTRIES (& esdi->rel_hdr);
              if (esdi->rel_hdr2)
-               *rel_count2 += (esdi->rel_hdr2->sh_size 
-                               / esdi->rel_hdr2->sh_entsize);
+               *rel_count2 += NUM_SHDR_ENTRIES (esdi->rel_hdr2);
+             output_section->flags |= SEC_RELOC;
            }
        }
 
@@ -4114,7 +4950,7 @@ elf_bfd_final_link (abfd, info)
        }
 
       /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
-        to count upwards while actually outputting the relocations. */
+        to count upwards while actually outputting the relocations.  */
       elf_section_data (o)->rel_count = 0;
       elf_section_data (o)->rel_count2 = 0;
     }
@@ -4136,7 +4972,7 @@ elf_bfd_final_link (abfd, info)
   /* sh_link is set in assign_section_numbers.  */
   /* sh_info is set below.  */
   /* sh_offset is set just below.  */
-  symtab_hdr->sh_addralign = 4;  /* FIXME: system dependent?  */
+  symtab_hdr->sh_addralign = bed->s->file_align;
 
   off = elf_tdata (abfd)->next_file_pos;
   off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, true);
@@ -4151,14 +4987,16 @@ elf_bfd_final_link (abfd, info)
     finfo.symbuf_size = 20;
   else
     finfo.symbuf_size = max_sym_count;
-  finfo.symbuf = ((Elf_External_Sym *)
-                 bfd_malloc (finfo.symbuf_size * sizeof (Elf_External_Sym)));
+  amt = finfo.symbuf_size;
+  amt *= sizeof (Elf_External_Sym);
+  finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt);
   if (finfo.symbuf == NULL)
     goto error_return;
 
   /* Start writing out the symbol table.  The first symbol is always a
      dummy symbol.  */
-  if (info->strip != strip_all || info->relocateable)
+  if (info->strip != strip_all
+      || emit_relocs)
     {
       elfsym.st_value = 0;
       elfsym.st_size = 0;
@@ -4191,7 +5029,8 @@ elf_bfd_final_link (abfd, info)
      symbols have no names.  We store the index of each one in the
      index field of the section, so that we can find it again when
      outputting relocs.  */
-  if (info->strip != strip_all || info->relocateable)
+  if (info->strip != strip_all
+      || emit_relocs)
     {
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
@@ -4291,9 +5130,11 @@ elf_bfd_final_link (abfd, info)
     }
 
   /* That wrote out all the local symbols.  Finish up the symbol table
-     with the global symbols.  */
+     with the global symbols. Even if we want to strip everything we
+     can, we still need to deal with those global symbols that got
+     converted to local in a version script.  */
 
-  if (info->strip != strip_all && info->shared)
+  if (info->shared)
     {
       /* Output any global symbols that got converted to local in a
          version script.  We do this in a separate step since ELF
@@ -4313,12 +5154,13 @@ elf_bfd_final_link (abfd, info)
   /* The sh_info field records the index of the first non local symbol.  */
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
-  if (dynamic)
+  if (dynamic
+      && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
       Elf_External_Sym *dynsym =
-       (Elf_External_Sym *)finfo.dynsym_sec->contents;
-      unsigned long last_local = 0;
+       (Elf_External_Sym *) finfo.dynsym_sec->contents;
+      long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
       if (info->shared)
@@ -4380,8 +5222,8 @@ elf_bfd_final_link (abfd, info)
            }
        }
 
-      elf_section_data (finfo.dynsym_sec->output_section)
-       ->this_hdr.sh_info = last_local + 1;
+      elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+       last_local + 1;
     }
 
   /* We get the global symbols from the hash table.  */
@@ -4397,13 +5239,14 @@ elf_bfd_final_link (abfd, info)
      table, do it now.  */
   if (bed->elf_backend_output_arch_syms)
     {
-      if (! (*bed->elf_backend_output_arch_syms)
-             (abfd, info, (PTR) &finfo,
-              (boolean (*) PARAMS ((PTR, const char *,
-                           Elf_Internal_Sym *, asection *)))
-              elf_link_output_sym))
+      typedef boolean (*out_sym_func) PARAMS ((PTR, const char *,
+                                              Elf_Internal_Sym *,
+                                              asection *));
+
+      if (! ((*bed->elf_backend_output_arch_syms)
+            (abfd, info, (PTR) &finfo, (out_sym_func) elf_link_output_sym)))
        return false;
-    }      
+    }
 
   /* Flush all symbols to the file.  */
   if (! elf_link_flush_output_syms (&finfo))
@@ -4442,13 +5285,13 @@ elf_bfd_final_link (abfd, info)
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
-      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, 
+      elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
                              elf_section_data (o)->rel_count,
                              elf_section_data (o)->rel_hashes);
       if (elf_section_data (o)->rel_hdr2 != NULL)
        elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
                                elf_section_data (o)->rel_count2,
-                               (elf_section_data (o)->rel_hashes 
+                               (elf_section_data (o)->rel_hashes
                                 + elf_section_data (o)->rel_count));
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
@@ -4456,6 +5299,9 @@ elf_bfd_final_link (abfd, info)
       o->reloc_count = 0;
     }
 
+  if (dynamic && info->combreloc && dynobj != NULL)
+    relativecount = elf_link_sort_relocs (abfd, info, &reldyn);
+
   /* If we are linking against a dynamic object, or generating a
      shared library, finish up the dynamic linking information.  */
   if (dynamic)
@@ -4480,6 +5326,23 @@ elf_bfd_final_link (abfd, info)
            {
            default:
              break;
+           case DT_NULL:
+             if (relativecount > 0 && dyncon + 1 < 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;
+                   }
+               }
+             break;
            case DT_INIT:
              name = info->init_function;
              goto get_sym;
@@ -4578,7 +5441,8 @@ elf_bfd_final_link (abfd, info)
       for (o = dynobj->sections; o != NULL; o = o->next)
        {
          if ((o->flags & SEC_HAS_CONTENTS) == 0
-             || o->_raw_size == 0)
+             || o->_raw_size == 0
+             || o->output_section == bfd_abs_section_ptr)
            continue;
          if ((o->flags & SEC_LINKER_CREATED) == 0)
            {
@@ -4591,20 +5455,19 @@ elf_bfd_final_link (abfd, info)
              || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0)
            {
              if (! bfd_set_section_contents (abfd, o->output_section,
-                                             o->contents, o->output_offset,
+                                             o->contents,
+                                             (file_ptr) o->output_offset,
                                              o->_raw_size))
                goto error_return;
            }
          else
            {
-             file_ptr off;
-
              /* The contents of the .dynstr section are actually in a
                  stringtab.  */
              off = elf_section_data (o->output_section)->this_hdr.sh_offset;
              if (bfd_seek (abfd, off, SEEK_SET) != 0
-                 || ! _bfd_stringtab_emit (abfd,
-                                           elf_hash_table (info)->dynstr))
+                 || ! _bfd_elf_strtab_emit (abfd,
+                                            elf_hash_table (info)->dynstr))
                goto error_return;
            }
        }
@@ -4639,7 +5502,7 @@ elf_bfd_final_link (abfd, info)
     {
       if ((o->flags & SEC_RELOC) != 0
          && elf_section_data (o)->rel_hashes != NULL)
-       free (elf_section_data (o)->rel_hashes);
+        free (elf_section_data (o)->rel_hashes);
     }
 
   elf_tdata (abfd)->linker = true;
@@ -4706,8 +5569,7 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
   else
     {
       elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
-                                                           name, true,
-                                                           false);
+                                                           name, true, false);
       if (elfsym->st_name == (unsigned long) -1)
        return false;
     }
@@ -4736,14 +5598,14 @@ elf_link_flush_output_syms (finfo)
   if (finfo->symbuf_count > 0)
     {
       Elf_Internal_Shdr *symtab;
+      file_ptr pos;
+      bfd_size_type amt;
 
       symtab = &elf_tdata (finfo->output_bfd)->symtab_hdr;
-
-      if (bfd_seek (finfo->output_bfd, symtab->sh_offset + symtab->sh_size,
-                   SEEK_SET) != 0
-         || (bfd_write ((PTR) finfo->symbuf, finfo->symbuf_count,
-                        sizeof (Elf_External_Sym), finfo->output_bfd)
-             != finfo->symbuf_count * sizeof (Elf_External_Sym)))
+      pos = symtab->sh_offset + symtab->sh_size;
+      amt = finfo->symbuf_count * sizeof (Elf_External_Sym);
+      if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
+         || bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt)
        return false;
 
       symtab->sh_size += finfo->symbuf_count * sizeof (Elf_External_Sym);
@@ -4754,6 +5616,33 @@ elf_link_flush_output_syms (finfo)
   return true;
 }
 
+/* Adjust all external symbols pointing into SEC_MERGE sections
+   to reflect the object merging within the sections.  */
+
+static boolean
+elf_link_sec_merge_syms (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  asection *sec;
+
+  if ((h->root.type == bfd_link_hash_defined
+       || h->root.type == bfd_link_hash_defweak)
+      && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
+      && elf_section_data (sec)->merge_info)
+    {
+      bfd *output_bfd = (bfd *) data;
+
+      h->root.u.def.value =
+       _bfd_merged_section_offset (output_bfd,
+                                   &h->root.u.def.section,
+                                   elf_section_data (sec)->merge_info,
+                                   h->root.u.def.value, (bfd_vma) 0);
+    }
+
+  return true;
+}
+
 /* Add an external symbol to the symbol table.  This is called from
    the hash table traversal routine.  When generating a shared object,
    we go through the symbol table twice.  The first time we output
@@ -4792,15 +5681,15 @@ elf_link_output_extsym (h, data)
      referenced by regular files, because we will already have issued
      warnings for them.  */
   if (! finfo->info->relocateable
-      && ! (finfo->info->shared
-           && !finfo->info->no_undefined)
+      && ! finfo->info->allow_shlib_undefined
+      && ! finfo->info->shared
       && 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)
     {
       if (! ((*finfo->info->callbacks->undefined_symbol)
             (finfo->info, h->root.root.string, h->root.u.undef.abfd,
-             (asection *) NULL, 0)))
+             (asection *) NULL, (bfd_vma) 0, true)))
        {
          eoinfo->failed = true;
          return false;
@@ -4828,8 +5717,10 @@ elf_link_output_extsym (h, data)
     strip = false;
 
   /* If we're stripping it, and it's not a dynamic symbol, there's
-     nothing else to do.  */
-  if (strip && h->dynindx == -1)
+     nothing else to do unless it is a forced local symbol.  */
+  if (strip
+      && h->dynindx == -1
+      && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
     return true;
 
   sym.st_value = 0;
@@ -4909,12 +5800,9 @@ elf_link_output_extsym (h, data)
          symbol foo@@GNU_1.2 is the default, which should be used when
          foo is used with no version, then we add an indirect symbol
          foo which points to foo@@GNU_1.2.  We ignore these symbols,
-         since the indirected symbol is already in the hash table.  If
-         the indirect symbol is non-ELF, fall through and output it.  */
-      if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) == 0)
-       return true;
+         since the indirected symbol is already in the hash table.  */
+      return true;
 
-      /* Fall through.  */
     case bfd_link_hash_warning:
       /* We can't represent these symbols in ELF, although a warning
          symbol may have come from a .gnu.warning.SYMBOL section.  We
@@ -4952,8 +5840,8 @@ elf_link_output_extsym (h, data)
      finish_dynamic_symbol routine gets through with it.  */
   if (sym.st_shndx == SHN_UNDEF
       && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0
-      && (ELF_ST_BIND(sym.st_info) == STB_GLOBAL
-         || ELF_ST_BIND(sym.st_info) == STB_WEAK))
+      && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL
+         || ELF_ST_BIND (sym.st_info) == STB_WEAK))
     {
       int bindtype;
 
@@ -4964,6 +5852,12 @@ elf_link_output_extsym (h, data)
       sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
     }
 
+  /* If a symbol is not defined locally, we clear the visibility
+     field.  */
+  if (! finfo->info->relocateable
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+    sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other);
+
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We have already know the symbol index.  We also fill
      in the entry in the .hash section.  */
@@ -4975,22 +5869,21 @@ elf_link_output_extsym (h, data)
       size_t hash_entry_size;
       bfd_byte *bucketpos;
       bfd_vma chain;
+      Elf_External_Sym *esym;
 
       sym.st_name = h->dynstr_index;
-
-      elf_swap_symbol_out (finfo->output_bfd, &sym,
-                          (PTR) (((Elf_External_Sym *)
-                                  finfo->dynsym_sec->contents)
-                                 + h->dynindx));
+      esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx;
+      elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym);
 
       bucketcount = elf_hash_table (finfo->info)->bucketcount;
       bucket = h->elf_hash_value % bucketcount;
-      hash_entry_size 
+      hash_entry_size
        = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
       bucketpos = ((bfd_byte *) finfo->hash_sec->contents
                   + (bucket + 2) * hash_entry_size);
       chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
-      bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
+      bfd_put (8 * hash_entry_size, finfo->output_bfd, (bfd_vma) h->dynindx,
+              bucketpos);
       bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
               ((bfd_byte *) finfo->hash_sec->contents
                + (bucketcount + 2 + h->dynindx) * hash_entry_size));
@@ -4998,6 +5891,7 @@ elf_link_output_extsym (h, data)
       if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
        {
          Elf_Internal_Versym iversym;
+         Elf_External_Versym *eversym;
 
          if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
            {
@@ -5017,10 +5911,9 @@ elf_link_output_extsym (h, data)
          if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0)
            iversym.vs_vers |= VERSYM_HIDDEN;
 
-         _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym,
-                                   (((Elf_External_Versym *)
-                                     finfo->symver_sec->contents)
-                                    + h->dynindx));
+         eversym = (Elf_External_Versym *) finfo->symver_sec->contents;
+         eversym += h->dynindx;
+         _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym);
        }
     }
 
@@ -5045,7 +5938,7 @@ elf_link_output_extsym (h, data)
    OUTPUT_BFD.  */
 
 static void
-elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, 
+elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
                        internal_relocs)
      bfd *output_bfd;
      asection *input_section;
@@ -5057,11 +5950,13 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
   Elf_Internal_Shdr *output_rel_hdr;
   asection *output_section;
   unsigned int *rel_countp = NULL;
+  struct elf_backend_data *bed;
+  bfd_size_type amt;
 
   output_section = input_section->output_section;
   output_rel_hdr = NULL;
 
-  if (elf_section_data (output_section)->rel_hdr.sh_entsize 
+  if (elf_section_data (output_section)->rel_hdr.sh_entsize
       == input_rel_hdr->sh_entsize)
     {
       output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
@@ -5076,38 +5971,62 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
     }
 
   BFD_ASSERT (output_rel_hdr != NULL);
-  
+
+  bed = get_elf_backend_data (output_bfd);
   irela = internal_relocs;
-  irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+  irelaend = irela + NUM_SHDR_ENTRIES (input_rel_hdr)
+                    * bed->s->int_rels_per_ext_rel;
+
   if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
     {
       Elf_External_Rel *erel;
+      Elf_Internal_Rel *irel;
+
+      amt = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel);
+      irel = (Elf_Internal_Rel *) bfd_zmalloc (amt);
+      if (irel == NULL)
+       {
+         (*_bfd_error_handler) (_("Error: out of memory"));
+         abort ();
+       }
 
       erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp);
-      for (; irela < irelaend; irela++, erel++)
+      for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erel++)
        {
-         Elf_Internal_Rel irel;
+         unsigned int i;
 
-         irel.r_offset = irela->r_offset;
-         irel.r_info = irela->r_info;
-         BFD_ASSERT (irela->r_addend == 0);
-         elf_swap_reloc_out (output_bfd, &irel, erel);
+         for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+           {
+             irel[i].r_offset = irela[i].r_offset;
+             irel[i].r_info = irela[i].r_info;
+             BFD_ASSERT (irela[i].r_addend == 0);
+           }
+
+         if (bed->s->swap_reloc_out)
+           (*bed->s->swap_reloc_out) (output_bfd, irel, (PTR) erel);
+         else
+           elf_swap_reloc_out (output_bfd, irel, erel);
        }
+
+      free (irel);
     }
   else
     {
       Elf_External_Rela *erela;
 
-      BFD_ASSERT (input_rel_hdr->sh_entsize
-                 == sizeof (Elf_External_Rela));
+      BFD_ASSERT (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rela));
+
       erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
-      for (; irela < irelaend; irela++, erela++)
-       elf_swap_reloca_out (output_bfd, irela, erela);
+      for (; irela < irelaend; irela += bed->s->int_rels_per_ext_rel, erela++)
+       if (bed->s->swap_reloca_out)
+         (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela);
+       else
+         elf_swap_reloca_out (output_bfd, irela, erela);
     }
 
   /* Bump the counter, so that we know where to add the next set of
      relocations.  */
-  *rel_countp += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+  *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr);
 }
 
 /* Link an input file into the linker output file.  This function
@@ -5136,6 +6055,8 @@ elf_link_input_bfd (finfo, input_bfd)
   asection **ppsection;
   asection *o;
   struct elf_backend_data *bed;
+  boolean emit_relocs;
+  struct elf_link_hash_entry **sym_hashes;
 
   output_bfd = finfo->output_bfd;
   bed = get_elf_backend_data (output_bfd);
@@ -5147,6 +6068,10 @@ elf_link_input_bfd (finfo, input_bfd)
   if ((input_bfd->flags & DYNAMIC) != 0)
     return true;
 
+  emit_relocs = (finfo->info->relocateable
+                 || finfo->info->emitrelocations
+                 || bed->elf_backend_emit_relocs);
+
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   if (elf_bad_symtab (input_bfd))
     {
@@ -5166,11 +6091,10 @@ elf_link_input_bfd (finfo, input_bfd)
     external_syms = NULL;
   else
     {
+      bfd_size_type amt = locsymcount * sizeof (Elf_External_Sym);
       external_syms = finfo->external_syms;
       if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || (bfd_read (external_syms, sizeof (Elf_External_Sym),
-                       locsymcount, input_bfd)
-             != locsymcount * sizeof (Elf_External_Sym)))
+         || bfd_bread (external_syms, amt, input_bfd) != amt)
        return false;
     }
 
@@ -5202,7 +6126,15 @@ elf_link_input_bfd (finfo, input_bfd)
       if (isym->st_shndx == SHN_UNDEF)
        isec = bfd_und_section_ptr;
       else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE)
-       isec = section_from_elf_index (input_bfd, isym->st_shndx);
+       {
+         isec = section_from_elf_index (input_bfd, isym->st_shndx);
+         if (isec && elf_section_data (isec)->merge_info
+             && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+           isym->st_value =
+             _bfd_merged_section_offset (output_bfd, &isec,
+                                         elf_section_data (isec)->merge_info,
+                                         isym->st_value, (bfd_vma) 0);
+       }
       else if (isym->st_shndx == SHN_ABS)
        isec = bfd_abs_section_ptr;
       else if (isym->st_shndx == SHN_COMMON)
@@ -5219,16 +6151,19 @@ elf_link_input_bfd (finfo, input_bfd)
       if (esym == external_syms)
        continue;
 
+      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+       {
+         /* We never output section symbols.  Instead, we use the
+            section symbol of the corresponding section in the output
+            file.  */
+         continue;
+       }
+
       /* If we are stripping all symbols, we don't want to output this
         one.  */
       if (finfo->info->strip == strip_all)
        continue;
 
-      /* We never output section symbols.  Instead, we use the section
-        symbol of the corresponding section in the output file.  */
-      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
-       continue;
-
       /* If we are discarding all local symbols, we don't want to
         output this one.  If we are generating a relocateable output
         file, then some of the local symbols may be required by
@@ -5260,7 +6195,9 @@ elf_link_input_bfd (finfo, input_bfd)
       if ((finfo->info->strip == strip_some
           && (bfd_hash_lookup (finfo->info->keep_hash, name, false, false)
               == NULL))
-         || (finfo->info->discard == discard_l
+         || (((finfo->info->discard == discard_sec_merge
+               && (isec->flags & SEC_MERGE) && ! finfo->info->relocateable)
+              || finfo->info->discard == discard_l)
              && bfd_is_local_label_name (input_bfd, name)))
        continue;
 
@@ -5292,6 +6229,7 @@ elf_link_input_bfd (finfo, input_bfd)
     }
 
   /* Relocate the contents of each section.  */
+  sym_hashes = elf_sym_hashes (input_bfd);
   for (o = input_bfd->sections; o != NULL; o = o->next)
     {
       bfd_byte *contents;
@@ -5339,6 +6277,122 @@ elf_link_input_bfd (finfo, input_bfd)
              && o->reloc_count > 0)
            return false;
 
+         /* Run through the relocs looking for any against symbols
+            from discarded sections and section symbols from
+            removed link-once sections.  Complain about relocs
+            against discarded sections.  Zero relocs against removed
+            link-once sections.  We should really complain if
+            anything in the final link tries to use it, but
+            DWARF-based exception handling might have an entry in
+            .eh_frame to describe a routine in the linkonce section,
+            and it turns out to be hard to remove the .eh_frame
+            entry too.  FIXME.  */
+         if (!finfo->info->relocateable)
+           {
+             Elf_Internal_Rela *rel, *relend;
+
+             rel = internal_relocs;
+             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);
+
+                 if (r_symndx >= locsymcount
+                     || (elf_bad_symtab (input_bfd)
+                         && finfo->sections[r_symndx] == NULL))
+                   {
+                     struct elf_link_hash_entry *h;
+
+                     h = sym_hashes[r_symndx - extsymoff];
+                     while (h->root.type == bfd_link_hash_indirect
+                            || h->root.type == bfd_link_hash_warning)
+                       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+                     /* Complain if the definition comes from a
+                        discarded section.  */
+                     if ((h->root.type == bfd_link_hash_defined
+                          || h->root.type == bfd_link_hash_defweak)
+                         && ! bfd_is_abs_section (h->root.u.def.section)
+                         && bfd_is_abs_section (h->root.u.def.section
+                                                ->output_section))
+                       {
+#if BFD_VERSION_DATE < 20031005
+                         if ((o->flags & SEC_DEBUGGING) != 0)
+                           {
+#if BFD_VERSION_DATE > 20021005
+                             (*finfo->info->callbacks->warning)
+                               (finfo->info,
+                                _("warning: relocation against removed section; zeroing"),
+                                NULL, input_bfd, o, rel->r_offset);
+#endif
+                             memset (rel, 0, sizeof (*rel));
+                           }
+                         else
+#endif
+                           {
+                             if (! ((*finfo->info->callbacks->undefined_symbol)
+                                    (finfo->info, h->root.root.string,
+                                     input_bfd, o, rel->r_offset,
+                                     true)))
+                               return false;
+                           }
+                       }
+                   }
+                 else
+                   {
+                     isym = finfo->internal_syms + r_symndx;
+                     if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+                       {
+                         asection *sec = finfo->sections[r_symndx];
+
+                         if (sec != NULL
+                             && ! bfd_is_abs_section (sec)
+                             && bfd_is_abs_section (sec->output_section))
+                           {
+#if BFD_VERSION_DATE < 20031005
+                             if ((o->flags & SEC_DEBUGGING) != 0
+                                 || (sec->flags & SEC_LINK_ONCE) != 0)
+                               {
+#if BFD_VERSION_DATE > 20021005
+                                 (*finfo->info->callbacks->warning)
+                                   (finfo->info,
+                                    _("warning: relocation against removed section"),
+                                    NULL, input_bfd, o, rel->r_offset);
+#endif
+                                 rel->r_info
+                                   = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
+                                 rel->r_addend = 0;
+                               }
+                             else
+#endif
+                               {
+                                 boolean ok;
+                                 const char *msg
+                                   = _("local symbols in discarded section %s");
+                                 bfd_size_type amt
+                                   = strlen (sec->name) + strlen (msg) - 1;
+                                 char *buf = (char *) bfd_malloc (amt);
+
+                                 if (buf != NULL)
+                                   sprintf (buf, msg, sec->name);
+                                 else
+                                   buf = (char *) sec->name;
+                                 ok = (*finfo->info->callbacks
+                                       ->undefined_symbol) (finfo->info, buf,
+                                                            input_bfd, o,
+                                                            rel->r_offset,
+                                                            true);
+                                 if (buf != sec->name)
+                                   free (buf);
+                                 if (!ok)
+                                   return false;
+                               }
+                           }
+                       }
+                   }
+               }
+           }
+
          /* Relocate the section by invoking a back end routine.
 
             The back end routine is responsible for adjusting the
@@ -5366,29 +6420,41 @@ elf_link_input_bfd (finfo, input_bfd)
                                     finfo->sections))
            return false;
 
-         if (finfo->info->relocateable)
+         if (emit_relocs)
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
              struct elf_link_hash_entry **rel_hash;
              Elf_Internal_Shdr *input_rel_hdr;
+             unsigned int next_erel;
+             void (*reloc_emitter) PARAMS ((bfd *, asection *,
+                                            Elf_Internal_Shdr *,
+                                            Elf_Internal_Rela *));
 
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
-             irelaend = 
-               irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
+             irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
                          + elf_section_data (o->output_section)->rel_count
                          + elf_section_data (o->output_section)->rel_count2);
-             for (; irela < irelaend; irela++, rel_hash++)
+             for (next_erel = 0; irela < irelaend; irela++, next_erel++)
                {
                  unsigned long r_symndx;
-                 Elf_Internal_Sym *isym;
                  asection *sec;
 
+                 if (next_erel == bed->s->int_rels_per_ext_rel)
+                   {
+                     rel_hash++;
+                     next_erel = 0;
+                   }
+
                  irela->r_offset += o->output_offset;
 
+                 /* Relocs in an executable have to be virtual addresses.  */
+                 if (finfo->info->emitrelocations)
+                   irela->r_offset += o->output_section->vma;
+
                  r_symndx = ELF_R_SYM (irela->r_info);
 
                  if (r_symndx == 0)
@@ -5399,7 +6465,7 @@ elf_link_input_bfd (finfo, input_bfd)
                          && finfo->sections[r_symndx] == NULL))
                    {
                      struct elf_link_hash_entry *rh;
-                     long indx;
+                     unsigned long indx;
 
                      /* This is a reloc against a global symbol.  We
                         have not yet output all the local symbols, so
@@ -5425,7 +6491,7 @@ elf_link_input_bfd (finfo, input_bfd)
                      continue;
                    }
 
-                 /* This is a reloc against a local symbol. */
+                 /* This is a reloc against a local symbol.  */
 
                  *rel_hash = NULL;
                  isym = finfo->internal_syms + r_symndx;
@@ -5457,7 +6523,7 @@ elf_link_input_bfd (finfo, input_bfd)
                    {
                      if (finfo->indices[r_symndx] == -1)
                        {
-                         unsigned long link;
+                         unsigned long shlink;
                          const char *name;
                          asection *osec;
 
@@ -5471,10 +6537,9 @@ elf_link_input_bfd (finfo, input_bfd)
                          /* This symbol was skipped earlier, but
                             since it is needed by a reloc, we
                             must output it now.  */
-                         link = symtab_hdr->sh_link;
-                         name = bfd_elf_string_from_elf_section (input_bfd,
-                                                                 link,
-                                                                 isym->st_name);
+                         shlink = symtab_hdr->sh_link;
+                         name = (bfd_elf_string_from_elf_section
+                                 (input_bfd, shlink, isym->st_name));
                          if (name == NULL)
                            return false;
 
@@ -5489,7 +6554,8 @@ elf_link_input_bfd (finfo, input_bfd)
                          if (! finfo->info->relocateable)
                            isym->st_value += osec->vma;
 
-                         finfo->indices[r_symndx] = bfd_get_symcount (output_bfd);
+                         finfo->indices[r_symndx]
+                           = bfd_get_symcount (output_bfd);
 
                          if (! elf_link_output_sym (finfo, name, isym, sec))
                            return false;
@@ -5503,36 +6569,51 @@ elf_link_input_bfd (finfo, input_bfd)
                }
 
              /* Swap out the relocs.  */
+              if (bed->elf_backend_emit_relocs
+                  && !(finfo->info->relocateable
+                      || finfo->info->emitrelocations))
+                reloc_emitter = bed->elf_backend_emit_relocs;
+              else
+                reloc_emitter = elf_link_output_relocs;
+
              input_rel_hdr = &elf_section_data (o)->rel_hdr;
-             elf_link_output_relocs (output_bfd, o, 
-                                     input_rel_hdr,
-                                     internal_relocs);
-             internal_relocs 
-               += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+              (*reloc_emitter) (output_bfd, o, input_rel_hdr, internal_relocs);
+
              input_rel_hdr = elf_section_data (o)->rel_hdr2;
-             if (input_rel_hdr)
-               elf_link_output_relocs (output_bfd, o, 
-                                       input_rel_hdr,
-                                       internal_relocs);
+              if (input_rel_hdr)
+                {
+                  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
+                                     * bed->s->int_rels_per_ext_rel);
+                  reloc_emitter (output_bfd, o, input_rel_hdr, internal_relocs);
+                }
+
            }
        }
 
       /* Write out the modified section contents.  */
-      if (elf_section_data (o)->stab_info == NULL)
+      if (elf_section_data (o)->stab_info)
+       {
+         if (! (_bfd_write_section_stabs
+                (output_bfd, &elf_hash_table (finfo->info)->stab_info,
+                 o, &elf_section_data (o)->stab_info, contents)))
+           return false;
+       }
+      else if (elf_section_data (o)->merge_info)
        {
-         if (! (o->flags & SEC_EXCLUDE) &&
-             ! bfd_set_section_contents (output_bfd, o->output_section,
-                                         contents, o->output_offset,
-                                         (o->_cooked_size != 0
-                                          ? o->_cooked_size
-                                          : o->_raw_size)))
+         if (! (_bfd_write_merged_section
+                (output_bfd, o, elf_section_data (o)->merge_info)))
            return false;
        }
       else
        {
-         if (! (_bfd_write_section_stabs
-                (output_bfd, &elf_hash_table (finfo->info)->stab_info,
-                 o, &elf_section_data (o)->stab_info, contents)))
+         bfd_size_type sec_size;
+
+         sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
+         if (! (o->flags & SEC_EXCLUDE)
+             && ! bfd_set_section_contents (output_bfd, o->output_section,
+                                            contents,
+                                            (file_ptr) o->output_offset,
+                                            sec_size))
            return false;
        }
     }
@@ -5558,6 +6639,7 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
   bfd_vma addend;
   struct elf_link_hash_entry **rel_hash_ptr;
   Elf_Internal_Shdr *rel_hdr;
+  struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
 
   howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
   if (howto == NULL)
@@ -5628,28 +6710,31 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       bfd_reloc_status_type rstat;
       bfd_byte *buf;
       boolean ok;
+      const char *sym_name;
 
       size = bfd_get_reloc_size (howto);
       buf = (bfd_byte *) bfd_zmalloc (size);
       if (buf == (bfd_byte *) NULL)
        return false;
-      rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
+      rstat = _bfd_relocate_contents (howto, output_bfd, (bfd_vma) addend, buf);
       switch (rstat)
        {
        case bfd_reloc_ok:
          break;
+
        default:
        case bfd_reloc_outofrange:
          abort ();
+
        case bfd_reloc_overflow:
+         if (link_order->type == bfd_section_reloc_link_order)
+           sym_name = bfd_section_name (output_bfd,
+                                        link_order->u.reloc.p->u.section);
+         else
+           sym_name = link_order->u.reloc.p->u.name;
          if (! ((*info->callbacks->reloc_overflow)
-                (info,
-                 (link_order->type == bfd_section_reloc_link_order
-                  ? bfd_section_name (output_bfd,
-                                      link_order->u.reloc.p->u.section)
-                  : link_order->u.reloc.p->u.name),
-                 howto->name, addend, (bfd *) NULL, (asection *) NULL,
-                 (bfd_vma) 0)))
+                (info, sym_name, howto->name, addend,
+                 (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
            {
              free (buf);
              return false;
@@ -5674,33 +6759,60 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
 
   if (rel_hdr->sh_type == SHT_REL)
     {
-      Elf_Internal_Rel irel;
+      bfd_size_type size;
+      Elf_Internal_Rel *irel;
       Elf_External_Rel *erel;
+      unsigned int i;
+
+      size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rel);
+      irel = (Elf_Internal_Rel *) bfd_zmalloc (size);
+      if (irel == NULL)
+       return false;
+
+      for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+       irel[i].r_offset = offset;
+      irel[0].r_info = ELF_R_INFO (indx, howto->type);
 
-      irel.r_offset = offset;
-      irel.r_info = ELF_R_INFO (indx, howto->type);
       erel = ((Elf_External_Rel *) rel_hdr->contents
              + elf_section_data (output_section)->rel_count);
-      elf_swap_reloc_out (output_bfd, &irel, erel);
+
+      if (bed->s->swap_reloc_out)
+       (*bed->s->swap_reloc_out) (output_bfd, irel, (bfd_byte *) erel);
+      else
+       elf_swap_reloc_out (output_bfd, irel, erel);
+
+      free (irel);
     }
   else
     {
-      Elf_Internal_Rela irela;
+      bfd_size_type size;
+      Elf_Internal_Rela *irela;
       Elf_External_Rela *erela;
+      unsigned int i;
+
+      size = bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela);
+      irela = (Elf_Internal_Rela *) bfd_zmalloc (size);
+      if (irela == NULL)
+       return false;
+
+      for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+       irela[i].r_offset = offset;
+      irela[0].r_info = ELF_R_INFO (indx, howto->type);
+      irela[0].r_addend = addend;
 
-      irela.r_offset = offset;
-      irela.r_info = ELF_R_INFO (indx, howto->type);
-      irela.r_addend = addend;
       erela = ((Elf_External_Rela *) rel_hdr->contents
               + elf_section_data (output_section)->rel_count);
-      elf_swap_reloca_out (output_bfd, &irela, erela);
+
+      if (bed->s->swap_reloca_out)
+       (*bed->s->swap_reloca_out) (output_bfd, irela, (bfd_byte *) erela);
+      else
+       elf_swap_reloca_out (output_bfd, irela, erela);
     }
 
   ++elf_section_data (output_section)->rel_count;
 
   return true;
 }
-
 \f
 /* Allocate a pointer to live in a linker created section.  */
 
@@ -5714,14 +6826,15 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
 {
   elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
   elf_linker_section_pointers_t *linker_section_ptr;
-  unsigned long r_symndx = ELF_R_SYM (rel->r_info);;
+  unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+  bfd_size_type amt;
 
   BFD_ASSERT (lsect != NULL);
 
-  /* Is this a global symbol? */
+  /* Is this a global symbol?  */
   if (h != NULL)
     {
-      /* Has this symbol already been allocated, if so, our work is done */
+      /* Has this symbol already been allocated?  If so, our work is done.  */
       if (_bfd_elf_find_pointer_linker_section (h->linker_section_pointer,
                                                rel->r_addend,
                                                lsect->which))
@@ -5738,29 +6851,30 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
       if (lsect->rel_section)
        lsect->rel_section->_raw_size += sizeof (Elf_External_Rela);
     }
-
-  else  /* Allocation of a pointer to a local symbol */
+  else
     {
+      /* Allocation of a pointer to a local symbol.  */
       elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
 
-      /* Allocate a table to hold the local symbols if first time */
+      /* Allocate a table to hold the local symbols if first time */
       if (!ptr)
        {
          unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info;
          register unsigned int i;
 
-         ptr = (elf_linker_section_pointers_t **)
-           bfd_alloc (abfd, num_symbols * sizeof (elf_linker_section_pointers_t *));
+         amt = num_symbols;
+         amt *= sizeof (elf_linker_section_pointers_t *);
+         ptr = (elf_linker_section_pointers_t **) bfd_alloc (abfd, amt);
 
          if (!ptr)
            return false;
 
          elf_local_ptr_offsets (abfd) = ptr;
          for (i = 0; i < num_symbols; i++)
-           ptr[i] = (elf_linker_section_pointers_t *)0;
+           ptr[i] = (elf_linker_section_pointers_t *) 0;
        }
 
-      /* Has this symbol already been allocated, if so, our work is done */
+      /* Has this symbol already been allocated?  If so, our work is done.  */
       if (_bfd_elf_find_pointer_linker_section (ptr[r_symndx],
                                                rel->r_addend,
                                                lsect->which))
@@ -5778,11 +6892,11 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
        }
     }
 
-  /* Allocate space for a pointer in the linker section, and allocate a new pointer record
-     from internal memory.  */
+  /* Allocate space for a pointer in the linker section, and allocate
+     a new pointer record from internal memory.  */
   BFD_ASSERT (ptr_linker_section_ptr != NULL);
-  linker_section_ptr = (elf_linker_section_pointers_t *)
-    bfd_alloc (abfd, sizeof (elf_linker_section_pointers_t));
+  amt = sizeof (elf_linker_section_pointers_t);
+  linker_section_ptr = (elf_linker_section_pointers_t *) bfd_alloc (abfd, amt);
 
   if (!linker_section_ptr)
     return false;
@@ -5796,17 +6910,19 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
 #if 0
   if (lsect->hole_size && lsect->hole_offset < lsect->max_hole_offset)
     {
-      linker_section_ptr->offset = lsect->section->_raw_size - lsect->hole_size + (ARCH_SIZE / 8);
+      linker_section_ptr->offset = (lsect->section->_raw_size
+                                   - lsect->hole_size + (ARCH_SIZE / 8));
       lsect->hole_offset += ARCH_SIZE / 8;
       lsect->sym_offset  += ARCH_SIZE / 8;
-      if (lsect->sym_hash)     /* Bump up symbol value if needed */
+      if (lsect->sym_hash)
        {
+         /* Bump up symbol value if needed.  */
          lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8;
 #ifdef DEBUG
          fprintf (stderr, "Bump up %s by %ld, current value = %ld\n",
                   lsect->sym_hash->root.root.string,
-                  (long)ARCH_SIZE / 8,
-                  (long)lsect->sym_hash->root.u.def.value);
+                  (long) ARCH_SIZE / 8,
+                  (long) lsect->sym_hash->root.u.def.value);
 #endif
        }
     }
@@ -5817,13 +6933,14 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
   lsect->section->_raw_size += ARCH_SIZE / 8;
 
 #ifdef DEBUG
-  fprintf (stderr, "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
-          lsect->name, (long)linker_section_ptr->offset, (long)lsect->section->_raw_size);
+  fprintf (stderr,
+          "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
+          lsect->name, (long) linker_section_ptr->offset,
+          (long) lsect->section->_raw_size);
 #endif
 
   return true;
 }
-
 \f
 #if ARCH_SIZE==64
 #define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_64 (BFD, VAL, ADDR)
@@ -5832,10 +6949,11 @@ elf_create_pointer_linker_section (abfd, info, lsect, h, rel)
 #define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_32 (BFD, VAL, ADDR)
 #endif
 
-/* Fill in the address for a pointer generated in alinker section.  */
+/* Fill in the address for a pointer generated in a linker section.  */
 
 bfd_vma
-elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, relocation, rel, relative_reloc)
+elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h,
+                                  relocation, rel, relative_reloc)
      bfd *output_bfd;
      bfd *input_bfd;
      struct bfd_link_info *info;
@@ -5849,11 +6967,13 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
 
   BFD_ASSERT (lsect != NULL);
 
-  if (h != NULL)               /* global symbol */
+  if (h != NULL)
     {
-      linker_section_ptr = _bfd_elf_find_pointer_linker_section (h->linker_section_pointer,
-                                                                rel->r_addend,
-                                                                lsect->which);
+      /* Handle global symbol.  */
+      linker_section_ptr = (_bfd_elf_find_pointer_linker_section
+                           (h->linker_section_pointer,
+                            rel->r_addend,
+                            lsect->which));
 
       BFD_ASSERT (linker_section_ptr != NULL);
 
@@ -5873,23 +6993,27 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
          if (!linker_section_ptr->written_address_p)
            {
              linker_section_ptr->written_address_p = true;
-             bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
-                         lsect->section->contents + linker_section_ptr->offset);
+             bfd_put_ptr (output_bfd,
+                          relocation + linker_section_ptr->addend,
+                          (lsect->section->contents
+                           + linker_section_ptr->offset));
            }
        }
     }
-  else                         /* local symbol */
+  else
     {
+      /* Handle local symbol.  */
       unsigned long r_symndx = ELF_R_SYM (rel->r_info);
       BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
       BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL);
-      linker_section_ptr = _bfd_elf_find_pointer_linker_section (elf_local_ptr_offsets (input_bfd)[r_symndx],
-                                                                rel->r_addend,
-                                                                lsect->which);
+      linker_section_ptr = (_bfd_elf_find_pointer_linker_section
+                           (elf_local_ptr_offsets (input_bfd)[r_symndx],
+                            rel->r_addend,
+                            lsect->which));
 
       BFD_ASSERT (linker_section_ptr != NULL);
 
-      /* Write out pointer if it hasn't been rewritten out before */
+      /* Write out pointer if it hasn't been rewritten out before */
       if (!linker_section_ptr->written_address_p)
        {
          linker_section_ptr->written_address_p = true;
@@ -5899,25 +7023,43 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
          if (info->shared)
            {
              asection *srel = lsect->rel_section;
-             Elf_Internal_Rela outrel;
+             Elf_Internal_Rela *outrel;
+             Elf_External_Rela *erel;
+             struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+             unsigned int i;
+             bfd_size_type amt;
+
+             amt = sizeof (Elf_Internal_Rela) * bed->s->int_rels_per_ext_rel;
+             outrel = (Elf_Internal_Rela *) bfd_zmalloc (amt);
+             if (outrel == NULL)
+               {
+                 (*_bfd_error_handler) (_("Error: out of memory"));
+                 return 0;
+               }
 
-             /* We need to generate a relative reloc for the dynamic linker.  */
+             /* We need to generate a relative reloc for the dynamic
+                linker.  */
              if (!srel)
-               lsect->rel_section = srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
-                                                                    lsect->rel_name);
+               {
+                 srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+                                                 lsect->rel_name);
+                 lsect->rel_section = srel;
+               }
 
              BFD_ASSERT (srel != NULL);
 
-             outrel.r_offset = (lsect->section->output_section->vma
-                                + lsect->section->output_offset
-                                + linker_section_ptr->offset);
-             outrel.r_info = ELF_R_INFO (0, relative_reloc);
-             outrel.r_addend = 0;
-             elf_swap_reloca_out (output_bfd, &outrel,
-                                  (((Elf_External_Rela *)
-                                    lsect->section->contents)
-                                   + elf_section_data (lsect->section)->rel_count));
+             for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+               outrel[i].r_offset = (lsect->section->output_section->vma
+                                     + lsect->section->output_offset
+                                     + linker_section_ptr->offset);
+             outrel[0].r_info = ELF_R_INFO (0, relative_reloc);
+             outrel[0].r_addend = 0;
+             erel = (Elf_External_Rela *) lsect->section->contents;
+             erel += elf_section_data (lsect->section)->rel_count;
+             elf_swap_reloca_out (output_bfd, outrel, erel);
              ++elf_section_data (lsect->section)->rel_count;
+
+             free (outrel);
            }
        }
     }
@@ -5928,8 +7070,9 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
                - lsect->sym_offset);
 
 #ifdef DEBUG
-  fprintf (stderr, "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
-          lsect->name, (long)relocation, (long)relocation);
+  fprintf (stderr,
+          "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
+          lsect->name, (long) relocation, (long) relocation);
 #endif
 
   /* Subtract out the addend, because it will get added back in by the normal
@@ -5964,7 +7107,8 @@ static boolean elf_gc_smash_unused_vtentry_relocs
   PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
 
 /* The mark phase of garbage collection.  For a given section, mark
-   it, and all the sections which define symbols to which it refers.  */
+   it and any sections in this section's group, and all the sections
+   which define symbols to which it refers.  */
 
 static boolean
 elf_gc_mark (info, sec, gc_mark_hook)
@@ -5974,12 +7118,19 @@ elf_gc_mark (info, sec, gc_mark_hook)
        PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
                struct elf_link_hash_entry *, Elf_Internal_Sym *));
 {
-  boolean ret = true;
+  boolean ret;
+  asection *group_sec;
 
   sec->gc_mark = 1;
 
-  /* Look through the section relocs.  */
+  /* Mark all the sections in the group.  */
+  group_sec = elf_section_data (sec)->next_in_group;
+  if (group_sec && !group_sec->gc_mark)
+    if (!elf_gc_mark (info, group_sec, gc_mark_hook))
+      return false;
 
+  /* Look through the section relocs.  */
+  ret = true;
   if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
     {
       Elf_Internal_Rela *relstart, *rel, *relend;
@@ -6011,13 +7162,11 @@ elf_gc_mark (info, sec, gc_mark_hook)
        locsyms = NULL;
       else
        {
-         locsyms = freesyms =
-           bfd_malloc (nlocsyms * sizeof (Elf_External_Sym));
+         bfd_size_type amt = nlocsyms * sizeof (Elf_External_Sym);
+         locsyms = freesyms = bfd_malloc (amt);
          if (freesyms == NULL
              || bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-             || (bfd_read (locsyms, sizeof (Elf_External_Sym),
-                           nlocsyms, input_bfd)
-                 != nlocsyms * sizeof (Elf_External_Sym)))
+             || bfd_bread (locsyms, amt, input_bfd) != amt)
            {
              ret = false;
              goto out1;
@@ -6050,22 +7199,22 @@ elf_gc_mark (info, sec, gc_mark_hook)
            {
              elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
              if (ELF_ST_BIND (s.st_info) == STB_LOCAL)
-               rsec = (*gc_mark_hook)(sec->owner, info, rel, NULL, &s);
+               rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
              else
                {
                  h = sym_hashes[r_symndx - extsymoff];
-                 rsec = (*gc_mark_hook)(sec->owner, info, rel, h, NULL);
+                 rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
                }
            }
          else if (r_symndx >= nlocsyms)
            {
              h = sym_hashes[r_symndx - extsymoff];
-             rsec = (*gc_mark_hook)(sec->owner, info, rel, h, NULL);
+             rsec = (*gc_mark_hook) (sec->owner, info, rel, h, NULL);
            }
          else
            {
              elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
-             rsec = (*gc_mark_hook)(sec->owner, info, rel, NULL, &s);
+             rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
            }
 
          if (rsec && !rsec->gc_mark)
@@ -6102,6 +7251,9 @@ elf_gc_sweep (info, gc_sweep_hook)
     {
       asection *o;
 
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+       continue;
+
       for (o = sub->sections; o != NULL; o = o->next)
        {
          /* Keep special sections.  Keep .debug sections.  */
@@ -6133,7 +7285,7 @@ elf_gc_sweep (info, gc_sweep_hook)
              if (internal_relocs == NULL)
                return false;
 
-             r = (*gc_sweep_hook)(o->owner, info, o, internal_relocs);
+             r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs);
 
              if (!info->keep_memory)
                free (internal_relocs);
@@ -6186,7 +7338,7 @@ elf_gc_propagate_vtable_entries_used (h, okp)
      struct elf_link_hash_entry *h;
      PTR okp;
 {
-  /* Those that are not vtables. */
+  /* Those that are not vtables.  */
   if (h->vtable_parent == NULL)
     return true;
 
@@ -6219,11 +7371,17 @@ elf_gc_propagate_vtable_entries_used (h, okp)
       pu = h->vtable_parent->vtable_entries_used;
       if (pu != NULL)
        {
-         n = h->vtable_parent->vtable_entries_size / FILE_ALIGN;
-         while (--n != 0)
+          asection *sec = h->root.u.def.section;
+          struct elf_backend_data *bed = get_elf_backend_data (sec->owner);
+          int file_align = bed->s->file_align;
+
+         n = h->vtable_parent->vtable_entries_size / file_align;
+         while (n--)
            {
-             if (*pu) *cu = true;
-             pu++, cu++;
+             if (*pu)
+               *cu = true;
+             pu++;
+             cu++;
            }
        }
     }
@@ -6240,6 +7398,7 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
   bfd_vma hstart, hend;
   Elf_Internal_Rela *relstart, *relend, *rel;
   struct elf_backend_data *bed;
+  int file_align;
 
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
@@ -6256,8 +7415,10 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
   relstart = (NAME(_bfd_elf,link_read_relocs)
              (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true));
   if (!relstart)
-    return *(boolean *)okp = false;
+    return *(boolean *) okp = false;
   bed = get_elf_backend_data (sec->owner);
+  file_align = bed->s->file_align;
+
   relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
   for (rel = relstart; rel < relend; ++rel)
@@ -6267,7 +7428,7 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
        if (h->vtable_entries_used
            && (rel->r_offset - hstart) < h->vtable_entries_size)
          {
-           bfd_vma entry = (rel->r_offset - hstart) / FILE_ALIGN;
+           bfd_vma entry = (rel->r_offset - hstart) / file_align;
            if (h->vtable_entries_used[entry])
              continue;
          }
@@ -6288,11 +7449,11 @@ elf_gc_sections (abfd, info)
   boolean ok = true;
   bfd *sub;
   asection * (*gc_mark_hook)
-    PARAMS ((bfd *abfd, struct bfd_link_info *, Elf_Internal_Rela *,
+    PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
              struct elf_link_hash_entry *h, Elf_Internal_Sym *));
 
   if (!get_elf_backend_data (abfd)->can_gc_sections
-      || info->relocateable
+      || info->relocateable || info->emitrelocations
       || elf_hash_table (info)->dynamic_sections_created)
     return true;
 
@@ -6316,6 +7477,10 @@ elf_gc_sections (abfd, info)
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
       asection *o;
+
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+       continue;
+
       for (o = sub->sections; o != NULL; o = o->next)
        {
          if (o->flags & SEC_KEEP)
@@ -6325,7 +7490,7 @@ elf_gc_sections (abfd, info)
     }
 
   /* ... and mark SEC_EXCLUDE for those that go.  */
-  if (!elf_gc_sweep(info, get_elf_backend_data (abfd)->gc_sweep_hook))
+  if (!elf_gc_sweep (info, get_elf_backend_data (abfd)->gc_sweep_hook))
     return false;
 
   return true;
@@ -6367,12 +7532,12 @@ elf_gc_record_vtinherit (abfd, sec, h, offset)
     }
 
   (*_bfd_error_handler) ("%s: %s+%lu: No symbol found for INHERIT",
-                        bfd_get_filename (abfd), sec->name,
-                        (unsigned long)offset);
+                        bfd_archive_filename (abfd), sec->name,
+                        (unsigned long) offset);
   bfd_set_error (bfd_error_invalid_operation);
   return false;
 
-win:
+ win:
   if (!h)
     {
       /* This *should* only be the absolute section.  It could potentially
@@ -6397,6 +7562,9 @@ elf_gc_record_vtentry (abfd, sec, h, addend)
      struct elf_link_hash_entry *h;
      bfd_vma addend;
 {
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  int file_align = bed->s->file_align;
+
   if (addend >= h->vtable_entries_size)
     {
       size_t size, bytes;
@@ -6419,32 +7587,33 @@ elf_gc_record_vtentry (abfd, sec, h, addend)
 
       /* Allocate one extra entry for use as a "done" flag for the
         consolidation pass.  */
-      bytes = (size / FILE_ALIGN + 1) * sizeof (boolean);
+      bytes = (size / file_align + 1) * sizeof (boolean);
 
       if (ptr)
        {
-         ptr = bfd_realloc (ptr - 1, bytes);
-         
+         ptr = bfd_realloc (ptr - 1, (bfd_size_type) bytes);
+
          if (ptr != NULL)
            {
              size_t oldbytes;
 
-             oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof (boolean);
-             memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes);
+             oldbytes = ((h->vtable_entries_size / file_align + 1)
+                         * sizeof (boolean));
+             memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes);
            }
        }
       else
-       ptr = bfd_zmalloc (bytes);
+       ptr = bfd_zmalloc ((bfd_size_type) bytes);
 
       if (ptr == NULL)
        return false;
-      
+
       /* And arrange for that done flag to be at index -1.  */
       h->vtable_entries_used = ptr + 1;
       h->vtable_entries_size = size;
     }
-  
-  h->vtable_entries_used[addend / FILE_ALIGN] = true;
+
+  h->vtable_entries_used[addend / file_align] = true;
 
   return true;
 }
@@ -6471,10 +7640,14 @@ elf_gc_common_finalize_got_offsets (abfd, info)
   /* Do the local .got entries first.  */
   for (i = info->input_bfds; i; i = i->link_next)
     {
-      bfd_signed_vma *local_got = elf_local_got_refcounts (i);
+      bfd_signed_vma *local_got;
       bfd_size_type j, locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
 
+      if (bfd_get_flavour (i) != bfd_target_elf_flavour)
+       continue;
+
+      local_got = elf_local_got_refcounts (i);
       if (!local_got)
        continue;
 
@@ -6496,7 +7669,8 @@ elf_gc_common_finalize_got_offsets (abfd, info)
        }
     }
 
-  /* Then the global .got and .plt entries.  */
+  /* Then the global .got entries.  .plt refcounts are handled by
+     adjust_dynamic_symbol  */
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_gc_allocate_got_offsets,
                          (PTR) &gotoff);
@@ -6561,8 +7735,8 @@ elf_collect_hash_codes (h, data)
   p = strchr (name, ELF_VER_CHR);
   if (p != NULL)
     {
-      alc = bfd_malloc (p - name + 1);
-      memcpy (alc, name, p - name);
+      alc = bfd_malloc ((bfd_size_type) (p - name + 1));
+      memcpy (alc, name, (size_t) (p - name));
       alc[p - name] = '\0';
       name = alc;
     }
This page took 0.088063 seconds and 4 git commands to generate.