2000-07-19 H.J. Lu <hjl@gnu.org>
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 35bf885d82cc21c931a3198be4177597ef885290..1bf366873a821a0998e92d3f612f310baeb6184c 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linker support.
-   Copyright 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -80,6 +80,138 @@ elf_bfd_link_add_symbols (abfd, info)
     }
 }
 \f
+/* Return true iff this is a non-common definition of a symbol.  */
+static boolean
+is_global_symbol_definition (abfd, sym)
+     bfd * abfd ATTRIBUTE_UNUSED;
+     Elf_Internal_Sym * sym;
+{
+  /* Local symbols do not count, but target specific ones might.  */
+  if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+      && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+    return false;
+
+  /* If the section is undefined, then so is the symbol.  */
+  if (sym->st_shndx == SHN_UNDEF)
+    return false;
+  
+  /* If the symbol is defined in the common section, then
+     it is a common definition and so does not count.  */
+  if (sym->st_shndx == SHN_COMMON)
+    return false;
+
+  /* If the symbol is in a target specific section then we
+     must rely upon the backend to tell us what it is.  */
+  if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS)
+    /* FIXME - this function is not coded yet:
+       
+       return _bfd_is_global_symbol_definition (abfd, sym);
+       
+       Instead for now assume that the definition is not global,
+       Even if this is wrong, at least the linker will behave
+       in the same way that it used to do.  */
+    return false;
+      
+  return true;
+}
+
+
+/* Search the symbol table of the archive element of the archive ABFD
+   whoes archove map contains a mention of SYMDEF, and determine if
+   the symbol is defined in this element.  */
+static boolean
+elf_link_is_defined_archive_symbol (abfd, symdef)
+     bfd * abfd;
+     carsym * symdef;
+{
+  Elf_Internal_Shdr * hdr;
+  Elf_External_Sym *  esym;
+  Elf_External_Sym *  esymend;
+  Elf_External_Sym *  buf = NULL;
+  size_t symcount;
+  size_t extsymcount;
+  size_t extsymoff;
+  boolean result = false;
+  
+  abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+  if (abfd == (bfd *) NULL)
+    return false;
+
+  if (! bfd_check_format (abfd, bfd_object))
+    return false;
+
+  /* If we have already included the element containing this symbol in the
+     link then we do not need to include it again.  Just claim that any symbol
+     it contains is not a definition, so that our caller will not decide to
+     (re)include this element.  */
+  if (abfd->archive_pass)
+    return false;
+  
+  /* Select the appropriate symbol table.  */
+  if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+    hdr = &elf_tdata (abfd)->symtab_hdr;
+  else
+    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+
+  symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+
+  /* The sh_info field of the symtab header tells us where the
+     external symbols start.  We don't care about the local symbols.  */
+  if (elf_bad_symtab (abfd))
+    {
+      extsymcount = symcount;
+      extsymoff = 0;
+    }
+  else
+    {
+      extsymcount = symcount - hdr->sh_info;
+      extsymoff = hdr->sh_info;
+    }
+
+  buf = ((Elf_External_Sym *)
+        bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+  if (buf == NULL && extsymcount != 0)
+    return false;
+
+  /* Read in the symbol table.
+     FIXME:  This ought to be cached somewhere.  */
+  if (bfd_seek (abfd,
+               hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
+               SEEK_SET) != 0
+      || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
+         != extsymcount * sizeof (Elf_External_Sym)))
+    {
+      free (buf);
+      return false;
+    }
+
+  /* Scan the symbol table looking for SYMDEF.  */
+  esymend = buf + extsymcount;
+  for (esym = buf;
+       esym < esymend;
+       esym++)
+    {
+      Elf_Internal_Sym sym;
+      const char * name;
+
+      elf_swap_symbol_in (abfd, esym, & sym);
+
+      name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+      if (name == (const char *) NULL)
+       break;
+
+      if (strcmp (name, symdef->name) == 0)
+       {
+         result = is_global_symbol_definition (abfd, & sym);
+         break;
+       }
+    }
+
+  free (buf);
+  
+  return result;
+}
+\f
 
 /* Add symbols from an ELF archive file to the linker hash table.  We
    don't use _bfd_generic_link_add_archive_symbols because of a
@@ -200,7 +332,24 @@ elf_link_add_archive_symbols (abfd, info)
          if (h == NULL)
            continue;
 
-         if (h->root.type != bfd_link_hash_undefined)
+         if (h->root.type == bfd_link_hash_common)
+           {
+             /* We currently have a common symbol.  The archive map contains
+                a reference to this symbol, so we may want to include it.  We
+                only want to include it however, if this archive element
+                contains a definition of the symbol, not just another common
+                declaration of it.
+
+                Unfortunately some archivers (including GNU ar) will put
+                declarations of common symbols into their archive maps, as
+                well as real definitions, so we cannot just go by the archive
+                map alone.  Instead we must read in the element's symbol
+                table and check that to see what kind of symbol definition
+                this is.  */
+             if (! elf_link_is_defined_archive_symbol (abfd, symdef))
+               continue;
+           }
+         else if (h->root.type != bfd_link_hash_undefined)
            {
              if (h->root.type != bfd_link_hash_undefweak)
                defined[i] = true;
@@ -208,7 +357,6 @@ elf_link_add_archive_symbols (abfd, info)
            }
 
          /* We need to include this archive member.  */
