2000-07-19 H.J. Lu <hjl@gnu.org>
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 841a8e728954c0d79a9d820cb7bf6c5697a0f020..1bf366873a821a0998e92d3f612f310baeb6184c 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linker support.
-   Copyright 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -48,10 +48,17 @@ static boolean elf_link_find_version_dependencies
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_link_assign_sym_version
   PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean elf_link_renumber_dynsyms
-  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 
+  PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
+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, 
+          struct elf_link_hash_entry **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -73,6 +80,138 @@ elf_bfd_link_add_symbols (abfd, info)
     }
 }
 \f
+/* Return true iff this is a non-common definition of a symbol.  */
+static boolean
+is_global_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;
+
+  /* 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
+   whoes archove 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;
+  size_t symcount;
+  size_t extsymcount;
+  size_t extsymoff;
+  boolean result = false;
+  
+  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;
+    }
+
+  buf = ((Elf_External_Sym *)
+        bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+  if (buf == NULL && extsymcount != 0)
+    return false;
+
+  /* Read in the symbol table.
+     FIXME:  This ought to be cached somewhere.  */
+  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)))
+    {
+      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_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
@@ -193,7 +332,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;
@@ -201,7 +357,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;
@@ -358,6 +513,17 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
       break;
     }
 
+  /* In cases involving weak versioned symbols, we may wind up trying
+     to merge a symbol with itself.  Catch that here, to avoid the
+     confusion that results if we try to override a symbol with
+     itself.  The additional tests catch cases like
+     _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
+     dynamic object, which we do want to handle here.  */
+  if (abfd == oldbfd
+      && ((abfd->flags & DYNAMIC) == 0
+         || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))
+    return true;
+
   /* NEWDYN and OLDDYN indicate whether the new or old symbol,
      respectively, is from a dynamic object.  */
 
@@ -366,10 +532,35 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
   else
     newdyn = false;
 
-  if (oldbfd == NULL || (oldbfd->flags & DYNAMIC) == 0)
-    olddyn = false;
+  if (oldbfd != NULL)
+    olddyn = (oldbfd->flags & DYNAMIC) != 0;
   else
-    olddyn = true;
+    {
+      asection *hsec;
+
+      /* This code handles the special SHN_MIPS_{TEXT,DATA} section
+         indices used by MIPS ELF.  */
+      switch (h->root.type)
+       {
+       default:
+         hsec = NULL;
+         break;
+
+       case bfd_link_hash_defined:
+       case bfd_link_hash_defweak:
+         hsec = h->root.u.def.section;
+         break;
+
+       case bfd_link_hash_common:
+         hsec = h->root.u.c.p->section;
+         break;
+       }
+
+      if (hsec == NULL)
+       olddyn = false;
+      else
+       olddyn = (hsec->symbol->flags & BSF_DYNAMIC) != 0;
+    }
 
   /* NEWDEF and OLDDEF indicate whether the new or old symbol,
      respectively, appear to be a definition rather than reference.  */
@@ -484,14 +675,19 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      represent variables; this can cause confusion in principle, but
      any such confusion would seem to indicate an erroneous program or
      shared library.  We also permit a common symbol in a regular
-     object to override a weak symbol in a shared object.  */
+     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.  */
 
   if (newdyn
       && newdef
       && (olddef
          || (h->root.type == bfd_link_hash_common
              && (bind == STB_WEAK
-                 || ELF_ST_TYPE (sym->st_info) == STT_FUNC))))
+                 || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
+      && (h->root.type != bfd_link_hash_defweak
+         || bind == STB_WEAK))
     {
       *override = true;
       newdef = false;
@@ -535,7 +731,10 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
 
      As above, we again permit a common symbol in a regular object to
      override a definition in a shared object if the shared object
-     symbol is a function or is weak.  */
+     symbol is a function or is weak.
+
+     As above, we permit a non-weak definition in a shared object to
+     override a weak definition in a regular object.  */
 
   if (! newdyn
       && (newdef
@@ -544,7 +743,9 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
                  || h->type == STT_FUNC)))
       && olddyn
       && olddef
-      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+      && (bind != STB_WEAK
+         || h->root.type == bfd_link_hash_defweak))
     {
       /* Change the hash table entry to undefined, and let
         _bfd_generic_link_add_one_symbol do the right thing with the
@@ -618,6 +819,45 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
       h->verinfo.vertree = NULL;
     }
 
+  /* 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.  */
+  if (olddef
+      && h->root.type == bfd_link_hash_defweak
+      && newdef
+      && newdyn
+      && bind != STB_WEAK)
+    {
+      /* 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.  */
+      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
+         defining a new indirect symbol we will wind up attaching it
+         to the entry we are overriding.  */
+      *sym_hash = h;
+    }
+
+  /* Handle the special case of a non-weak definition in a shared
+     object followed by a weak definition in a regular object.  In
+     this case we prefer to definition in the shared object.  To make
+     this work we have to tell the caller to not treat the new symbol
+     as a definition.  */
+  if (olddef
+      && olddyn
+      && h->root.type != bfd_link_hash_defweak
+      && newdef
+      && ! newdyn
+      && bind == STB_WEAK)
+    *override = true;
+
   return true;
 }
 
@@ -649,9 +889,12 @@ elf_link_add_object_symbols (abfd, info)
   struct elf_link_hash_entry *weaks;
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
+  struct elf_backend_data *bed;
+  boolean dt_needed;
 
-  add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook;
-  collect = get_elf_backend_data (abfd)->collect;
+  bed = get_elf_backend_data (abfd);
+  add_symbol_hook = bed->elf_add_symbol_hook;
+  collect = bed->collect;
 
   if ((abfd->flags & DYNAMIC) == 0)
     dynamic = false;
@@ -807,6 +1050,8 @@ elf_link_add_object_symbols (abfd, info)
     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
@@ -843,7 +1088,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)
@@ -866,6 +1116,23 @@ elf_link_add_object_symbols (abfd, info)
            goto error_return;
          link = 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
+              instead.  */
+           Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[link];
+           if (hdr->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)
+                 goto error_return;
+               link = elf_elfsections (abfd)[elfsec]->sh_link;
+             }
+         }
+
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
          for (; extdyn < extdynend; extdyn++)
@@ -1126,7 +1393,7 @@ elf_link_add_object_symbols (abfd, info)
                        {
                          (*_bfd_error_handler)
                            (_("%s: %s: invalid version %u (max %d)"),
-                            abfd->filename, name, vernum,
+                            bfd_get_filename (abfd), name, vernum,
                             elf_tdata (abfd)->dynverdef_hdr.sh_info);
                          bfd_set_error (bfd_error_bad_value);
                          goto error_return;
@@ -1167,7 +1434,7 @@ elf_link_add_object_symbols (abfd, info)
                        {
                          (*_bfd_error_handler)
                            (_("%s: %s: invalid needed version %d"),
-                            abfd->filename, name, vernum);
+                            bfd_get_filename (abfd), name, vernum);
                          bfd_set_error (bfd_error_bad_value);
                          goto error_return;
                        }
@@ -1184,7 +1451,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);
 
@@ -1308,9 +1579,24 @@ elf_link_add_object_symbols (abfd, info)
              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
