* elf-eh-frame.c (ENSURE_NO_RELOCS): Disregard R_*_NONE relocs.
[deliverable/binutils-gdb.git] / bfd / elflink.h
index 7fa2ccb04743835cd038b73836cf987afd89453e..c94519478288ee4a3848b0f748da3f61892096c0 100644 (file)
@@ -343,7 +343,7 @@ elf_link_add_archive_symbols (abfd, info)
                                        false, false, false);
 
              if (h == NULL)
-               {
+               {
                  /* We also need to check references to the symbol
                     without the version.  */
 
@@ -899,19 +899,19 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
 
 /* This function is called to create an indirect symbol from the
    default for the symbol with the default version if needed. The
-   symbol is described by H, NAME, SYM, SEC, VALUE, and OVERRIDE.  We
+   symbol is described by H, NAME, SYM, PSEC, VALUE, and OVERRIDE.  We
    set DYNSYM if the new indirect symbol is dynamic. DT_NEEDED
    indicates if it comes from a DT_NEEDED entry of a shared object.  */
 
 static boolean
-elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
+elf_add_default_symbol (abfd, info, h, name, sym, psec, value,
                        dynsym, override, dt_needed)
      bfd *abfd;
      struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
      const char *name;
      Elf_Internal_Sym *sym;
-     asection **sec;
+     asection **psec;
      bfd_vma *value;
      boolean *dynsym;
      boolean override;
@@ -921,11 +921,13 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   boolean size_change_ok;
   char *shortname;
   struct elf_link_hash_entry *hi;
+  struct bfd_link_hash_entry *bh;
   struct elf_backend_data *bed;
   boolean collect;
   boolean dynamic;
   char *p;
   size_t len, shortlen;
+  asection *sec;
 
   /* If this symbol has a version, and it is the default version, we
      create an indirect symbol from the default name to the fully
@@ -970,18 +972,20 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
      actually going to define an indirect symbol.  */
   type_change_ok = false;
   size_change_ok = false;
-  if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+  sec = *psec;
+  if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
                          &hi, &override, &type_change_ok,
                          &size_change_ok, dt_needed))
     return false;
 
   if (! override)
     {
+      bh = &hi->root;
       if (! (_bfd_generic_link_add_one_symbol
             (info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr,
-             (bfd_vma) 0, name, false, collect,
-             (struct bfd_link_hash_entry **) &hi)))
+             (bfd_vma) 0, name, false, collect, &bh)))
        return false;
+      hi = (struct elf_link_hash_entry *) bh;
     }
   else
     {
@@ -1042,7 +1046,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
                      | ELF_LINK_HASH_DEF_REGULAR)) == 0);
 
       ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-      (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
+      (*bed->elf_backend_copy_indirect_symbol) (bed, ht, hi);
 
       /* See if the new flags lead us to realize that the symbol must
         be dynamic.  */
@@ -1077,7 +1081,8 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   /* Once again, merge with any existing symbol.  */
   type_change_ok = false;
   size_change_ok = false;
-  if (! elf_merge_symbol (abfd, info, shortname, sym, sec, value,
+  sec = *psec;
+  if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
                          &hi, &override, &type_change_ok,
                          &size_change_ok, dt_needed))
     return false;
@@ -1085,18 +1090,22 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
   if (override)
     {
       /* Here SHORTNAME is a versioned name, so we don't expect to see
-        the type of override we do in the case above.  */
-      (*_bfd_error_handler)
-       (_("%s: warning: unexpected redefinition of `%s'"),
-        bfd_archive_filename (abfd), shortname);
+        the type of override we do in the case above unless it is
+        overridden by a versioned definiton.  */
+      if (hi->root.type != bfd_link_hash_defined
+         && hi->root.type != bfd_link_hash_defweak)
+       (*_bfd_error_handler)
+         (_("%s: warning: unexpected redefinition of indirect versioned symbol `%s'"),
+          bfd_archive_filename (abfd), shortname);
     }
   else
     {
+      bh = &hi->root;
       if (! (_bfd_generic_link_add_one_symbol
             (info, abfd, shortname, BSF_INDIRECT,
-             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-             collect, (struct bfd_link_hash_entry **) &hi)))
+             bfd_ind_section_ptr, (bfd_vma) 0, name, false, collect, &bh)))
        return false;
+      hi = (struct elf_link_hash_entry *) bh;
 
       /* If there is a duplicate definition somewhere, then HI may not
         point to an indirect symbol.  We will have reported an error
@@ -1110,7 +1119,7 @@ elf_add_default_symbol (abfd, info, h, name, sym, sec, value,
                       & (ELF_LINK_HASH_DEF_DYNAMIC
                          | ELF_LINK_HASH_DEF_REGULAR)) == 0);
 
-         (*bed->elf_backend_copy_indirect_symbol) (h, hi);
+         (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi);
 
          /* See if the new flags lead us to realize that the symbol
             must be dynamic.  */
@@ -1289,6 +1298,14 @@ elf_link_add_object_symbols (abfd, info)
       const char *name;
       bfd_size_type oldsize;
       bfd_size_type strindex;