-
          element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
          if (element == (bfd *) NULL)
            goto error_return;
@@ -683,8 +831,12 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
       /* To make this work we have to frob the flags so that the rest
          of the code does not think we are using the regular
          definition.  */
-      h->elf_link_hash_flags &= ~ ELF_LINK_HASH_DEF_REGULAR;
-      h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+       h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+      else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+       h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+      h->elf_link_hash_flags &= ~ (ELF_LINK_HASH_DEF_REGULAR
+                                  | ELF_LINK_HASH_DEF_DYNAMIC);
 
       /* If H is the target of an indirection, we want the caller to
          use H rather than the indirect symbol.  Otherwise if we are
@@ -737,9 +889,12 @@ elf_link_add_object_symbols (abfd, info)
   struct elf_link_hash_entry *weaks;
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
+  struct elf_backend_data *bed;
+  boolean dt_needed;
 
-  add_symbol_hook = get_elf_backend_data (abfd)->elf_add_symbol_hook;
-  collect = get_elf_backend_data (abfd)->collect;
+  bed = get_elf_backend_data (abfd);
+  add_symbol_hook = bed->elf_add_symbol_hook;
+  collect = bed->collect;
 
   if ((abfd->flags & DYNAMIC) == 0)
     dynamic = false;
@@ -895,6 +1050,8 @@ elf_link_add_object_symbols (abfd, info)
     goto error_return;
   elf_sym_hashes (abfd) = sym_hash;
 
+  dt_needed = false;
+
   if (! dynamic)
     {
       /* If we are creating a shared library, create all the dynamic
@@ -931,7 +1088,12 @@ elf_link_add_object_symbols (abfd, info)
        {
          name = elf_dt_name (abfd);
          if (*name == '\0')
-           add_needed = false;
+           {
+             if (elf_dt_soname (abfd) != NULL)
+               dt_needed = true;
+
+             add_needed = false;
+           }
        }
       s = bfd_get_section_by_name (abfd, ".dynamic");
       if (s != NULL)
@@ -954,6 +1116,23 @@ elf_link_add_object_symbols (abfd, info)
            goto error_return;
          link = elf_elfsections (abfd)[elfsec]->sh_link;
 
+         {
+           /* The shared libraries distributed with hpux11 have a bogus
+              sh_link field for the ".dynamic" section.  This code detects
+              when LINK refers to a section that is not a string table and
+              tries to find the string table for the ".dynsym" section
+              instead.  */
+           Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[link];
+           if (hdr->sh_type != SHT_STRTAB)
+             {
+               asection *s = bfd_get_section_by_name (abfd, ".dynsym");
+               int elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
+               if (elfsec == -1)
+                 goto error_return;
+               link = elf_elfsections (abfd)[elfsec]->sh_link;
+             }
+         }
+
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
          for (; extdyn < extdynend; extdyn++)
@@ -1272,7 +1451,11 @@ elf_link_add_object_symbols (abfd, info)
                  strcpy (newname, name);
                  p = newname + namelen;
                  *p++ = ELF_VER_CHR;
-                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0)
+                 /* If this is a defined non-hidden version symbol,
+                    we add another @ to the name.  This indicates the
+                    default version of the symbol.  */
+                 if ((iver.vs_vers & VERSYM_HIDDEN) == 0
+                     && sym.st_shndx != SHN_UNDEF)
                    *p++ = ELF_VER_CHR;
                  strcpy (p, verstr);
 
@@ -1396,9 +1579,24 @@ elf_link_add_object_symbols (abfd, info)
              h->type = ELF_ST_TYPE (sym.st_info);
            }
 