@@ -1322,7 +1608,11 @@ elf_link_add_object_symbols (abfd, info)
          if (! dynamic)
            {
              if (! definition)
-               new_flag = ELF_LINK_HASH_REF_REGULAR;
+               {
+                 new_flag = ELF_LINK_HASH_REF_REGULAR;
+                 if (bind != STB_WEAK)
+                   new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
+               }
              else
                new_flag = ELF_LINK_HASH_DEF_REGULAR;
              if (info->shared
@@ -1457,43 +1747,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));
-
-                     /* 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.  */
@@ -1566,42 +1820,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));
-
-                         /* 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.  */
@@ -1640,6 +1859,65 @@ elf_link_add_object_symbols (abfd, info)
                    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);
+               break;
+             }
+
+         if (dt_needed && definition
+             && (h->elf_link_hash_flags
+                 & ELF_LINK_HASH_REF_REGULAR) != 0)
+           {
+             bfd_size_type oldsize;
+             bfd_size_type strindex;
+
+             /* The symbol from a DT_NEEDED object is referenced from
+                the regular object to create a dynamic executable. We
+                have to make sure there is a DT_NEEDED entry for it. */
+
+             dt_needed = false;
+             oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+             strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+                                            elf_dt_soname (abfd),
+                                            true, false);
+             if (strindex == (bfd_size_type) -1)
+               goto error_return;
+
+             if (oldsize
+                 == _bfd_stringtab_size (elf_hash_table (info)->dynstr))
+               {
+                 asection *sdyn;
+                 Elf_External_Dyn *dyncon, *dynconend;
+
+                 sdyn = bfd_get_section_by_name (elf_hash_table (info)->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 (elf_hash_table (info)->dynobj,
+                                      dyncon, &dyn);
+                     BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
+                                 dyn.d_un.d_val != strindex);
+                   }
+               }
+
+             if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+               goto error_return;
+           }
        }
     }
 
@@ -1931,16 +2209,18 @@ elf_link_create_dynamic_sections (abfd, info)
       && ! _bfd_elf_link_record_dynamic_symbol (info, h))
     return false;
 
+  bed = get_elf_backend_data (abfd);
+
   s = bfd_make_section (abfd, ".hash");
   if (s == NULL
       || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
     return false;
+  elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
 
   /* Let the backend create the rest of the sections.  This lets the
      backend set the right flags.  The backend will normally create
      the .got and .plt sections.  */
-  bed = get_elf_backend_data (abfd);
   if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
     return false;
 
@@ -1983,14 +2263,174 @@ elf_add_dynamic_entry (info, tag, val)
 
   return true;
 }
+
+/* Record a new local dynamic symbol.  */
+
+boolean
+elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     long input_indx;
+{
+  struct elf_link_local_dynamic_entry *entry;
+  struct elf_link_hash_table *eht;
+  struct bfd_strtab_hash *dynstr;
+  Elf_External_Sym esym;
+  unsigned long dynstr_index;
+  char *name;
+
+  /* See if the entry exists already.  */
+  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+    if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
+      return true;
+
+  entry = (struct elf_link_local_dynamic_entry *)
+    bfd_alloc (input_bfd, 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)))
+    return false;
+  elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
+
+  name = (bfd_elf_string_from_elf_section
+         (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
+          entry->isym.st_name));
+
+  dynstr = elf_hash_table (info)->dynstr;
+  if (dynstr == NULL)
+    {
+      /* Create a strtab to hold the dynamic symbol names.  */
+      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+      if (dynstr == NULL)
+       return false;
+    }
+
+  dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+  if (dynstr_index == (unsigned long) -1)
+    return false;
+  entry->isym.st_name = dynstr_index;
+
+  eht = elf_hash_table (info);
+
+  entry->next = eht->dynlocal;
+  eht->dynlocal = entry;
+  entry->input_bfd = input_bfd;
+  entry->input_indx = input_indx;
+  eht->dynsymcount++;
+
+  /* Whatever binding the symbol had before, it's now local.  */
+  entry->isym.st_info
+    = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
+
+  /* The dynindx will be set at the end of size_dynamic_sections.  */
+
+  return true;
+}
 \f
 
-/* Read and swap the relocs for a section.  They may have been cached.
-   If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL,
-   they are used as buffers to read into.  They are known to be large
-   enough.  If the INTERNAL_RELOCS relocs argument is NULL, the return
-   value is allocated using either malloc or bfd_alloc, according to
-   the KEEP_MEMORY argument.  */
+/* 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,
+   which should have already been allocated to contain enough space.
+   The EXTERNAL_RELOCS are a buffer where the external form of the
+   relocations should be stored.
+
+   Returns false if something goes wrong.  */
+
+static boolean
+elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
+                                  internal_relocs)
+     bfd *abfd;
+     Elf_Internal_Shdr *shdr;
+     PTR external_relocs;
+     Elf_Internal_Rela *internal_relocs;
+{
+  struct elf_backend_data *bed;
+
+  /* If there aren't any relocations, that's OK.  */
+  if (!shdr)
+    return true;
+
+  /* Position ourselves at the start of the section.  */
+  if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0)
+    return false;
+
+  /* Read the relocations.  */
+  if (bfd_read (external_relocs, 1, shdr->sh_size, abfd)
+      != shdr->sh_size)
+    return false;
+
+  bed = get_elf_backend_data (abfd);
+
+  /* Convert the external relocations to the internal format.  */
+  if (shdr->sh_entsize == sizeof (Elf_External_Rel))
+    {
+      Elf_External_Rel *erel;
+      Elf_External_Rel *erelend;
+      Elf_Internal_Rela *irela;
+      Elf_Internal_Rel *irel;
+
+      erel = (Elf_External_Rel *) external_relocs;
+      erelend = erel + shdr->sh_size / shdr->sh_entsize;
+      irela = internal_relocs;
+      irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel
+                              * sizeof (Elf_Internal_Rel)));
+      for (; erel < erelend; erel++, irela += bed->s->int_rels_per_ext_rel)
+       {
+         unsigned char i;
+
+         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 (i = 0; i < bed->s->int_rels_per_ext_rel; ++i)
+           {
+             irela[i].r_offset = irel[i].r_offset;
+             irela[i].r_info = irel[i].r_info;
+             irela[i].r_addend = 0;
+           }
+       }
+    }
+  else
+    {
+      Elf_External_Rela *erela;
+      Elf_External_Rela *erelaend;
+      Elf_Internal_Rela *irela;
+
+      BFD_ASSERT (shdr->sh_entsize == sizeof (Elf_External_Rela));
+
+      erela = (Elf_External_Rela *) external_relocs;
+      erelaend = erela + shdr->sh_size / shdr->sh_entsize;
+      irela = internal_relocs;
+      for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel)
+       {
+         if (bed->s->swap_reloca_in)
+           (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela);
+         else
+           elf_swap_reloca_in (abfd, erela, irela);
+       }
+    }
+
+  return true;
+}
+
+/* Read and swap the relocs for a section O.  They may have been
+   cached.  If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are
+   not NULL, they are used as buffers to read into.  They are known to
+   be large enough.  If the INTERNAL_RELOCS relocs argument is NULL,
+   the return value is allocated using either malloc or bfd_alloc,
+   according to the KEEP_MEMORY argument.  If O has two relocation
+   sections (both REL and RELA relocations), then the REL_HDR
+   relocations will appear first in INTERNAL_RELOCS, followed by the
+   REL_HDR2 relocations.  */
 
 Elf_Internal_Rela *
 NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
@@ -2004,6 +2444,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
   Elf_Internal_Shdr *rel_hdr;
   PTR alloc1 = NULL;
   Elf_Internal_Rela *alloc2 = NULL;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (elf_section_data (o)->relocs != NULL)
     return elf_section_data (o)->relocs;
