* elflink.h (elf_link_add_object_symbols): Don't let a common
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 940bd2a92c7f0af4de5614e46e3203dadd41eb49..09a7d8b2252d7998f1ac63001bee441c84cc220d 100644 (file)
@@ -19,12 +19,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* ELF linker code.  */
 
+/* This struct is used to pass information to routines called via
+   elf_link_hash_traverse which must return failure.  */
+
+struct elf_info_failed
+{
+  boolean failed;
+  struct bfd_link_info *info;
+};
+
 static boolean elf_link_add_object_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_link_add_archive_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_fix_symbol_flags
+  PARAMS ((struct elf_link_hash_entry *, struct elf_info_failed *));
 static boolean elf_adjust_dynamic_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_link_find_version_dependencies
@@ -36,15 +47,6 @@ static boolean elf_link_assign_sym_version
 static boolean elf_link_renumber_dynsyms
   PARAMS ((struct elf_link_hash_entry *, PTR));
 
-/* This struct is used to pass information to routines called via
-   elf_link_hash_traverse which must return failure.  */
-
-struct elf_info_failed
-{
-  boolean failed;
-  struct bfd_link_info *info;
-};
-
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
 
@@ -395,57 +397,8 @@ elf_link_add_object_symbols (abfd, info)
     {
       /* Read in any version definitions.  */
 
-      if (elf_dynverdef (abfd) != 0)
-       {
-         Elf_Internal_Shdr *verdefhdr;
-         bfd_byte *dynver;
-         int i;
-         const Elf_External_Verdef *extverdef;
-         Elf_Internal_Verdef *intverdef;
-
-         verdefhdr = &elf_tdata (abfd)->dynverdef_hdr;
-         elf_tdata (abfd)->verdef =
-           ((Elf_Internal_Verdef *)
-            bfd_zalloc (abfd,
-                        verdefhdr->sh_info * sizeof (Elf_Internal_Verdef)));
-         if (elf_tdata (abfd)->verdef == NULL)
-           goto error_return;
-
-         dynver = (bfd_byte *) bfd_malloc (verdefhdr->sh_size);
-         if (dynver == NULL)
-           goto error_return;
-
-         if (bfd_seek (abfd, verdefhdr->sh_offset, SEEK_SET) != 0
-             || (bfd_read ((PTR) dynver, 1, verdefhdr->sh_size, abfd)
-                 != verdefhdr->sh_size))
-           goto error_return;
-
-         extverdef = (const Elf_External_Verdef *) dynver;
-         intverdef = elf_tdata (abfd)->verdef;
-         for (i = 0; i < verdefhdr->sh_info; i++, intverdef++)
-           {
-             const Elf_External_Verdaux *extverdaux;
-             Elf_Internal_Verdaux intverdaux;
-
-             _bfd_elf_swap_verdef_in (abfd, extverdef, intverdef);
-
-             /* Pick up the name of the version.  */
-             extverdaux = ((const Elf_External_Verdaux *)
-                           ((bfd_byte *) extverdef + intverdef->vd_aux));
-             _bfd_elf_swap_verdaux_in (abfd, extverdaux, &intverdaux);
-
-             intverdef->vd_bfd = abfd;
-             intverdef->vd_nodename =
-               bfd_elf_string_from_elf_section (abfd, verdefhdr->sh_link,
-                                                intverdaux.vda_name);
-
-             extverdef = ((const Elf_External_Verdef *)
-                          ((bfd_byte *) extverdef + intverdef->vd_next));
-           }
-
-         free (dynver);
-         dynver = NULL;
-       }
+      if (! _bfd_elf_slurp_version_tables (abfd))
+       goto error_return;
 
       /* Read in the symbol versions, but don't bother to convert them
          to internal format.  */
@@ -679,7 +632,7 @@ elf_link_add_object_symbols (abfd, info)
 
   weaks = NULL;
 
-  ever = extversym != NULL ? extversym + hdr->sh_info : NULL;
+  ever = extversym != NULL ? extversym + extsymoff : NULL;
   esymend = buf + extsymcount;
   for (esym = buf;
        esym < esymend;
@@ -695,6 +648,7 @@ elf_link_add_object_symbols (abfd, info)
       boolean definition;
       boolean size_change_ok, type_change_ok;
       boolean new_weakdef;
+      unsigned int old_alignment;
 
       elf_swap_symbol_in (abfd, esym, &sym);
 
@@ -732,10 +686,10 @@ elf_link_add_object_symbols (abfd, info)
       else if (sym.st_shndx > 0 && sym.st_shndx < SHN_LORESERVE)
        {
          sec = section_from_elf_index (abfd, sym.st_shndx);
-         if (sec != NULL)
-           value -= sec->vma;
-         else
+         if (sec == NULL)
            sec = bfd_abs_section_ptr;
+         else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+           value -= sec->vma;
        }
       else if (sym.st_shndx == SHN_ABS)
        sec = bfd_abs_section_ptr;
@@ -782,10 +736,12 @@ elf_link_add_object_symbols (abfd, info)
 
       size_change_ok = false;
       type_change_ok = get_elf_backend_data (abfd)->type_change_ok;
+      old_alignment = 0;
       if (info->hash->creator->flavour == bfd_target_elf_flavour)
        {
          Elf_Internal_Versym iver;
          int vernum;
+         boolean indirect;
          boolean override;
 
          if (ever != NULL)
@@ -805,10 +761,58 @@ elf_link_add_object_symbols (abfd, info)
                  int namelen, newlen;
                  char *newname, *p;
 
-                 if (vernum > 1)
-                   verstr = elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+                 if (sym.st_shndx != SHN_UNDEF)
+                   {
+                     if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info)
+                       {
+                         (*_bfd_error_handler)
+                           ("%s: %s: invalid version %d (max %d)",
+                            abfd->filename, name, vernum,
+                            elf_tdata (abfd)->dynverdef_hdr.sh_info);
+                         bfd_set_error (bfd_error_bad_value);
+                         goto error_return;
+                       }
+                     else if (vernum > 1)
+                       verstr =
+                         elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+                     else
+                       verstr = "";
+                   }
                  else
-                   verstr = "";
+                   {
+                     /* We cannot simply test for the number of
+                        entries in the VERNEED section since the
+                        numbers for the needed versions do not start
+                        at 0.  */
+                     Elf_Internal_Verneed *t;
+
+                     verstr = NULL;
+                     for (t = elf_tdata (abfd)->verref;
+                          t != NULL;
+                          t = t->vn_nextref)
+                       {
+                         Elf_Internal_Vernaux *a;
+
+                         for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
+                           {
+                             if (a->vna_other == vernum)
+                               {
+                                 verstr = a->vna_nodename;
+                                 break;
+                               }
+                           }
+                         if (a != NULL)
+                           break;
+                       }
+                     if (verstr == NULL)
+                       {
+                         (*_bfd_error_handler)
+                           ("%s: %s: invalid needed version %d",
+                            abfd->filename, name, vernum);
+                         bfd_set_error (bfd_error_bad_value);
+                         goto error_return;
+                       }
+                   }
 
                  namelen = strlen (name);
                  newlen = namelen + strlen (verstr) + 2;
@@ -847,14 +851,24 @@ elf_link_add_object_symbols (abfd, info)
          if (h->root.type == bfd_link_hash_new)
            h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
 
+         indirect = false;
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           {
+             if (h->root.type == bfd_link_hash_indirect)
+               indirect = true;
+             h = (struct elf_link_hash_entry *) h->root.u.i.link;
+           }
+
+         /* FIXME: There are too many cases here, and it's too
+             confusing.  This code needs to be reorganized somehow.  */
 
          /* It's OK to change the type if it used to be a weak
-             definition.  */
+             definition, or if the current definition is weak (and
+             hence might be ignored).  */
          if (h->root.type == bfd_link_hash_defweak
-             || h->root.type == bfd_link_hash_undefweak)
+             || h->root.type == bfd_link_hash_undefweak
+             || bind == STB_WEAK)
            type_change_ok = true;
 
          /* It's OK to change the size if it used to be a weak
@@ -864,6 +878,9 @@ elf_link_add_object_symbols (abfd, info)
              || h->root.type == bfd_link_hash_undefined)
            size_change_ok = true;
 
+         if (h->root.type == bfd_link_hash_common)
+           old_alignment = h->root.u.c.p->alignment_power;
+
          override = false;
 
          /* If we are looking at a dynamic object, and this is a
@@ -885,6 +902,39 @@ elf_link_add_object_symbols (abfd, info)
                      && (bind == STB_WEAK
                          || ELF_ST_TYPE (sym.st_info) == STT_FUNC)))
                {
+                 /* In the special case of two symbols which look
+                     like common symbols in a dynamic object, set the
+                     size of the symbol to the larger of the two.  */
+                 if ((sec->flags & SEC_ALLOC) != 0
+                     && (sec->flags & SEC_LOAD) == 0
+                     && sym.st_size > 0
+                     && bind != STB_WEAK
+                     && ELF_ST_TYPE (sym.st_info) != STT_FUNC
+                     && h->root.type == bfd_link_hash_defined
+                     && (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                     && (h->root.u.def.section->owner->flags & DYNAMIC) != 0
+                     && (h->root.u.def.section->flags & SEC_ALLOC) != 0
+                     && (h->root.u.def.section->flags & SEC_LOAD) == 0
+                     && h->size > 0
+                     && h->type != STT_FUNC
+                     && sym.st_size != h->size)
+                   {
+                     /* Note that we only warn if the size is
+                         different.  If the size is the same, then we
+                         simply let the first shared library override
+                         the second.  */
+                     if (! ((*info->callbacks->multiple_common)
+                            (info, h->root.root.string,
+                             h->root.u.def.section->owner,
+                             bfd_link_hash_common,
+                             h->size, abfd, bfd_link_hash_common,
+                             sym.st_size)))
+                       goto error_return;
+                     if (sym.st_size > h->size)
+                       h->size = sym.st_size;
+                   }
+
                  override = true;
                  sec = bfd_und_section_ptr;
                  definition = false;
@@ -894,12 +944,32 @@ elf_link_add_object_symbols (abfd, info)
                }
            }
 
