2000-12-13 Kazu Hirata <kazu@hxi.com>
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 1cf6be991e20d462f3c71052ef67513ed59355d9..b3e1bbc6fc1e9969fb52878ec038e9af26966e00 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.
 
@@ -35,7 +35,7 @@ static boolean elf_link_add_archive_symbols
 static boolean elf_merge_symbol
   PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
           asection **, bfd_vma *, struct elf_link_hash_entry **,
-          boolean *, boolean *, boolean *));
+          boolean *, boolean *, boolean *, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static boolean elf_fix_symbol_flags
@@ -83,7 +83,7 @@ elf_bfd_link_add_symbols (abfd, info)
 /* Return true iff this is a non-common definition of a symbol.  */
 static boolean
 is_global_symbol_definition (abfd, sym)
-     bfd * abfd;
+     bfd * abfd ATTRIBUTE_UNUSED;
      Elf_Internal_Sym * sym;
 {
   /* Local symbols do not count, but target specific ones might.  */
@@ -357,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;
@@ -434,11 +433,12 @@ elf_link_add_archive_symbols (abfd, info)
    TYPE_CHANGE_OK if it is OK for the type to change.  We set
    SIZE_CHANGE_OK if it is OK for the size to change.  By OK to
    change, we mean that we shouldn't warn if the type or size does
-   change.  */
+   change. DT_NEEDED indicates if it comes from a DT_NEEDED entry of
+   a shared object.  */
 
 static boolean
 elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
-                 override, type_change_ok, size_change_ok)
+                 override, type_change_ok, size_change_ok, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
      const char *name;
@@ -449,6 +449,7 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      boolean *override;
      boolean *type_change_ok;
      boolean *size_change_ok;