@@ -2017,7 +2458,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
     {
       size_t size;
 
-      size = o->reloc_count * sizeof (Elf_Internal_Rela);
+      size = (o->reloc_count * bed->s->int_rels_per_ext_rel 
+             * sizeof (Elf_Internal_Rela));
       if (keep_memory)
        internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
       else
@@ -2028,53 +2470,27 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
 
   if (external_relocs == NULL)
     {
-      alloc1 = (PTR) bfd_malloc ((size_t) rel_hdr->sh_size);
+      size_t size = (size_t) rel_hdr->sh_size;
+
+      if (elf_section_data (o)->rel_hdr2)
+       size += (size_t) elf_section_data (o)->rel_hdr2->sh_size;
+      alloc1 = (PTR) bfd_malloc (size);
       if (alloc1 == NULL)
        goto error_return;
       external_relocs = alloc1;
     }
 
-  if ((bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0)
-      || (bfd_read (external_relocs, 1, rel_hdr->sh_size, abfd)
-         != rel_hdr->sh_size))
+  if (!elf_link_read_relocs_from_section (abfd, rel_hdr,
+                                         external_relocs,
+                                         internal_relocs))
+    goto error_return;
+  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
+                         * bed->s->int_rels_per_ext_rel)))
     goto error_return;
-
-  /* Swap in the relocs.  For convenience, we always produce an
-     Elf_Internal_Rela array; if the relocs are Rel, we set the addend
-     to 0.  */
-  if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-    {
-      Elf_External_Rel *erel;
-      Elf_External_Rel *erelend;
-      Elf_Internal_Rela *irela;
-
-      erel = (Elf_External_Rel *) external_relocs;
-      erelend = erel + o->reloc_count;
-      irela = internal_relocs;
-      for (; erel < erelend; erel++, irela++)
-       {
-         Elf_Internal_Rel irel;
-
-         elf_swap_reloc_in (abfd, erel, &irel);
-         irela->r_offset = irel.r_offset;
-         irela->r_info = irel.r_info;
-         irela->r_addend = 0;
-       }
-    }
-  else
-    {
-      Elf_External_Rela *erela;
-      Elf_External_Rela *erelaend;
-      Elf_Internal_Rela *irela;
-
-      BFD_ASSERT (rel_hdr->sh_entsize == sizeof (Elf_External_Rela));
-
-      erela = (Elf_External_Rela *) external_relocs;
-      erelaend = erela + o->reloc_count;
-      irela = internal_relocs;
-      for (; erela < erelaend; erela++, irela++)
-       elf_swap_reloca_in (abfd, erela, irela);
-    }
 
   /* Cache the results for next time, if we can.  */
   if (keep_memory)
@@ -2103,7 +2519,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
 /*ARGSUSED*/
 boolean
 NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
      const char *name;
      boolean provide;
@@ -2139,7 +2555,10 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
     h->verinfo.verdef = NULL;
 
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-  h->type = STT_OBJECT;
+
+  /* When possible, keep the original type of the symbol */
+  if (h->type == STT_NOTYPE)
+    h->type = STT_OBJECT;
 
   if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC
                                  | ELF_LINK_HASH_REF_DYNAMIC)) != 0
@@ -2176,8 +2595,6 @@ struct elf_assign_sym_version_info
   struct bfd_elf_version_tree *verdefs;
   /* Whether we are exporting all dynamic symbols.  */
   boolean export_dynamic;
-  /* Whether we removed any symbols from the dynamic symbol table.  */
-  boolean removed_dynamic;
   /* Whether we had a failure.  */
   boolean failed;
 };
@@ -2222,7 +2639,7 @@ compute_bucket_count (info)
      struct bfd_link_info *info;
 {
   size_t dynsymcount = elf_hash_table (info)->dynsymcount;
-  size_t best_size;
+  size_t best_size = 0;
   unsigned long int *hashcodes;
   unsigned long int *hashcodesp;
   unsigned long int i;
@@ -2240,13 +2657,10 @@ compute_bucket_count (info)
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_collect_hash_codes, &hashcodesp);
 
-/* We have a problem here.  The following code to optimize the table size
-   requires an integer type with more the 32 bits.  If BFD_HOST_U_64_BIT
-   is set or GCC 2 is used we know about such a type.  */
-#if defined BFD_HOST_U_64_BIT || __GNUC__ >= 2
-# ifndef BFD_HOST_U_64_BIT
-#  define BFD_HOST_U_64_BIT    unsigned long long int
-# endif
+/* We have a problem here.  The following code to optimize the table
+   size requires an integer type with more the 32 bits.  If
+   BFD_HOST_U_64_BIT is set we know about such a type.  */
+#ifdef BFD_HOST_U_64_BIT
   if (info->optimize == true)
     {
       unsigned long int nsyms = hashcodesp - hashcodes;
@@ -2336,7 +2750,7 @@ compute_bucket_count (info)
       free (counts);
     }
   else
-#endif
+#endif /* defined (BFD_HOST_U_64_BIT) */
     {
       /* This is the fallback solution if no 64bit type is available or if we
         are not supposed to spend much time on optimizations.  We select the
@@ -2378,7 +2792,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   bfd_size_type soname_indx;
   bfd *dynobj;
   struct elf_backend_data *bed;
-  bfd_size_type old_dynsymcount;
   struct elf_assign_sym_version_info asvinfo;
 
   *sinterpptr = NULL;
@@ -2402,20 +2815,6 @@ 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;
@@ -2438,6 +2837,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
            return false;
+         info->flags |= DF_SYMBOLIC;
        }
 
       if (rpath != NULL)
@@ -2447,7 +2847,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
                                     true, true);
          if (indx == (bfd_size_type) -1
-             || ! elf_add_dynamic_entry (info, DT_RPATH, indx))
+             || ! elf_add_dynamic_entry (info, DT_RPATH, indx)
+             || ! elf_add_dynamic_entry (info, DT_RUNPATH, indx))
            return false;
        }
 
@@ -2478,12 +2879,25 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            }
        }
 
+      /* 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;
+       }
+
       /* 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.removed_dynamic = false;
       asvinfo.failed = false;
 
       elf_link_hash_traverse (elf_hash_table (info),
@@ -2505,8 +2919,14 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       /* Add some entries to the .dynamic section.  We fill in some of the
         values later, in elf_bfd_final_link, but we must add the entries
         now so that we know the final size of the .dynamic section.  */
-      h =  elf_link_hash_lookup (elf_hash_table (info), "_init", false,
-                               false, false);
+
+      /* If there are initialization and/or finalization functions to
+        call then add the corresponding DT_INIT/DT_FINI entries.  */
+      h = (info->init_function
+          ? elf_link_hash_lookup (elf_hash_table (info), 
+                                  info->init_function, false,
+                                  false, false)
+          : NULL);
       if (h != NULL
          && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
                                        | ELF_LINK_HASH_DEF_REGULAR)) != 0)
@@ -2514,8 +2934,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          if (! elf_add_dynamic_entry (info, DT_INIT, 0))
            return false;
        }
-      h =  elf_link_hash_lookup (elf_hash_table (info), "_fini", false,
-                                false, false);
+      h = (info->fini_function
+          ? elf_link_hash_lookup (elf_hash_table (info), 
+                                  info->fini_function, false,
+                                  false, false)
+          : NULL);
       if (h != NULL
          && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
                                        | ELF_LINK_HASH_DEF_REGULAR)) != 0)
