* elflink.c (_bfd_elf_merge_symbol): Rewrite weak symbol handling.
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 48b86cf36f15ceb950dd321bf7a5b9ee9e80f4e6..ec20e75167dad55cc076f6d9e5b39ec0881de289 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linker support.
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -20,9 +20,9 @@
 
 /* ELF linker code.  */
 
+#include "safe-ctype.h"
+
 static bfd_boolean elf_link_add_object_symbols (bfd *, struct bfd_link_info *);
-static bfd_boolean elf_link_add_archive_symbols (bfd *,
-                                                struct bfd_link_info *);
 static bfd_boolean elf_finalize_dynstr (bfd *, struct bfd_link_info *);
 static bfd_boolean elf_collect_hash_codes (struct elf_link_hash_entry *,
                                           void *);
@@ -39,355 +39,33 @@ elf_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
     case bfd_object:
       return elf_link_add_object_symbols (abfd, info);
     case bfd_archive:
-      return elf_link_add_archive_symbols (abfd, info);
+      return _bfd_elf_link_add_archive_symbols (abfd, info);
     default:
       bfd_set_error (bfd_error_wrong_format);
       return FALSE;
     }
 }
 \f
-/* Return TRUE iff this is a non-common, definition of a non-function symbol.  */
-static bfd_boolean
-is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
-                                 Elf_Internal_Sym *sym)
-{
-  /* Local symbols do not count, but target specific ones might.  */
-  if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
-      && ELF_ST_BIND (sym->st_info) < STB_LOOS)
-    return FALSE;
-
-  /* Function symbols do not count.  */
-  if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
-    return FALSE;
-
-  /* If the section is undefined, then so is the symbol.  */
-  if (sym->st_shndx == SHN_UNDEF)
-    return FALSE;
-
-  /* If the symbol is defined in the common section, then
-     it is a common definition and so does not count.  */
-  if (sym->st_shndx == SHN_COMMON)
-    return FALSE;
-
-  /* If the symbol is in a target specific section then we
-     must rely upon the backend to tell us what it is.  */
-  if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS)
-    /* FIXME - this function is not coded yet:
-
-       return _bfd_is_global_symbol_definition (abfd, sym);
-
-       Instead for now assume that the definition is not global,
-       Even if this is wrong, at least the linker will behave
-       in the same way that it used to do.  */
-    return FALSE;
-
-  return TRUE;
-}
-
-/* Search the symbol table of the archive element of the archive ABFD
-   whose archive map contains a mention of SYMDEF, and determine if
-   the symbol is defined in this element.  */
-static bfd_boolean
-elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
+/* Sort symbol by value and section.  */
+static int
+sort_symbol (const void *arg1, const void *arg2)
 {
-  Elf_Internal_Shdr * hdr;
-  bfd_size_type symcount;
-  bfd_size_type extsymcount;
-  bfd_size_type extsymoff;
-  Elf_Internal_Sym *isymbuf;
-  Elf_Internal_Sym *isym;
-  Elf_Internal_Sym *isymend;
-  bfd_boolean result;
-
-  abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
-  if (abfd == 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;
+  const struct elf_link_hash_entry *h1
+    = *(const struct elf_link_hash_entry **) arg1;
+  const struct elf_link_hash_entry *h2
+    = *(const struct elf_link_hash_entry **) arg2;
+  bfd_signed_vma vdiff = h1->root.u.def.value - h2->root.u.def.value;
+
+  if (vdiff)
+    return vdiff > 0 ? 1 : -1;
   else
-    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;
-    }
-
-  if (extsymcount == 0)
-    return FALSE;
-
-  /* Read in the symbol table.  */
-  isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff,
-                                 NULL, NULL, NULL);
-  if (isymbuf == NULL)
-    return FALSE;
-
-  /* Scan the symbol table looking for SYMDEF.  */
-  result = FALSE;
-  for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++)
-    {
-      const char *name;
-
-      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                             isym->st_name);
-      if (name == NULL)
-       break;
-
-      if (strcmp (name, symdef->name) == 0)
-       {
-         result = is_global_data_symbol_definition (abfd, isym);
-         break;
-       }
-    }
-
-  free (isymbuf);
-
-  return result;
-}
-\f
-/* Add symbols from an ELF archive file to the linker hash table.  We
-   don't use _bfd_generic_link_add_archive_symbols because of a
-   problem which arises on UnixWare.  The UnixWare libc.so is an
-   archive which includes an entry libc.so.1 which defines a bunch of
-   symbols.  The libc.so archive also includes a number of other
-   object files, which also define symbols, some of which are the same
-   as those defined in libc.so.1.  Correct linking requires that we
-   consider each object file in turn, and include it if it defines any
-   symbols we need.  _bfd_generic_link_add_archive_symbols does not do
-   this; it looks through the list of undefined symbols, and includes
-   any object file which defines them.  When this algorithm is used on
-   UnixWare, it winds up pulling in libc.so.1 early and defining a
-   bunch of symbols.  This means that some of the other objects in the
-   archive are not included in the link, which is incorrect since they
-   precede libc.so.1 in the archive.
-
-   Fortunately, ELF archive handling is simpler than that done by
-   _bfd_generic_link_add_archive_symbols, which has to allow for a.out
-   oddities.  In ELF, if we find a symbol in the archive map, and the
-   symbol is currently undefined, we know that we must pull in that
-   object file.
-
-   Unfortunately, we do have to make multiple passes over the symbol
-   table until nothing further is resolved.  */
-
-static bfd_boolean
-elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
-{
-  symindex c;
-  bfd_boolean *defined = NULL;
-  bfd_boolean *included = NULL;
-  carsym *symdefs;
-  bfd_boolean loop;
-  bfd_size_type amt;
-
-  if (! bfd_has_map (abfd))
     {
-      /* An empty archive is a special case.  */
-      if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
-       return TRUE;
-      bfd_set_error (bfd_error_no_armap);
-      return FALSE;
-    }
-
-  /* Keep track of all symbols we know to be already defined, and all
-     files we know to be already included.  This is to speed up the
-     second and subsequent passes.  */
-  c = bfd_ardata (abfd)->symdef_count;
-  if (c == 0)
-    return TRUE;
-  amt = c;
-  amt *= sizeof (bfd_boolean);
-  defined = bfd_zmalloc (amt);
-  included = bfd_zmalloc (amt);
-  if (defined == NULL || included == NULL)
-    goto error_return;
-
-  symdefs = bfd_ardata (abfd)->symdefs;
-
-  do
-    {
-      file_ptr last;
-      symindex i;
-      carsym *symdef;
-      carsym *symdefend;
-
-      loop = FALSE;
-      last = -1;
-
-      symdef = symdefs;
-      symdefend = symdef + c;
-      for (i = 0; symdef < symdefend; symdef++, i++)
-       {
-         struct elf_link_hash_entry *h;
-         bfd *element;
-         struct bfd_link_hash_entry *undefs_tail;
-         symindex mark;
-
-         if (defined[i] || included[i])
-           continue;
-         if (symdef->file_offset == last)
-           {
-             included[i] = TRUE;
-             continue;
-           }
-
-         h = elf_link_hash_lookup (elf_hash_table (info), symdef->name,
-                                   FALSE, FALSE, FALSE);
-
-         if (h == NULL)
-           {
-             char *p, *copy;
-             size_t len, first;
-
-             /* If this is a default version (the name contains @@),
-                look up the symbol again with only one `@' as well
-                as without the version.  The effect is that references
-                to the symbol with and without the version will be
-                matched by the default symbol in the archive.  */
-
-             p = strchr (symdef->name, ELF_VER_CHR);
-             if (p == NULL || p[1] != ELF_VER_CHR)
-               continue;
-
-             /* First check with only one `@'.  */
-             len = strlen (symdef->name);
-             copy = bfd_alloc (abfd, len);
-             if (copy == NULL)
-               goto error_return;
-             first = p - symdef->name + 1;
-             memcpy (copy, symdef->name, first);
-             memcpy (copy + first, symdef->name + first + 1, len - first);
-
-             h = elf_link_hash_lookup (elf_hash_table (info), copy,
-                                       FALSE, FALSE, FALSE);
-
-             if (h == NULL)
-               {
-                 /* We also need to check references to the symbol
-                    without the version.  */
-
-                 copy[first - 1] = '\0';
-                 h = elf_link_hash_lookup (elf_hash_table (info),
-                                           copy, FALSE, FALSE, FALSE);
-               }
-
-             bfd_release (abfd, copy);
-           }
-
-         if (h == NULL)
-           continue;
-
-         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;
-             continue;
-           }
-
-         /* We need to include this archive member.  */
-         element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
-         if (element == NULL)
-           goto error_return;
-
-         if (! bfd_check_format (element, bfd_object))
-           goto error_return;
-
-         /* Doublecheck that we have not included this object
-            already--it should be impossible, but there may be
-            something wrong with the archive.  */
-         if (element->archive_pass != 0)
-           {
-             bfd_set_error (bfd_error_bad_value);
-             goto error_return;
-           }
-         element->archive_pass = 1;
-
-         undefs_tail = info->hash->undefs_tail;
-
-         if (! (*info->callbacks->add_archive_element) (info, element,
-                                                        symdef->name))
-           goto error_return;
-         if (! elf_link_add_object_symbols (element, info))
-           goto error_return;
-
-         /* If there are any new undefined symbols, we need to make
-            another pass through the archive in order to see whether
-            they can be defined.  FIXME: This isn't perfect, because
-            common symbols wind up on undefs_tail and because an
-            undefined symbol which is defined later on in this pass
-            does not require another pass.  This isn't a bug, but it
-            does make the code less efficient than it could be.  */
-         if (undefs_tail != info->hash->undefs_tail)
-           loop = TRUE;
-
-         /* Look backward to mark all symbols from this object file
-            which we have already seen in this pass.  */
-         mark = i;
-         do
-           {
-             included[mark] = TRUE;
-             if (mark == 0)
-               break;
-             --mark;
-           }
-         while (symdefs[mark].file_offset == symdef->file_offset);
-
-         /* We mark subsequent symbols from this object file as we go
-            on through the loop.  */
-         last = symdef->file_offset;
-       }
+      long sdiff = h1->root.u.def.section - h2->root.u.def.section;
+      if (sdiff)
+       return sdiff > 0 ? 1 : -1;
+      else
+       return 0;
     }