+     boolean dt_needed;
 {
   asection *sec;
   struct elf_link_hash_entry *h;
@@ -625,9 +626,11 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
     olddyncommon = false;
 
   /* It's OK to change the type if either the existing symbol or the
-     new symbol is weak.  */
+     new symbol is weak unless it comes from a DT_NEEDED entry of
+     a shared object, in which case, the DT_NEEDED entry may not be
+     required at the run time. */
 
-  if (h->root.type == bfd_link_hash_defweak
+  if ((! dt_needed && h->root.type == bfd_link_hash_defweak)
       || h->root.type == bfd_link_hash_undefweak
       || bind == STB_WEAK)
     *type_change_ok = true;
@@ -679,7 +682,9 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
      object to override a weak symbol in a shared object.
 
      We prefer a non-weak definition in a shared library to a weak
-     definition in the executable.  */
+     definition in the executable unless it comes from a DT_NEEDED
+     entry of a shared object, in which case, the DT_NEEDED entry
+     may not be required at the run time. */
 
   if (newdyn
       && newdef
@@ -687,7 +692,8 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
          || (h->root.type == bfd_link_hash_common
              && (bind == STB_WEAK
                  || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
-      && (h->root.type != bfd_link_hash_defweak
+      && (h->root.type != bfd_link_hash_defweak 
+         || dt_needed
          || bind == STB_WEAK))
     {
       *override = true;
@@ -822,8 +828,11 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
 
   /* Handle the special case of a weak definition in a regular object
      followed by a non-weak definition in a shared object.  In this
-     case, we prefer the definition in the shared object.  */
+     case, we prefer the definition in the shared object unless it
+     comes from a DT_NEEDED entry of a shared object, in which case,
+     the DT_NEEDED entry may not be required at the run time. */
   if (olddef
+      && ! dt_needed
       && h->root.type == bfd_link_hash_defweak
       && newdef
       && newdyn
@@ -890,9 +899,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;
@@ -1048,6 +1060,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
@@ -1084,7 +1098,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)
@@ -1093,6 +1112,8 @@ elf_link_add_object_symbols (abfd, info)
          Elf_External_Dyn *extdynend;
          int elfsec;
          unsigned long link;
+         int rpath;
+         int runpath;
 
          dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size);
          if (dynbuf == NULL)
@@ -1126,6 +1147,8 @@ elf_link_add_object_symbols (abfd, info)
 
          extdyn = dynbuf;
          extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+         rpath = 0;
+         runpath = 0;
          for (; extdyn < extdynend; extdyn++)
            {
              Elf_Internal_Dyn dyn;
@@ -1162,6 +1185,65 @@ elf_link_add_object_symbols (abfd, info)
                    ;
                  *pn = n;
                }
+             if (dyn.d_tag == DT_RUNPATH)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+
+                 /* When we see DT_RPATH before DT_RUNPATH, we have
+                    to clear runpath.  Do _NOT_ bfd_release, as that
+                    frees all more recently bfd_alloc'd blocks as
+                    well.  */
+                 if (rpath && elf_hash_table (info)->runpath)
+                   elf_hash_table (info)->runpath = NULL;
+
+                 n = ((struct bfd_link_needed_list *)
+                      bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+                 fnm = bfd_elf_string_from_elf_section (abfd, link,
+                                                        dyn.d_un.d_val);
+                 if (n == NULL || fnm == NULL)
+                   goto error_return;
+                 anm = bfd_alloc (abfd, strlen (fnm) + 1);
+                 if (anm == NULL)
+                   goto error_return;
+                 strcpy (anm, fnm);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = &elf_hash_table (info)->runpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+                 runpath = 1;
+                 rpath = 0;
+               }
+             /* Ignore DT_RPATH if we have seen DT_RUNPATH. */
+             if (!runpath && dyn.d_tag == DT_RPATH)
+               {
+                 struct bfd_link_needed_list *n, **pn;
+                 char *fnm, *anm;
+
+                 n = ((struct bfd_link_needed_list *)
+                      bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+                 fnm = bfd_elf_string_from_elf_section (abfd, link,
+                                                        dyn.d_un.d_val);
+                 if (n == NULL || fnm == NULL)
+                   goto error_return;
+                 anm = bfd_alloc (abfd, strlen (fnm) + 1);
+                 if (anm == NULL)
+                   goto error_return;
+                 strcpy (anm, fnm);
+                 n->name = anm;
+                 n->by = abfd;
+                 n->next = NULL;
+                 for (pn = &elf_hash_table (info)->runpath;
+                      *pn != NULL;
+                      pn = &(*pn)->next)
+                   ;
+                 *pn = n;
+                 rpath = 1;
+               }
            }
 
          free (dynbuf);
@@ -1289,8 +1371,6 @@ elf_link_add_object_symbols (abfd, info)
          if (sym.st_shndx != SHN_UNDEF
              && sym.st_shndx != SHN_COMMON)
            flags = BSF_GLOBAL;
-         else
-           flags = 0;
        }
       else if (bind == STB_WEAK)
        flags = BSF_WEAK;
@@ -1442,7 +1522,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);
 
@@ -1452,7 +1536,7 @@ elf_link_add_object_symbols (abfd, info)
 
          if (! elf_merge_symbol (abfd, info, name, &sym, &sec, &value,
                                  sym_hash, &override, &type_change_ok,
-                                 &size_change_ok))
+                                 &size_change_ok, dt_needed))
            goto error_return;
 
          if (override)
@@ -1521,7 +1605,10 @@ elf_link_add_object_symbols (abfd, info)
          unsigned int align;
 
          align = bfd_log2 (sym.st_value);
-         if (align > old_alignment)
+         if (align > old_alignment
+             /* Permit an alignment power of zero if an alignment of one
+                is specified and no other alignments have been specified.  */
+             || (sym.st_value == 1 && old_alignment == 0))
            h->root.u.c.p->alignment_power = align;
        }
 
@@ -1566,9 +1653,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
@@ -1613,7 +1715,7 @@ elf_link_add_object_symbols (abfd, info)
              name to the fully decorated name.  This will cause
              external references which do not specify a version to be
              bound to this version of the symbol.  */
-         if (definition)
+         if (definition || h->root.type == bfd_link_hash_common)
            {
              char *p;
 
@@ -1640,7 +1742,8 @@ elf_link_add_object_symbols (abfd, info)
                  size_change_ok = false;
                  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
                                          &value, &hi, &override,
-                                         &type_change_ok, &size_change_ok))
+                                         &type_change_ok,
+                                         &size_change_ok, dt_needed))
                    goto error_return;
 
                  if (! override)
@@ -1719,45 +1822,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
-                           | ELF_LINK_NON_GOT_REF));
-
-                     /* 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.  */
@@ -1795,7 +1860,8 @@ elf_link_add_object_symbols (abfd, info)
                  size_change_ok = false;
                  if (! elf_merge_symbol (abfd, info, shortname, &sym, &sec,
                                          &value, &hi, &override,
-                                         &type_change_ok, &size_change_ok))
+                                         &type_change_ok,
+                                         &size_change_ok, dt_needed))
                    goto error_return;
 
                  if (override)