-         /* Similarly, if we are not looking at a dynamic object, and
-            we have a definition, we want to override any definition
-            we may have from a dynamic object.  Symbols from regular
-            files always take precedence over symbols from dynamic
-            objects, even if they are defined after the dynamic
-            object in the link.  */
+         /* If we already have a common symbol, and the symbol in the
+             shared library is in an uninitialized section, then treat
+             the shared library symbol as a common symbol.  This will
+             not always be correct, but it should do little harm.  */
+         if (dynamic
+             && definition
+             && h->root.type == bfd_link_hash_common
+             && (sec->flags & SEC_ALLOC) != 0
+             && (sec->flags & SEC_LOAD) == 0
+             && sym.st_size > 0
+             && bind != STB_WEAK
+             && ELF_ST_TYPE (sym.st_info) != STT_FUNC)
+           {
+             override = true;
+             sec = bfd_com_section_ptr;
+             definition = false;
+             value = sym.st_size;
+             size_change_ok = true;
+           }
+
+         /* If we are not looking at a dynamic object, and we have a
+            definition, we want to override any definition we may
+            have from a dynamic object.  Symbols from regular files
+            always take precedence over symbols from dynamic objects,
+            even if they are defined after the dynamic object in the
+            link.  */
          if (! dynamic
              && (definition
                  || (bfd_is_com_section (sec)
@@ -927,6 +997,50 @@ elf_link_add_object_symbols (abfd, info)
              h->verinfo.vertree = NULL;
            }
 
+         /* If we are not looking at a shared library and we have a
+             common symbol, and the symbol in the shared library is in
+             an uninitialized section, then treat the shared library
+             symbol as a common symbol.  This will not always be
+             correct, but it should do little harm.  Note that the
+             above condition already handled cases in which a common
+             symbol should simply override the definition in the
+             shared library.  */
+         if (! dynamic
+             && ! override
+             && bfd_is_com_section (sec)
+             && h->root.type == bfd_link_hash_defined
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+             && (h->root.u.def.section->owner->flags & DYNAMIC) != 0
+             && (h->root.u.def.section->flags & SEC_ALLOC) != 0
+             && (h->root.u.def.section->flags & SEC_LOAD) == 0
+             && h->size > 0
+             && h->type != STT_FUNC
+             && ! indirect)
+           {
+             /* It would be best if we could set the hash table entry
+                 to a common symbol, but we don't know what to use for
+                 the section or the alignment.  */
+             if (! ((*info->callbacks->multiple_common)
+                    (info, h->root.root.string,
+                     h->root.u.def.section->owner, bfd_link_hash_common,
+                     h->size, abfd, bfd_link_hash_common, value)))
+               goto error_return;
+
+             if (h->size > value)
+               value = h->size;
+
+             /* FIXME: We no longer know the alignment required by
+                the symbol in the shared library, so we just wind up
+                using the one from the regular object.  */
+
+             override = true;
+             h->root.type = bfd_link_hash_undefined;
+             h->root.u.undef.abfd = h->root.u.def.section->owner;
+             size_change_ok = true;
+             type_change_ok = true;
+             h->verinfo.vertree = NULL;
+           }
+
          if (ever != NULL
              && ! override
              && vernum > 1
@@ -970,10 +1084,16 @@ elf_link_add_object_symbols (abfd, info)
          new_weakdef = true;
        }
 
-      /* Get the alignment of a common symbol.  */
+      /* Set the alignment of a common symbol.  */
       if (sym.st_shndx == SHN_COMMON
          && h->root.type == bfd_link_hash_common)
-       h->root.u.c.p->alignment_power = bfd_log2 (sym.st_value);
+       {
+         unsigned int align;
+
+         align = bfd_log2 (sym.st_value);
+         if (align > old_alignment)
+           h->root.u.c.p->alignment_power = align;
+       }
 
       if (info->hash->creator->flavour == bfd_target_elf_flavour)
        {
@@ -993,6 +1113,15 @@ elf_link_add_object_symbols (abfd, info)
 
              h->size = sym.st_size;
            }
+
+         /* If this is a common symbol, then we always want H->SIZE
+             to be the size of the common symbol.  The code just above
+             won't fix the size if a common symbol becomes larger.  We
+             don't warn about a size change here, because that is
+             covered by --warn-common.  */
+         if (h->root.type == bfd_link_hash_common)
+           h->size = h->root.u.c.size;
+
          if (ELF_ST_TYPE (sym.st_info) != STT_NOTYPE
              && (definition || h->type == STT_NOTYPE))
            {
@@ -1058,7 +1187,7 @@ elf_link_add_object_symbols (abfd, info)
              if (p != NULL && p[1] == ELF_VER_CHR)
                {
                  char *shortname;
-                 struct elf_link_hash_entry *hi;
+                 struct elf_link_hash_entry *hold;
 
                  shortname = bfd_hash_allocate (&info->hash->table,
                                                 p - name + 1);
@@ -1067,15 +1196,259 @@ elf_link_add_object_symbols (abfd, info)
                  strncpy (shortname, name, p - name);
                  shortname[p - name] = '\0';
 
-                 hi = NULL;
-                 if (! (_bfd_generic_link_add_one_symbol
-                        (info, abfd, shortname, BSF_INDIRECT,
-                         bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-                         collect, (struct bfd_link_hash_entry **) &hi)))
+                 /* First look to see if we have an existing symbol
+                     with this name.  */
+                 hold = elf_link_hash_lookup (elf_hash_table (info),
+                                              shortname, false, false,
+                                              false);
+
+                 /* If we are looking at a normal object, and the
+                     symbol was seen in a shared object, clobber the
+                     definition in the shared object.  */
+                 if (hold != NULL
+                     && ! dynamic
+                     && (hold->root.type == bfd_link_hash_defined
+                         || hold->root.type == bfd_link_hash_defweak)
+                     && (hold->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                     && ((hold->root.u.def.section->owner->flags & DYNAMIC)
+                         != 0))
+                   {
+                     /* Change the hash table entry to undefined, so
+                         that _bfd_generic_link_add_one_symbol will do
+                         the right thing.  */
+                     hold->root.type = bfd_link_hash_undefined;
+                     hold->root.u.undef.abfd =
+                       hold->root.u.def.section->owner;
+                     hold->verinfo.vertree = NULL;
+                     hold = NULL;
+                   }
+
+                 /* If we are looking at a shared object, and we have
+                     already seen this symbol defined elsewhere, then
+                     don't try to define it again. */
+                 if (hold != NULL
+                     && dynamic
+                     && (hold->root.type == bfd_link_hash_defined
+                         || hold->root.type == bfd_link_hash_defweak
+                         || hold->root.type == bfd_link_hash_indirect
+                         || (hold->root.type == bfd_link_hash_common
+                             && (bind == STB_WEAK
+                                 || ELF_ST_TYPE (sym.st_info) == STT_FUNC))))
+                   {
+                     /* Don't add an indirect symbol.  */
+                   }
+                 else
+                   {
+                     struct elf_link_hash_entry *hi;
+
+                     hi = NULL;
+                     if (! (_bfd_generic_link_add_one_symbol
+                            (info, abfd, shortname, BSF_INDIRECT,
+                             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
+                             collect, (struct bfd_link_hash_entry **) &hi)))
+                       goto error_return;
+
+                     /* If there is a duplicate definition somewhere,
+                         then HI may not point to an indirect symbol.
+                         We will have reported an error to the user in
+                         that case.  */
+
+                     if (hi->root.type == bfd_link_hash_indirect)
+                       {
+                         hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+
+                         /* If the symbol became indirect, then we
+                             assume that we have not seen a definition
+                             before.  */
+                         BFD_ASSERT ((hi->elf_link_hash_flags
+                                      & (ELF_LINK_HASH_DEF_DYNAMIC
+                                         | 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 table offset entry.
+                             This 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->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.  */
+
+                         /* See if the new flags lead us to realize
+                             that the symbol must be dynamic.  */
+                         if (! dynsym)
+                           {
+                             if (! dynamic)
+                               {
+                                 if (info->shared
+                                     || ((hi->elf_link_hash_flags
+                                          & ELF_LINK_HASH_REF_DYNAMIC)
+                                         != 0))
+                                   dynsym = true;
+                               }
+                             else
+                               {
+                                 if ((hi->elf_link_hash_flags
+                                      & ELF_LINK_HASH_REF_REGULAR) != 0)
+                                   dynsym = true;
+                               }
+                           }
+                       }
+                   }
+
+                 /* We also need to define an indirection from the
+                     nondefault version of the symbol.  */
+
+                 shortname = bfd_hash_allocate (&info->hash->table,
+                                                strlen (name));
+                 if (shortname == NULL)
                    goto error_return;
+                 strncpy (shortname, name, p - name);
+                 strcpy (shortname + (p - name), p + 1);
+
+                 /* First look to see if we have an existing symbol
+                     with this name.  */
+                 hold = elf_link_hash_lookup (elf_hash_table (info),
+                                              shortname, false, false,
+                                              false);
+
+                 /* If we are looking at a normal object, and the
+                     symbol was seen in a shared object, clobber the
+                     definition in the shared object.  */
+                 if (hold != NULL
+                     && ! dynamic
+                     && (hold->root.type == bfd_link_hash_defined
+                         || hold->root.type == bfd_link_hash_defweak)
+                     && (hold->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                     && ((hold->root.u.def.section->owner->flags & DYNAMIC)
+                         != 0))
+                   {
+                     /* Change the hash table entry to undefined, so
+                         that _bfd_generic_link_add_one_symbol will do
+                         the right thing.  */
+                     hold->root.type = bfd_link_hash_undefined;
+                     hold->root.u.undef.abfd =
+                       hold->root.u.def.section->owner;
+                     hold->verinfo.vertree = NULL;
+                     hold = NULL;
+                   }
 
-                 if (hi->root.type == bfd_link_hash_indirect)
-                   hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+                 /* If we are looking at a shared object, and we have
+                     already seen this symbol defined elsewhere, then
+                     don't try to define it again. */
+                 if (hold != NULL
+                     && dynamic
+                     && (hold->root.type == bfd_link_hash_defined
+                         || hold->root.type == bfd_link_hash_defweak
+                         || hold->root.type == bfd_link_hash_indirect
+                         || (hold->root.type == bfd_link_hash_common
+                             && (bind == STB_WEAK
+                                 || ELF_ST_TYPE (sym.st_info) == STT_FUNC))))
+                   {
+                     /* Don't add an indirect symbol.  */
+                   }
+                 else
+                   {
+                     struct elf_link_hash_entry *hi;
+
+                     hi = NULL;
+                     if (! (_bfd_generic_link_add_one_symbol
+                            (info, abfd, shortname, BSF_INDIRECT,
+                             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
+                             collect, (struct bfd_link_hash_entry **) &hi)))
+                       goto error_return;
+
+                     /* If there is a duplicate definition somewhere,
+                         then HI may not point to an indirect symbol.
+                         We will have reported an error to the user in
+                         that case.  */
+
+                     if (hi->root.type == bfd_link_hash_indirect)
+                       {
+                         hi->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
+
+                         /* If the symbol became indirect, then we
+                             assume that we have not seen a definition
+                             before.  */
+                         BFD_ASSERT ((hi->elf_link_hash_flags
+                                      & (ELF_LINK_HASH_DEF_DYNAMIC
+                                         | 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 table offset entry.
+                             This 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->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.  */
+
+                         /* See if the new flags lead us to realize
+                             that the symbol must be dynamic.  */
+                         if (! dynsym)
+                           {
+                             if (! dynamic)
+                               {
+                                 if (info->shared
+                                     || ((hi->elf_link_hash_flags
+                                          & ELF_LINK_HASH_REF_DYNAMIC)
+                                         != 0))
+                                   dynsym = true;
+                               }
+                             else
+                               {
+                                 if ((hi->elf_link_hash_flags
+                                      & ELF_LINK_HASH_REF_REGULAR) != 0)
+                                   dynsym = true;
+                               }
+                           }
+                       }
+                   }
                }
            }
 
@@ -1210,7 +1583,10 @@ elf_link_add_object_symbols (abfd, info)
          boolean ok;
 
          if ((o->flags & SEC_RELOC) == 0
-             || o->reloc_count == 0)
+             || o->reloc_count == 0
+             || ((info->strip == strip_all || info->strip == strip_debugger)
+                 && (o->flags & SEC_DEBUGGING) != 0)
+             || bfd_is_abs_section (o->output_section))
            continue;
 
          internal_relocs = (NAME(_bfd_elf,link_read_relocs)
@@ -1672,6 +2048,8 @@ 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;
 
@@ -1770,6 +2148,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            }
        }
 
+      /* 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),
+                             elf_link_assign_sym_version,
+                             (PTR) &asvinfo);
+      if (asvinfo.failed)
+       return false;
+
       /* Find all symbols which were defined in a dynamic object and make
         the backend pick a reasonable value for them.  */
       eif.failed = false;
@@ -1813,6 +2205,7 @@ 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) (output_bfd, info))
     return false;
 
@@ -1827,26 +2220,15 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
       BFD_ASSERT (s != NULL);
+
+      /* We may have created additional version definitions if we are
+         just linking a regular application.  */
+      verdefs = asvinfo.verdefs;
+
       if (verdefs == NULL)
        {
-         struct elf_assign_sym_version_info sinfo;
          asection **spp;
 
-         /* No version script was used.  In this case, we just check
-             that there were no version overrides for any symbols.  */
-         sinfo.output_bfd = output_bfd;
-         sinfo.info = info;
-         sinfo.verdefs = verdefs;
-         sinfo.removed_dynamic = false;
-         sinfo.export_dynamic = export_dynamic;
-         sinfo.failed = false;
-
-         elf_link_hash_traverse (elf_hash_table (info),
-                                 elf_link_assign_sym_version,
-                                 (PTR) &sinfo);
-         if (sinfo.failed)
-           return false;
-
          /* Don't include this section in the output file.  */
          for (spp = &output_bfd->sections;
               *spp != s->output_section;
@@ -1857,7 +2239,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        }
       else
        {
-         struct elf_assign_sym_version_info sinfo;
          unsigned int cdefs;
          bfd_size_type size;
          struct bfd_elf_version_tree *t;
@@ -1865,28 +2246,18 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          Elf_Internal_Verdef def;
          Elf_Internal_Verdaux defaux;
 
-         /* Attach all of the symbols to their version information.
-             This may cause some symbols to be unexported.  */
-         sinfo.output_bfd = output_bfd;
-         sinfo.info = info;
-         sinfo.verdefs = verdefs;
-         sinfo.export_dynamic = export_dynamic;
-         sinfo.removed_dynamic = false;
-         sinfo.failed = false;
-         elf_link_hash_traverse (elf_hash_table (info),
-                                 elf_link_assign_sym_version,
-                                 (PTR) &sinfo);
-         if (sinfo.failed)
-           return false;
-
-         if (sinfo.removed_dynamic)
+         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.
-                 FIXME: The names of the removed symbols will still be
-                 in the dynamic string table, wasting space.  */
-             elf_hash_table (info)->dynsymcount = 1;
+                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);
@@ -1979,11 +2350,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              h->type = STT_OBJECT;
              h->verinfo.vertree = t;
 
-             if (info->shared)
-               {
-                 if (! _bfd_elf_link_record_dynamic_symbol (info, h))
-                   return false;
-               }
+             if (! _bfd_elf_link_record_dynamic_symbol (info, h))
+               return false;
 
              def.vd_version = VER_DEF_CURRENT;
              def.vd_flags = 0;
@@ -2075,6 +2443,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            bfd_byte *p;
 
            /* Build the version definition section.  */
+           size = 0;
+           crefs = 0;
            for (t = elf_tdata (output_bfd)->verref;
                 t != NULL;
                 t = t->vn_nextref)
@@ -2107,8 +2477,13 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
                t->vn_version = VER_NEED_CURRENT;
                t->vn_cnt = caux;
-               indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                          t->vn_bfd->filename, true, false);
+               if (elf_dt_name (t->vn_bfd) != NULL)
+                 indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+                                            elf_dt_name (t->vn_bfd),
+                                            true, false);
+               else
+                 indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+                                            t->vn_bfd->filename, true, false);
                if (indx == (bfd_size_type) -1)
                  return false;
                t->vn_file = indx;
@@ -2172,17 +2547,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        }
       else
        {
-         Elf_Internal_Versym intversym;
-
          s->_raw_size = dynsymcount * sizeof (Elf_External_Versym);
-         s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
+         s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size);
          if (s->contents == NULL)
            return false;
 
-         intversym.vs_vers = 0;
-         _bfd_elf_swap_versym_out (output_bfd, &intversym,
-                                   (Elf_External_Versym *) s->contents);
-
          if (! elf_add_dynamic_entry (info, DT_VERSYM, 0))
            return false;
        }
@@ -2241,23 +2610,17 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   return true;
 }
 \f
-/* Make the backend pick a good value for a dynamic symbol.  This is
-   called via elf_link_hash_traverse, and also calls itself
-   recursively.  */
+/* Fix up the flags for a symbol.  This handles various cases which
+   can only be fixed after all the input files are seen.  This is
+   currently called by both adjust_dynamic_symbol and
+   assign_sym_version, which is unnecessary but perhaps more robust in
+   the face of future changes.  */
 
 static boolean
-elf_adjust_dynamic_symbol (h, data)
+elf_fix_symbol_flags (h, eif)
      struct elf_link_hash_entry *h;
-     PTR data;
+     struct elf_info_failed *eif;
 {
-  struct elf_info_failed *eif = (struct elf_info_failed *) data;
-  bfd *dynobj;
-  struct elf_backend_data *bed;
-
-  /* Ignore indirect symbols.  There are added by the versioning code.  */
-  if (h->root.type == bfd_link_hash_indirect)
-    return true;
-
   /* If this symbol was mentioned in a non-ELF file, try to set
      DEF_REGULAR and REF_REGULAR correctly.  This is the only way to
      permit a non-ELF file to correctly refer to a symbol defined in
@@ -2277,8 +2640,9 @@ elf_adjust_dynamic_symbol (h, data)
            h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
        }
 
-      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-         || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)
+      if (h->dynindx == -1
+         && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+             || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
        {
          if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h))
            {
@@ -2310,6 +2674,30 @@ elf_adjust_dynamic_symbol (h, data)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
     h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
 
+  return true;
+}
+
+/* Make the backend pick a good value for a dynamic symbol.  This is
+   called via elf_link_hash_traverse, and also calls itself
+   recursively.  */
+
+static boolean
+elf_adjust_dynamic_symbol (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  struct elf_info_failed *eif = (struct elf_info_failed *) data;
+  bfd *dynobj;
+  struct elf_backend_data *bed;
+
+  /* Ignore indirect symbols.  These are added by the versioning code.  */
+  if (h->root.type == bfd_link_hash_indirect)
+    return true;
+
+  /* Fix the symbol flags.  */
+  if (! elf_fix_symbol_flags (h, eif))
+    return false;
+
   /* If this symbol does not require a PLT entry, and it is not
      defined by a dynamic object, or is not referenced by a regular
      object, ignore it.  We do have to handle a weak defined symbol,
@@ -2411,6 +2799,10 @@ elf_export_symbol (h, data)
 {
   struct elf_info_failed *eif = (struct elf_info_failed *) data;
 
+  /* Ignore indirect symbols.  These are added by the versioning code.  */
+  if (h->root.type == bfd_link_hash_indirect)
+    return true;
+
   if (h->dynindx == -1
       && (h->elf_link_hash_flags
          & (ELF_LINK_HASH_DEF_REGULAR | ELF_LINK_HASH_REF_REGULAR)) != 0)
@@ -2450,7 +2842,7 @@ elf_link_find_version_dependencies (h, data)
   /* See if we already know about this version.  */
   for (t = elf_tdata (rinfo->output_bfd)->verref; t != NULL; t = t->vn_nextref)
     {
-      if (t->vn_bfd == h->verinfo.verdef->vd_bfd)
+      if (t->vn_bfd != h->verinfo.verdef->vd_bfd)
        continue;
 
       for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
@@ -2510,8 +2902,19 @@ 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_info_failed eif;
   char *p;
 
+  /* Fix the symbol flags.  */
+  eif.failed = false;
+  eif.info = info;
+  if (! elf_fix_symbol_flags (h, &eif))
+    {
+      if (eif.failed)
+       sinfo->failed = true;
+      return false;
+    }
+
   /* We only need version numbers for symbols defined in regular
      objects.  */
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
@@ -2549,17 +2952,98 @@ elf_link_assign_sym_version (h, data)
            {
              h->verinfo.vertree = t;
              t->used = true;
+
+             /* See if there is anything to force this symbol to
+                 local scope.  */
+             if (t->locals != NULL)
+               {
+                 int len;
+                 char *alc;
+                 struct bfd_elf_version_expr *d;
+
+                 len = p - h->root.root.string;
+                 alc = bfd_alloc (sinfo->output_bfd, len);
+                 if (alc == NULL)
+                   return false;
+                 strncpy (alc, h->root.root.string, len - 1);
+                 alc[len - 1] = '\0';
+                 if (alc[len - 2] == ELF_VER_CHR)
+                   alc[len - 2] = '\0';
+
+                 for (d = t->locals; d != NULL; d = d->next)
+                   {
+                     if ((d->match[0] == '*' && d->match[1] == '\0')
+                         || fnmatch (d->match, alc, 0) == 0)
+                       {
+                         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;
+                             /* FIXME: The name of the symbol has
+                                already been recorded in the dynamic
+                                string table section.  */
+                           }
+
+                         break;
+                       }
+                   }
+
+                 bfd_release (sinfo->output_bfd, alc);
+               }
+
              break;
            }
        }
 
-      if (t == NULL)
+      /* If we are building an application, we need to create a
+         version node for this version.  */
+      if (t == NULL && ! info->shared)
        {
-         /* We could not find the version.  Return an error.
-            FIXME: Why?  */
+         struct bfd_elf_version_tree **pp;
+         int version_index;
+
+         /* If we aren't going to export this symbol, we don't need
+             to worry about it. */
+         if (h->dynindx == -1)
+           return true;
+
+         t = ((struct bfd_elf_version_tree *)
+              bfd_alloc (sinfo->output_bfd, sizeof *t));
+         if (t == NULL)
+           {
+             sinfo->failed = true;
+             return false;
+           }
+
+         t->next = NULL;
+         t->name = p;
+         t->globals = NULL;
+         t->locals = NULL;
+         t->deps = NULL;
+         t->name_indx = (unsigned int) -1;
+         t->used = true;
+
+         version_index = 1;
+         for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
+           ++version_index;
+         t->vernum = version_index;
+
+         *pp = t;
+
+         h->verinfo.vertree = t;
+       }
+      else if (t == NULL)
+       {
+         /* We could not find the version for a symbol when
+             generating a shared archive.  Return an error.  */
          (*_bfd_error_handler)
-           ("%s: invalid version %s", bfd_get_filename (sinfo->output_bfd),
-            h->root.root.string);
+           ("%s: undefined version name %s",
+            bfd_get_filename (sinfo->output_bfd), h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
          sinfo->failed = true;
          return false;
@@ -2578,7 +3062,7 @@ elf_link_assign_sym_version (h, data)
       struct bfd_elf_version_expr *d;
 
       /* See if can find what version this symbol is in.  If the
-         symbol is supposed to eb local, then don't actually register
+         symbol is supposed to be local, then don't actually register
          it.  */
       deflt = NULL;
       for (t = sinfo->verdefs; t != NULL; t = t->next)
@@ -2609,11 +3093,11 @@ elf_link_assign_sym_version (h, data)
                      h->verinfo.vertree = t;
                      if (h->dynindx != -1
                          && info->shared
-                         && ! sinfo->export_dynamic
-                         && (h->elf_link_hash_flags
-                             & ELF_LINK_HASH_NEEDS_PLT) == 0)
+                         && ! 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;
                          /* FIXME: The name of the symbol has already
                             been recorded in the dynamic string table
@@ -2633,10 +3117,11 @@ elf_link_assign_sym_version (h, data)
          h->verinfo.vertree = deflt;
          if (h->dynindx != -1
              && info->shared
-             && ! sinfo->export_dynamic
-             && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0)
+             && ! 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;
              /* FIXME: The name of the symbol has already been
                 recorded in the dynamic string table section.  */
@@ -2724,12 +3209,12 @@ static boolean elf_reloc_link_order
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
           struct bfd_link_order *));
 
-/* This struct is used to pass information to routines called via
-   elf_link_hash_traverse which must return failure.  */
+/* This struct is used to pass information to elf_link_output_extsym.  */
 
-struct elf_finfo_failed
+struct elf_outext_info
 {
   boolean failed;
+  boolean localsyms;
   struct elf_final_link_info *finfo;
 };
 
@@ -2756,7 +3241,7 @@ elf_bfd_final_link (abfd, info)
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  struct elf_finfo_failed eif;
+  struct elf_outext_info eoinfo;
 
   if (info->shared)
     abfd->flags |= DYNAMIC;
@@ -2997,7 +3482,6 @@ elf_bfd_final_link (abfd, info)
      outputting relocs.  */
   if (info->strip != strip_all || info->relocateable)
     {
-      elfsym.st_value = 0;
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
       elfsym.st_other = 0;
@@ -3007,6 +3491,10 @@ elf_bfd_final_link (abfd, info)
          if (o != NULL)
            o->target_index = abfd->symcount;
          elfsym.st_shndx = i;
+         if (info->relocateable || o == NULL)
+           elfsym.st_value = 0;
+         else
+           elfsym.st_value = o->vma;
          if (! elf_link_output_sym (&finfo, (const char *) NULL,
                                     &elfsym, o))
            goto error_return;
@@ -3093,6 +3581,23 @@ elf_bfd_final_link (abfd, info)
   /* That wrote out all the local symbols.  Finish up the symbol table
      with the global symbols.  */
 
+  if (info->strip != strip_all && info->shared)
+    {
+      /* Output any global symbols that got converted to local in a
+         version script.  We do this in a separate step since ELF
+         requires all local symbols to appear prior to any global
+         symbols.  FIXME: We should only do this if some global
+         symbols were, in fact, converted to become local.  FIXME:
+         Will this work correctly with the Irix 5 linker?  */
+      eoinfo.failed = false;
+      eoinfo.finfo = &finfo;
+      eoinfo.localsyms = true;
+      elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
+                             (PTR) &eoinfo);
+      if (eoinfo.failed)
+       return false;
+    }
+
   /* The sh_info field records the index of the first non local
      symbol.  */
   symtab_hdr->sh_info = abfd->symcount;
@@ -3100,11 +3605,12 @@ elf_bfd_final_link (abfd, info)
     elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
 
   /* We get the global symbols from the hash table.  */
-  eif.failed = false;
-  eif.finfo = &finfo;
+  eoinfo.failed = false;
+  eoinfo.localsyms = false;
+  eoinfo.finfo = &finfo;
   elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym,
-                         (PTR) &eif);
-  if (eif.failed)
+                         (PTR) &eoinfo);
+  if (eoinfo.failed)
     return false;
 
   /* Flush all symbols to the file.  */