+      struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
+
+      /* ld --just-symbols and dynamic objects don't mix very well.
+        Test for --just-symbols by looking at info set up by
+        _bfd_elf_link_just_syms.  */
+      if ((s = abfd->sections) != NULL
+         && elf_section_data (s)->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+       goto error_return;
 
       /* Find the name to use in a DT_NEEDED entry that refers to this
         object.  If the object has a DT_SONAME entry, we use it.
@@ -1318,8 +1335,6 @@ elf_link_add_object_symbols (abfd, info)
          Elf_External_Dyn *extdynend;
          int elfsec;
          unsigned long shlink;
-         int rpath;
-         int runpath;
 
          dynbuf = (Elf_External_Dyn *) bfd_malloc (s->_raw_size);
          if (dynbuf == NULL)
@@ -1336,8 +1351,6 @@ 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;
@@ -1381,13 +1394,6 @@ elf_link_add_object_symbols (abfd, info)
                  char *fnm, *anm;
                  unsigned int tagv = dyn.d_un.d_val;
 
-                 /* 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 && hash_table->runpath)
-                   hash_table->runpath = NULL;
-
                  amt = sizeof (struct bfd_link_needed_list);
                  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
                  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
@@ -1401,13 +1407,11 @@ elf_link_add_object_symbols (abfd, info)
                  n->name = anm;
                  n->by = abfd;
                  n->next = NULL;
-                 for (pn = & hash_table->runpath;
+                 for (pn = & 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)
@@ -1433,18 +1437,32 @@ elf_link_add_object_symbols (abfd, info)
                  n->name = anm;
                  n->by = abfd;
                  n->next = NULL;
-                 for (pn = & hash_table->runpath;
+                 for (pn = & rpath;
                       *pn != NULL;
                       pn = &(*pn)->next)
                    ;
                  *pn = n;
-                 rpath = 1;
                }
            }
 
          free (dynbuf);
        }
 
+      /* DT_RUNPATH overrides DT_RPATH.  Do _NOT_ bfd_release, as that
+        frees all more recently bfd_alloc'd blocks as well.  */
+      if (runpath)
+       rpath = runpath;
+
+      if (rpath)
+       {
+         struct bfd_link_needed_list **pn;
+         for (pn = & hash_table->runpath;
+              *pn != NULL;
+              pn = &(*pn)->next)
+           ;
+         *pn = rpath;
+       }
+
       /* We do not want to include any of the sections in a dynamic
         object in the output file.  We hack by simply clobbering the
         list of sections in the BFD.  This could be handled more
@@ -1920,19 +1938,17 @@ elf_link_add_object_symbols (abfd, info)
             might be needed here.  */
          if (isym->st_other != 0)
            {
+             unsigned char hvis, symvis, other;
+
+             /* Take the balance of OTHER from the definition.  */
+             other = (definition ? isym->st_other : h->other);
+             other &= ~ ELF_ST_VISIBILITY (-1);
+
              /* Combine visibilities, using the most constraining one.  */
-             unsigned char hvis   = ELF_ST_VISIBILITY (h->other);
-             unsigned char symvis = ELF_ST_VISIBILITY (isym->st_other);
-
-             if (symvis && (hvis > symvis || hvis == 0))
-               h->other = isym->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 = isym->st_other;
+             hvis   = ELF_ST_VISIBILITY (h->other);
+             symvis = ELF_ST_VISIBILITY (isym->st_other);
+
+             h->other = other | (hvis > symvis ? hvis : symvis);
            }
 
          /* Set a flag in the hash table entry indicating the type of
@@ -2190,10 +2206,9 @@ elf_link_add_object_symbols (abfd, info)
        }
     }
 
-  /* If this is a non-traditional, non-relocateable link, try to
-     optimize the handling of the .stab/.stabstr sections.  */
+  /* If this is a non-traditional link, try to optimize the handling
+     of the .stab/.stabstr sections.  */
   if (! dynamic
-      && ! info->relocateable
       && ! info->traditional_format
       && info->hash->creator->flavour == bfd_target_elf_flavour
       && is_elf_hash_table (info)
@@ -2286,6 +2301,7 @@ elf_link_create_dynamic_sections (abfd, info)
   flagword flags;
   register asection *s;
   struct elf_link_hash_entry *h;
+  struct bfd_link_hash_entry *bh;
   struct elf_backend_data *bed;
 
   if (! is_elf_hash_table (info))
@@ -2323,6 +2339,7 @@ elf_link_create_dynamic_sections (abfd, info)
          || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
          || ! bfd_set_section_alignment (abfd, s, 2))
        return false;
+      elf_hash_table (info)->eh_info.hdr_sec = s;
     }
 
   /* Create sections to hold version informations.  These are removed
@@ -2378,12 +2395,12 @@ elf_link_create_dynamic_sections (abfd, info)
      creating a .dynamic section.  We don't want to define it if there
      is no .dynamic section, since on some ELF platforms the start up
      code examines it to decide how to initialize the process.  */
-  h = NULL;
+  bh = NULL;
   if (! (_bfd_generic_link_add_one_symbol
         (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, (bfd_vma) 0,
-         (const char *) NULL, false, get_elf_backend_data (abfd)->collect,
-         (struct bfd_link_hash_entry **) &h)))
+         (const char *) 0, false, get_elf_backend_data (abfd)->collect, &bh)))
     return false;
+  h = (struct elf_link_hash_entry *) bh;
   h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
   h->type = STT_OBJECT;
 
@@ -2448,93 +2465,6 @@ elf_add_dynamic_entry (info, tag, val)
 
   return true;
 }
-
-/* Record a new local dynamic symbol.  */
-
-boolean
-elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
-     struct bfd_link_info *info;
-     bfd *input_bfd;
-     long input_indx;
-{
-  struct elf_link_local_dynamic_entry *entry;
-  struct elf_link_hash_table *eht;
-  struct elf_strtab_hash *dynstr;
-  Elf_External_Sym esym;
-  Elf_External_Sym_Shndx eshndx;
-  Elf_External_Sym_Shndx *shndx;
-  unsigned long dynstr_index;
-  char *name;
-  file_ptr pos;
-  bfd_size_type amt;
-
-  if (! is_elf_hash_table (info))
-    return false;
-
-  /* See if the entry exists already.  */
-  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
-    if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
-      return true;
-
-  entry = (struct elf_link_local_dynamic_entry *)
-    bfd_alloc (input_bfd, (bfd_size_type) sizeof (*entry));
-  if (entry == NULL)
-    return false;
-
-  /* Go find the symbol, so that we can find it's name.  */
-  amt = sizeof (Elf_External_Sym);
-  pos = elf_tdata (input_bfd)->symtab_hdr.sh_offset + input_indx * amt;
-  if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
-      || bfd_bread ((PTR) &esym, amt, input_bfd) != amt)
-    return false;
-  shndx = NULL;
-  if (elf_tdata (input_bfd)->symtab_shndx_hdr.sh_size != 0)
-    {
-      amt = sizeof (Elf_External_Sym_Shndx);
-      pos = elf_tdata (input_bfd)->symtab_shndx_hdr.sh_offset;
-      pos += input_indx * amt;
-      shndx = &eshndx;
-      if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
-         || bfd_bread ((PTR) shndx, amt, input_bfd) != amt)
-       return false;
-    }
-  elf_swap_symbol_in (input_bfd, (const PTR) &esym, (const PTR) shndx,
-                     &entry->isym);
-
-  name = (bfd_elf_string_from_elf_section
-         (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
-          entry->isym.st_name));
-
-  dynstr = elf_hash_table (info)->dynstr;
-  if (dynstr == NULL)
-    {
-      /* Create a strtab to hold the dynamic symbol names.  */
-      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
-      if (dynstr == NULL)
-       return false;
-    }
-
-  dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
-  if (dynstr_index == (unsigned long) -1)
-    return false;
-  entry->isym.st_name = dynstr_index;
-
-  eht = elf_hash_table (info);
-
-  entry->next = eht->dynlocal;
-  eht->dynlocal = entry;
-  entry->input_bfd = input_bfd;
-  entry->input_indx = input_indx;
-  eht->dynsymcount++;
-
-  /* Whatever binding the symbol had before, it's now local.  */
-  entry->isym.st_info
-    = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info));
-
-  /* The dynindx will be set at the end of size_dynamic_sections.  */
-
-  return true;
-}
 \f
 /* Read and swap the relocs from the section indicated by SHDR.  This
    may be either a REL or a RELA section.  The relocations are
@@ -2852,9 +2782,9 @@ compute_bucket_count (info)
   elf_link_hash_traverse (elf_hash_table (info),
                          elf_collect_hash_codes, &hashcodesp);
 
-/* We have a problem here.  The following code to optimize the table
-   size requires an integer type with more the 32 bits.  If
-   BFD_HOST_U_64_BIT is set we know about such a type.  */
+  /* We have a problem here.  The following code to optimize the table
+     size requires an integer type with more the 32 bits.  If
+     BFD_HOST_U_64_BIT is set we know about such a type.  */
 #ifdef BFD_HOST_U_64_BIT
   if (info->optimize)
     {
@@ -3025,6 +2955,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
       asection *dynstr;
+      struct bfd_elf_version_tree *t;
+      struct bfd_elf_version_expr *d;
+      boolean all_defined;
 
       *sinterpptr = bfd_get_section_by_name (dynobj, ".interp");
       BFD_ASSERT (*sinterpptr != NULL || info->shared);
@@ -3105,6 +3038,57 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            return false;
        }
 