-  while (loop);
-
-  free (defined);
-  free (included);
-
-  return TRUE;
-
- error_return:
-  if (defined != NULL)
-    free (defined);
-  if (included != NULL)
-    free (included);
-  return FALSE;
 }
 
 /* Add symbols from an ELF object file to the linker hash table.  */
@@ -417,6 +95,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   Elf_Internal_Sym *isymend;
   const struct elf_backend_data *bed;
   bfd_boolean dt_needed;
+  bfd_boolean add_needed;
   struct elf_link_hash_table * hash_table;
   bfd_size_type amt;
 
@@ -435,7 +114,9 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       /* You can't use -r against a dynamic object.  Also, there's no
         hope of using a dynamic object which does not exactly match
         the format of the output file.  */
-      if (info->relocatable || info->hash->creator != abfd->xvec)
+      if (info->relocatable
+         || !is_elf_hash_table (hash_table)
+         || hash_table->root.creator != abfd->xvec)
        {
          bfd_set_error (bfd_error_invalid_operation);
          goto error_return;
@@ -473,7 +154,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                 fix is to keep track of what warnings we are supposed
                 to emit, and then handle them all at the end of the
                 link.  */
-             if (dynamic && abfd->xvec == info->hash->creator)
+             if (dynamic)
                {
                  struct elf_link_hash_entry *h;
 
@@ -521,6 +202,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
     }
 
   dt_needed = FALSE;
+  add_needed = FALSE;
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -529,20 +211,19 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
         format.  FIXME: If there are no input BFD's of the same
         format as the output, we can't make a shared library.  */
       if (info->shared
-         && is_elf_hash_table (info)
-         && ! hash_table->dynamic_sections_created
-         && abfd->xvec == info->hash->creator)
+         && is_elf_hash_table (hash_table)
+         && hash_table->root.creator == abfd->xvec
+         && ! hash_table->dynamic_sections_created)
        {
          if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
            goto error_return;
        }
     }