-         if (sym.st_other != 0
-             && (definition || h->other == 0))
-           h->other = sym.st_other;
+         /* If st_other has a processor-specific meaning, specific code
+            might be needed here.  */
+         if (sym.st_other != 0)
+           {
+             /* Combine visibilities, using the most constraining one.  */
+             unsigned char hvis   = ELF_ST_VISIBILITY (h->other);
+             unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+             
+             if (symvis && (hvis > symvis || hvis == 0))
+               h->other = sym.st_other;
+             
+             /* If neither has visibility, use the st_other of the
+                definition.  This is an arbitrary choice, since the
+                other bits have no general meaning.  */
+             if (!symvis && !hvis
+                 && (definition || h->other == 0))
+               h->other = sym.st_other;
+           }
 
          /* Set a flag in the hash table entry indicating the type of
             reference or definition we just found.  Keep a count of
@@ -1549,44 +1747,7 @@ elf_link_add_object_symbols (abfd, info)
                                  == 0);
 
                      ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-
-                     /* Copy down any references that we may have
-                        already seen to the symbol which just became
-                        indirect.  */
-                     ht->elf_link_hash_flags |=
-                       (hi->elf_link_hash_flags
-                        & (ELF_LINK_HASH_REF_DYNAMIC
-                           | ELF_LINK_HASH_REF_REGULAR
-                           | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
-
-                     /* Copy over the global and procedure linkage table
-                        offset entries.  These may have been already set
-                        up by a check_relocs routine.  */
-                     if (ht->got.offset == (bfd_vma) -1)
-                       {
-                         ht->got.offset = hi->got.offset;
-                         hi->got.offset = (bfd_vma) -1;
-                       }
-                     BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
-                     if (ht->plt.offset == (bfd_vma) -1)
-                       {
-                         ht->plt.offset = hi->plt.offset;
-                         hi->plt.offset = (bfd_vma) -1;
-                       }
-                     BFD_ASSERT (hi->plt.offset == (bfd_vma) -1);
-
-                     if (ht->dynindx == -1)
-                       {
-                         ht->dynindx = hi->dynindx;
-                         ht->dynstr_index = hi->dynstr_index;
-                         hi->dynindx = -1;
-                         hi->dynstr_index = 0;
-                       }
-                     BFD_ASSERT (hi->dynindx == -1);
-
-                     /* FIXME: There may be other information to copy
-                        over for particular targets.  */
+                     (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
 
                      /* See if the new flags lead us to realize that
                         the symbol must be dynamic.  */
@@ -1659,43 +1820,7 @@ elf_link_add_object_symbols (abfd, info)
                                          | ELF_LINK_HASH_DEF_REGULAR))
                                      == 0);
 
-                         /* Copy down any references that we may have
-                             already seen to the symbol which just
-                             became indirect.  */
-                         h->elf_link_hash_flags |=
-                           (hi->elf_link_hash_flags
-                            & (ELF_LINK_HASH_REF_DYNAMIC
-                               | ELF_LINK_HASH_REF_REGULAR
-                               | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
-
-                         /* Copy over the global and procedure linkage
-                             table offset entries.  These may have been
-                             already set up by a check_relocs routine.  */
-                         if (h->got.offset == (bfd_vma) -1)
-                           {
-                             h->got.offset = hi->got.offset;
-                             hi->got.offset = (bfd_vma) -1;
-                           }
-                         BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
-                         if (h->plt.offset == (bfd_vma) -1)
-                           {
-                             h->plt.offset = hi->plt.offset;
-                             hi->plt.offset = (bfd_vma) -1;
-                           }
-                         BFD_ASSERT (hi->got.offset == (bfd_vma) -1);
-
-                         if (h->dynindx == -1)
-                           {
-                             h->dynindx = hi->dynindx;
-                             h->dynstr_index = hi->dynstr_index;
-                             hi->dynindx = -1;
-                             hi->dynstr_index = 0;
-                           }
-                         BFD_ASSERT (hi->dynindx == -1);
-
-                         /* FIXME: There may be other information to
-                             copy over for particular targets.  */
+                         (*bed->elf_backend_copy_indirect_symbol) (h, hi);
 
                          /* See if the new flags lead us to realize
                              that the symbol must be dynamic.  */
@@ -1734,6 +1859,65 @@ elf_link_add_object_symbols (abfd, info)
                    goto error_return;
                }
            }