+      /* Make all global versions with definiton.  */
+      for (t = verdefs; t != NULL; t = t->next)
+       for (d = t->globals; d != NULL; d = d->next)
+         if (!d->symver && strchr (d->pattern, '*') == NULL)
+           {
+             const char *verstr, *name;
+             size_t namelen, verlen, newlen;
+             char *newname, *p;
+             struct elf_link_hash_entry *newh;
+
+             name = d->pattern;
+             namelen = strlen (name);
+             verstr = t->name;
+             verlen = strlen (verstr);
+             newlen = namelen + verlen + 3; 
+
+             newname = (char *) bfd_malloc ((bfd_size_type) newlen);
+             if (newname == NULL)
+               return false;
+             memcpy (newname, name, namelen);
+
+             /* Check the hidden versioned definition.  */
+             p = newname + namelen;
+             *p++ = ELF_VER_CHR;
+             memcpy (p, verstr, verlen + 1);
+             newh = elf_link_hash_lookup (elf_hash_table (info),
+                                          newname, false, false,
+                                          false);
+             if (newh == NULL
+                 || (newh->root.type != bfd_link_hash_defined
+                     && newh->root.type != bfd_link_hash_defweak))
+               {
+                 /* Check the default versioned definition.  */
+                 *p++ = ELF_VER_CHR;
+                 memcpy (p, verstr, verlen + 1);
+                 newh = elf_link_hash_lookup (elf_hash_table (info),
+                                              newname, false, false,
+                                              false);
+               }
+             free (newname);
+
+             /* Mark this version if there is a definition and it is
+                not defined in a shared object.  */
+             if (newh != NULL
+                 && ((newh->elf_link_hash_flags
+                      & ELF_LINK_HASH_DEF_DYNAMIC) == 0)
+                 && (newh->root.type == bfd_link_hash_defined
+                     || newh->root.type == bfd_link_hash_defweak))
+               d->symver = 1;
+           }
+
       /* Attach all the symbols to their version information.  */
       asvinfo.output_bfd = output_bfd;
       asvinfo.info = info;
@@ -3117,6 +3101,28 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       if (asvinfo.failed)
        return false;
 
+      if (!info->allow_undefined_version)
+       {
+         /* Check if all global versions have a definiton.  */
+         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)
+               {
+                 (*_bfd_error_handler)
+                   (_("%s: undefined version: %s"),
+                    d->pattern, t->name);
+                 all_defined = false;
+               }
+
+         if (!all_defined)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+       }
+
       /* Find all symbols which were defined in a dynamic object and make
         the backend pick a reasonable value for them.  */
       elf_link_hash_traverse (elf_hash_table (info),
@@ -3172,7 +3178,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                    {
                      (*_bfd_error_handler)
                        (_("%s: .preinit_array section is not allowed in DSO"),
-                         bfd_archive_filename (sub));
+                        bfd_archive_filename (sub));
                      break;
                    }
 
@@ -3331,19 +3337,20 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              unsigned int cdeps;
              struct bfd_elf_version_deps *n;
              struct elf_link_hash_entry *h;
+             struct bfd_link_hash_entry *bh;
 
              cdeps = 0;
              for (n = t->deps; n != NULL; n = n->next)
                ++cdeps;
 
              /* Add a symbol representing this version.  */
-             h = NULL;
+             bh = NULL;
              if (! (_bfd_generic_link_add_one_symbol
                     (info, dynobj, t->name, BSF_GLOBAL, bfd_abs_section_ptr,
                      (bfd_vma) 0, (const char *) NULL, false,
-                     get_elf_backend_data (dynobj)->collect,
-                     (struct bfd_link_hash_entry **) &h)))
+                     get_elf_backend_data (dynobj)->collect, &bh)))
                return false;
+             h = (struct elf_link_hash_entry *) bh;
              h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF;
              h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
              h->type = STT_OBJECT;
@@ -3891,9 +3898,12 @@ elf_fix_symbol_flags (h, eif)
     {
       struct elf_link_hash_entry *weakdef;
 
+      weakdef = h->weakdef;
+      if (h->root.type == bfd_link_hash_indirect)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
       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);
@@ -3908,7 +3918,7 @@ elf_fix_symbol_flags (h, eif)
          struct elf_backend_data *bed;
 
          bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
-         (*bed->elf_backend_copy_indirect_symbol) (weakdef, h);
+         (*bed->elf_backend_copy_indirect_symbol) (bed, weakdef, h);
        }
     }
 
@@ -4028,7 +4038,7 @@ elf_adjust_dynamic_symbol (h, data)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0)
     (*_bfd_error_handler)
       (_("warning: type and size of dynamic symbol `%s' are not defined"),
-        h->root.root.string);
+       h->root.root.string);
 
   dynobj = elf_hash_table (eif->info)->dynobj;
   bed = get_elf_backend_data (dynobj);
@@ -4088,7 +4098,7 @@ elf_export_symbol (h, data)
 
       if (!eif->verdefs)
        {
-doit:
+       doit:
          if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h))
            {
              eif->failed = true;
@@ -4345,7 +4355,6 @@ elf_link_assign_sym_version (h, data)
            (_("%s: undefined versioned symbol name %s"),
             bfd_get_filename (sinfo->output_bfd), h->root.root.string);
          bfd_set_error (bfd_error_bad_value);
-error_return:
          sinfo->failed = true;
          return false;
        }
@@ -4359,45 +4368,58 @@ error_return:
   if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL)
     {
       struct bfd_elf_version_tree *t;
-      struct bfd_elf_version_tree *deflt;
+      struct bfd_elf_version_tree *local_ver;
       struct bfd_elf_version_expr *d;
 
       /* See if can find what version this symbol is in.  If the
         symbol is supposed to be local, then don't actually register
         it.  */
-      deflt = NULL;
+      local_ver = NULL;
       for (t = sinfo->verdefs; t != NULL; t = t->next)
        {
          if (t->globals != NULL)
            {
+             boolean matched;
+
+             matched = false;
              for (d = t->globals; d != NULL; d = d->next)
                {
                  if ((*d->match) (d, h->root.root.string))
                    {
-                     h->verinfo.vertree = t;
-                     break;
+                     if (d->symver)
+                       matched = true;
+                     else
+                       {
+                         /* There is a version without definition.  Make
+                            the symbol the default definition for this
+                            version.  */
+                         h->verinfo.vertree = t;
+                         local_ver = NULL;
+                         d->script = 1;
+                         break;
+                       }
                    }
                }
 
              if (d != NULL)
                break;
+             else if (matched)
+               /* There is no undefined version for this symbol. Hide the
+                  default one.  */
+               (*bed->elf_backend_hide_symbol) (info, h, true);
            }
 
          if (t->locals != NULL)
            {
              for (d = t->locals; d != NULL; d = d->next)
                {
+                 /* If the match is "*", keep looking for a more
+                    explicit, perhaps even global, match.  */
                  if (d->pattern[0] == '*' && d->pattern[1] == '\0')
-                   deflt = t;
+                   local_ver = t;
                  else if ((*d->match) (d, h->root.root.string))
                    {
-                     h->verinfo.vertree = t;
-                     if (h->dynindx != -1
-                         && info->shared
-                         && ! info->export_dynamic)
-                       {
-                         (*bed->elf_backend_hide_symbol) (info, h, true);
-                       }
+                     local_ver = t;
                      break;
                    }
                }
@@ -4407,9 +4429,9 @@ error_return:
            }
        }
 
-      if (deflt != NULL && h->verinfo.vertree == NULL)
+      if (local_ver != NULL)
        {
-         h->verinfo.vertree = deflt;
+         h->verinfo.vertree = local_ver;
          if (h->dynindx != -1
              && info->shared
              && ! info->export_dynamic)
@@ -4417,43 +4439,6 @@ error_return:
              (*bed->elf_backend_hide_symbol) (info, h, true);
            }
        }