@@ -1830,44 +1896,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
-                               | ELF_LINK_NON_GOT_REF));
-
-                         /* 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.  */
@@ -1906,6 +1935,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;
+           }
        }
     }
 
@@ -2807,7 +2895,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
-      bfd_size_type strsize;
+      asection *dynstr;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || info->shared);
@@ -2825,6 +2913,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)
@@ -2834,7 +2923,9 @@ 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)
+             || (info->new_dtags
+                 && ! elf_add_dynamic_entry (info, DT_RUNPATH, indx)))
            return false;
        }
 
@@ -2933,14 +3024,24 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            return false;
        }
 
-      strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
-      if (! elf_add_dynamic_entry (info, DT_HASH, 0)
-         || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
-         || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
-         || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
-         || ! elf_add_dynamic_entry (info, DT_SYMENT,
-                                     sizeof (Elf_External_Sym)))
-       return false;
+      dynstr = bfd_get_section_by_name (dynobj, ".dynstr");
+      /* If .dynstr is excluded from the link, we don't want any of
+        these tags.  Strictly, we should be checking each section
+        individually;  This quick check covers for the case where
+        someone does a /DISCARD/ : { *(*) }.  */
+      if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr)
+       {
+         bfd_size_type strsize;
+
+         strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+         if (! elf_add_dynamic_entry (info, DT_HASH, 0)
+             || ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
+             || ! elf_add_dynamic_entry (info, DT_SYMTAB, 0)
+             || ! elf_add_dynamic_entry (info, DT_STRSZ, strsize)
+             || ! elf_add_dynamic_entry (info, DT_SYMENT,
+                                         sizeof (Elf_External_Sym)))
+           return false;
+       }
     }
 
   /* The backend must work out the sizes of all the other dynamic
@@ -2954,7 +3055,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       size_t dynsymcount;
       asection *s;
       size_t bucketcount = 0;
-      Elf_Internal_Sym isym;
       size_t hash_entry_size;
 
       /* Set up the version definition section.  */
@@ -2966,7 +3066,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;
@@ -3123,6 +3223,22 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          elf_tdata (output_bfd)->cverdefs = cdefs;
        }
 
+      if (info->new_dtags && 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");
@@ -3142,7 +3258,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;
@@ -3246,7 +3362,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);
@@ -3275,15 +3391,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (s->contents == NULL && s->_raw_size != 0)
        return false;
 
-      /* The first entry in .dynsym is a dummy symbol.  */
-      isym.st_value = 0;
-      isym.st_size = 0;
-      isym.st_name = 0;
-      isym.st_info = 0;
-      isym.st_other = 0;
-      isym.st_shndx = 0;
-      elf_swap_symbol_out (output_bfd, &isym,
-                          (PTR) (Elf_External_Sym *) s->contents);
+      if (dynsymcount != 0)
+       {
+         Elf_Internal_Sym isym;
+
+         /* The first entry in .dynsym is a dummy symbol.  */
+         isym.st_value = 0;
+         isym.st_size = 0;
+         isym.st_name = 0;
+         isym.st_info = 0;
+         isym.st_other = 0;
+         isym.st_shndx = 0;
+         elf_swap_symbol_out (output_bfd, &isym,
+                              (PTR) (Elf_External_Sym *) s->contents);
+       }
 
       /* Compute the size of the hashing table.  As a side effect this
         computes the hash values for all the names we export.  */
@@ -3332,6 +3453,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
@@ -3393,10 +3517,12 @@ 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;
@@ -3658,6 +3784,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;
 
@@ -3676,6 +3803,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)
     {
@@ -3743,10 +3871,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.  */
@@ -3858,9 +3983,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.  */
@@ -3882,9 +4005,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.  */
            }
@@ -3982,8 +4103,10 @@ elf_link_size_reloc_section (abfd, rel_hdr, o)
   rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count;
 
   /* The contents field must last into write_object_contents, so we
-     allocate it with bfd_alloc rather than malloc.  */
-  rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+     allocate it with bfd_alloc rather than malloc.  Also since we
+     cannot be sure that the contents will actually be filled in,
+     we zero the allocated space.  */
+  rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size);
   if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
     return false;
   