+         else if (dynsym && h->dynindx != -1)
+           /* If the symbol already has a dynamic index, but
+              visibility says it should not be visible, turn it into
+              a local symbol.  */
+           switch (ELF_ST_VISIBILITY (h->other))
+             {
+             case STV_INTERNAL:
+             case STV_HIDDEN:  
+               h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+               (*bed->elf_backend_hide_symbol) (info, h);
+               break;
+             }
+
+         if (dt_needed && definition
+             && (h->elf_link_hash_flags
+                 & ELF_LINK_HASH_REF_REGULAR) != 0)
+           {
+             bfd_size_type oldsize;
+             bfd_size_type strindex;
+
+             /* The symbol from a DT_NEEDED object is referenced from
+                the regular object to create a dynamic executable. We
+                have to make sure there is a DT_NEEDED entry for it. */
+
+             dt_needed = false;
+             oldsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+             strindex = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
+                                            elf_dt_soname (abfd),
+                                            true, false);
+             if (strindex == (bfd_size_type) -1)
+               goto error_return;
+
+             if (oldsize
+                 == _bfd_stringtab_size (elf_hash_table (info)->dynstr))
+               {
+                 asection *sdyn;
+                 Elf_External_Dyn *dyncon, *dynconend;
+
+                 sdyn = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
+                                                 ".dynamic");
+                 BFD_ASSERT (sdyn != NULL);
+
+                 dyncon = (Elf_External_Dyn *) sdyn->contents;
+                 dynconend = (Elf_External_Dyn *) (sdyn->contents +
+                                                   sdyn->_raw_size);
+                 for (; dyncon < dynconend; dyncon++)
+                   {
+                     Elf_Internal_Dyn dyn;
+
+                     elf_swap_dyn_in (elf_hash_table (info)->dynobj,
+                                      dyncon, &dyn);
+                     BFD_ASSERT (dyn.d_tag != DT_NEEDED ||
+                                 dyn.d_un.d_val != strindex);
+                   }
+               }
+
+             if (! elf_add_dynamic_entry (info, DT_NEEDED, strindex))
+               goto error_return;
+           }
        }
     }
 
@@ -2631,20 +2815,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   if (dynobj == NULL)
     return true;
 
-  /* If we are supposed to export all symbols into the dynamic symbol
-     table (this is not the normal case), then do so.  */
-  if (export_dynamic)
-    {
-      struct elf_info_failed eif;
-
-      eif.failed = false;
-      eif.info = info;
-      elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
-                             (PTR) &eif);
-      if (eif.failed)
-       return false;
-    }
-
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
@@ -2667,6 +2837,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          if (! elf_add_dynamic_entry (info, DT_SYMBOLIC, 0))
            return false;
+         info->flags |= DF_SYMBOLIC;
        }
 
       if (rpath != NULL)
@@ -2676,7 +2847,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
                                     true, true);
          if (indx == (bfd_size_type) -1
-             || ! elf_add_dynamic_entry (info, DT_RPATH, indx))
+             || ! elf_add_dynamic_entry (info, DT_RPATH, indx)
+             || ! elf_add_dynamic_entry (info, DT_RUNPATH, indx))
            return false;
        }
 
@@ -2707,6 +2879,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            }
        }
 
+      /* If we are supposed to export all symbols into the dynamic symbol
+         table (this is not the normal case), then do so.  */
+      if (export_dynamic)
+       {
+         struct elf_info_failed eif;
+
+         eif.failed = false;
+         eif.info = info;
+         elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol,
+                                 (PTR) &eif);
+         if (eif.failed)
+           return false;
+       }
+
       /* Attach all the symbols to their version information.  */
       asvinfo.output_bfd = output_bfd;
       asvinfo.info = info;
@@ -2794,7 +2980,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       verdefs = asvinfo.verdefs;
 
       if (verdefs == NULL)
-       _bfd_strip_section_from_output (s);
+       _bfd_strip_section_from_output (info, s);
       else
        {
          unsigned int cdefs;
@@ -2951,6 +3137,22 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          elf_tdata (output_bfd)->cverdefs = cdefs;
        }
 
+      if (info->flags)
+       {
+         if (! elf_add_dynamic_entry (info, DT_FLAGS, info->flags))
+           return false;
+       }
+
+      if (info->flags_1)
+       {
+         if (! info->shared)
+           info->flags_1 &= ~ (DF_1_INITFIRST
+                               | DF_1_NODELETE
+                               | DF_1_NOOPEN);
+         if (! elf_add_dynamic_entry (info, DT_FLAGS_1, info->flags_1))
+           return false;
+       }
+
       /* Work out the size of the version reference section.  */
 
       s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
@@ -2970,7 +3172,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                                (PTR) &sinfo);
 
        if (elf_tdata (output_bfd)->verref == NULL)