-
-      /* We need to check if a hidden versioned definition should
-        hide the default one.  */
-      if (h->dynindx != -1 && h->verinfo.vertree != NULL)
-       {
-         const char *verstr, *name;
-         size_t namelen, verlen, newlen;
-         char *newname;
-         struct elf_link_hash_entry *newh;
-
-         name = h->root.root.string;
-         namelen = strlen (name);
-         verstr = h->verinfo.vertree->name;
-         verlen = strlen (verstr);
-         newlen = namelen + verlen + 2;
-
-         newname = (char *) bfd_malloc ((bfd_size_type) newlen);
-         if (newname == NULL)
-           goto error_return;
-         memcpy (newname, name, namelen);
-
-         /* Check the hidden versioned definition.  */
-         p = newname + namelen;
-         *p++ = ELF_VER_CHR;
-         memcpy (p, verstr, verlen + 1);
-         newh = elf_link_hash_lookup (elf_hash_table (info), newname,
-                                   false, false, false);
-
-         if (newh
-             && (newh->root.type == bfd_link_hash_defined
-                 || newh->root.type == bfd_link_hash_defweak))
-           /* We find a hidden versioned definition. Hide the default
-              one.  */
-           (*bed->elf_backend_hide_symbol) (info, h, true);
-
-         free (newname);
-       }
     }
 
   return true;
@@ -4507,6 +4492,8 @@ struct elf_final_link_info
   size_t symbuf_count;
   /* Number of symbols which fit in symbuf.  */
   size_t symbuf_size;
+  /* And same for symshndxbuf.  */
+  size_t shndxbuf_size;
 };
 
 static boolean elf_link_output_sym
@@ -4663,7 +4650,7 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
 
          for (j = 0; j < bed->s->int_rels_per_ext_rel; j++)
            irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx,
-                                      ELF_R_TYPE (irela[j].r_info));
+                                         ELF_R_TYPE (irela[j].r_info));
 
          if (bed->s->swap_reloca_out)
            (*bed->s->swap_reloca_out) (abfd, irela, (bfd_byte *) erela);
@@ -4676,12 +4663,15 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
   free (irela);
 }
 
-struct elf_link_sort_rela {
+struct elf_link_sort_rela
+{
   bfd_vma offset;
   enum elf_reloc_type_class type;
-  union {
-    Elf_Internal_Rel rel;
-    Elf_Internal_Rela rela;
+  union
+  {
+    /* We use these as arrays of size int_rels_per_ext_rel.  */
+    Elf_Internal_Rel rel[1];
+    Elf_Internal_Rela rela[1];
   } u;
 };
 
@@ -4701,13 +4691,13 @@ elf_link_sort_cmp1 (A, B)
     return 1;
   if (relativea > relativeb)
     return -1;
-  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+  if (ELF_R_SYM (a->u.rel->r_info) < ELF_R_SYM (b->u.rel->r_info))
     return -1;
-  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+  if (ELF_R_SYM (a->u.rel->r_info) > ELF_R_SYM (b->u.rel->r_info))
     return 1;
-  if (a->u.rel.r_offset < b->u.rel.r_offset)
+  if (a->u.rel->r_offset < b->u.rel->r_offset)
     return -1;
-  if (a->u.rel.r_offset > b->u.rel.r_offset)
+  if (a->u.rel->r_offset > b->u.rel->r_offset)
     return 1;
   return 0;
 }
@@ -4731,9 +4721,9 @@ elf_link_sort_cmp2 (A, B)
     return -1;
   if (copya > copyb)
     return 1;
-  if (a->u.rel.r_offset < b->u.rel.r_offset)
+  if (a->u.rel->r_offset < b->u.rel->r_offset)
     return -1;
-  if (a->u.rel.r_offset > b->u.rel.r_offset)
+  if (a->u.rel->r_offset > b->u.rel->r_offset)
     return 1;
   return 0;
 }
@@ -4751,6 +4741,7 @@ elf_link_sort_relocs (abfd, info, psec)
   size_t i, j, ret;
   struct elf_link_sort_rela *rela;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  int i2e = bed->s->int_rels_per_ext_rel;
 
   reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
   if (reldyn == NULL || reldyn->_raw_size == 0)
@@ -4774,7 +4765,23 @@ elf_link_sort_relocs (abfd, info, psec)
   if (size != reldyn->_raw_size)
     return 0;
 
-  rela = (struct elf_link_sort_rela *) bfd_zmalloc (sizeof (*rela) * count);
+  /* We waste some memory here when N = i2e is greater than 1, since
+     we allocate space for N * sizeof (*rela) where sizeof (*rela) +
+     (N - 1) * sizeof (Elf_Internal_Rel/Rela) would do.  Also, we use
+     rela[k] only when k is a multiple of N, and then we index the
+     array within the union, such that rela[k].u.rel[i], i < N, is the
+     (i+1)th internal relocation corresponding to the (k/N)th external
+     relocation.  This is done such that the relocation swap-in and
+     swap-out functions can gen pointers to arrays of internal
+     relocations that form a single external relocation.
+
+     If C permitted arrays of structures with dynamic sizes, we could
+     do better, but trying to avoid wasting space at the end of the
+     chunk from rela[k] to rela[k+N-1] would require us to allocate a
+     separate array of pointers and since most ports have N == 1, this
+     would be more wasteful.  */
+  rela = (struct elf_link_sort_rela *) bfd_zmalloc
+    (sizeof (*rela) * count * i2e);
   if (rela == NULL)
     {
       (*info->callbacks->warning)
@@ -4795,15 +4802,16 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erel = (Elf_External_Rel *) o->contents;
            erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rel);
-           for (; erel < erelend; erel++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+           for (; erel < erelend; erel++, s += i2e)
              {
                if (bed->s->swap_reloc_in)
-                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel,
+                                           s->u.rel);
                else
-                 elf_swap_reloc_in (abfd, erel, &s->u.rel);
+                 elf_swap_reloc_in (abfd, erel, s->u.rel);
 
-               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+               s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
              }
          }
        else
@@ -4813,30 +4821,34 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erela = (Elf_External_Rela *) o->contents;
            erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rela);
-           for (; erela < erelaend; erela++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+           for (; erela < erelaend; erela++, s += i2e)
              {
                if (bed->s->swap_reloca_in)
                  (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela,
-                                            &s->u.rela);
+                                            s->u.rela);
                else
-                 elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+                 elf_swap_reloca_in (dynobj, erela, s->u.rela);
 
-               s->type = (*bed->elf_backend_reloc_type_class) (&s->u.rela);
+               s->type = (*bed->elf_backend_reloc_type_class) (s->u.rela);
              }
          }
       }
 