@@ -2523,6 +2946,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          if (! elf_add_dynamic_entry (info, DT_FINI, 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)
@@ -2535,7 +2959,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
-  old_dynsymcount = elf_hash_table (info)->dynsymcount;
   if (bed->elf_backend_size_dynamic_sections
       && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return false;
@@ -2544,9 +2967,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
     {
       size_t dynsymcount;
       asection *s;
-      size_t i;
       size_t bucketcount = 0;
       Elf_Internal_Sym isym;
+      size_t hash_entry_size;
 
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -2557,17 +2980,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       verdefs = asvinfo.verdefs;
 
       if (verdefs == NULL)
-       {
-         asection **spp;
-
-         /* Don't include this section in the output file.  */
-         for (spp = &output_bfd->sections;
-              *spp != s->output_section;
-              spp = &(*spp)->next)
-           ;
-         *spp = s->output_section->next;
-         --output_bfd->section_count;
-       }
+       _bfd_strip_section_from_output (info, s);
       else
        {
          unsigned int cdefs;
@@ -2577,23 +2990,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          Elf_Internal_Verdef def;
          Elf_Internal_Verdaux defaux;
 
-         if (asvinfo.removed_dynamic)
-           {
-             /* Some dynamic symbols were changed to be local
-                symbols.  In this case, we renumber all of the
-                dynamic symbols, so that we don't have a hole.  If
-                the backend changed dynsymcount, then assume that the
-                new symbols are at the start.  This is the case on
-                the MIPS.  FIXME: The names of the removed symbols
-                will still be in the dynamic string table, wasting
-                space.  */
-             elf_hash_table (info)->dynsymcount =
-               1 + (elf_hash_table (info)->dynsymcount - old_dynsymcount);
-             elf_link_hash_traverse (elf_hash_table (info),
-                                     elf_link_renumber_dynsyms,
-                                     (PTR) info);
-           }
-
          cdefs = 0;
          size = 0;
 
@@ -2633,7 +3029,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
          if (soname_indx != (bfd_size_type) -1)
            {
-             def.vd_hash = bfd_elf_hash ((const unsigned char *) soname);
+             def.vd_hash = bfd_elf_hash (soname);
              defaux.vda_name = soname_indx;
            }
          else
@@ -2642,7 +3038,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              bfd_size_type indx;
 
              name = output_bfd->filename;
-             def.vd_hash = bfd_elf_hash ((const unsigned char *) name);
+             def.vd_hash = bfd_elf_hash (name);
              indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
                                            name, true, false);
              if (indx == (bfd_size_type) -1)
@@ -2690,7 +3086,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                def.vd_flags |= VER_FLG_WEAK;
              def.vd_ndx = t->vernum + 1;
              def.vd_cnt = cdeps + 1;
-             def.vd_hash = bfd_elf_hash ((const unsigned char *) t->name);
+             def.vd_hash = bfd_elf_hash (t->name);
              def.vd_aux = sizeof (Elf_External_Verdef);
              if (t->next != NULL)
                def.vd_next = (sizeof (Elf_External_Verdef)
@@ -2741,6 +3137,22 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          elf_tdata (output_bfd)->cverdefs = cdefs;
        }
 
+      if (info->flags)
+       {
+         if (! elf_add_dynamic_entry (info, 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, 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");
@@ -2760,19 +3172,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                                (PTR) &sinfo);
 
        if (elf_tdata (output_bfd)->verref == NULL)
-         {
-           asection **spp;
-
-           /* We don't have any version definitions, so we can just
-               remove the section.  */
-
-           for (spp = &output_bfd->sections;
-                *spp != s->output_section;
-                spp = &(*spp)->next)
-             ;
-           *spp = s->output_section->next;
-           --output_bfd->section_count;
-         }
+         _bfd_strip_section_from_output (info, s);
        else
          {
            Elf_Internal_Verneed *t;
@@ -2838,8 +3238,7 @@ 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 ((const unsigned char *)
-                                               a->vna_nodename);
+                   a->vna_hash = bfd_elf_hash (a->vna_nodename);
                    indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
                                               a->vna_nodename, true, false);
                    if (indx == (bfd_size_type) -1)
@@ -2864,7 +3263,12 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          }
       }
 
-      dynsymcount = elf_hash_table (info)->dynsymcount;
+      /* Assign dynsym indicies.  In a shared library we generate a 
+        section symbol for each output section, which come first.
+        Next come all of the back-end allocated local dynamic syms,
+        followed by the rest of the global symbols.  */
+
+      dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
 
       /* Work out the size of the symbol version section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version");
@@ -2872,16 +3276,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (dynsymcount == 0
          || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
        {
-         asection **spp;
-
-         /* We don't need any symbol versions; just discard the
-             section.  */
-         for (spp = &output_bfd->sections;
-              *spp != s->output_section;
-              spp = &(*spp)->next)
-           ;
-         *spp = s->output_section->next;
-         --output_bfd->section_count;
+         _bfd_strip_section_from_output (info, s);
+         /* The DYNSYMCOUNT might have changed if we were going to
+            output a dynamic symbol table entry for S.  */
+         dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
        }
       else
        {
@@ -2923,14 +3321,16 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
       s = bfd_get_section_by_name (dynobj, ".hash");
       BFD_ASSERT (s != NULL);
-      s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8);
+      hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
+      s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
       s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
       if (s->contents == NULL)
        return false;
       memset (s->contents, 0, (size_t) s->_raw_size);
 
-      put_word (output_bfd, bucketcount, s->contents);
-      put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8));
+      bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
+      bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, 
+              s->contents + hash_entry_size);
 
       elf_hash_table (info)->bucketcount = bucketcount;
 
@@ -2962,15 +3362,20 @@ elf_fix_symbol_flags (h, eif)
      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;
+       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
              && (bfd_get_flavour (h->root.u.def.section->owner)
                  == bfd_target_elf_flavour))
-           h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+           h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
+                                      | ELF_LINK_HASH_REF_REGULAR_NONWEAK);
          else
            h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
        }
@@ -2986,6 +3391,25 @@ elf_fix_symbol_flags (h, eif)
            }
        }
     }
+  else
+    {
+      /* Unfortunately, ELF_LINK_NON_ELF is only correct if the symbol
+         was first seen in a non-ELF file.  Fortunately, if the symbol
+         was first seen in an ELF file, we're probably OK unless the
+         symbol was defined in a non-ELF file.  Catch that case here.
+         FIXME: We're still in trouble if the symbol was first seen in
+         a dynamic object, and then later in a non-ELF regular object.  */
+      if ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+         && (h->root.u.def.section->owner != NULL
+             ? (bfd_get_flavour (h->root.u.def.section->owner)
+                != bfd_target_elf_flavour)
+             : (bfd_is_abs_section (h->root.u.def.section)
+                && (h->elf_link_hash_flags
+                    & ELF_LINK_HASH_DEF_DYNAMIC) == 0)))
+       h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+    }
 
   /* If this is a final link, and the symbol was defined as a common
      symbol in a regular object file, and there was no definition in
@@ -3002,16 +3426,45 @@ 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.  Likewise, if the symbol has any kind of
+     visibility (internal, hidden, or protected), it doesn't need a
+     PLT.  */
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
       && eif->info->shared
-      && eif->info->symbolic
+      && (eif->info->symbolic || ELF_ST_VISIBILITY (h->other))
       && (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;
     }
 