@@ -3489,19 +3995,35 @@ elf_link_flush_output_syms (finfo)
 }
 
 /* Add an external symbol to the symbol table.  This is called from
-   the hash table traversal routine.  */
+   the hash table traversal routine.  When generating a shared object,
+   we go through the symbol table twice.  The first time we output
+   anything that might have been forced to local scope in a version
+   script.  The second time we output the symbols that are still
+   global symbols.  */
 
 static boolean
 elf_link_output_extsym (h, data)
      struct elf_link_hash_entry *h;
      PTR data;
 {
-  struct elf_finfo_failed *eif = (struct elf_finfo_failed *) data;
-  struct elf_final_link_info *finfo = eif->finfo;
+  struct elf_outext_info *eoinfo = (struct elf_outext_info *) data;
+  struct elf_final_link_info *finfo = eoinfo->finfo;
   boolean strip;
   Elf_Internal_Sym sym;
   asection *input_sec;
 
+  /* Decide whether to output this symbol in this pass.  */
+  if (eoinfo->localsyms)
+    {
+      if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+       return true;
+    }
+  else
+    {
+      if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+       return true;
+    }
+
   /* If we are not creating a shared library, and this symbol is
      referenced by a shared library but is not defined anywhere, then
      warn that it is undefined.  If we do not do this, the runtime
@@ -3519,7 +4041,7 @@ elf_link_output_extsym (h, data)
             (finfo->info, h->root.root.string, h->root.u.undef.abfd,
              (asection *) NULL, 0)))
        {
-         eif->failed = true;
+         eoinfo->failed = true;
          return false;
        }
     }
@@ -3552,8 +4074,10 @@ elf_link_output_extsym (h, data)
   sym.st_value = 0;
   sym.st_size = h->size;
   sym.st_other = h->other;
-  if (h->root.type == bfd_link_hash_undefweak
-      || h->root.type == bfd_link_hash_defweak)
+  if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+    sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type);
+  else if (h->root.type == bfd_link_hash_undefweak
+          || h->root.type == bfd_link_hash_defweak)
     sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
   else
     sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
@@ -3586,7 +4110,7 @@ elf_link_output_extsym (h, data)
                                                 input_sec->output_section);
            if (sym.st_shndx == (unsigned short) -1)
              {
-               eif->failed = true;
+               eoinfo->failed = true;
                return false;
              }
 
@@ -3599,7 +4123,8 @@ elf_link_output_extsym (h, data)
          }
        else
          {
-           BFD_ASSERT ((input_sec->owner->flags & DYNAMIC) != 0);
+           BFD_ASSERT (input_sec->owner == NULL
+                       || (input_sec->owner->flags & DYNAMIC) != 0);
            sym.st_shndx = SHN_UNDEF;
            input_sec = bfd_und_section_ptr;
          }
@@ -3617,8 +4142,10 @@ elf_link_output_extsym (h, data)
          to the decorated version of the name.  For example, if the
          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.  */
-      if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
+         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;
 
       /* Fall through.  */
@@ -3633,13 +4160,30 @@ elf_link_output_extsym (h, data)
              ((struct elf_link_hash_entry *) h->root.u.i.link, data));
     }
 