@@ -4019,6 +4142,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++)
     {
@@ -4033,10 +4157,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
        {
@@ -4047,10 +4177,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);
        }
     }
 }
@@ -4145,7 +4281,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)
@@ -4213,7 +4349,7 @@ elf_bfd_final_link (abfd, info)
   /* Figure out how many relocations we will have in each section.
      Just using RELOC_COUNT isn't good enough since that doesn't
      maintain a separate value for REL vs. RELA relocations.  */
-  if (info->relocateable)
+  if (info->relocateable || info->emitrelocations)
     for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
       for (o = sub->sections; o != NULL; o = o->next)
        {
@@ -4321,7 +4457,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;
@@ -4354,7 +4490,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);
@@ -4454,9 +4590,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
@@ -4476,7 +4614,8 @@ elf_bfd_final_link (abfd, info)
   /* The sh_info field records the index of the first non local symbol.  */
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
-  if (dynamic)
+  if (dynamic
+      && finfo.dynsym_sec->output_section != bfd_abs_section_ptr)
     {
       Elf_Internal_Sym sym;
       Elf_External_Sym *dynsym =
@@ -4741,7 +4880,8 @@ elf_bfd_final_link (abfd, info)
       for (o = dynobj->sections; o != NULL; o = o->next)
        {
          if ((o->flags & SEC_HAS_CONTENTS) == 0
-             || o->_raw_size == 0)
+             || o->_raw_size == 0
+             || o->output_section == bfd_abs_section_ptr)
            continue;
          if ((o->flags & SEC_LINKER_CREATED) == 0)
            {
@@ -4955,6 +5095,7 @@ elf_link_output_extsym (h, data)
      referenced by regular files, because we will already have issued
      warnings for them.  */
   if (! finfo->info->relocateable
+      && ! finfo->info->allow_shlib_undefined
       && ! (finfo->info->shared
            && !finfo->info->no_undefined)
       && h->root.type == bfd_link_hash_undefined
@@ -4963,7 +5104,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;
@@ -4991,8 +5132,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;
@@ -5072,12 +5215,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
@@ -5127,6 +5267,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.  */
@@ -5220,6 +5365,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;
@@ -5239,7 +5385,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))
@@ -5254,7 +5401,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
@@ -5265,7 +5415,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
@@ -5382,16 +5535,43 @@ elf_link_input_bfd (finfo, input_bfd)
       if (esym == external_syms)
        continue;
 
+      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+       {
+         asection *ksec;
+
+         /* Save away all section symbol values.  */
+         if (isec != NULL)
+           isec->symbol->value = isym->st_value;
+
+         /* If this is a discarded link-once section symbol, update
+            it's value to that of the kept section symbol.  The
+            linker will keep the first of any matching link-once
+            sections, so we should have already seen it's section
+            symbol.  I trust no-one will have the bright idea of
+            re-ordering the bfd list...  */
+         if (isec != NULL
+             && (bfd_get_section_flags (input_bfd, isec) & SEC_LINK_ONCE) != 0
+             && (ksec = isec->kept_section) != NULL)
+           {
+             isym->st_value = ksec->symbol->value;
+
+             /* That put the value right, but the section info is all
+                wrong.  I hope this works.  */
+             isec->output_offset = ksec->output_offset;
+             isec->output_section = ksec->output_section;
+           }
+
+         /* We never output section symbols.  Instead, we use the
+            section symbol of the corresponding section in the output
+            file.  */
+         continue;
+       }
+
       /* If we are stripping all symbols, we don't want to output this
         one.  */
       if (finfo->info->strip == strip_all)
        continue;
 
-      /* We never output section symbols.  Instead, we use the section
-        symbol of the corresponding section in the output file.  */
-      if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
-       continue;
-
       /* If we are discarding all local symbols, we don't want to
         output this one.  If we are generating a relocateable output
         file, then some of the local symbols may be required by
@@ -5529,7 +5709,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;
@@ -5552,6 +5732,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)
@@ -5721,6 +5905,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)
@@ -5844,7 +6029,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
     {
@@ -5856,7 +6044,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;
@@ -6265,6 +6456,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.  */
@@ -6455,7 +6649,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;
 
@@ -6479,6 +6673,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)
@@ -6634,10 +6832,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;
 
@@ -6659,7 +6861,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.037601 seconds and 4 git commands to generate.