+  /* 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
+       weakdef->elf_link_hash_flags |=
+         (h->elf_link_hash_flags
+          & (ELF_LINK_HASH_REF_REGULAR
+             | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+             | ELF_LINK_NON_GOT_REF));
+    }
+
   return true;
 }
 
@@ -3094,29 +3547,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;
-         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
@@ -3255,6 +3693,7 @@ elf_link_assign_sym_version (h, data)
   struct elf_assign_sym_version_info *sinfo =
     (struct elf_assign_sym_version_info *) data;
   struct bfd_link_info *info = sinfo->info;
+  struct elf_backend_data *bed;
   struct elf_info_failed eif;
   char *p;
 
@@ -3273,6 +3712,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)
     {
@@ -3323,11 +3763,8 @@ elf_link_assign_sym_version (h, data)
              if (t->globals != NULL)
                {
                  for (d = t->globals; d != NULL; d = d->next)
-                   {
-                     if ((d->match[0] == '*' && d->match[1] == '\0')
-                         || fnmatch (d->match, alc, 0) == 0)
-                       break;
-                   }
+                   if ((*d->match) (d, alc))
+                     break;
                }
 
              /* See if there is anything to force this symbol to
@@ -3336,19 +3773,14 @@ elf_link_assign_sym_version (h, data)
                {
                  for (d = t->locals; d != NULL; d = d->next)
                    {
-                     if ((d->match[0] == '*' && d->match[1] == '\0')
-                         || fnmatch (d->match, alc, 0) == 0)
+                     if ((*d->match) (d, alc))
                        {
                          if (h->dynindx != -1
                              && info->shared
                              && ! sinfo->export_dynamic)
                            {
-                             sinfo->removed_dynamic = true;
                              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;
+                             (*bed->elf_backend_hide_symbol) (info, h);
                              /* FIXME: The name of the symbol has
                                 already been recorded in the dynamic
                                 string table section.  */