-         _bfd_strip_section_from_output (s);
+         _bfd_strip_section_from_output (info, s);
        else
          {
            Elf_Internal_Verneed *t;
@@ -3074,7 +3276,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (dynsymcount == 0
          || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
        {
-         _bfd_strip_section_from_output (s);
+         _bfd_strip_section_from_output (info, s);
          /* The DYNSYMCOUNT might have changed if we were going to
             output a dynamic symbol table entry for S.  */
          dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
@@ -3160,6 +3362,9 @@ elf_fix_symbol_flags (h, eif)
      an ELF dynamic object.  */
   if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0)
     {
+      while (h->root.type == bfd_link_hash_indirect)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
       if (h->root.type != bfd_link_hash_defined
          && h->root.type != bfd_link_hash_defweak)
        h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR
@@ -3221,16 +3426,45 @@ elf_fix_symbol_flags (h, eif)
   /* If -Bsymbolic was used (which means to bind references to global
      symbols to the definition within the shared object), and this
      symbol was defined in a regular object, then it actually doesn't
-     need a PLT entry.  */
+     need a PLT entry.  Likewise, if the symbol has any kind of
+     visibility (internal, hidden, or protected), it doesn't need a
+     PLT.  */
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
       && eif->info->shared
-      && eif->info->symbolic
+      && (eif->info->symbolic || ELF_ST_VISIBILITY (h->other))
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
     {
       h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
       h->plt.offset = (bfd_vma) -1;
     }
 
+  /* If this is a weak defined symbol in a dynamic object, and we know
+     the real definition in the dynamic object, copy interesting flags
+     over to the real definition.  */
+  if (h->weakdef != NULL)
+    {
+      struct elf_link_hash_entry *weakdef;
+
+      BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak);
+      weakdef = h->weakdef;
+      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
+                 || weakdef->root.type == bfd_link_hash_defweak);
+      BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
+
+      /* If the real definition is defined by a regular object file,
+        don't do anything special.  See the longer description in
+        elf_adjust_dynamic_symbol, below.  */
+      if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
+       h->weakdef = NULL;
+      else
+       weakdef->elf_link_hash_flags |=
+         (h->elf_link_hash_flags
+          & (ELF_LINK_HASH_REF_REGULAR
+             | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+             | ELF_LINK_NON_GOT_REF));
+    }
+
   return true;
 }
 
@@ -3313,32 +3547,14 @@ elf_adjust_dynamic_symbol (h, data)
 
   if (h->weakdef != NULL)
     {
-      struct elf_link_hash_entry *weakdef;
+      /* If we get to this point, we know there is an implicit
+        reference by a regular object file via the weak symbol H.
+        FIXME: Is this really true?  What if the traversal finds
+        H->WEAKDEF before it finds H?  */
+      h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
 
-      BFD_ASSERT (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak);
-      weakdef = h->weakdef;
-      BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined
-                 || weakdef->root.type == bfd_link_hash_defweak);
-      BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC);
-      if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
-       {
-         /* This symbol is defined by a regular object file, so we
-            will not do anything special.  Clear weakdef for the
-            convenience of the processor backend.  */
-         h->weakdef = NULL;
-       }
-      else
-       {
-         /* There is an implicit reference by a regular object file
-            via the weak symbol.  */
-         weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
-         if (h->weakdef->elf_link_hash_flags
-             & ELF_LINK_HASH_REF_REGULAR_NONWEAK)
-           weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR_NONWEAK;
-         if (! elf_adjust_dynamic_symbol (weakdef, (PTR) eif))
-           return false;
-       }
+      if (! elf_adjust_dynamic_symbol (h->weakdef, (PTR) eif))
+       return false;
     }
 
   /* If a symbol has no type and no size and does not require a PLT
@@ -3477,6 +3693,7 @@ elf_link_assign_sym_version (h, data)
   struct elf_assign_sym_version_info *sinfo =
     (struct elf_assign_sym_version_info *) data;
   struct bfd_link_info *info = sinfo->info;
+  struct elf_backend_data *bed;
   struct elf_info_failed eif;
   char *p;
 
@@ -3495,6 +3712,7 @@ elf_link_assign_sym_version (h, data)
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
     return true;
 
+  bed = get_elf_backend_data (sinfo->output_bfd);
   p = strchr (h->root.root.string, ELF_VER_CHR);
   if (p != NULL && h->verinfo.vertree == NULL)
     {
@@ -3562,10 +3780,7 @@ elf_link_assign_sym_version (h, data)
                              && ! sinfo->export_dynamic)
                            {
                              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                             h->elf_link_hash_flags &=~
-                               ELF_LINK_HASH_NEEDS_PLT;
-                             h->dynindx = -1;
-                             h->plt.offset = (bfd_vma) -1;
+                             (*bed->elf_backend_hide_symbol) (info, h);
                              /* FIXME: The name of the symbol has
                                 already been recorded in the dynamic
                                 string table section.  */