-  qsort (rela, (size_t) count, sizeof (*rela), elf_link_sort_cmp1);
-  for (ret = 0; ret < count && rela[ret].type == reloc_class_relative; ret++)
+  qsort (rela, (size_t) count, sizeof (*rela) * i2e, elf_link_sort_cmp1);
+  for (ret = 0; ret < count * i2e && rela[ret].type == reloc_class_relative;
+       ret += i2e)
     ;
-  for (i = ret, j = ret; i < count; i++)
+  for (i = ret, j = ret; i < count * i2e; i += i2e)
     {
-      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+      if (ELF_R_SYM (rela[i].u.rel->r_info)
+         != ELF_R_SYM (rela[j].u.rel->r_info))
        j = i;
-      rela[i].offset = rela[j].u.rel.r_offset;
+      rela[i].offset = rela[j].u.rel->r_offset;
     }
-  qsort (rela + ret, (size_t) count - ret, sizeof (*rela), elf_link_sort_cmp2);
+  ret /= i2e;
+  qsort (rela + ret, (size_t) count - ret,
+        sizeof (*rela) * i2e, elf_link_sort_cmp2);
 
   for (o = dynobj->sections; o != NULL; o = o->next)
     if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
@@ -4850,14 +4862,14 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erel = (Elf_External_Rel *) o->contents;
            erelend = (Elf_External_Rel *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rel);
-           for (; erel < erelend; erel++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rel) * i2e);
+           for (; erel < erelend; erel++, s += i2e)
              {
                if (bed->s->swap_reloc_out)
-                 (*bed->s->swap_reloc_out) (abfd, &s->u.rel,
+                 (*bed->s->swap_reloc_out) (abfd, s->u.rel,
                                             (bfd_byte *) erel);
                else
-                 elf_swap_reloc_out (abfd, &s->u.rel, erel);
+                 elf_swap_reloc_out (abfd, s->u.rel, erel);
              }
          }
        else
@@ -4867,14 +4879,14 @@ elf_link_sort_relocs (abfd, info, psec)
 
            erela = (Elf_External_Rela *) o->contents;
            erelaend = (Elf_External_Rela *) (o->contents + o->_raw_size);
-           s = rela + o->output_offset / sizeof (Elf_External_Rela);
-           for (; erela < erelaend; erela++, s++)
+           s = rela + (o->output_offset / sizeof (Elf_External_Rela) * i2e);
+           for (; erela < erelaend; erela++, s += i2e)
              {
                if (bed->s->swap_reloca_out)
-                 (*bed->s->swap_reloca_out) (dynobj, &s->u.rela,
+                 (*bed->s->swap_reloca_out) (dynobj, s->u.rela,
                                              (bfd_byte *) erela);
                else
-                 elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+                 elf_swap_reloca_out (dynobj, s->u.rela, erela);
              }
          }
       }
@@ -4907,6 +4919,7 @@ elf_bfd_final_link (abfd, info)
   Elf_Internal_Sym elfsym;
   unsigned int i;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
@@ -4960,6 +4973,7 @@ elf_bfd_final_link (abfd, info)
   finfo.symbuf = NULL;
   finfo.symshndxbuf = NULL;
   finfo.symbuf_count = 0;
+  finfo.shndxbuf_size = 0;
   finfo.first_tls_sec = NULL;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     if ((o->flags & SEC_THREAD_LOCAL) != 0
@@ -5180,9 +5194,7 @@ elf_bfd_final_link (abfd, info)
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   /* sh_name is set in prep_headers.  */
   symtab_hdr->sh_type = SHT_SYMTAB;
-  symtab_hdr->sh_flags = 0;
-  symtab_hdr->sh_addr = 0;
-  symtab_hdr->sh_size = 0;
+  /* sh_flags, sh_addr and sh_size all start off zero.  */
   symtab_hdr->sh_entsize = sizeof (Elf_External_Sym);
   /* sh_link is set in assign_section_numbers.  */
   /* sh_info is set below.  */
@@ -5209,9 +5221,11 @@ elf_bfd_final_link (abfd, info)
     goto error_return;
   if (elf_numsections (abfd) > SHN_LORESERVE)
     {
-      amt = finfo.symbuf_size;
+      /* Wild guess at number of output symbols.  realloc'd as needed.  */
+      amt = 2 * max_sym_count + elf_numsections (abfd) + 1000;
+      finfo.shndxbuf_size = amt;
       amt *= sizeof (Elf_External_Sym_Shndx);
-      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt);
       if (finfo.symshndxbuf == NULL)
        goto error_return;
     }
@@ -5271,7 +5285,7 @@ elf_bfd_final_link (abfd, info)
          if (! elf_link_output_sym (&finfo, (const char *) NULL,
                                     &elfsym, o))
            goto error_return;
-         if (i == SHN_LORESERVE)
+         if (i == SHN_LORESERVE - 1)
            i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
        }
     }
@@ -5353,7 +5367,7 @@ elf_bfd_final_link (abfd, info)
              size = 0;
              for (o = sec->link_order_head; o != NULL; o = o->next)
                if (size < o->offset + o->size)
-             size = o->offset + o->size;
+                 size = o->offset + o->size;
            }
          end = sec->vma + size;
        }
@@ -5492,8 +5506,8 @@ elf_bfd_final_link (abfd, info)
              sym = e->isym;
 
              if (e->isym.st_shndx != SHN_UNDEF
-                  && (e->isym.st_shndx < SHN_LORESERVE
-                      || e->isym.st_shndx > SHN_HIRESERVE))
+                 && (e->isym.st_shndx < SHN_LORESERVE
+                     || e->isym.st_shndx > SHN_HIRESERVE))
                {
                  s = bfd_section_from_elf_index (e->input_bfd,
                                                  e->isym.st_shndx);
@@ -5546,6 +5560,24 @@ elf_bfd_final_link (abfd, info)
   /* Now we know the size of the symtab section.  */
   off += symtab_hdr->sh_size;
 
+  symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (symtab_shndx_hdr->sh_name != 0)
+    {
+      symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+      symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+      amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_size = amt;
+
+      off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr,
+                                                      off, true);
+
+      if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
+         || (bfd_bwrite ((PTR) finfo.symshndxbuf, amt, abfd) != amt))
+       return false;
+    }
+
+
   /* Finish up and write out the symbol string table (.strtab)
      section.  */
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
@@ -5820,17 +5852,10 @@ elf_bfd_final_link (abfd, info)
        goto error_return;
     }
 
-  if (info->eh_frame_hdr && elf_hash_table (info)->dynobj)
+  if (info->eh_frame_hdr)
     {
-      o = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
-                                  ".eh_frame_hdr");
-      if (o
-         && (elf_section_data (o)->sec_info_type
-             == ELF_INFO_TYPE_EH_FRAME_HDR))
-       {
-         if (! _bfd_elf_write_section_eh_frame_hdr (abfd, o))
-           goto error_return;
-       }
+      if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info))
+       goto error_return;
     }
 
   if (finfo.symstrtab != NULL)
@@ -5854,7 +5879,7 @@ elf_bfd_final_link (abfd, info)
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
   if (finfo.symshndxbuf != NULL)