+  /* Give the processor backend a chance to tweak the symbol value,
+     and also to finish up anything that needs to be done for this
+     symbol.  */
+  if ((h->dynindx != -1
+       || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
+      && elf_hash_table (finfo->info)->dynamic_sections_created)
+    {
+      struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (finfo->output_bfd);
+      if (! ((*bed->elf_backend_finish_dynamic_symbol)
+            (finfo->output_bfd, finfo->info, h, &sym)))
+       {
+         eoinfo->failed = true;
+         return false;
+       }
+    }
+
   /* 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.  */
   if (h->dynindx != -1
       && elf_hash_table (finfo->info)->dynamic_sections_created)
     {
-      struct elf_backend_data *bed;
       char *p, *copy;
       const char *name;
       size_t bucketcount;
@@ -3649,17 +4193,6 @@ elf_link_output_extsym (h, data)
 
       sym.st_name = h->dynstr_index;
 
-      /* Give the processor backend a chance to tweak the symbol
-        value, and also to finish up anything that needs to be done
-        for this symbol.  */
-      bed = get_elf_backend_data (finfo->output_bfd);
-      if (! ((*bed->elf_backend_finish_dynamic_symbol)
-            (finfo->output_bfd, finfo->info, h, &sym)))
-       {
-         eif->failed = true;
-         return false;
-       }
-
       elf_swap_symbol_out (finfo->output_bfd, &sym,
                           (PTR) (((Elf_External_Sym *)
                                   finfo->dynsym_sec->contents)
@@ -3730,7 +4263,7 @@ elf_link_output_extsym (h, data)
 
   if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
     {
-      eif->failed = true;
+      eoinfo->failed = true;
       return false;
     }
 
@@ -4172,9 +4705,9 @@ elf_link_input_bfd (finfo, input_bfd)
        }
       else
        {
-         if (! _bfd_write_section_stabs (output_bfd, o,
-                                         &elf_section_data (o)->stab_info,
-                                         contents))
+         if (! (_bfd_write_section_stabs
+                (output_bfd, &elf_hash_table (finfo->info)->stab_info,
+                 o, &elf_section_data (o)->stab_info, contents)))
            return false;
        }
     }
This page took 0.040059 seconds and 4 git commands to generate.