@@ -3677,9 +3892,7 @@ elf_link_assign_sym_version (h, data)
                          && ! sinfo->export_dynamic)
                        {
                          h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                         h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
-                         h->dynindx = -1;
-                         h->plt.offset = (bfd_vma) -1;
+                         (*bed->elf_backend_hide_symbol) (info, h);
                          /* FIXME: The name of the symbol has already
                             been recorded in the dynamic string table
                             section.  */
@@ -3701,9 +3914,7 @@ elf_link_assign_sym_version (h, data)
              && ! sinfo->export_dynamic)
            {
              h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-             h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
-             h->dynindx = -1;
-             h->plt.offset = (bfd_vma) -1;
+             (*bed->elf_backend_hide_symbol) (info, h);
              /* FIXME: The name of the symbol has already been
                 recorded in the dynamic string table section.  */
            }
@@ -3838,6 +4049,7 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
      struct elf_link_hash_entry **rel_hash;
 {
   unsigned int i;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   for (i = 0; i < count; i++, rel_hash++)
     {
@@ -3852,10 +4064,16 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
          Elf_Internal_Rel irel;
          
          erel = (Elf_External_Rel *) rel_hdr->contents + i;
-         elf_swap_reloc_in (abfd, erel, &irel);
+         if (bed->s->swap_reloc_in)
+           (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &irel);
+         else
+           elf_swap_reloc_in (abfd, erel, &irel);
          irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
                                    ELF_R_TYPE (irel.r_info));
-         elf_swap_reloc_out (abfd, &irel, erel);
+         if (bed->s->swap_reloc_out)
+           (*bed->s->swap_reloc_out) (abfd, &irel, (bfd_byte *) erel);
+         else
+           elf_swap_reloc_out (abfd, &irel, erel);
        }
       else
        {
@@ -3866,10 +4084,16 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
                      == sizeof (Elf_External_Rela));
          
          erela = (Elf_External_Rela *) rel_hdr->contents + i;
-         elf_swap_reloca_in (abfd, erela, &irela);
+         if (bed->s->swap_reloca_in)
+           (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, &irela);
+         else
+           elf_swap_reloca_in (abfd, erela, &irela);
          irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
                                     ELF_R_TYPE (irela.r_info));
-         elf_swap_reloca_out (abfd, &irela, erela);
+         if (bed->s->swap_reloca_out)
+           (*bed->s->swap_reloca_out) (abfd, &irela, (bfd_byte *) erela);
+         else
+           elf_swap_reloca_out (abfd, &irela, erela);
        }
     }
 }
@@ -3964,7 +4188,7 @@ elf_bfd_final_link (abfd, info)
                 the linker has decided to not include.  */
              sec->linker_mark = true;
 
-             if (info->relocateable)
+             if (info->relocateable || info->emitrelocations)
                o->reloc_count += sec->reloc_count;
 
              if (sec->_raw_size > max_contents_size)
@@ -4032,13 +4256,22 @@ elf_bfd_final_link (abfd, info)
   /* Figure out how many relocations we will have in each section.
      Just using RELOC_COUNT isn't good enough since that doesn't
      maintain a separate value for REL vs. RELA relocations.  */