-  else if (! is_elf_hash_table (info))
+  else if (!is_elf_hash_table (hash_table))
     goto error_return;
   else
     {
       asection *s;
-      bfd_boolean add_needed;
       const char *name;
       bfd_size_type oldsize;
       bfd_size_type strindex;
@@ -721,9 +402,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 
       /* If this is the first dynamic object found in the link, create
         the special sections required for dynamic linking.  */
-      if (! hash_table->dynamic_sections_created)
-       if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
-         goto error_return;
+      if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
+       goto error_return;
 
       if (add_needed)
        {
@@ -873,7 +553,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
        {
          /* This should be impossible, since ELF requires that all
             global symbols follow all local symbols, and that sh_info
-            point to the first global symbol.  Unfortunatealy, Irix 5
+            point to the first global symbol.  Unfortunately, Irix 5
             screws this up.  */
          continue;
        }
@@ -966,7 +646,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       old_alignment = 0;
       old_bfd = NULL;
 
-      if (info->hash->creator->flavour == bfd_target_elf_flavour)
+      if (is_elf_hash_table (hash_table))
        {
          Elf_Internal_Versym iver;
          unsigned int vernum = 0;
@@ -1099,7 +779,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
            case bfd_link_hash_defweak:
              old_bfd = h->root.u.def.section->owner;
              break;
-           
+
            case bfd_link_hash_common:
              old_bfd = h->root.u.c.p->section->owner;
              old_alignment = h->root.u.c.p->alignment_power;
@@ -1129,7 +809,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          && definition
          && (flags & BSF_WEAK) != 0
          && ELF_ST_TYPE (isym->st_info) != STT_FUNC
-         && info->hash->creator->flavour == bfd_target_elf_flavour
+         && is_elf_hash_table (hash_table)
          && h->weakdef == NULL)
        {
          /* Keep a list of all weak defined non function symbols from
@@ -1165,14 +845,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
            h->root.u.c.p->alignment_power = old_alignment;
        }
 
-      if (info->hash->creator->flavour == bfd_target_elf_flavour)
+      if (is_elf_hash_table (hash_table))
        {
          int old_flags;
          bfd_boolean dynsym;
          int new_flag;
 
          /* Check the alignment when a common symbol is involved. This
-            can change when a common symbol is overriden by a normal
+            can change when a common symbol is overridden by a normal
             definition or a common symbol is ignored due to the old
             normal definition. We need to make sure the maximum
             alignment is maintained.  */
@@ -1259,6 +939,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          /* If st_other has a processor-specific meaning, specific
             code might be needed here. We never merge the visibility
             attribute with the one from a dynamic object.  */
+         if (bed->elf_backend_merge_symbol_attribute)
+           (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition,
+                                                       dynamic);
+
          if (isym->st_other != 0 && !dynamic)
            {
              unsigned char hvis, symvis, other, nvis;
@@ -1367,21 +1051,18 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                break;
              }
 
-         if (dt_needed && definition
+         if (dt_needed && !add_needed && definition
              && (h->elf_link_hash_flags
                  & ELF_LINK_HASH_REF_REGULAR) != 0)
            {
              bfd_size_type oldsize;
              bfd_size_type strindex;
 
-             if (! is_elf_hash_table (info))
-               goto error_free_vers;
-
              /* 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;
+             add_needed = TRUE;
              oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
              strindex = _bfd_elf_strtab_add (hash_table->dynstr,
                                              elf_dt_soname (abfd), FALSE);
@@ -1440,7 +1121,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          shortname[amt] = '\0';
 
          hi = (struct elf_link_hash_entry *)
-              bfd_link_hash_lookup (info->hash, shortname,
+              bfd_link_hash_lookup (&hash_table->root, shortname,
                                     FALSE, FALSE, FALSE);
          if (hi != NULL
              && hi->root.type == h->root.type
@@ -1489,63 +1170,132 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
      assembler code, handling it correctly would be very time
      consuming, and other ELF linkers don't handle general aliasing
      either.  */
-  while (weaks != NULL)
+  if (weaks != NULL)
     {
-      struct elf_link_hash_entry *hlook;
-      asection *slook;
-      bfd_vma vlook;
       struct elf_link_hash_entry **hpp;
       struct elf_link_hash_entry **hppend;
+      struct elf_link_hash_entry **sorted_sym_hash;
+      struct elf_link_hash_entry *h;
+      size_t sym_count;
 
-      hlook = weaks;
-      weaks = hlook->weakdef;
-      hlook->weakdef = NULL;
-
-      BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
-                 || hlook->root.type == bfd_link_hash_defweak
-                 || hlook->root.type == bfd_link_hash_common
-                 || hlook->root.type == bfd_link_hash_indirect);
-      slook = hlook->root.u.def.section;
-      vlook = hlook->root.u.def.value;
-
+      /* Since we have to search the whole symbol list for each weak
+        defined symbol, search time for N weak defined symbols will be
+        O(N^2). Binary search will cut it down to O(NlogN).  */
+      amt = extsymcount * sizeof (struct elf_link_hash_entry *);
+      sorted_sym_hash = bfd_malloc (amt);
+      if (sorted_sym_hash == NULL)
+       goto error_return;
+      sym_hash = sorted_sym_hash;
       hpp = elf_sym_hashes (abfd);
       hppend = hpp + extsymcount;
+      sym_count = 0;
       for (; hpp < hppend; hpp++)
        {
-         struct elf_link_hash_entry *h;
-
          h = *hpp;
-         if (h != NULL && h != hlook
+         if (h != NULL
              && h->root.type == bfd_link_hash_defined
-             && h->root.u.def.section == slook
-             && h->root.u.def.value == vlook)
+             && h->type != STT_FUNC)
            {
-             hlook->weakdef = h;
+             *sym_hash = h;
+             sym_hash++;
+             sym_count++;
+           }
+       }
+
+      qsort (sorted_sym_hash, sym_count,
+            sizeof (struct elf_link_hash_entry *),
+            sort_symbol);
 
-             /* If the weak definition is in the list of dynamic
-                symbols, make sure the real definition is put there
-                as well.  */
-             if (hlook->dynindx != -1
-                 && h->dynindx == -1)
+      while (weaks != NULL)
+       {
+         struct elf_link_hash_entry *hlook;
+         asection *slook;
+         bfd_vma vlook;
+         long ilook;
+         size_t i, j, idx;
+
+         hlook = weaks;
+         weaks = hlook->weakdef;
+         hlook->weakdef = NULL;
+
+         BFD_ASSERT (hlook->root.type == bfd_link_hash_defined
+                     || hlook->root.type == bfd_link_hash_defweak
+                     || hlook->root.type == bfd_link_hash_common
+                     || hlook->root.type == bfd_link_hash_indirect);
+         slook = hlook->root.u.def.section;
+         vlook = hlook->root.u.def.value;
+
+         ilook = -1;
+         i = 0;
+         j = sym_count;
+         while (i < j)
+           {
+             bfd_signed_vma vdiff;
+             idx = (i + j) / 2;
+             h = sorted_sym_hash [idx];
+             vdiff = vlook - h->root.u.def.value;
+             if (vdiff < 0)
+               j = idx;
+             else if (vdiff > 0)
+               i = idx + 1;
+             else
                {
-                 if (! _bfd_elf_link_record_dynamic_symbol (info, h))
-                   goto error_return;
+                 long sdiff = slook - h->root.u.def.section;
+                 if (sdiff < 0)
+                   j = idx;
+                 else if (sdiff > 0)
+                   i = idx + 1;
+                 else
+                   {
+                     ilook = idx;
+                     break;
+                   }
                }
+           }
 
-             /* If the real definition is in the list of dynamic
-                symbols, make sure the weak definition is put there
-                as well.  If we don't do this, then the dynamic
-                loader might not merge the entries for the real
-                definition and the weak definition.  */
-             if (h->dynindx != -1
-                 && hlook->dynindx == -1)
+         /* We didn't find a value/section match.  */
+         if (ilook == -1)
+           continue;
+
+         for (i = ilook; i < sym_count; i++)
+           {
+             h = sorted_sym_hash [i];
+
+             /* Stop if value or section doesn't match.  */
+             if (h->root.u.def.value != vlook
+                 || h->root.u.def.section != slook)
+               break;
+             else if (h != hlook)
                {
-                 if (! _bfd_elf_link_record_dynamic_symbol (info, hlook))
-                   goto error_return;
+                 hlook->weakdef = h;
+
+                 /* If the weak definition is in the list of dynamic
+                    symbols, make sure the real definition is put
+                    there as well.  */
+                 if (hlook->dynindx != -1 && h->dynindx == -1)
+                   {
+                     if (! _bfd_elf_link_record_dynamic_symbol (info,
+                                                                h))
+                       goto error_return;
+                   }
+
+                 /* If the real definition is in the list of dynamic
+                    symbols, make sure the weak definition is put
+                    there as well.  If we don't do this, then the
+                    dynamic loader might not merge the entries for the
+                    real definition and the weak definition.  */
+                 if (h->dynindx != -1 && hlook->dynindx == -1)
+                   {
+                     if (! _bfd_elf_link_record_dynamic_symbol (info,
+                                                                hlook))
+                       goto error_return;
+                   }
+                 break;
                }
-             break;
            }
        }
+
+      free (sorted_sym_hash);
     }
 
   /* If this object is the same format as the output object, and it is
@@ -1567,7 +1317,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
      different format.  It probably can't be done.  */
   check_relocs = get_elf_backend_data (abfd)->check_relocs;
   if (! dynamic
-      && abfd->xvec == info->hash->creator
+      && is_elf_hash_table (hash_table)
+      && hash_table->root.creator == abfd->xvec
       && check_relocs != NULL)
     {
       asection *o;
@@ -1603,37 +1354,42 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
      of the .stab/.stabstr sections.  */
   if (! dynamic
       && ! info->traditional_format
-      && info->hash->creator->flavour == bfd_target_elf_flavour
-      && is_elf_hash_table (info)
+      && is_elf_hash_table (hash_table)
       && (info->strip != strip_all && info->strip != strip_debugger))
     {
-      asection *stab, *stabstr;
+      asection *stabstr;
 
-      stab = bfd_get_section_by_name (abfd, ".stab");
-      if (stab != NULL
-         && (stab->flags & SEC_MERGE) == 0
-         && !bfd_is_abs_section (stab->output_section))
+      stabstr = bfd_get_section_by_name (abfd, ".stabstr");
+      if (stabstr != NULL)
        {
-         stabstr = bfd_get_section_by_name (abfd, ".stabstr");
-
-         if (stabstr != NULL)
-           {
-             struct bfd_elf_section_data *secdata;
-
-             secdata = elf_section_data (stab);
-             if (! _bfd_link_section_stabs (abfd,
-                                            & hash_table->stab_info,
-                                            stab, stabstr,
-                                            &secdata->sec_info))
-               goto error_return;
-             if (secdata->sec_info)
-               stab->sec_info_type = ELF_INFO_TYPE_STABS;
+         bfd_size_type string_offset = 0;
+         asection *stab;
+
+         for (stab = abfd->sections; stab; stab = stab->next)
+           if (strncmp (".stab", stab->name, 5) == 0
+               && (!stab->name[5] ||
+                   (stab->name[5] == '.' && ISDIGIT (stab->name[6])))
+               && (stab->flags & SEC_MERGE) == 0
+               && !bfd_is_abs_section (stab->output_section))
+             {
+               struct bfd_elf_section_data *secdata;
+
+               secdata = elf_section_data (stab);
+               if (! _bfd_link_section_stabs (abfd,
+                                              & hash_table->stab_info,
+                                              stab, stabstr,
+                                              &secdata->sec_info,
+                                              &string_offset))
+                 goto error_return;
+               if (secdata->sec_info)
+                 stab->sec_info_type = ELF_INFO_TYPE_STABS;
            }
        }
     }
 
-  if (! info->relocatable && ! dynamic
-      && is_elf_hash_table (info))
+  if (! info->relocatable
+      && ! dynamic
+      && is_elf_hash_table (hash_table))
     {
       asection *s;
 
@@ -1653,7 +1409,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
          }
     }
 
-  if (is_elf_hash_table (info))
+  if (is_elf_hash_table (hash_table))
     {
       /* Add this bfd to the loaded list.  */
       struct elf_link_loaded_list *n;
@@ -1691,7 +1447,7 @@ elf_add_dynamic_entry (struct bfd_link_info *info, bfd_vma tag, bfd_vma val)
   bfd_size_type newsize;
   bfd_byte *newcontents;
 
-  if (! is_elf_hash_table (info))
+  if (! is_elf_hash_table (info->hash))
     return FALSE;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -1821,7 +1577,7 @@ compute_bucket_count (struct bfd_link_info *info)
 
 # if 1
          /* Variant 1: optimize for short chains.  We add the squares
-            of all the chain lengths (which favous many small chain
+            of all the chain lengths (which favors many small chain
             over a few long chains).  */
          for (j = 0; j < i; ++j)
            max += counts[j] * counts[j];
@@ -1896,10 +1652,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
 
   soname_indx = (bfd_size_type) -1;
 
-  if (info->hash->creator->flavour != bfd_target_elf_flavour)
-    return TRUE;
-
-  if (! is_elf_hash_table (info))
+  if (!is_elf_hash_table (info->hash))
     return TRUE;
 
   if (info->execstack)
@@ -1970,7 +1723,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
       bfd_boolean all_defined;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
-      BFD_ASSERT (*sinterpptr != NULL || info->shared);
+      BFD_ASSERT (*sinterpptr != NULL || !info->executable);
 
       if (soname != NULL)
        {
@@ -2045,17 +1798,17 @@ NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
            return FALSE;
        }
 
-      /* Make all global versions with definiton.  */
+      /* Make all global versions with definition.  */
       for (t = verdefs; t != NULL; t = t->next)
-       for (d = t->globals; d != NULL; d = d->next)
-         if (!d->symver && strchr (d->pattern, '*') == NULL)
+       for (d = t->globals.list; d != NULL; d = d->next)
+         if (!d->symver && d->symbol)
            {
              const char *verstr, *name;
              size_t namelen, verlen, newlen;
              char *newname, *p;
              struct elf_link_hash_entry *newh;
 
-             name = d->pattern;
+             name = d->symbol;
              namelen = strlen (name);
              verstr = t->name;
              verlen = strlen (verstr);
@@ -2110,12 +1863,11 @@ NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
 
       if (!info->allow_undefined_version)
        {
-         /* Check if all global versions have a definiton.  */
+         /* Check if all global versions have a definition.  */
          all_defined = TRUE;
          for (t = verdefs; t != NULL; t = t->next)
-           for (d = t->globals; d != NULL; d = d->next)
-             if (!d->symver && !d->script
-                 && strchr (d->pattern, '*') == NULL)
+           for (d = t->globals.list; d != NULL; d = d->next)
+             if (!d->symver && !d->script)
                {
                  (*_bfd_error_handler)
                    (_("%s: undefined version: %s"),
@@ -2362,7 +2114,7 @@ NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
 
              def.vd_version = VER_DEF_CURRENT;
              def.vd_flags = 0;
-             if (t->globals == NULL && t->locals == NULL && ! t->used)
+             if (t->globals.list == NULL && t->locals.list == NULL && ! t->used)
                def.vd_flags |= VER_FLG_WEAK;
              def.vd_ndx = t->vernum + 1;
              def.vd_cnt = cdeps + 1;
@@ -2428,6 +2180,11 @@ NAME(bfd_elf,size_dynamic_sections) (bfd *output_bfd,
          if (! elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
            return FALSE;
        }
+      else if (info->flags & DF_BIND_NOW)
+       {
+         if (! elf_add_dynamic_entry (info, DT_BIND_NOW, 0))
+           return FALSE;
+       }
 
       if (info->flags_1)
        {
@@ -2794,8 +2551,6 @@ struct elf_final_link_info
   asection *hash_sec;
   /* symbol version section (.gnu.version).  */
   asection *symver_sec;
-  /* first SHF_TLS section (if any).  */
-  asection *first_tls_sec;
   /* Buffer large enough to hold contents of any section.  */
   bfd_byte *contents;
   /* Buffer large enough to hold external relocs of any section.  */
@@ -2829,7 +2584,8 @@ struct elf_final_link_info
 };
 
 static bfd_boolean elf_link_output_sym
-  (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *);
+  (struct elf_final_link_info *, const char *, Elf_Internal_Sym *, asection *,
+   struct elf_link_hash_entry *);
 static bfd_boolean elf_link_flush_output_syms
   (struct elf_final_link_info *);
 static bfd_boolean elf_link_output_extsym
@@ -3104,7 +2860,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   asection *reldyn = 0;
   bfd_size_type amt;
 
-  if (! is_elf_hash_table (info))
+  if (! is_elf_hash_table (info->hash))
     return FALSE;
 
   if (info->shared)
@@ -3150,14 +2906,6 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   finfo.symshndxbuf = NULL;
   finfo.symbuf_count = 0;
   finfo.shndxbuf_size = 0;
-  finfo.first_tls_sec = NULL;
-  for (o = abfd->sections; o != NULL; o = o->next)
-    if ((o->flags & SEC_THREAD_LOCAL) != 0
-       && (o->flags & SEC_LOAD) != 0)
-      {
-       finfo.first_tls_sec = o;
-       break;
-      }
 
   /* Count up the number of relocations we will output for each output
      section, so that we know the sizes of the reloc sections.  We
@@ -3411,7 +3159,8 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
       elfsym.st_info = 0;
       elfsym.st_other = 0;
       elfsym.st_shndx = SHN_UNDEF;
-      if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr))
+      if (! elf_link_output_sym (&finfo, NULL, &elfsym, bfd_und_section_ptr,
+                                NULL))
        goto error_return;
     }
 
@@ -3427,7 +3176,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   elfsym.st_other = 0;
   elfsym.st_shndx = SHN_ABS;
   if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd),
-                            &elfsym, bfd_abs_section_ptr))
+                            &elfsym, bfd_abs_section_ptr, NULL))
     goto error_return;
 #endif
 
@@ -3452,7 +3201,7 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
            elfsym.st_value = 0;
          else
            elfsym.st_value = o->vma;
-         if (! elf_link_output_sym (&finfo, NULL, &elfsym, o))
+         if (! elf_link_output_sym (&finfo, NULL, &elfsym, o, NULL))
            goto error_return;
          if (i == SHN_LORESERVE - 1)
            i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
@@ -3515,38 +3264,30 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
        goto error_return;
     }
 
-  if (finfo.first_tls_sec)
+  if (elf_hash_table (info)->tls_sec)
     {
-      unsigned int align = 0;
-      bfd_vma base = finfo.first_tls_sec->vma, end = 0;
+      bfd_vma base, end = 0;
       asection *sec;
 
-      for (sec = finfo.first_tls_sec;
+      for (sec = elf_hash_table (info)->tls_sec;
           sec && (sec->flags & SEC_THREAD_LOCAL);
           sec = sec->next)
        {
          bfd_vma size = sec->_raw_size;
 
-         if (bfd_get_section_alignment (abfd, sec) > align)
-           align = bfd_get_section_alignment (abfd, sec);
-         if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0)
+         if (size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0)
            {
              struct bfd_link_order *o;
 
-             size = 0;
              for (o = sec->link_order_head; o != NULL; o = o->next)
                if (size < o->offset + o->size)
                  size = o->offset + o->size;
            }
          end = sec->vma + size;
        }
-      elf_hash_table (info)->tls_segment
-       = bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment));
-      if (elf_hash_table (info)->tls_segment == NULL)
-       goto error_return;
-      elf_hash_table (info)->tls_segment->start = base;
-      elf_hash_table (info)->tls_segment->size = end - base;
-      elf_hash_table (info)->tls_segment->align = align;
+      base = elf_hash_table (info)->tls_sec->vma;
+      end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power);
+      elf_hash_table (info)->tls_size = end - base;
     }
 
   /* Since ELF permits relocations to be against local symbols, we
@@ -3714,7 +3455,8 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
   if (bed->elf_backend_output_arch_syms)
     {
       typedef bfd_boolean (*out_sym_func)
-       (void *, const char *, Elf_Internal_Sym *, asection *);
+       (void *, const char *, Elf_Internal_Sym *, asection *,
+        struct elf_link_hash_entry *);
 
       if (! ((*bed->elf_backend_output_arch_syms)
             (abfd, info, &finfo, (out_sym_func) elf_link_output_sym)))
@@ -4098,20 +3840,20 @@ static bfd_boolean
 elf_link_output_sym (struct elf_final_link_info *finfo,
                     const char *name,
                     Elf_Internal_Sym *elfsym,
-                    asection *input_sec)
+                    asection *input_sec,
+                    struct elf_link_hash_entry *h)
 {
   Elf_External_Sym *dest;
   Elf_External_Sym_Shndx *destshndx;
   bfd_boolean (*output_symbol_hook)
-    (bfd *, struct bfd_link_info *info, const char *,
-     Elf_Internal_Sym *, asection *);
+    (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *,
+     struct elf_link_hash_entry *);
 
   output_symbol_hook = get_elf_backend_data (finfo->output_bfd)->
     elf_backend_link_output_symbol_hook;
   if (output_symbol_hook != NULL)
     {
-      if (! ((*output_symbol_hook)
-            (finfo->output_bfd, finfo->info, name, elfsym, input_sec)))
+      if (! (*output_symbol_hook) (finfo->info, name, elfsym, input_sec, h))
        return FALSE;
     }
 
@@ -4196,7 +3938,7 @@ elf_link_check_versioned_symbol (struct bfd_link_info *info,
   bfd *abfd;
   struct elf_link_loaded_list *loaded;
 
-  if (info->hash->creator->flavour != bfd_target_elf_flavour)
+  if (!is_elf_hash_table (info->hash))
     return FALSE;
 
   switch (h->root.type)
@@ -4493,8 +4235,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
                  {
                    /* STT_TLS symbols are relative to PT_TLS segment
                       base.  */
-                   BFD_ASSERT (finfo->first_tls_sec != NULL);
-                   sym.st_value -= finfo->first_tls_sec->vma;
+                   BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
+                   sym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
                  }
              }
          }
@@ -4652,7 +4394,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
 
   h->indx = bfd_get_symcount (finfo->output_bfd);
 
-  if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec))
+  if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec, h))
     {
       eoinfo->failed = TRUE;
       return FALSE;
@@ -4852,12 +4594,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
          if (ELF_ST_TYPE (osym.st_info) == STT_TLS)
            {
              /* STT_TLS symbols are relative to PT_TLS segment base.  */
-             BFD_ASSERT (finfo->first_tls_sec != NULL);
-             osym.st_value -= finfo->first_tls_sec->vma;
+             BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL);
+             osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma;
            }
        }
 
-      if (! elf_link_output_sym (finfo, name, &osym, isec))
+      if (! elf_link_output_sym (finfo, name, &osym, isec, NULL))
        return FALSE;
     }
 
@@ -5209,15 +4951,18 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                                {
                                  /* STT_TLS symbols are relative to PT_TLS
                                     segment base.  */
-                                 BFD_ASSERT (finfo->first_tls_sec != NULL);
-                                 sym.st_value -= finfo->first_tls_sec->vma;
+                                 BFD_ASSERT (elf_hash_table (finfo->info)
+                                             ->tls_sec != NULL);
+                                 sym.st_value -= (elf_hash_table (finfo->info)
+                                                  ->tls_sec->vma);
                                }
                            }
 
                          finfo->indices[r_symndx]
                            = bfd_get_symcount (output_bfd);
 
-                         if (! elf_link_output_sym (finfo, name, &sym, sec))
+                         if (! elf_link_output_sym (finfo, name, &sym, sec,
+                                                    NULL))
                            return FALSE;
                        }
 