-    free (finfo.symbuf);
+    free (finfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5888,7 +5913,7 @@ elf_bfd_final_link (abfd, info)
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
   if (finfo.symshndxbuf != NULL)
-    free (finfo.symbuf);
+    free (finfo.symshndxbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5947,11 +5972,24 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
   dest = finfo->symbuf + finfo->symbuf_count;
   destshndx = finfo->symshndxbuf;
   if (destshndx != NULL)
-    destshndx += finfo->symbuf_count;
-  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
-  ++finfo->symbuf_count;
+    {
+      if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size)
+       {
+         bfd_size_type amt;
+
+         amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx);
+         finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2);
+         if (destshndx == NULL)
+           return false;
+         memset ((char *) destshndx + amt, 0, amt);
+         finfo->shndxbuf_size *= 2;
+       }
+      destshndx += bfd_get_symcount (finfo->output_bfd);
+    }
 
-  ++ bfd_get_symcount (finfo->output_bfd);
+  elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx);
+  finfo->symbuf_count += 1;
+  bfd_get_symcount (finfo->output_bfd) += 1;
 
   return true;
 }
@@ -5976,20 +6014,6 @@ elf_link_flush_output_syms (finfo)
        return false;
 
       hdr->sh_size += amt;
-
-      if (finfo->symshndxbuf != NULL)
-       {
-         hdr = &elf_tdata (finfo->output_bfd)->symtab_shndx_hdr;
-         pos = hdr->sh_offset + hdr->sh_size;
-         amt = finfo->symbuf_count * sizeof (Elf_External_Sym_Shndx);
-         if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
-             || (bfd_bwrite ((PTR) finfo->symshndxbuf, amt, finfo->output_bfd)
-                 != amt))
-           return false;
-
-         hdr->sh_size += amt;
-       }
-
       finfo->symbuf_count = 0;
     }
 
@@ -6363,11 +6387,10 @@ 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 a symbol is not defined locally, we clear the visibility field.  */
   if (! finfo->info->relocateable
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
-    sym.st_other ^= ELF_ST_VISIBILITY (sym.st_other);
+    sym.st_other &= ~ ELF_ST_VISIBILITY (-1);
 
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
@@ -6430,7 +6453,7 @@ elf_link_output_extsym (h, data)
 
   /* If we're stripping it, then it was just a dynamic symbol, and
      there's nothing else to do.  */
-  if (strip)
+  if (strip || (input_sec->flags & SEC_EXCLUDE) != 0)
     return true;
 
   h->indx = bfd_get_symcount (finfo->output_bfd);
@@ -6482,19 +6505,19 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
     }
   else
     {
-      (*_bfd_error_handler) (
-        _("%s: relocation size mismatch in %s section %s"),
-        bfd_get_filename (output_bfd),
-        bfd_archive_filename (input_section->owner),
-        input_section->name);
+      (*_bfd_error_handler)
+       (_("%s: relocation size mismatch in %s section %s"),
+        bfd_get_filename (output_bfd),
+        bfd_archive_filename (input_section->owner),
+        input_section->name);
       bfd_set_error (bfd_error_wrong_object_format);
       return false;
     }
 
   bed = get_elf_backend_data (output_bfd);
   irela = internal_relocs;
-  irelaend = irela + NUM_SHDR_ENTRIES (input_rel_hdr)
-                    * bed->s->int_rels_per_ext_rel;
+  irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr)
+                     * bed->s->int_rels_per_ext_rel);
 
   if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
     {
@@ -6806,12 +6829,7 @@ elf_link_input_bfd (finfo, input_bfd)
             from discarded sections and section symbols from
             removed link-once sections.  Complain about relocs
             against discarded sections.  Zero relocs against removed
-            link-once sections.  We should really complain if
-            anything in the final link tries to use it, but
-            DWARF-based exception handling might have an entry in
-            .eh_frame to describe a routine in the linkonce section,
-            and it turns out to be hard to remove the .eh_frame
-            entry too.  FIXME.  */
+            link-once sections.  */
          if (!finfo->info->relocateable
              && !elf_section_ignore_discarded_relocs (o))
            {
@@ -6840,20 +6858,12 @@ elf_link_input_bfd (finfo, input_bfd)
                           || h->root.type == bfd_link_hash_defweak)
                          && elf_discarded_section (h->root.u.def.section))
                        {
-#if BFD_VERSION_DATE < 20031005
                          if ((o->flags & SEC_DEBUGGING) != 0)
                            {
-#if BFD_VERSION_DATE > 20021005
-                             (*finfo->info->callbacks->warning)
-                               (finfo->info,
-                                _("warning: relocation against removed section; zeroing"),
-                                NULL, input_bfd, o, rel->r_offset);
-#endif
                              BFD_ASSERT (r_symndx != 0);
                              memset (rel, 0, sizeof (*rel));
                            }
                          else
-#endif
                            {
                              if (! ((*finfo->info->callbacks->undefined_symbol)
                                     (finfo->info, h->root.root.string,
@@ -6869,23 +6879,15 @@ elf_link_input_bfd (finfo, input_bfd)
 
                      if (sec != NULL && elf_discarded_section (sec))
                        {
-#if BFD_VERSION_DATE < 20031005
                          if ((o->flags & SEC_DEBUGGING) != 0
                              || (sec->flags & SEC_LINK_ONCE) != 0)
                            {
-#if BFD_VERSION_DATE > 20021005
-                             (*finfo->info->callbacks->warning)
-                               (finfo->info,
-                                _("warning: relocation against removed section"),
-                                NULL, input_bfd, o, rel->r_offset);
-#endif
                              BFD_ASSERT (r_symndx != 0);
                              rel->r_info
                                = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info));
                              rel->r_addend = 0;
                            }
                          else
-#endif
                            {
                              boolean ok;
                              const char *msg
@@ -6944,8 +6946,9 @@ elf_link_input_bfd (finfo, input_bfd)
            {
              Elf_Internal_Rela *irela;
              Elf_Internal_Rela *irelaend;
+             bfd_vma last_offset;
              struct elf_link_hash_entry **rel_hash;
-             Elf_Internal_Shdr *input_rel_hdr;
+             Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2;
              unsigned int next_erel;
              boolean (*reloc_emitter) PARAMS ((bfd *, asection *,
                                                Elf_Internal_Shdr *,
@@ -6964,10 +6967,14 @@ elf_link_input_bfd (finfo, input_bfd)
              rel_hash = (elf_section_data (o->output_section)->rel_hashes
                          + elf_section_data (o->output_section)->rel_count
                          + elf_section_data (o->output_section)->rel_count2);
+             last_offset = o->output_offset;
+             if (!finfo->info->relocateable)
+               last_offset += o->output_section->vma;
              for (next_erel = 0; irela < irelaend; irela++, next_erel++)
                {
                  unsigned long r_symndx;
                  asection *sec;
+                 Elf_Internal_Sym sym;
 
                  if (next_erel == bed->s->int_rels_per_ext_rel)
                    {
@@ -6975,15 +6982,32 @@ elf_link_input_bfd (finfo, input_bfd)
                      next_erel = 0;
                    }
 
+                 irela->r_offset = _bfd_elf_section_offset (output_bfd,
+                                                            finfo->info, o,
+                                                            irela->r_offset);
+                 if (irela->r_offset >= (bfd_vma) -2)
+                   {
+                     /* This is a reloc for a deleted entry or somesuch.
+                        Turn it into an R_*_NONE reloc, at the same
+                        offset as the last reloc.  elf_eh_frame.c and
+                        elf_bfd_discard_info rely on reloc offsets
+                        being ordered.  */ 
+                     irela->r_offset = last_offset;
+                     irela->r_info = 0;
+                     irela->r_addend = 0;
+                     continue;
+                   }
+
                  irela->r_offset += o->output_offset;
 
                  /* Relocs in an executable have to be virtual addresses.  */
                  if (!finfo->info->relocateable)
                    irela->r_offset += o->output_section->vma;
 
-                 r_symndx = ELF_R_SYM (irela->r_info);
+                 last_offset = irela->r_offset;
 
-                 if (r_symndx == 0)
+                 r_symndx = ELF_R_SYM (irela->r_info);
+                 if (r_symndx == STN_UNDEF)
                    continue;
 
                  if (r_symndx >= locsymcount
@@ -7020,9 +7044,9 @@ elf_link_input_bfd (finfo, input_bfd)
                  /* This is a reloc against a local symbol.  */
 
                  *rel_hash = NULL;
-                 isym = isymbuf + r_symndx;
+                 sym = isymbuf[r_symndx];
                  sec = finfo->sections[r_symndx];
-                 if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+                 if (ELF_ST_TYPE (sym.st_info) == STT_SECTION)
                    {
                      /* I suppose the backend ought to fill in the
                         section of any STT_SECTION symbol against a
@@ -7069,34 +7093,34 @@ elf_link_input_bfd (finfo, input_bfd)
                             must output it now.  */
                          shlink = symtab_hdr->sh_link;
                          name = (bfd_elf_string_from_elf_section
-                                 (input_bfd, shlink, isym->st_name));
+                                 (input_bfd, shlink, sym.st_name));
                          if (name == NULL)
                            return false;
 
                          osec = sec->output_section;
-                         isym->st_shndx =
+                         sym.st_shndx =
                            _bfd_elf_section_from_bfd_section (output_bfd,
                                                               osec);
-                         if (isym->st_shndx == SHN_BAD)
+                         if (sym.st_shndx == SHN_BAD)
                            return false;
 
-                         isym->st_value += sec->output_offset;
+                         sym.st_value += sec->output_offset;
                          if (! finfo->info->relocateable)
                            {
-                             isym->st_value += osec->vma;
-                             if (ELF_ST_TYPE (isym->st_info) == STT_TLS)
+                             sym.st_value += osec->vma;
+                             if (ELF_ST_TYPE (sym.st_info) == STT_TLS)
                                {
                                  /* STT_TLS symbols are relative to PT_TLS
                                     segment base.  */
                                  BFD_ASSERT (finfo->first_tls_sec != NULL);
-                                 isym->st_value -= finfo->first_tls_sec->vma;
+                                 sym.st_value -= finfo->first_tls_sec->vma;
                                }
                            }
 
                          finfo->indices[r_symndx]
                            = bfd_get_symcount (output_bfd);
 
-                         if (! elf_link_output_sym (finfo, name, isym, sec))
+                         if (! elf_link_output_sym (finfo, name, &sym, sec))
                            return false;
                        }
 
@@ -7115,20 +7139,20 @@ elf_link_input_bfd (finfo, input_bfd)
              else
                reloc_emitter = elf_link_output_relocs;
 
-             if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
-                                     internal_relocs))
+             if (input_rel_hdr->sh_size != 0
+                 && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+                                        internal_relocs))
                return false;
 
-             input_rel_hdr = elf_section_data (o)->rel_hdr2;
-             if (input_rel_hdr)
+             input_rel_hdr2 = elf_section_data (o)->rel_hdr2;
+             if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0)
                {
                  internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr)
                                      * bed->s->int_rels_per_ext_rel);
-                 if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr,
+                 if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2,
                                          internal_relocs))
                    return false;
                }
-
            }
        }
 