@@ -3435,7 +3867,7 @@ elf_link_assign_sym_version (h, data)
            {
              for (d = t->globals; d != NULL; d = d->next)
                {
-                 if (fnmatch (d->match, h->root.root.string, 0) == 0)
+                 if ((*d->match) (d, h->root.root.string))
                    {
                      h->verinfo.vertree = t;
                      break;
@@ -3450,20 +3882,17 @@ elf_link_assign_sym_version (h, data)
            {
              for (d = t->locals; d != NULL; d = d->next)
                {
-                 if (d->match[0] == '*' && d->match[1] == '\0')
+                 if (d->pattern[0] == '*' && d->pattern[1] == '\0')
                    deflt = t;
-                 else if (fnmatch (d->match, h->root.root.string, 0) == 0)
+                 else if ((*d->match) (d, h->root.root.string))
                    {
                      h->verinfo.vertree = t;
                      if (h->dynindx != -1
                          && info->shared
                          && ! sinfo->export_dynamic)
                        {
-                         sinfo->removed_dynamic = true;
                          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;
+                         (*bed->elf_backend_hide_symbol) (info, h);
                          /* FIXME: The name of the symbol has already
                             been recorded in the dynamic string table
                             section.  */
@@ -3484,11 +3913,8 @@ elf_link_assign_sym_version (h, data)
              && info->shared
              && ! sinfo->export_dynamic)
            {
-             sinfo->removed_dynamic = true;
              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;
+             (*bed->elf_backend_hide_symbol) (info, h);
              /* FIXME: The name of the symbol has already been
                 recorded in the dynamic string table section.  */
            }
@@ -3497,26 +3923,6 @@ elf_link_assign_sym_version (h, data)
 
   return true;
 }
-
-/* This function is used to renumber the dynamic symbols, if some of
-   them are removed because they are marked as local.  This is called
-   via elf_link_hash_traverse.  */
-
-static boolean
-elf_link_renumber_dynsyms (h, data)
-     struct elf_link_hash_entry *h;
-     PTR data;
-{
-  struct bfd_link_info *info = (struct bfd_link_info *) data;
-
-  if (h->dynindx != -1)
-    {
-      h->dynindx = elf_hash_table (info)->dynsymcount;
-      ++elf_hash_table (info)->dynsymcount;
-    }
-
-  return true;
-}
 \f
 /* Final phase of ELF linker.  */
 
@@ -3584,6 +3990,114 @@ struct elf_outext_info
   struct elf_final_link_info *finfo;
 };
 
+/* Compute the size of, and allocate space for, REL_HDR which is the
+   section header for a section containing relocations for O.  */
+
+static boolean
+elf_link_size_reloc_section (abfd, rel_hdr, o)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     asection *o;
+{
+  register struct elf_link_hash_entry **p, **pend;
+  unsigned reloc_count;
+
+  /* Figure out how many relocations there will be.  */
+  if (rel_hdr == &elf_section_data (o)->rel_hdr)
+    reloc_count = elf_section_data (o)->rel_count;
+  else
+    reloc_count = elf_section_data (o)->rel_count2;
+
+  /* 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);
+  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)
+    {
+      p = ((struct elf_link_hash_entry **)
+          bfd_malloc (o->reloc_count
+                      * sizeof (struct elf_link_hash_entry *)));
+      if (p == NULL && o->reloc_count != 0)
+       return false;
+
+      elf_section_data (o)->rel_hashes = p;
+      pend = p + o->reloc_count;
+      for (; p < pend; p++)
+       *p = NULL;
+    }
+
+  return true;
+}
+
+/* When performing a relocateable link, the input relocations are
+   preserved.  But, if they reference global symbols, the indices
+   referenced must be updated.  Update all the relocations in
+   REL_HDR (there are COUNT of them), using the data in REL_HASH.  */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+     bfd *abfd;
+     Elf_Internal_Shdr *rel_hdr;
+     unsigned int count;
+     struct elf_link_hash_entry **rel_hash;
+{
+  unsigned int i;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  for (i = 0; i < count; i++, rel_hash++)
+    {
+      if (*rel_hash == NULL)
+       continue;
+
+      BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+      if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+       {
+         Elf_External_Rel *erel;
+         Elf_Internal_Rel irel;
+         
+         erel = (Elf_External_Rel *) rel_hdr->contents + i;
+         if (bed->s->swap_reloc_in)
+           (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &irel);
+         else
+           elf_swap_reloc_in (abfd, erel, &irel);
+         irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+                                   ELF_R_TYPE (irel.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;
+         
+         BFD_ASSERT (rel_hdr->sh_entsize
+                     == sizeof (Elf_External_Rela));
+         
+         erela = (Elf_External_Rela *) rel_hdr->contents + i;
+         if (bed->s->swap_reloca_in)
+           (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, &irela);
+         else
+           elf_swap_reloca_in (abfd, erela, &irela);
+         irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+                                    ELF_R_TYPE (irela.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);
+       }
+    }
+}
+
 /* Do the final step of an ELF link.  */
 
 boolean
@@ -3674,7 +4188,7 @@ elf_bfd_final_link (abfd, info)
                 the linker has decided to not include.  */
              sec->linker_mark = true;
 
-             if (info->relocateable)
+             if (info->relocateable || info->emitrelocations)
                o->reloc_count += sec->reloc_count;
 
              if (sec->_raw_size > max_contents_size)
@@ -3734,44 +4248,81 @@ elf_bfd_final_link (abfd, info)
   /* 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.  */
-  abfd->symcount = info->strip == strip_all ? 0 : 1;
+  bfd_get_symcount (abfd) = info->strip == strip_all ? 0 : 1;
   BFD_ASSERT (! abfd->output_has_begun);
   if (! _bfd_elf_compute_section_file_positions (abfd, info))
     goto error_return;
 
+  /* 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 || info->emitrelocations)
+    for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+      for (o = sub->sections; o != NULL; o = o->next)
+       {
+         asection *output_section;
+
+         if (! o->linker_mark)
+           {
+             /* This section was omitted from the link.  */
+             continue;
+           }
+
+         output_section = o->output_section;
+
+         if (output_section != NULL
+             && (o->flags & SEC_RELOC) != 0)
+           {
+             struct bfd_elf_section_data *esdi 
+               = elf_section_data (o);
+             struct bfd_elf_section_data *esdo 
+               = elf_section_data (output_section);
+             unsigned int *rel_count;
+             unsigned int *rel_count2;
+
+             /* We must be careful to add the relocation froms the
+                input section to the right output count.  */
+             if (esdi->rel_hdr.sh_entsize == esdo->rel_hdr.sh_entsize)
+               {
+                 rel_count = &esdo->rel_count;
+                 rel_count2 = &esdo->rel_count2;
+               }
+             else
+               {
+                 rel_count = &esdo->rel_count2;
+                 rel_count2 = &esdo->rel_count;
+               }
+             
+             *rel_count += (esdi->rel_hdr.sh_size 
+                            / esdi->rel_hdr.sh_entsize);
+             if (esdi->rel_hdr2)
+               *rel_count2 += (esdi->rel_hdr2->sh_size 
+                               / esdi->rel_hdr2->sh_entsize);
+           }
+       }
+
   /* That created the reloc sections.  Set their sizes, and assign
      them file positions, and allocate some buffers.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0)
        {
-         Elf_Internal_Shdr *rel_hdr;
-         register struct elf_link_hash_entry **p, **pend;
-
-         rel_hdr = &elf_section_data (o)->rel_hdr;
-
-         rel_hdr->sh_size = rel_hdr->sh_entsize * o->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);
-         if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+         if (!elf_link_size_reloc_section (abfd,
+                                           &elf_section_data (o)->rel_hdr,
+                                           o))
            goto error_return;
 
-         p = ((struct elf_link_hash_entry **)
-              bfd_malloc (o->reloc_count
-                          * sizeof (struct elf_link_hash_entry *)));
-         if (p == NULL && o->reloc_count != 0)
+         if (elf_section_data (o)->rel_hdr2
+             && !elf_link_size_reloc_section (abfd,
+                                              elf_section_data (o)->rel_hdr2,
+                                              o))
            goto error_return;
-         elf_section_data (o)->rel_hashes = p;
-         pend = p + o->reloc_count;
-         for (; p < pend; p++)
-           *p = NULL;
-
-         /* Use the reloc_count field as an index when outputting the
-            relocs.  */
-         o->reloc_count = 0;
        }
+
+      /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them
+        to count upwards while actually outputting the relocations. */
+      elf_section_data (o)->rel_count = 0;
+      elf_section_data (o)->rel_count2 = 0;
     }
 
   _bfd_elf_assign_file_positions_for_relocs (abfd);
@@ -3780,7 +4331,7 @@ elf_bfd_final_link (abfd, info)
      .symtab and .strtab.  We start the .symtab section at the current
      file position, and write directly to it.  We build the .strtab
      section in memory.  */
-  abfd->symcount = 0;
+  bfd_get_symcount (abfd) = 0;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   /* sh_name is set in prep_headers.  */
   symtab_hdr->sh_type = SHT_SYMTAB;
@@ -3813,7 +4364,7 @@ elf_bfd_final_link (abfd, info)
 
   /* 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 || info->relocateable || info->emitrelocations)
     {
       elfsym.st_value = 0;
       elfsym.st_size = 0;
@@ -3846,7 +4397,7 @@ 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 || info->relocateable || info->emitrelocations)
     {
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
@@ -3855,7 +4406,7 @@ elf_bfd_final_link (abfd, info)
        {
          o = section_from_elf_index (abfd, i);
          if (o != NULL)
-           o->target_index = abfd->symcount;
+           o->target_index = bfd_get_symcount (abfd);
          elfsym.st_shndx = i;
          if (info->relocateable || o == NULL)
            elfsym.st_value = 0;
@@ -3873,7 +4424,8 @@ elf_bfd_final_link (abfd, info)
   finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
   finfo.internal_relocs = ((Elf_Internal_Rela *)
                           bfd_malloc (max_internal_reloc_count
-                                      * sizeof (Elf_Internal_Rela)));
+                                      * sizeof (Elf_Internal_Rela)
+                                      * bed->s->int_rels_per_ext_rel));
   finfo.external_syms = ((Elf_External_Sym *)
                         bfd_malloc (max_sym_count
                                     * sizeof (Elf_External_Sym)));
@@ -3945,9 +4497,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
@@ -3964,11 +4518,79 @@ elf_bfd_final_link (abfd, info)
        return false;
     }
 
-  /* The sh_info field records the index of the first non local
-     symbol.  */
-  symtab_hdr->sh_info = abfd->symcount;
+  /* The sh_info field records the index of the first non local symbol.  */
+  symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
   if (dynamic)
-    elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
+    {
+      Elf_Internal_Sym sym;
+      Elf_External_Sym *dynsym =
+       (Elf_External_Sym *)finfo.dynsym_sec->contents;
+      long last_local = 0;
+
+      /* Write out the section symbols for the output sections.  */
+      if (info->shared)
+       {
+         asection *s;
+
+         sym.st_size = 0;
+         sym.st_name = 0;
+         sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+         sym.st_other = 0;
+
+         for (s = abfd->sections; s != NULL; s = s->next)
+           {
+             int indx;
+             indx = elf_section_data (s)->this_idx;
+             BFD_ASSERT (indx > 0);
+             sym.st_shndx = indx;
+             sym.st_value = s->vma;
+
+             elf_swap_symbol_out (abfd, &sym,
+                                  dynsym + elf_section_data (s)->dynindx);
+           }
+
+         last_local = bfd_count_sections (abfd);
+       }
+
+      /* Write out the local dynsyms.  */
+      if (elf_hash_table (info)->dynlocal)
+       {
+         struct elf_link_local_dynamic_entry *e;
+         for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+           {
+             asection *s;
+
+             sym.st_size = e->isym.st_size;
+             sym.st_other = e->isym.st_other;
+
+             /* Copy the internal symbol as is.
+                Note that we saved a word of storage and overwrote
+                 the original st_name with the dynstr_index.  */
+              sym = e->isym;
+
+             if (e->isym.st_shndx > 0 && e->isym.st_shndx < SHN_LORESERVE)
+               {
+                 s = bfd_section_from_elf_index (e->input_bfd,
+                                                 e->isym.st_shndx);
+
+                 sym.st_shndx =
+                   elf_section_data (s->output_section)->this_idx;
+                 sym.st_value = (s->output_section->vma
+                                 + s->output_offset
+                                 + e->isym.st_value);
+               }
+
+             if (last_local < e->dynindx)
+               last_local = e->dynindx;
+
+             elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx);
+           }
+       }
+
+      elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+       last_local + 1;
+    }
 
   /* We get the global symbols from the hash table.  */
   eoinfo.failed = false;
@@ -3979,6 +4601,18 @@ elf_bfd_final_link (abfd, info)
   if (eoinfo.failed)
     return false;
 
+  /* If backend needs to output some symbols not present in the hash
+     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))
+       return false;
+    }      
+
   /* Flush all symbols to the file.  */
   if (! elf_link_flush_output_syms (&finfo))
     return false;
@@ -4003,7 +4637,7 @@ elf_bfd_final_link (abfd, info)
   off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, true);
   elf_tdata (abfd)->next_file_pos = off;
 