-  if (info->relocateable)
+  if (info->relocateable || info->emitrelocations)
     for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
       for (o = sub->sections; o != NULL; o = o->next)
        {
-         asection* output_section = o->output_section;
+         asection *output_section;
 
-         if (output_section && (o->flags & SEC_RELOC) != 0)
+         if (! o->linker_mark)
+           {
+             /* This section was omitted from the link.  */
+             continue;
+           }
+
+         output_section = o->output_section;
+
+         if (output_section != NULL
+             && (o->flags & SEC_RELOC) != 0)
            {
              struct bfd_elf_section_data *esdi 
                = elf_section_data (o);
@@ -4131,7 +4364,7 @@ elf_bfd_final_link (abfd, info)
 
   /* Start writing out the symbol table.  The first symbol is always a
      dummy symbol.  */
-  if (info->strip != strip_all || info->relocateable)
+  if (info->strip != strip_all || info->relocateable || info->emitrelocations)
     {
       elfsym.st_value = 0;
       elfsym.st_size = 0;
@@ -4164,7 +4397,7 @@ elf_bfd_final_link (abfd, info)
      symbols have no names.  We store the index of each one in the
      index field of the section, so that we can find it again when
      outputting relocs.  */
-  if (info->strip != strip_all || info->relocateable)
+  if (info->strip != strip_all || info->relocateable || info->emitrelocations)
     {
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
@@ -4264,9 +4497,11 @@ elf_bfd_final_link (abfd, info)
     }
 
   /* That wrote out all the local symbols.  Finish up the symbol table
-     with the global symbols.  */
+     with the global symbols. Even if we want to strip everything we
+     can, we still need to deal with those global symbols that got
+     converted to local in a version script. */
 
-  if (info->strip != strip_all && info->shared)
+  if (info->shared)
     {
       /* Output any global symbols that got converted to local in a
          version script.  We do this in a separate step since ELF
@@ -4291,7 +4526,7 @@ elf_bfd_final_link (abfd, info)
       Elf_Internal_Sym sym;
       Elf_External_Sym *dynsym =
        (Elf_External_Sym *)finfo.dynsym_sec->contents;
-      unsigned long last_local = 0;
+      long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
       if (info->shared)
@@ -4353,8 +4588,8 @@ elf_bfd_final_link (abfd, info)
            }
        }
 
-      elf_section_data (finfo.dynsym_sec->output_section)
-       ->this_hdr.sh_info = last_local + 1;
+      elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info =
+       last_local + 1;
     }
 
   /* We get the global symbols from the hash table.  */
@@ -4773,7 +5008,7 @@ elf_link_output_extsym (h, data)
     {
       if (! ((*finfo->info->callbacks->undefined_symbol)
             (finfo->info, h->root.root.string, h->root.u.undef.abfd,
-             (asection *) NULL, 0)))
+             (asection *) NULL, 0, true)))
        {
          eoinfo->failed = true;
          return false;
@@ -4801,8 +5036,10 @@ elf_link_output_extsym (h, data)
     strip = false;
 
   /* If we're stripping it, and it's not a dynamic symbol, there's
-     nothing else to do.  */
-  if (strip && h->dynindx == -1)
+     nothing else to do unless it is a forced local symbol.  */
+  if (strip
+      && h->dynindx == -1
+      && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
     return true;
 
   sym.st_value = 0;
@@ -4882,12 +5119,9 @@ elf_link_output_extsym (h, data)
          symbol foo@@GNU_1.2 is the default, which should be used when
          foo is used with no version, then we add an indirect symbol
          foo which points to foo@@GNU_1.2.  We ignore these symbols,
-         since the indirected symbol is already in the hash table.  If
-         the indirect symbol is non-ELF, fall through and output it.  */
-      if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) == 0)
-       return true;
+         since the indirected symbol is already in the hash table.  */
+      return true;
 
-      /* Fall through.  */
     case bfd_link_hash_warning:
       /* We can't represent these symbols in ELF, although a warning
          symbol may have come from a .gnu.warning.SYMBOL section.  We
@@ -4937,6 +5171,11 @@ elf_link_output_extsym (h, data)
       sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info));
     }
 
+  /* If a symbol is not defined locally, we clear the visibility
+     field. */
+  if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+    sym.st_other ^= ELF_ST_VISIBILITY(sym.st_other);
+
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We have already know the symbol index.  We also fill
      in the entry in the .hash section.  */
@@ -5030,6 +5269,7 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
   Elf_Internal_Shdr *output_rel_hdr;
   asection *output_section;
   unsigned int *rel_countp = NULL;
+  struct elf_backend_data *bed;
 
   output_section = input_section->output_section;
   output_rel_hdr = NULL;
@@ -5049,7 +5289,8 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
     }
 
   BFD_ASSERT (output_rel_hdr != NULL);
-  
+
+  bed = get_elf_backend_data (output_bfd);
   irela = internal_relocs;
   irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
   if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
@@ -5064,7 +5305,10 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
          irel.r_offset = irela->r_offset;
          irel.r_info = irela->r_info;
          BFD_ASSERT (irela->r_addend == 0);
-         elf_swap_reloc_out (output_bfd, &irel, erel);
+         if (bed->s->swap_reloc_out)
+           (*bed->s->swap_reloc_out) (output_bfd, &irel, (PTR) erel);
+         else
+           elf_swap_reloc_out (output_bfd, &irel, erel);
        }
     }
   else
@@ -5075,7 +5319,10 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
                  == sizeof (Elf_External_Rela));
       erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
       for (; irela < irelaend; irela++, erela++)
-       elf_swap_reloca_out (output_bfd, irela, erela);
+       if (bed->s->swap_reloca_out)
+         (*bed->s->swap_reloca_out) (output_bfd, irela, (PTR) erela);
+       else
+         elf_swap_reloca_out (output_bfd, irela, erela);
     }
 
   /* Bump the counter, so that we know where to add the next set of
@@ -5339,7 +5586,7 @@ elf_link_input_bfd (finfo, input_bfd)
                                     finfo->sections))
            return false;
 
-         if (finfo->info->relocateable)
+         if (finfo->info->relocateable || finfo->info->emitrelocations)
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
@@ -5362,6 +5609,10 @@ elf_link_input_bfd (finfo, input_bfd)
 
                  irela->r_offset += o->output_offset;
 
+                 /* Relocs in an executable have to be virtual addresses.  */
+                 if (finfo->info->emitrelocations)
+                   irela->r_offset += o->output_section->vma;
+
                  r_symndx = ELF_R_SYM (irela->r_info);
 
                  if (r_symndx == 0)