@@ -7148,19 +7172,14 @@ elf_link_input_bfd (finfo, input_bfd)
            return false;
          break;
        case ELF_INFO_TYPE_MERGE:
-         if (! (_bfd_write_merged_section
-                (output_bfd, o, elf_section_data (o)->sec_info)))
+         if (! _bfd_write_merged_section (output_bfd, o,
+                                          elf_section_data (o)->sec_info))
            return false;
          break;
        case ELF_INFO_TYPE_EH_FRAME:
          {
-           asection *ehdrsec;
-
-           ehdrsec
-             = bfd_get_section_by_name (elf_hash_table (finfo->info)->dynobj,
-                                        ".eh_frame_hdr");
-           if (! (_bfd_elf_write_section_eh_frame (output_bfd, o, ehdrsec,
-                                                   contents)))
+           if (! _bfd_elf_write_section_eh_frame (output_bfd, finfo->info,
+                                                  o, contents))
              return false;
          }
          break;
@@ -7645,28 +7664,27 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h,
 /* Garbage collect unused sections.  */
 
 static boolean elf_gc_mark
-  PARAMS ((struct bfd_link_info *info, asection *sec,
-          asection * (*gc_mark_hook)
-            PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-                     struct elf_link_hash_entry *, Elf_Internal_Sym *))));
+  PARAMS ((struct bfd_link_info *, asection *,
+          asection * (*) (asection *, struct bfd_link_info *,
+                          Elf_Internal_Rela *, struct elf_link_hash_entry *,
+                          Elf_Internal_Sym *)));
 
 static boolean elf_gc_sweep
-  PARAMS ((struct bfd_link_info *info,
-          boolean (*gc_sweep_hook)
-            PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
-                     const Elf_Internal_Rela *relocs))));
+  PARAMS ((struct bfd_link_info *,
+          boolean (*) (bfd *, struct bfd_link_info *, asection *,
+                       const Elf_Internal_Rela *)));
 
 static boolean elf_gc_sweep_symbol