-  if (abfd->symcount > 0)
+  if (bfd_get_symcount (abfd) > 0)
     {
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
          || ! _bfd_stringtab_emit (abfd, finfo.symstrtab))
@@ -4013,47 +4647,17 @@ elf_bfd_final_link (abfd, info)
   /* Adjust the relocs to have the correct symbol indices.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
-      struct elf_link_hash_entry **rel_hash;
-      Elf_Internal_Shdr *rel_hdr;
-
       if ((o->flags & SEC_RELOC) == 0)
        continue;
 
-      rel_hash = elf_section_data (o)->rel_hashes;
-      rel_hdr = &elf_section_data (o)->rel_hdr;
-      for (i = 0; i < o->reloc_count; i++, rel_hash++)
-       {
-         if (*rel_hash == NULL)
-           continue;
-
-         BFD_ASSERT ((*rel_hash)->indx >= 0);
-
-         if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-           {
-             Elf_External_Rel *erel;
-             Elf_Internal_Rel irel;
-
-             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);
-           }
-         else
-           {
-             Elf_External_Rela *erela;
-             Elf_Internal_Rela irela;
-
-             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);
-           }
-       }
+      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_count));
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -4084,15 +4688,11 @@ elf_bfd_final_link (abfd, info)
            {
            default:
              break;
-
-             /* SVR4 linkers seem to set DT_INIT and DT_FINI based on
-                 magic _init and _fini symbols.  This is pretty ugly,
-                 but we are compatible.  */
            case DT_INIT:
-             name = "_init";
+             name = info->init_function;
              goto get_sym;
            case DT_FINI:
-             name = "_fini";
+             name = info->fini_function;
            get_sym:
              {
                struct elf_link_hash_entry *h;
@@ -4309,6 +4909,8 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
 
   if (name == (const char *) NULL || *name == '\0')
     elfsym->st_name = 0;
+  else if (input_sec->flags & SEC_EXCLUDE)
+    elfsym->st_name = 0;
   else
     {
       elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab,
@@ -4328,7 +4930,7 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
                       (PTR) (finfo->symbuf + finfo->symbuf_count));
   ++finfo->symbuf_count;
 
-  ++finfo->output_bfd->symcount;
+  ++ bfd_get_symcount (finfo->output_bfd);
 
   return true;
 }
@@ -4398,14 +5000,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->shared
+           && !finfo->info->no_undefined)
       && 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, 0, true)))
        {
          eoinfo->failed = true;
          return false;
@@ -4433,8 +5036,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;
@@ -4514,12 +5119,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
@@ -4549,6 +5151,31 @@ elf_link_output_extsym (h, data)
        }
     }
 
+  /* If we are marking the symbol as undefined, and there are no
+     non-weak references to this symbol from a regular object, then
+     mark the symbol as weak undefined; if there are non-weak
+     references, mark the symbol as strong.  We can't do this earlier,
+     because it might not be marked as undefined until the
+     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))
+    {
+      int bindtype;
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0)
+       bindtype = STB_GLOBAL;
+      else
+       bindtype = STB_WEAK;
+      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 ((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.  */
@@ -4557,6 +5184,7 @@ elf_link_output_extsym (h, data)
     {
       size_t bucketcount;
       size_t bucket;
+      size_t hash_entry_size;
       bfd_byte *bucketpos;
       bfd_vma chain;
 
@@ -4569,13 +5197,15 @@ elf_link_output_extsym (h, data)
 
       bucketcount = elf_hash_table (finfo->info)->bucketcount;
       bucket = h->elf_hash_value % bucketcount;
+      hash_entry_size 
+       = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
       bucketpos = ((bfd_byte *) finfo->hash_sec->contents
-                  + (bucket + 2) * (ARCH_SIZE / 8));
-      chain = get_word (finfo->output_bfd, bucketpos);
-      put_word (finfo->output_bfd, h->dynindx, bucketpos);
-      put_word (finfo->output_bfd, chain,
-               ((bfd_byte *) finfo->hash_sec->contents
-                + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8)));
+                  + (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, chain,
+              ((bfd_byte *) finfo->hash_sec->contents
+               + (bucketcount + 2 + h->dynindx) * hash_entry_size));
 
       if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
        {
@@ -4611,7 +5241,7 @@ elf_link_output_extsym (h, data)
   if (strip)
     return true;
 
-  h->indx = finfo->output_bfd->symcount;
+  h->indx = bfd_get_symcount (finfo->output_bfd);
 
   if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
     {
@@ -4622,6 +5252,84 @@ elf_link_output_extsym (h, data)
   return true;
 }
 
+/* Copy the relocations indicated by the INTERNAL_RELOCS (which
+   originated from the section given by INPUT_REL_HDR) to the
+   OUTPUT_BFD.  */
+
+static void
+elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, 
+                       internal_relocs)
+     bfd *output_bfd;
+     asection *input_section;
+     Elf_Internal_Shdr *input_rel_hdr;
+     Elf_Internal_Rela *internal_relocs;
+{
+  Elf_Internal_Rela *irela;
+  Elf_Internal_Rela *irelaend;
+  Elf_Internal_Shdr *output_rel_hdr;
+  asection *output_section;
+  unsigned int *rel_countp = NULL;
+  struct elf_backend_data *bed;
+
+  output_section = input_section->output_section;
+  output_rel_hdr = NULL;
+
+  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;
+      rel_countp = &elf_section_data (output_section)->rel_count;
+    }
+  else if (elf_section_data (output_section)->rel_hdr2
+          && (elf_section_data (output_section)->rel_hdr2->sh_entsize
+              == input_rel_hdr->sh_entsize))
+    {
+      output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
+      rel_countp = &elf_section_data (output_section)->rel_count2;
+    }
+
+  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;
+  if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+    {
+      Elf_External_Rel *erel;
+
+      erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp);
+      for (; irela < irelaend; irela++, erel++)
+       {
+         Elf_Internal_Rel irel;
+
+         irel.r_offset = irela->r_offset;
+         irel.r_info = irela->r_info;
+         BFD_ASSERT (irela->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);
+       }
+    }
+  else
+    {
+      Elf_External_Rela *erela;
+
+      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++)
+       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;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.
    This is so that we only have to read the local symbols once, and
@@ -4647,10 +5355,11 @@ elf_link_input_bfd (finfo, input_bfd)
   long *pindex;
   asection **ppsection;
   asection *o;
+  struct elf_backend_data *bed;
 
   output_bfd = finfo->output_bfd;