@@ -5531,6 +5782,7 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
   bfd_vma addend;
   struct elf_link_hash_entry **rel_hash_ptr;
   Elf_Internal_Shdr *rel_hdr;
+  struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
 
   howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
   if (howto == NULL)
@@ -5654,7 +5906,10 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       irel.r_info = ELF_R_INFO (indx, howto->type);
       erel = ((Elf_External_Rel *) rel_hdr->contents
              + elf_section_data (output_section)->rel_count);
-      elf_swap_reloc_out (output_bfd, &irel, erel);
+      if (bed->s->swap_reloc_out)
+       (*bed->s->swap_reloc_out) (output_bfd, &irel, (bfd_byte *) erel);
+      else
+       elf_swap_reloc_out (output_bfd, &irel, erel);
     }
   else
     {
@@ -5666,7 +5921,10 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
       irela.r_addend = addend;
       erela = ((Elf_External_Rela *) rel_hdr->contents
               + elf_section_data (output_section)->rel_count);
-      elf_swap_reloca_out (output_bfd, &irela, erela);
+      if (bed->s->swap_reloca_out)
+       (*bed->s->swap_reloca_out) (output_bfd, &irela, (bfd_byte *) erela);
+      else
+       elf_swap_reloca_out (output_bfd, &irela, erela);
     }
 
   ++elf_section_data (output_section)->rel_count;
@@ -6075,6 +6333,9 @@ elf_gc_sweep (info, gc_sweep_hook)
     {
       asection *o;
 
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+       continue;
+
       for (o = sub->sections; o != NULL; o = o->next)
        {
          /* Keep special sections.  Keep .debug sections.  */
@@ -6265,7 +6526,7 @@ elf_gc_sections (abfd, info)
              struct elf_link_hash_entry *h, Elf_Internal_Sym *));
 
   if (!get_elf_backend_data (abfd)->can_gc_sections
-      || info->relocateable
+      || info->relocateable || info->emitrelocations
       || elf_hash_table (info)->dynamic_sections_created)
     return true;
 
@@ -6289,6 +6550,10 @@ elf_gc_sections (abfd, info)
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
       asection *o;
+
+      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
+       continue;
+
       for (o = sub->sections; o != NULL; o = o->next)
        {
          if (o->flags & SEC_KEEP)
@@ -6392,30 +6657,31 @@ elf_gc_record_vtentry (abfd, sec, h, addend)
 
       /* Allocate one extra entry for use as a "done" flag for the
         consolidation pass.  */
-      bytes = (size / FILE_ALIGN + 1) * sizeof(boolean);
+      bytes = (size / FILE_ALIGN + 1) * sizeof (boolean);
 
       if (ptr)
        {
-         size_t oldbytes;
-
-         ptr = realloc (ptr-1, bytes);
-         if (ptr == NULL)
-           return false;
+         ptr = bfd_realloc (ptr - 1, bytes);
+         
+         if (ptr != NULL)
+           {
+             size_t oldbytes;
 
-         oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof(boolean);
-         memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes);
+             oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof (boolean);
+             memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes);
+           }
        }
       else
-       {
-         ptr = calloc (1, bytes);
-         if (ptr == NULL)
-           return false;
-       }
+       ptr = bfd_zmalloc (bytes);
 
+      if (ptr == NULL)
+       return false;
+      
       /* And arrange for that done flag to be at index -1.  */
-      h->vtable_entries_used = ptr+1;
+      h->vtable_entries_used = ptr + 1;
       h->vtable_entries_size = size;
     }
+  
   h->vtable_entries_used[addend / FILE_ALIGN] = true;
 
   return true;
@@ -6443,10 +6709,14 @@ elf_gc_common_finalize_got_offsets (abfd, info)
   /* Do the local .got entries first.  */
   for (i = info->input_bfds; i; i = i->link_next)
     {
-      bfd_signed_vma *local_got = elf_local_got_refcounts (i);
+      bfd_signed_vma *local_got;
       bfd_size_type j, locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
 
+      if (bfd_get_flavour (i) != bfd_target_elf_flavour)
+       continue;
+
+      local_got = elf_local_got_refcounts (i);
       if (!local_got)
        continue;
 
@@ -6468,7 +6738,8 @@ elf_gc_common_finalize_got_offsets (abfd, info)
        }
     }
 
-  /* Then the global .got and .plt entries.  */
+  /* Then the global .got entries.  .plt refcounts are handled by
+     adjust_dynamic_symbol  */
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_gc_allocate_got_offsets,
                          (PTR) &gotoff);
This page took 0.038967 seconds and 4 git commands to generate.