-  PARAMS ((struct elf_link_hash_entry *h, PTR idxptr));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 static boolean elf_gc_allocate_got_offsets
-  PARAMS ((struct elf_link_hash_entry *h, PTR offarg));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 static boolean elf_gc_propagate_vtable_entries_used
-  PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 static boolean elf_gc_smash_unused_vtentry_relocs
-  PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
+  PARAMS ((struct elf_link_hash_entry *, PTR));
 
 /* The mark phase of garbage collection.  For a given section, mark
    it and any sections in this section's group, and all the sections
@@ -7676,9 +7694,10 @@ static boolean
 elf_gc_mark (info, sec, gc_mark_hook)
      struct bfd_link_info *info;
      asection *sec;
-     asection * (*gc_mark_hook)
-       PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-               struct elf_link_hash_entry *, Elf_Internal_Sym *));
+     asection * (*gc_mark_hook) PARAMS ((asection *, struct bfd_link_info *,
+                                        Elf_Internal_Rela *,
+                                        struct elf_link_hash_entry *,
+                                        Elf_Internal_Sym *));
 {
   boolean ret;
   asection *group_sec;
@@ -7790,9 +7809,8 @@ elf_gc_mark (info, sec, gc_mark_hook)
 static boolean
 elf_gc_sweep (info, gc_sweep_hook)
      struct bfd_link_info *info;
-     boolean (*gc_sweep_hook)
-       PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o,
-               const Elf_Internal_Rela *relocs));
+     boolean (*gc_sweep_hook) PARAMS ((bfd *, struct bfd_link_info *,
+                                      asection *, const Elf_Internal_Rela *));
 {
   bfd *sub;
 
@@ -8333,7 +8351,7 @@ elf_reloc_symbol_deleted_p (offset, cookie)
 
   for (; rcookie->rel < rcookie->relend; rcookie->rel++)
     {
-      unsigned long r_symndx = ELF_R_SYM (rcookie->rel->r_info);
+      unsigned long r_symndx;
 
       if (! rcookie->bad_symtab)
        if (rcookie->rel->r_offset > offset)
@@ -8341,6 +8359,10 @@ elf_reloc_symbol_deleted_p (offset, cookie)
       if (rcookie->rel->r_offset != offset)
        continue;
 
+      r_symndx = ELF_R_SYM (rcookie->rel->r_info);
+      if (r_symndx == SHN_UNDEF)
+       return true;
+
       if (r_symndx >= rcookie->locsymcount
          || ELF_ST_BIND (rcookie->locsyms[r_symndx].st_info) != STB_LOCAL)
        {
@@ -8392,24 +8414,18 @@ elf_bfd_discard_info (output_bfd, info)
      struct bfd_link_info *info;
 {
   struct elf_reloc_cookie cookie;
-  asection *stab, *eh, *ehdr;
+  asection *stab, *eh;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_backend_data *bed;
   bfd *abfd;
+  unsigned int count;
   boolean ret = false;
-  boolean strip = info->strip == strip_all || info->strip == strip_debugger;
 
-  if (info->relocateable
-      || info->traditional_format
+  if (info->traditional_format
       || info->hash->creator->flavour != bfd_target_elf_flavour
       || ! is_elf_hash_table (info))
     return false;
 
-  ehdr = NULL;
-  if (elf_hash_table (info)->dynobj != NULL)
-    ehdr = bfd_get_section_by_name (elf_hash_table (info)->dynobj,
-                                   ".eh_frame_hdr");
-
   for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
     {
       if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
@@ -8420,27 +8436,22 @@ elf_bfd_discard_info (output_bfd, info)
       if ((abfd->flags & DYNAMIC) != 0)
        continue;
 
-      eh = NULL;
-      if (ehdr)
-       {
-         eh = bfd_get_section_by_name (abfd, ".eh_frame");
-         if (eh && (eh->_raw_size == 0
-                    || bfd_is_abs_section (eh->output_section)))
-           eh = NULL;
-       }
+      eh = bfd_get_section_by_name (abfd, ".eh_frame");
+      if (eh != NULL
+         && (eh->_raw_size == 0
+             || bfd_is_abs_section (eh->output_section)))
+       eh = NULL;
 
-      stab = NULL;
-      if (!strip)
-       {
-         stab = bfd_get_section_by_name (abfd, ".stab");
-         if (stab && (stab->_raw_size == 0
-                      || bfd_is_abs_section (stab->output_section)))
-           stab = NULL;
-       }
-      if ((! stab
-          || elf_section_data(stab)->sec_info_type != ELF_INFO_TYPE_STABS)
-         && ! eh
-         && (strip || ! bed->elf_backend_discard_info))
+      stab = bfd_get_section_by_name (abfd, ".stab");
+      if (stab != NULL
+         && (stab->_raw_size == 0
+             || bfd_is_abs_section (stab->output_section)
+             || elf_section_data (stab)->sec_info_type != ELF_INFO_TYPE_STABS))
+       stab = NULL;
+
+      if (stab == NULL
+         && eh == NULL
+         && bed->elf_backend_discard_info == NULL)
        continue;
 
       symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -8449,8 +8460,7 @@ elf_bfd_discard_info (output_bfd, info)
       cookie.bad_symtab = elf_bad_symtab (abfd);
       if (cookie.bad_symtab)
        {
-         cookie.locsymcount =
-           symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+         cookie.locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym);
          cookie.extsymoff = 0;
        }
       else
@@ -8469,16 +8479,19 @@ elf_bfd_discard_info (output_bfd, info)
            return false;
        }
 
-      if (stab)
+      if (stab != NULL)
        {
-         cookie.rels = (NAME(_bfd_elf,link_read_relocs)
-                        (abfd, stab, (PTR) NULL, (Elf_Internal_Rela *) NULL,
-                         info->keep_memory));
-         if (cookie.rels)
+         cookie.rels = NULL;
+         count = stab->reloc_count;
+         if (count != 0)
+           cookie.rels = (NAME(_bfd_elf,link_read_relocs)
+                          (abfd, stab, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+                           info->keep_memory));
+         if (cookie.rels != NULL)
            {
              cookie.rel = cookie.rels;
-             cookie.relend =
-               cookie.rels + stab->reloc_count * bed->s->int_rels_per_ext_rel;
+             cookie.relend = cookie.rels;
+             cookie.relend += count * bed->s->int_rels_per_ext_rel;
              if (_bfd_discard_section_stabs (abfd, stab,
                                              elf_section_data (stab)->sec_info,
                                              elf_reloc_symbol_deleted_p,
@@ -8489,34 +8502,32 @@ elf_bfd_discard_info (output_bfd, info)
            }
        }
 
-      if (eh)
+      if (eh != NULL)
        {
          cookie.rels = NULL;
-         cookie.rel = NULL;
-         cookie.relend = NULL;
-         if (eh->reloc_count)
+         count = eh->reloc_count;
+         if (count != 0)
            cookie.rels = (NAME(_bfd_elf,link_read_relocs)
                           (abfd, eh, (PTR) NULL, (Elf_Internal_Rela *) NULL,
                            info->keep_memory));
-         if (cookie.rels)
-           {
-             cookie.rel = cookie.rels;
-             cookie.relend =
-               cookie.rels + eh->reloc_count * bed->s->int_rels_per_ext_rel;
-           }
-         if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, ehdr,
+         cookie.rel = cookie.rels;
+         cookie.relend = cookie.rels;
+         if (cookie.rels != NULL)
+           cookie.relend += count * bed->s->int_rels_per_ext_rel;
+
+         if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
                                                 elf_reloc_symbol_deleted_p,
                                                 &cookie))
            ret = true;
-         if (cookie.rels && elf_section_data (eh)->relocs != cookie.rels)
+
+         if (cookie.rels != NULL
+             && elf_section_data (eh)->relocs != cookie.rels)
            free (cookie.rels);
        }
 
-      if (bed->elf_backend_discard_info)
-       {
-         if (bed->elf_backend_discard_info (abfd, &cookie, info))
-           ret = true;
-       }
+      if (bed->elf_backend_discard_info != NULL
+         && (*bed->elf_backend_discard_info) (abfd, &cookie, info))
+       ret = true;
 
       if (cookie.locsyms != NULL
          && symtab_hdr->contents != (unsigned char *) cookie.locsyms)
@@ -8528,8 +8539,10 @@ elf_bfd_discard_info (output_bfd, info)
        }
     }
 
-  if (ehdr && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info, ehdr))
+  if (info->eh_frame_hdr
+      && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info))
     ret = true;
+
   return ret;
 }
 
This page took 0.045644 seconds and 4 git commands to generate.