-  relocate_section =
-    get_elf_backend_data (output_bfd)->elf_backend_relocate_section;
+  bed = get_elf_backend_data (output_bfd);
+  relocate_section = bed->elf_backend_relocate_section;
 
   /* If this is a dynamic object, we don't want to do anything here:
      we don't want the local symbols, and we don't want the section
@@ -4785,7 +5494,7 @@ elf_link_input_bfd (finfo, input_bfd)
       if (osym.st_shndx == (unsigned short) -1)
        return false;
 
-      *pindex = output_bfd->symcount;
+      *pindex = bfd_get_symcount (output_bfd);
 
       /* ELF symbols in relocateable files are section relative, but
         in executable files they are virtual addresses.  Note that
@@ -4877,20 +5586,21 @@ elf_link_input_bfd (finfo, input_bfd)
                                     finfo->sections))
            return false;
 
-         if (finfo->info->relocateable)
+         if (finfo->info->relocateable || finfo->info->emitrelocations)
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
              struct elf_link_hash_entry **rel_hash;
              Elf_Internal_Shdr *input_rel_hdr;
-             Elf_Internal_Shdr *output_rel_hdr;
 
              /* Adjust the reloc addresses and symbol indices.  */
 
              irela = internal_relocs;
-             irelaend = irela + o->reloc_count;
+             irelaend = 
+               irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
-                         + o->output_section->reloc_count);
+                         + elf_section_data (o->output_section)->rel_count
+                         + elf_section_data (o->output_section)->rel_count2);
              for (; irela < irelaend; irela++, rel_hash++)
                {
                  unsigned long r_symndx;
@@ -4899,6 +5609,10 @@ elf_link_input_bfd (finfo, input_bfd)
 
                  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)
@@ -4999,7 +5713,7 @@ elf_link_input_bfd (finfo, input_bfd)
                          if (! finfo->info->relocateable)
                            isym->st_value += osec->vma;
 
-                         finfo->indices[r_symndx] = output_bfd->symcount;
+                         finfo->indices[r_symndx] = bfd_get_symcount (output_bfd);
 
                          if (! elf_link_output_sym (finfo, name, isym, sec))
                            return false;
@@ -5014,40 +5728,16 @@ elf_link_input_bfd (finfo, input_bfd)
 
              /* Swap out the relocs.  */
              input_rel_hdr = &elf_section_data (o)->rel_hdr;
-             output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr;
-             BFD_ASSERT (output_rel_hdr->sh_entsize
-                         == input_rel_hdr->sh_entsize);
-             irela = internal_relocs;
-             irelaend = irela + o->reloc_count;
-             if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
-               {
-                 Elf_External_Rel *erel;
-
-                 erel = ((Elf_External_Rel *) output_rel_hdr->contents
-                         + o->output_section->reloc_count);
-                 for (; irela < irelaend; irela++, erel++)
-                   {
-                     Elf_Internal_Rel irel;
-
-                     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);
-                   }
-               }
-             else
-               {
-                 Elf_External_Rela *erela;
-
-                 BFD_ASSERT (input_rel_hdr->sh_entsize
-                             == sizeof (Elf_External_Rela));
-                 erela = ((Elf_External_Rela *) output_rel_hdr->contents
-                          + o->output_section->reloc_count);
-                 for (; irela < irelaend; irela++, erela++)
-                   elf_swap_reloca_out (output_bfd, irela, erela);
-               }
-
-             o->output_section->reloc_count += o->reloc_count;
+             elf_link_output_relocs (output_bfd, o, 
+                                     input_rel_hdr,
+                                     internal_relocs);
+             internal_relocs 
+               += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+             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);
            }
        }
 
@@ -5092,6 +5782,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)
@@ -5104,7 +5795,8 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
 
   /* Figure out the symbol index.  */
   rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
-                 + output_section->reloc_count);
+                 + elf_section_data (output_section)->rel_count
+                 + elf_section_data (output_section)->rel_count2);
   if (link_order->type == bfd_section_reloc_link_order)
     {
       indx = link_order->u.reloc.p->u.section->target_index;
@@ -5213,8 +5905,11 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       irel.r_offset = offset;
       irel.r_info = ELF_R_INFO (indx, howto->type);
       erel = ((Elf_External_Rel *) rel_hdr->contents
-             + output_section->reloc_count);
-      elf_swap_reloc_out (output_bfd, &irel, erel);
+             + elf_section_data (output_section)->rel_count);
+      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);
     }
   else
     {
@@ -5225,11 +5920,14 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       irela.r_info = ELF_R_INFO (indx, howto->type);
       irela.r_addend = addend;
       erela = ((Elf_External_Rela *) rel_hdr->contents
-              + output_section->reloc_count);
-      elf_swap_reloca_out (output_bfd, &irela, erela);
+              + elf_section_data (output_section)->rel_count);
+      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);
     }
 
-  ++output_section->reloc_count;
+  ++elf_section_data (output_section)->rel_count;
 
   return true;
 }
@@ -5449,8 +6147,8 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
              elf_swap_reloca_out (output_bfd, &outrel,
                                   (((Elf_External_Rela *)
                                     lsect->section->contents)
-                                   + lsect->section->reloc_count));
-             ++lsect->section->reloc_count;
+                                   + elf_section_data (lsect->section)->rel_count));
+             ++elf_section_data (lsect->section)->rel_count;
            }
        }
     }
@@ -5522,6 +6220,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
       size_t extsymoff;
       Elf_External_Sym *locsyms, *freesyms = NULL;
       bfd *input_bfd = sec->owner;
+      struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
 
       /* GCFIXME: how to arrange so that relocs and symbols are not
         reread continually?  */
@@ -5565,7 +6264,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
          ret = false;
          goto out1;
        }
-      relend = relstart + sec->reloc_count;
+      relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
       for (rel = relstart; rel < relend; rel++)
        {
@@ -5634,6 +6333,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.  */
@@ -5771,6 +6473,7 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
   asection *sec;
   bfd_vma hstart, hend;
   Elf_Internal_Rela *relstart, *relend, *rel;
+  struct elf_backend_data *bed;
 
   /* Take care of both those symbols that do not describe vtables as
      well as those that are not loaded.  */
@@ -5788,7 +6491,8 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
              (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true));
   if (!relstart)
     return *(boolean *)okp = false;
-  relend = relstart + sec->reloc_count;
+  bed = get_elf_backend_data (sec->owner);
+  relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
   for (rel = relstart; rel < relend; ++rel)
     if (rel->r_offset >= hstart && rel->r_offset < hend)
@@ -5822,7 +6526,7 @@ elf_gc_sections (abfd, info)
              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;
 
@@ -5846,6 +6550,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)
@@ -5922,8 +6630,8 @@ win:
 
 boolean
 elf_gc_record_vtentry (abfd, sec, h, addend)
-     bfd *abfd;
-     asection *sec;
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec ATTRIBUTE_UNUSED;
      struct elf_link_hash_entry *h;
      bfd_vma addend;
 {
@@ -5949,30 +6657,31 @@ 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)
        {
-         size_t oldbytes;
-
-         ptr = realloc (ptr-1, bytes);
-         if (ptr == NULL)
-           return false;
+         ptr = bfd_realloc (ptr - 1, bytes);
+         
+         if (ptr != NULL)
+           {
+             size_t oldbytes;
 
-         oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof(boolean);
-         memset (ptr + oldbytes, 0, bytes - oldbytes);
+             oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof (boolean);
+             memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes);
+           }
        }
       else
-       {
-         ptr = calloc (1, bytes);
-         if (ptr == NULL)
-           return false;
-       }
+       ptr = bfd_zmalloc (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_used = ptr + 1;
       h->vtable_entries_size = size;
     }
+  
   h->vtable_entries_used[addend / FILE_ALIGN] = true;
 
   return true;
@@ -6000,10 +6709,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;
 
@@ -6025,7 +6738,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);
This page took 0.055262 seconds and 4 git commands to generate.