@@ -5680,7 +5425,7 @@ elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *idxptr)
   return TRUE;
 }
 
-/* Propogate collected vtable information.  This is called through
+/* Propagate collected vtable information.  This is called through
    elf_link_hash_traverse.  */
 
 static bfd_boolean
@@ -5803,9 +5548,14 @@ elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
      struct elf_link_hash_entry *h, Elf_Internal_Sym *);
 
   if (!get_elf_backend_data (abfd)->can_gc_sections
-      || info->relocatable || info->emitrelocations
+      || info->relocatable
+      || info->emitrelocations
+      || !is_elf_hash_table (info->hash)
       || elf_hash_table (info)->dynamic_sections_created)
-    return TRUE;
+    {
+      (*_bfd_error_handler)(_("Warning: gc-sections option ignored"));
+      return TRUE;
+    }
 
   /* Apply transitive closure to the vtable entry usage info.  */
   elf_link_hash_traverse (elf_hash_table (info),
@@ -5846,7 +5596,7 @@ elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 \f
-/* Called from check_relocs to record the existance of a VTINHERIT reloc.  */
+/* Called from check_relocs to record the existence of a VTINHERIT reloc.  */
 
 bfd_boolean
 elf_gc_record_vtinherit (bfd *abfd,
@@ -5902,7 +5652,7 @@ elf_gc_record_vtinherit (bfd *abfd,
   return TRUE;
 }
 
-/* Called from check_relocs to record the existance of a VTENTRY reloc.  */
+/* Called from check_relocs to record the existence of a VTENTRY reloc.  */
 
 bfd_boolean
 elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
@@ -5979,6 +5729,9 @@ elf_gc_common_finalize_got_offsets (bfd *abfd,
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   bfd_vma gotoff;
 
+  if (! is_elf_hash_table (info->hash))
+    return FALSE;
+
   /* The GOT offset is relative to the .got section, but the GOT header is
      put into the .got.plt section, if the backend uses it.  */
   if (bed->want_got_plt)
@@ -6185,8 +5938,7 @@ elf_bfd_discard_info (bfd *output_bfd, struct bfd_link_info *info)
   bfd_boolean ret = FALSE;
 
   if (info->traditional_format
-      || info->hash->creator->flavour != bfd_target_elf_flavour
-      || ! is_elf_hash_table (info))
+      || !is_elf_hash_table (info->hash))
     return FALSE;
 
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
This page took 0.058486 seconds and 4 git commands to generate.