* elf32-i386 (elf_i386_adjust_dynamic_symbol): Do not replace PLT32
[deliverable/binutils-gdb.git] / bfd / elflink.h
index bc85175d4927bcffa4eae994abd8bcfa46affdb4..47927d3830e46e6468cc415b1c5fe573b8415b8b 100644 (file)
@@ -39,11 +39,18 @@ static boolean elf_link_add_object_symbols
 static boolean elf_link_add_archive_symbols
   PARAMS ((bfd *, struct bfd_link_info *));
 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));
+  PARAMS ((bfd *, struct bfd_link_info *, const char *,
+          Elf_Internal_Sym *, asection **, bfd_vma *,
+          struct elf_link_hash_entry **, boolean *, boolean *,
+          boolean *, boolean));
+static boolean elf_add_default_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+          const char *, Elf_Internal_Sym *, asection **, bfd_vma *,
+          boolean *, boolean, boolean));
 static boolean elf_export_symbol
   PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_finalize_dynstr
+  PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_fix_symbol_flags
   PARAMS ((struct elf_link_hash_entry *, struct elf_info_failed *));
 static boolean elf_adjust_dynamic_symbol
@@ -73,6 +80,8 @@ static int elf_link_sort_cmp2
   PARAMS ((const void *, const void *));
 static size_t elf_link_sort_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection **));
+static boolean elf_section_ignore_discarded_relocs
+  PARAMS ((asection *));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -142,9 +151,12 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
      carsym * symdef;
 {
   Elf_Internal_Shdr * hdr;
+  Elf_Internal_Shdr * shndx_hdr;
   Elf_External_Sym *  esym;
   Elf_External_Sym *  esymend;
   Elf_External_Sym *  buf = NULL;
+  Elf_External_Sym_Shndx * shndx_buf = NULL;
+  Elf_External_Sym_Shndx * shndx;
   bfd_size_type symcount;
   bfd_size_type extsymcount;
   bfd_size_type extsymoff;
@@ -168,9 +180,15 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
 
   /* Select the appropriate symbol table.  */
   if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
-    hdr = &elf_tdata (abfd)->symtab_hdr;
+    {
+      hdr = &elf_tdata (abfd)->symtab_hdr;
+      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+    }
   else
-    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+    {
+      hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+      shndx_hdr = NULL;
+    }
 
   symcount = hdr->sh_size / sizeof (Elf_External_Sym);
 
@@ -197,21 +215,31 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
   pos = hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym);
   if (bfd_seek (abfd, pos, SEEK_SET) != 0
       || bfd_bread ((PTR) buf, amt, abfd) != amt)
+    goto error_exit;
+
+  if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
     {
-      free (buf);
-      return false;
+      amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
+      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (shndx_buf == NULL && extsymcount != 0)
+       goto error_exit;
+
+      pos = shndx_hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym_Shndx);
+      if (bfd_seek (abfd, pos, SEEK_SET) != 0
+         || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+       goto error_exit;
     }
 
   /* Scan the symbol table looking for SYMDEF.  */
   esymend = buf + extsymcount;
-  for (esym = buf;
+  for (esym = buf, shndx = shndx_buf;
        esym < esymend;
-       esym++)
+       esym++, shndx = (shndx != NULL ? shndx + 1 : NULL))
     {
       Elf_Internal_Sym sym;
       const char * name;
 
-      elf_swap_symbol_in (abfd, esym, sym);
+      elf_swap_symbol_in (abfd, esym, shndx, &sym);
 
       name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
       if (name == (const char *) NULL)
@@ -224,7 +252,11 @@ elf_link_is_defined_archive_symbol (abfd, symdef)
        }
     }
 
-  free (buf);
+ error_exit:
+  if (shndx_buf != NULL)
+    free (shndx_buf);
+  if (buf != NULL)
+    free (buf);
 
   return result;
 }
@@ -890,6 +922,243 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
   return true;
 }
 
+/* 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
+   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,
+                       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;
+     bfd_vma *value;
+     boolean *dynsym;
+     boolean override;
+     boolean dt_needed;
+{
+  boolean type_change_ok;
+  boolean size_change_ok;
+  char *shortname;
+  struct elf_link_hash_entry *hi;
+  struct elf_backend_data *bed;
+  boolean collect;
+  boolean dynamic;
+  char *p;
+
+  /* If this symbol has a version, and it is the default version, we
+     create an indirect symbol from the default 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.  */
+  p = strchr (name, ELF_VER_CHR);
+  if (p == NULL || p[1] != ELF_VER_CHR)
+    return true;
+
+  if (override)
+    {
+      /* We are overridden by an old defition. We need to check if we
+        need to crreate the indirect symbol from the default name.  */
+      hi = elf_link_hash_lookup (elf_hash_table (info), name, true,
+                                false, false);
+      BFD_ASSERT (hi != NULL);
+      if (hi == h)
+       return true;
+      while (hi->root.type == bfd_link_hash_indirect
+            || hi->root.type == bfd_link_hash_warning)
+       {
+         hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+         if (hi == h)
+           return true;
+       }
+    }
+
+  bed = get_elf_backend_data (abfd);
+  collect = bed->collect;
+  dynamic = (abfd->flags & DYNAMIC) != 0;
+
+  shortname = bfd_hash_allocate (&info->hash->table,
+                                (size_t) (p - name + 1));
+  if (shortname == NULL)
+    return false;
+  strncpy (shortname, name, (size_t) (p - name));
+  shortname [p - name] = '\0';
+
+  /* We are going to create a new symbol.  Merge it with any existing
+     symbol with this name.  For the purposes of the merge, act as
+     though we were defining the symbol we just defined, although we
+     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,
+                         &hi, &override, &type_change_ok,
+                         &size_change_ok, dt_needed))
+    return false;
+
+  if (! override)
+    {
+      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)))
+       return false;
+    }
+  else
+    {
+      /* In this case the symbol named SHORTNAME is overriding the
+        indirect symbol we want to add.  We were planning on making
+        SHORTNAME an indirect symbol referring to NAME.  SHORTNAME
+        is the name without a version.  NAME is the fully versioned
+        name, and it is the default version.
+
+        Overriding means that we already saw a definition for the
+        symbol SHORTNAME in a regular object, and it is overriding
+        the symbol defined in the dynamic object.
+
+        When this happens, we actually want to change NAME, the
+        symbol we just added, to refer to SHORTNAME.  This will cause
+        references to NAME in the shared object to become references
+        to SHORTNAME in the regular object.  This is what we expect
+        when we override a function in a shared object: that the
+        references in the shared object will be mapped to the
+        definition in the regular object.  */
+
+      while (hi->root.type == bfd_link_hash_indirect
+            || hi->root.type == bfd_link_hash_warning)
+       hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
+
+      h->root.type = bfd_link_hash_indirect;
+      h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
+      if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+       {
+         h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
+         hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
+         if (hi->elf_link_hash_flags
+             & (ELF_LINK_HASH_REF_REGULAR
+                | ELF_LINK_HASH_DEF_REGULAR))
+           {
+             if (! _bfd_elf_link_record_dynamic_symbol (info, hi))
+               return false;
+           }
+       }
+
+      /* Now set HI to H, so that the following code will set the
+         other fields correctly.  */
+      hi = h;
+    }
+
+  /* If there is a duplicate definition somewhere, then HI may not
+     point to an indirect symbol.  We will have reported an error to
+     the user in that case.  */
+
+  if (hi->root.type == bfd_link_hash_indirect)
+    {
+      struct elf_link_hash_entry *ht;
+
+      /* If the symbol became indirect, then we assume that we have
+        not seen a definition before.  */
+      BFD_ASSERT ((hi->elf_link_hash_flags
+                  & (ELF_LINK_HASH_DEF_DYNAMIC
+                     | ELF_LINK_HASH_DEF_REGULAR)) == 0);
+
+      ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
+      (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
+
+      /* See if the new flags lead us to realize that the symbol must
+        be dynamic.  */
+      if (! *dynsym)
+       {
+         if (! dynamic)
+           {
+             if (info->shared
+                 || ((hi->elf_link_hash_flags
+                      & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+               *dynsym = true;
+           }
+         else
+           {
+             if ((hi->elf_link_hash_flags
+                  & ELF_LINK_HASH_REF_REGULAR) != 0)
+               *dynsym = true;
+           }
+       }
+    }
+
+  /* We also need to define an indirection from the nondefault version
+     of the symbol.  */
+
+  shortname = bfd_hash_allocate (&info->hash->table, strlen (name));
+  if (shortname == NULL)
+    return false;
+  strncpy (shortname, name, (size_t) (p - name));
+  strcpy (shortname + (p - name), p + 1);
+
+  /* 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,
+                         &hi, &override, &type_change_ok,
+                         &size_change_ok, dt_needed))
+    return false;
+
+  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);
+    }
+  else
+    {
+      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)))
+       return false;
+
+      /* If there is a duplicate definition somewhere, then HI may not
+        point to an indirect symbol.  We will have reported an error
+        to the user in that case.  */
+
+      if (hi->root.type == bfd_link_hash_indirect)
+       {
+         /* If the symbol became indirect, then we assume that we have
+            not seen a definition before.  */
+         BFD_ASSERT ((hi->elf_link_hash_flags
+                      & (ELF_LINK_HASH_DEF_DYNAMIC
+                         | ELF_LINK_HASH_DEF_REGULAR)) == 0);
+
+          (*bed->elf_backend_copy_indirect_symbol) (h, hi);
+
+         /* See if the new flags lead us to realize that the symbol
+            must be dynamic.  */
+         if (! *dynsym)
+           {
+             if (! dynamic)
+               {
+                 if (info->shared
+                     || ((hi->elf_link_hash_flags
+                          & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+                   *dynsym = true;
+               }
+             else
+               {
+                 if ((hi->elf_link_hash_flags
+                      & ELF_LINK_HASH_REF_REGULAR) != 0)
+                   *dynsym = true;
+               }
+           }
+       }
+    }
+
+  return true;
+}
+
 /* Add symbols from an ELF object file to the linker hash table.  */
 
 static boolean
@@ -905,10 +1174,13 @@ elf_link_add_object_symbols (abfd, info)
                                   asection *, const Elf_Internal_Rela *));
   boolean collect;
   Elf_Internal_Shdr *hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   bfd_size_type symcount;
   bfd_size_type extsymcount;
   bfd_size_type extsymoff;
   Elf_External_Sym *buf = NULL;
+  Elf_External_Sym_Shndx *shndx_buf = NULL;
+  Elf_External_Sym_Shndx *shndx;
   struct elf_link_hash_entry **sym_hash;
   boolean dynamic;
   Elf_External_Versym *extversym = NULL;
@@ -1025,9 +1297,15 @@ elf_link_add_object_symbols (abfd, info)
      look at .symtab for a dynamic object.  */
 
   if (! dynamic || elf_dynsymtab (abfd) == 0)
-    hdr = &elf_tdata (abfd)->symtab_hdr;
+    {
+      hdr = &elf_tdata (abfd)->symtab_hdr;
+      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+    }
   else
-    hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+    {
+      hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+      shndx_hdr = NULL;
+    }
 
   if (dynamic)
     {
@@ -1074,6 +1352,14 @@ elf_link_add_object_symbols (abfd, info)
   if (buf == NULL && extsymcount != 0)
     goto error_return;
 
+  if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
+    {
+      amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
+      shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (shndx_buf == NULL && extsymcount != 0)
+       goto error_return;
+    }
+
   /* We store a pointer to the hash table entry for each external
      symbol.  */
   amt = extsymcount * sizeof (struct elf_link_hash_entry *);
@@ -1282,8 +1568,7 @@ elf_link_add_object_symbols (abfd, info)
         SEC_NEVER_LOAD flag is not the one we want, because that one
         still implies that the section takes up space in the output
         file.  */
-      abfd->sections = NULL;
-      abfd->section_count = 0;
+      bfd_section_list_clear (abfd);
 
       /* If this is the first dynamic object found in the link, create
         the special sections required for dynamic linking.  */
@@ -1294,13 +1579,12 @@ elf_link_add_object_symbols (abfd, info)
       if (add_needed)
        {
          /* Add a DT_NEEDED entry for this dynamic object.  */
-         oldsize = _bfd_stringtab_size (hash_table->dynstr);
-         strindex = _bfd_stringtab_add (hash_table->dynstr, name,
-                                        true, false);
+         oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+         strindex = _bfd_elf_strtab_add (hash_table->dynstr, name, false);
          if (strindex == (bfd_size_type) -1)
            goto error_return;
 
-         if (oldsize == _bfd_stringtab_size (hash_table->dynstr))
+         if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
            {
              asection *sdyn;
              Elf_External_Dyn *dyncon, *dynconend;
@@ -1328,6 +1612,7 @@ elf_link_add_object_symbols (abfd, info)
                        free (buf);
                      if (extversym != NULL)
                        free (extversym);
+                     _bfd_elf_strtab_delref (hash_table->dynstr, strindex);
                      return true;
                    }
                }
@@ -1350,13 +1635,23 @@ elf_link_add_object_symbols (abfd, info)
       || bfd_bread ((PTR) buf, amt, abfd) != amt)
     goto error_return;
 
+  if (shndx_hdr != NULL && shndx_hdr->sh_size != 0)
+    {
+      amt = extsymcount * sizeof (Elf_External_Sym_Shndx);
+      pos = shndx_hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym_Shndx);
+      if (bfd_seek (abfd, pos, SEEK_SET) != 0
+         || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
+       goto error_return;
+    }
+
   weaks = NULL;
 
   ever = extversym != NULL ? extversym + extsymoff : NULL;
   esymend = buf + extsymcount;
-  for (esym = buf;
+  for (esym = buf, shndx = shndx_buf;
        esym < esymend;
-       esym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
+       esym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL),
+        shndx = (shndx != NULL ? shndx + 1 : NULL))
     {
       Elf_Internal_Sym sym;
       int bind;
@@ -1369,8 +1664,11 @@ elf_link_add_object_symbols (abfd, info)
       boolean size_change_ok, type_change_ok;
       boolean new_weakdef;
       unsigned int old_alignment;
+      boolean override;
+
+      override = false;
 
-      elf_swap_symbol_in (abfd, esym, &sym);
+      elf_swap_symbol_in (abfd, esym, shndx, &sym);
 
       flags = BSF_NO_FLAGS;
       sec = NULL;
@@ -1401,7 +1699,7 @@ elf_link_add_object_symbols (abfd, info)
 
       if (sym.st_shndx == SHN_UNDEF)
        sec = bfd_und_section_ptr;
-      else if (sym.st_shndx > 0 && sym.st_shndx < SHN_LORESERVE)
+      else if (sym.st_shndx < SHN_LORESERVE || sym.st_shndx > SHN_HIRESERVE)
        {
          sec = section_from_elf_index (abfd, sym.st_shndx);
          if (sec == NULL)
@@ -1459,7 +1757,6 @@ elf_link_add_object_symbols (abfd, info)
        {
          Elf_Internal_Versym iver;
          unsigned int vernum = 0;
-         boolean override;
 
          if (ever != NULL)
            {
@@ -1731,217 +2028,13 @@ elf_link_add_object_symbols (abfd, info)
 
          h->elf_link_hash_flags |= new_flag;
 
-         /* If this symbol has a version, and it is the default
-             version, we create an indirect symbol from the default
-             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.  */
+         /* Check to see if we need to add an indirect symbol for
+            the default name.  */
          if (definition || h->root.type == bfd_link_hash_common)
-           {
-             char *p;
-
-             p = strchr (name, ELF_VER_CHR);
-             if (p != NULL && p[1] == ELF_VER_CHR)
-               {
-                 char *shortname;
-                 struct elf_link_hash_entry *hi;
-                 boolean override;
-
-                 shortname = bfd_hash_allocate (&info->hash->table,
-                                                (size_t) (p - name + 1));
-                 if (shortname == NULL)
-                   goto error_return;
-                 strncpy (shortname, name, (size_t) (p - name));
-                 shortname[p - name] = '\0';
-
-                 /* We are going to create a new symbol.  Merge it
-                     with any existing symbol with this name.  For the
-                     purposes of the merge, act as though we were
-                     defining the symbol we just defined, although we
-                     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, &hi, &override,
-                                         &type_change_ok,
-                                         &size_change_ok, dt_needed))
-                   goto error_return;
-
-                 if (! override)
-                   {
-                     if (! (_bfd_generic_link_add_one_symbol
-                            (info, abfd, shortname, BSF_INDIRECT,
-                             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-                             collect, (struct bfd_link_hash_entry **) &hi)))
-                       goto error_return;
-                   }
-                 else
-                   {
-                     /* In this case the symbol named SHORTNAME is
-                         overriding the indirect symbol we want to
-                         add.  We were planning on making SHORTNAME an
-                         indirect symbol referring to NAME.  SHORTNAME
-                         is the name without a version.  NAME is the
-                         fully versioned name, and it is the default
-                         version.
-
-                        Overriding means that we already saw a
-                        definition for the symbol SHORTNAME in a
-                        regular object, and it is overriding the
-                        symbol defined in the dynamic object.
-
-                        When this happens, we actually want to change
-                        NAME, the symbol we just added, to refer to
-                        SHORTNAME.  This will cause references to
-                        NAME in the shared object to become
-                        references to SHORTNAME in the regular
-                        object.  This is what we expect when we
-                        override a function in a shared object: that
-                        the references in the shared object will be
-                        mapped to the definition in the regular
-                        object.  */
-
-                     while (hi->root.type == bfd_link_hash_indirect
-                            || hi->root.type == bfd_link_hash_warning)
-                       hi = (struct elf_link_hash_entry *) hi->root.u.i.link;
-
-                     h->root.type = bfd_link_hash_indirect;
-                     h->root.u.i.link = (struct bfd_link_hash_entry *) hi;
-                     if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
-                       {
-                         h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC;
-                         hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC;
-                         if (hi->elf_link_hash_flags
-                             & (ELF_LINK_HASH_REF_REGULAR
-                                | ELF_LINK_HASH_DEF_REGULAR))
-                           {
-                             if (! _bfd_elf_link_record_dynamic_symbol (info,
-                                                                        hi))
-                               goto error_return;
-                           }
-                       }
-
-                     /* Now set HI to H, so that the following code
-                         will set the other fields correctly.  */
-                     hi = h;
-                   }
-
-                 /* If there is a duplicate definition somewhere,
-                    then HI may not point to an indirect symbol.  We
-                    will have reported an error to the user in that
-                    case.  */
-
-                 if (hi->root.type == bfd_link_hash_indirect)
-                   {
-                     struct elf_link_hash_entry *ht;
-
-                     /* If the symbol became indirect, then we assume
-                        that we have not seen a definition before.  */
-                     BFD_ASSERT ((hi->elf_link_hash_flags
-                                  & (ELF_LINK_HASH_DEF_DYNAMIC
-                                     | ELF_LINK_HASH_DEF_REGULAR))
-                                 == 0);
-
-                     ht = (struct elf_link_hash_entry *) hi->root.u.i.link;
-                     (*bed->elf_backend_copy_indirect_symbol) (ht, hi);
-
-                     /* See if the new flags lead us to realize that
-                        the symbol must be dynamic.  */
-                     if (! dynsym)
-                       {
-                         if (! dynamic)
-                           {
-                             if (info->shared
-                                 || ((hi->elf_link_hash_flags
-                                      & ELF_LINK_HASH_REF_DYNAMIC)
-                                     != 0))
-                               dynsym = true;
-                           }
-                         else
-                           {
-                             if ((hi->elf_link_hash_flags
-                                  & ELF_LINK_HASH_REF_REGULAR) != 0)
-                               dynsym = true;
-                           }
-                       }
-                   }
-
-                 /* We also need to define an indirection from the
-                     nondefault version of the symbol.  */
-
-                 shortname = bfd_hash_allocate (&info->hash->table,
-                                                strlen (name));
-                 if (shortname == NULL)
-                   goto error_return;
-                 strncpy (shortname, name, (size_t) (p - name));
-                 strcpy (shortname + (p - name), p + 1);
-
-                 /* 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, &hi, &override,
-                                         &type_change_ok,
-                                         &size_change_ok, dt_needed))
-                   goto error_return;
-
-                 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);
-                   }
-                 else
-                   {
-                     if (! (_bfd_generic_link_add_one_symbol
-                            (info, abfd, shortname, BSF_INDIRECT,
-                             bfd_ind_section_ptr, (bfd_vma) 0, name, false,
-                             collect, (struct bfd_link_hash_entry **) &hi)))
-                       goto error_return;
-
-                     /* If there is a duplicate definition somewhere,
-                         then HI may not point to an indirect symbol.
-                         We will have reported an error to the user in
-                         that case.  */
-
-                     if (hi->root.type == bfd_link_hash_indirect)
-                       {
-                         /* If the symbol became indirect, then we
-                             assume that we have not seen a definition
-                             before.  */
-                         BFD_ASSERT ((hi->elf_link_hash_flags
-                                      & (ELF_LINK_HASH_DEF_DYNAMIC
-                                         | ELF_LINK_HASH_DEF_REGULAR))
-                                     == 0);
-
-                         (*bed->elf_backend_copy_indirect_symbol) (h, hi);
-
-                         /* See if the new flags lead us to realize
-                             that the symbol must be dynamic.  */
-                         if (! dynsym)
-                           {
-                             if (! dynamic)
-                               {
-                                 if (info->shared
-                                     || ((hi->elf_link_hash_flags
-                                          & ELF_LINK_HASH_REF_DYNAMIC)
-                                         != 0))
-                                   dynsym = true;
-                               }
-                             else
-                               {
-                                 if ((hi->elf_link_hash_flags
-                                      & ELF_LINK_HASH_REF_REGULAR) != 0)
-                                   dynsym = true;
-                               }
-                           }
-                       }
-                   }
-               }
-           }
+           if (! elf_add_default_symbol (abfd, info, h, name, &sym,
+                                         &sec, &value, &dynsym,
+                                         override, dt_needed))
+             goto error_return;
 
          if (dynsym && h->dynindx == -1)
            {
@@ -1963,8 +2056,7 @@ elf_link_add_object_symbols (abfd, info)
              {
              case STV_INTERNAL:
              case STV_HIDDEN:
-               h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-               (*bed->elf_backend_hide_symbol) (info, h);
+               (*bed->elf_backend_hide_symbol) (info, h, true);
                break;
              }
 
@@ -1983,15 +2075,13 @@ elf_link_add_object_symbols (abfd, info)
                 have to make sure there is a DT_NEEDED entry for it.  */
 
              dt_needed = false;
-             oldsize = _bfd_stringtab_size (hash_table->dynstr);
-             strindex = _bfd_stringtab_add (hash_table->dynstr,
-                                            elf_dt_soname (abfd),
-                                            true, false);
+             oldsize = _bfd_elf_strtab_size (hash_table->dynstr);
+             strindex = _bfd_elf_strtab_add (hash_table->dynstr,
+                                             elf_dt_soname (abfd), false);
              if (strindex == (bfd_size_type) -1)
                goto error_return;
 
-             if (oldsize
-                 == _bfd_stringtab_size (hash_table->dynstr))
+             if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr))
                {
                  asection *sdyn;
                  Elf_External_Dyn *dyncon, *dynconend;
@@ -2170,7 +2260,7 @@ elf_link_add_object_symbols (abfd, info)
       asection *stab, *stabstr;
 
       stab = bfd_get_section_by_name (abfd, ".stab");
-      if (stab != NULL)
+      if (stab != NULL && !(stab->flags & SEC_MERGE))
        {
          stabstr = bfd_get_section_by_name (abfd, ".stabstr");
 
@@ -2182,8 +2272,10 @@ elf_link_add_object_symbols (abfd, info)
              if (! _bfd_link_section_stabs (abfd,
                                             & hash_table->stab_info,
                                             stab, stabstr,
-                                            &secdata->stab_info))
+                                            &secdata->sec_info))
                goto error_return;
+             if (secdata->sec_info)
+               secdata->sec_info_type = ELF_INFO_TYPE_STABS;
            }
        }
     }
@@ -2194,10 +2286,18 @@ elf_link_add_object_symbols (abfd, info)
       asection *s;
 
       for (s = abfd->sections; s != NULL; s = s->next)
-       if ((s->flags & SEC_MERGE)
-           && ! _bfd_merge_section (abfd, & hash_table->merge_info, s,
-                                    & elf_section_data (s)->merge_info))
-         goto error_return;
+       if (s->flags & SEC_MERGE)
+         {
+           struct bfd_elf_section_data *secdata;
+
+           secdata = elf_section_data (s);
+           if (! _bfd_merge_section (abfd,
+                                     & hash_table->merge_info,
+                                     s, &secdata->sec_info))
+             goto error_return;
+           else if (secdata->sec_info)
+             secdata->sec_info_type = ELF_INFO_TYPE_MERGE;
+         }
     }
 
   return true;
@@ -2256,6 +2356,16 @@ elf_link_create_dynamic_sections (abfd, info)
        return false;
     }
 
+  if (! info->traditional_format
+      && info->hash->creator->flavour == bfd_target_elf_flavour)
+    {
+      s = bfd_make_section (abfd, ".eh_frame_hdr");
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+         || ! bfd_set_section_alignment (abfd, s, 2))
+       return false;
+    }
+
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
   s = bfd_make_section (abfd, ".gnu.version_d");
@@ -2290,7 +2400,7 @@ elf_link_create_dynamic_sections (abfd, info)
   /* Create a strtab to hold the dynamic symbol names.  */
   if (elf_hash_table (info)->dynstr == NULL)
     {
-      elf_hash_table (info)->dynstr = elf_stringtab_init ();
+      elf_hash_table (info)->dynstr = _bfd_elf_strtab_init ();
       if (elf_hash_table (info)->dynstr == NULL)
        return false;
     }
@@ -2390,8 +2500,10 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
 {
   struct elf_link_local_dynamic_entry *entry;
   struct elf_link_hash_table *eht;
-  struct bfd_strtab_hash *dynstr;
+  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;
@@ -2414,9 +2526,20 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
   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 (&esym, amt, input_bfd) != amt)
+      || bfd_bread ((PTR) &esym, amt, input_bfd) != amt)
     return false;
-  elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
+  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, &esym, shndx, &entry->isym);
 
   name = (bfd_elf_string_from_elf_section
          (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
@@ -2426,12 +2549,12 @@ elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
   if (dynstr == NULL)
     {
       /* Create a strtab to hold the dynamic symbol names.  */
-      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+      elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init ();
       if (dynstr == NULL)
        return false;
     }
 
-  dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+  dynstr_index = _bfd_elf_strtab_add (dynstr, name, false);
   if (dynstr_index == (unsigned long) -1)
     return false;
   entry->isym.st_name = dynstr_index;
@@ -2938,6 +3061,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   if (dynobj == NULL)
     return true;
 
+  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+    return false;
+
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
@@ -2949,8 +3075,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
       if (soname != NULL)
        {
-         soname_indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                           soname, true, true);
+         soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                            soname, true);
          if (soname_indx == (bfd_size_type) -1
              || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SONAME,
                                          soname_indx))
@@ -2969,8 +3095,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          bfd_size_type indx;
 
-         indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, rpath,
-                                    true, true);
+         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath,
+                                     true);
+         if (info->new_dtags)
+           _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx);
          if (indx == (bfd_size_type) -1
              || ! elf_add_dynamic_entry (info, (bfd_vma) DT_RPATH, indx)
              || (info->new_dtags
@@ -2983,8 +3111,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          bfd_size_type indx;
 
-         indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                    filter_shlib, true, true);
+         indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                     filter_shlib, true);
          if (indx == (bfd_size_type) -1
              || ! elf_add_dynamic_entry (info, (bfd_vma) DT_FILTER, indx))
            return false;
@@ -2998,8 +3126,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
            {
              bfd_size_type indx;
 
-             indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                        *p, true, true);
+             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                         *p, true);
              if (indx == (bfd_size_type) -1
                  || ! elf_add_dynamic_entry (info, (bfd_vma) DT_AUXILIARY,
                                              indx))
@@ -3081,7 +3209,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
        {
          bfd_size_type strsize;
 
-         strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+         strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
          if (! elf_add_dynamic_entry (info, (bfd_vma) DT_HASH, (bfd_vma) 0)
              || ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRTAB, (bfd_vma) 0)
              || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMTAB, (bfd_vma) 0)
@@ -3114,6 +3242,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          just linking a regular application.  */
       verdefs = asvinfo.verdefs;
 
+      /* Skip anonymous version tag.  */
+      if (verdefs != NULL && verdefs->vernum == 0)
+       verdefs = verdefs->next;
+
       if (verdefs == NULL)
        _bfd_strip_section_from_output (info, s);
       else
@@ -3164,6 +3296,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
          if (soname_indx != (bfd_size_type) -1)
            {
+             _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+                                     soname_indx);
              def.vd_hash = bfd_elf_hash (soname);
              defaux.vda_name = soname_indx;
            }
@@ -3174,8 +3308,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
              name = basename (output_bfd->filename);
              def.vd_hash = bfd_elf_hash (name);
-             indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                           name, true, false);
+             indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                         name, false);
              if (indx == (bfd_size_type) -1)
                return false;
              defaux.vda_name = indx;
@@ -3234,6 +3368,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
              p += sizeof (Elf_External_Verdef);
 
              defaux.vda_name = h->dynstr_index;
+             _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+                                     h->dynstr_index);
              if (t->deps == NULL)
                defaux.vda_next = 0;
              else
@@ -3253,7 +3389,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                      defaux.vda_name = 0;
                    }
                  else
-                   defaux.vda_name = n->version_needed->name_indx;
+                   {
+                     defaux.vda_name = n->version_needed->name_indx;
+                     _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr,
+                                             defaux.vda_name);
+                   }
                  if (n->next == NULL)
                    defaux.vda_next = 0;
                  else
@@ -3352,14 +3492,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
                t->vn_version = VER_NEED_CURRENT;
                t->vn_cnt = caux;
-               if (elf_dt_name (t->vn_bfd) != NULL)
-                 indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                            elf_dt_name (t->vn_bfd),
-                                            true, false);
-               else
-                 indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                            basename (t->vn_bfd->filename),
-                                            true, false);
+               indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                           elf_dt_name (t->vn_bfd) != NULL
+                                           ? elf_dt_name (t->vn_bfd)
+                                           : basename (t->vn_bfd->filename),
+                                           false);
                if (indx == (bfd_size_type) -1)
                  return false;
                t->vn_file = indx;
@@ -3377,8 +3514,8 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
                for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
                  {
                    a->vna_hash = bfd_elf_hash (a->vna_nodename);
-                   indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
-                                              a->vna_nodename, true, false);
+                   indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr,
+                                               a->vna_nodename, false);
                    if (indx == (bfd_size_type) -1)
                      return false;
                    a->vna_name = indx;
@@ -3456,8 +3593,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
          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);
+         elf_swap_symbol_out (output_bfd, &isym, (PTR) s->contents, (PTR) 0);
        }
 
       /* Compute the size of the hashing table.  As a side effect this
@@ -3482,7 +3618,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
 
       s = bfd_get_section_by_name (dynobj, ".dynstr");
       BFD_ASSERT (s != NULL);
-      s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
+
+      elf_finalize_dynstr (output_bfd, info);
+
+      s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
 
       for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
        if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NULL, (bfd_vma) 0))
@@ -3492,6 +3631,150 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
   return true;
 }
 \f
+/* This function is used to adjust offsets into .dynstr for
+   dynamic symbols.  This is called via elf_link_hash_traverse.  */
+      
+static boolean elf_adjust_dynstr_offsets
+PARAMS ((struct elf_link_hash_entry *, PTR));
+        
+static boolean
+elf_adjust_dynstr_offsets (h, data)
+     struct elf_link_hash_entry *h;
+     PTR data;
+{
+  struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data;
+
+  if (h->dynindx != -1)
+    h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index);
+  return true;
+}
+
+/* Assign string offsets in .dynstr, update all structures referencing
+   them.  */
+
+static boolean
+elf_finalize_dynstr (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  struct elf_link_local_dynamic_entry *entry;
+  struct elf_strtab_hash *dynstr = elf_hash_table (info)->dynstr;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *sdyn;
+  bfd_size_type size;
+  Elf_External_Dyn *dyncon, *dynconend;
+
+  _bfd_elf_strtab_finalize (dynstr);
+  size = _bfd_elf_strtab_size (dynstr);
+
+  /* Update all .dynamic entries referencing .dynstr strings.  */
+  sdyn = bfd_get_section_by_name (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 (dynobj, dyncon, & dyn);
+      switch (dyn.d_tag)
+       {
+       case DT_STRSZ:
+         dyn.d_un.d_val = size;
+         elf_swap_dyn_out (dynobj, & dyn, dyncon);
+         break;
+       case DT_NEEDED:
+       case DT_SONAME:
+       case DT_RPATH:
+       case DT_RUNPATH:
+       case DT_FILTER:
+       case DT_AUXILIARY:
+         dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val);
+         elf_swap_dyn_out (dynobj, & dyn, dyncon);
+         break;
+       default:
+         break;
+       }
+    }
+
+  /* Now update local dynamic symbols.  */
+  for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+    entry->isym.st_name = _bfd_elf_strtab_offset (dynstr,
+                                                 entry->isym.st_name);
+
+  /* And the rest of dynamic symbols.  */
+  elf_link_hash_traverse (elf_hash_table (info),
+                         elf_adjust_dynstr_offsets, dynstr);
+
+  /* Adjust version definitions.  */
+  if (elf_tdata (output_bfd)->cverdefs)
+    {
+      asection *s;
+      bfd_byte *p;
+      bfd_size_type i;
+      Elf_Internal_Verdef def;
+      Elf_Internal_Verdaux defaux;
+                    
+      s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
+      p = (bfd_byte *) s->contents;
+      do
+       {
+         _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p,
+                                  &def);
+         p += sizeof (Elf_External_Verdef);
+         for (i = 0; i < def.vd_cnt; ++i)
+           {
+             _bfd_elf_swap_verdaux_in (output_bfd,
+                                       (Elf_External_Verdaux *) p, &defaux);
+             defaux.vda_name = _bfd_elf_strtab_offset (dynstr,
+                                                       defaux.vda_name);
+             _bfd_elf_swap_verdaux_out (output_bfd,
+                                        &defaux, (Elf_External_Verdaux *) p);
+             p += sizeof (Elf_External_Verdaux);
+           }
+       }
+      while (def.vd_next);
+    }
+
+  /* Adjust version references.  */
+  if (elf_tdata (output_bfd)->verref)
+    {
+      asection *s;
+      bfd_byte *p;
+      bfd_size_type i;
+      Elf_Internal_Verneed need;
+      Elf_Internal_Vernaux needaux;
+                    
+      s = bfd_get_section_by_name (dynobj, ".gnu.version_r");
+      p = (bfd_byte *) s->contents;
+      do
+       {
+         _bfd_elf_swap_verneed_in (output_bfd, (Elf_External_Verneed *) p,
+                                   &need);
+         need.vn_file = _bfd_elf_strtab_offset (dynstr, need.vn_file);
+         _bfd_elf_swap_verneed_out (output_bfd, &need,
+                                    (Elf_External_Verneed *) p);
+         p += sizeof (Elf_External_Verneed);
+         for (i = 0; i < need.vn_cnt; ++i)
+           {
+             _bfd_elf_swap_vernaux_in (output_bfd,
+                                       (Elf_External_Vernaux *) p, &needaux);
+             needaux.vna_name = _bfd_elf_strtab_offset (dynstr,
+                                                        needaux.vna_name);
+             _bfd_elf_swap_vernaux_out (output_bfd,
+                                        &needaux,
+                                        (Elf_External_Vernaux *) p);
+             p += sizeof (Elf_External_Vernaux);
+           }
+       }
+      while (need.vn_next);
+    }
+
+  return true;
+}
+
 /* Fix up the flags for a symbol.  This handles various cases which
    can only be fixed after all the input files are seen.  This is
    currently called by both adjust_dynamic_symbol and
@@ -3587,12 +3870,13 @@ elf_fix_symbol_flags (h, eif)
       && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
     {
       struct elf_backend_data *bed;
+      boolean force_local;
 
       bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
-      if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
-         || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)
-       h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-      (*bed->elf_backend_hide_symbol) (eif->info, h);
+
+      force_local = (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL
+                    || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN);
+      (*bed->elf_backend_hide_symbol) (eif->info, h, force_local);
     }
 
   /* If this is a weak defined symbol in a dynamic object, and we know
@@ -3943,7 +4227,7 @@ elf_link_assign_sym_version (h, data)
              struct bfd_elf_version_expr *d;
 
              len = p - h->root.root.string;
-             alc = bfd_alloc (sinfo->output_bfd, (bfd_size_type) len);
+             alc = bfd_malloc ((bfd_size_type) len);
              if (alc == NULL)
                return false;
              strncpy (alc, h->root.root.string, len - 1);
@@ -3974,11 +4258,7 @@ elf_link_assign_sym_version (h, data)
                              && info->shared
                              && ! info->export_dynamic)
                            {
-                             h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                             (*bed->elf_backend_hide_symbol) (info, h);
-                             /* FIXME: The name of the symbol has
-                                already been recorded in the dynamic
-                                string table section.  */
+                             (*bed->elf_backend_hide_symbol) (info, h, true);
                            }
 
                          break;
@@ -3986,7 +4266,7 @@ elf_link_assign_sym_version (h, data)
                    }
                }
 
-             bfd_release (sinfo->output_bfd, alc);
+             free (alc);
              break;
            }
        }
@@ -4021,6 +4301,9 @@ elf_link_assign_sym_version (h, data)
          t->used = true;
 
          version_index = 1;
+         /* Don't count anonymous version tag.  */
+         if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0)
+           version_index = 0;
          for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next)
            ++version_index;
          t->vernum = version_index;
@@ -4087,11 +4370,7 @@ elf_link_assign_sym_version (h, data)
                          && info->shared
                          && ! info->export_dynamic)
                        {
-                         h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-                         (*bed->elf_backend_hide_symbol) (info, h);
-                         /* FIXME: The name of the symbol has already
-                            been recorded in the dynamic string table
-                            section.  */
+                         (*bed->elf_backend_hide_symbol) (info, h, true);
                        }
                      break;
                    }
@@ -4109,10 +4388,7 @@ elf_link_assign_sym_version (h, data)
              && info->shared
              && ! info->export_dynamic)
            {
-             h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
-             (*bed->elf_backend_hide_symbol) (info, h);
-             /* FIXME: The name of the symbol has already been
-                recorded in the dynamic string table section.  */
+             (*bed->elf_backend_hide_symbol) (info, h, true);
            }
        }
     }
@@ -4147,6 +4423,8 @@ struct elf_final_link_info
   /* Buffer large enough to hold external local symbols of any input
      BFD.  */
   Elf_External_Sym *external_syms;
+  /* And a buffer for symbol section indices.  */
+  Elf_External_Sym_Shndx *locsym_shndx;
   /* Buffer large enough to hold internal local symbols of any input
      BFD.  */
   Elf_Internal_Sym *internal_syms;
@@ -4158,6 +4436,8 @@ struct elf_final_link_info
   asection **sections;
   /* Buffer to hold swapped out symbols.  */
   Elf_External_Sym *symbuf;
+  /* And one for symbol section indices.  */
+  Elf_External_Sym_Shndx *symshndxbuf;
   /* Number of swapped out symbols in buffer.  */
   size_t symbuf_count;
   /* Number of symbols which fit in symbuf.  */
@@ -4555,6 +4835,7 @@ elf_bfd_final_link (abfd, info)
   bfd_size_type max_external_reloc_size;
   bfd_size_type max_internal_reloc_count;
   bfd_size_type max_sym_count;
+  bfd_size_type max_sym_shndx_count;
   file_ptr off;
   Elf_Internal_Sym elfsym;
   unsigned int i;
@@ -4605,10 +4886,12 @@ elf_bfd_final_link (abfd, info)
   finfo.external_relocs = NULL;
   finfo.internal_relocs = NULL;
   finfo.external_syms = NULL;
+  finfo.locsym_shndx = NULL;
   finfo.internal_syms = NULL;
   finfo.indices = NULL;
   finfo.sections = NULL;
   finfo.symbuf = NULL;
+  finfo.symshndxbuf = NULL;
   finfo.symbuf_count = 0;
 
   /* Count up the number of relocations we will output for each output
@@ -4618,6 +4901,7 @@ elf_bfd_final_link (abfd, info)
   max_external_reloc_size = 0;
   max_internal_reloc_count = 0;
   max_sym_count = 0;
+  max_sym_shndx_count = 0;
   merged = false;
   for (o = abfd->sections; o != (asection *) NULL; o = o->next)
     {
@@ -4681,6 +4965,10 @@ elf_bfd_final_link (abfd, info)
                  if (sym_count > max_sym_count)
                    max_sym_count = sym_count;
 
+                 if (sym_count > max_sym_shndx_count
+                     && elf_symtab_shndx (sec->owner) != 0)
+                   max_sym_shndx_count = sym_count;
+
                  if ((sec->flags & SEC_RELOC) != 0)
                    {
                      size_t ext_size;
@@ -4834,6 +5122,14 @@ elf_bfd_final_link (abfd, info)
   finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt);
   if (finfo.symbuf == NULL)
     goto error_return;
+  if (elf_numsections (abfd) > SHN_LORESERVE)
+    {
+      amt = finfo.symbuf_size;
+      amt *= sizeof (Elf_External_Sym_Shndx);
+      finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (finfo.symshndxbuf == NULL)
+       goto error_return;
+    }
 
   /* Start writing out the symbol table.  The first symbol is always a
      dummy symbol.  */
@@ -4877,7 +5173,7 @@ elf_bfd_final_link (abfd, info)
       elfsym.st_size = 0;
       elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
       elfsym.st_other = 0;
-      for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+      for (i = 1; i < elf_numsections (abfd); i++)
        {
          o = section_from_elf_index (abfd, i);
          if (o != NULL)
@@ -4890,34 +5186,66 @@ elf_bfd_final_link (abfd, info)
          if (! elf_link_output_sym (&finfo, (const char *) NULL,
                                     &elfsym, o))
            goto error_return;
+         if (i == SHN_LORESERVE)
+           i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
        }
     }
 
   /* Allocate some memory to hold information read in from the input
      files.  */
-  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
-  finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
-  finfo.internal_relocs = ((Elf_Internal_Rela *)
-                          bfd_malloc (max_internal_reloc_count
-                                      * sizeof (Elf_Internal_Rela)
-                                      * bed->s->int_rels_per_ext_rel));
-  finfo.external_syms = ((Elf_External_Sym *)
-                        bfd_malloc (max_sym_count
-                                    * sizeof (Elf_External_Sym)));
-  finfo.internal_syms = ((Elf_Internal_Sym *)
-                        bfd_malloc (max_sym_count
-                                    * sizeof (Elf_Internal_Sym)));
-  finfo.indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
-  finfo.sections = ((asection **)
-                   bfd_malloc (max_sym_count * sizeof (asection *)));
-  if ((finfo.contents == NULL && max_contents_size != 0)
-      || (finfo.external_relocs == NULL && max_external_reloc_size != 0)
-      || (finfo.internal_relocs == NULL && max_internal_reloc_count != 0)
-      || (finfo.external_syms == NULL && max_sym_count != 0)
-      || (finfo.internal_syms == NULL && max_sym_count != 0)
-      || (finfo.indices == NULL && max_sym_count != 0)
-      || (finfo.sections == NULL && max_sym_count != 0))
-    goto error_return;
+  if (max_contents_size != 0)
+    {
+      finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+      if (finfo.contents == NULL)
+       goto error_return;
+    }
+
+  if (max_external_reloc_size != 0)
+    {
+      finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
+      if (finfo.external_relocs == NULL)
+       goto error_return;
+    }
+
+  if (max_internal_reloc_count != 0)
+    {
+      amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel;
+      amt *= sizeof (Elf_Internal_Rela);
+      finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+      if (finfo.internal_relocs == NULL)
+       goto error_return;
+    }
+
+  if (max_sym_count != 0)
+    {
+      amt = max_sym_count * sizeof (Elf_External_Sym);
+      finfo.external_syms = (Elf_External_Sym *) bfd_malloc (amt);
+      if (finfo.external_syms == NULL)
+       goto error_return;
+
+      amt = max_sym_count * sizeof (Elf_Internal_Sym);
+      finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
+      if (finfo.internal_syms == NULL)
+       goto error_return;
+
+      amt = max_sym_count * sizeof (long);
+      finfo.indices = (long *) bfd_malloc (amt);
+      if (finfo.indices == NULL)
+       goto error_return;
+
+      amt = max_sym_count * sizeof (asection *);
+      finfo.sections = (asection **) bfd_malloc (amt);
+      if (finfo.sections == NULL)
+       goto error_return;
+    }
+
+  if (max_sym_shndx_count != 0)
+    {
+      amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx);
+      finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+      if (finfo.locsym_shndx == NULL)
+       goto error_return;
+    }
 
   /* Since ELF permits relocations to be against local symbols, we
      must have the local symbols available when we do the relocations.
@@ -5017,13 +5345,14 @@ elf_bfd_final_link (abfd, info)
          for (s = abfd->sections; s != NULL; s = s->next)
            {
              int indx;
+             Elf_External_Sym *dest;
+
              indx = elf_section_data (s)->this_idx;
              BFD_ASSERT (indx > 0);
              sym.st_shndx = indx;
              sym.st_value = s->vma;
-
-             elf_swap_symbol_out (abfd, &sym,
-                                  dynsym + elf_section_data (s)->dynindx);
+             dest = dynsym + elf_section_data (s)->dynindx;
+             elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0);
            }
 
          last_local = bfd_count_sections (abfd);
@@ -5036,6 +5365,7 @@ elf_bfd_final_link (abfd, info)
          for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
            {
              asection *s;
+             Elf_External_Sym *dest;
 
              sym.st_size = e->isym.st_size;
              sym.st_other = e->isym.st_other;
@@ -5045,7 +5375,8 @@ elf_bfd_final_link (abfd, info)
                  the original st_name with the dynstr_index.  */
               sym = e->isym;
 
-             if (e->isym.st_shndx > 0 && e->isym.st_shndx < SHN_LORESERVE)
+             if (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);
@@ -5060,7 +5391,8 @@ elf_bfd_final_link (abfd, info)
              if (last_local < e->dynindx)
                last_local = e->dynindx;
 
-             elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx);
+             dest = dynsym + e->dynindx;
+             elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0);
            }
        }
 
@@ -5250,7 +5582,7 @@ elf_bfd_final_link (abfd, info)
              else
                type = SHT_RELA;
              dyn.d_un.d_val = 0;
-             for (i = 1; i < elf_elfheader (abfd)->e_shnum; i++)
+             for (i = 1; i < elf_numsections (abfd); i++)
                {
                  Elf_Internal_Shdr *hdr;
 
@@ -5308,8 +5640,8 @@ elf_bfd_final_link (abfd, info)
                  stringtab.  */
              off = elf_section_data (o->output_section)->this_hdr.sh_offset;
              if (bfd_seek (abfd, off, SEEK_SET) != 0
-                 || ! _bfd_stringtab_emit (abfd,
-                                           elf_hash_table (info)->dynstr))
+                 || ! _bfd_elf_strtab_emit (abfd,
+                                            elf_hash_table (info)->dynstr))
                goto error_return;
            }
        }
@@ -5322,6 +5654,19 @@ elf_bfd_final_link (abfd, info)
        goto error_return;
     }
 
+  if (info->eh_frame_hdr && elf_hash_table (info)->dynobj)
+    {
+      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 (finfo.symstrtab != NULL)
     _bfd_stringtab_free (finfo.symstrtab);
   if (finfo.contents != NULL)
@@ -5332,6 +5677,8 @@ elf_bfd_final_link (abfd, info)
     free (finfo.internal_relocs);
   if (finfo.external_syms != NULL)
     free (finfo.external_syms);
+  if (finfo.locsym_shndx != NULL)
+    free (finfo.locsym_shndx);
   if (finfo.internal_syms != NULL)
     free (finfo.internal_syms);
   if (finfo.indices != NULL)
@@ -5340,6 +5687,8 @@ elf_bfd_final_link (abfd, info)
     free (finfo.sections);
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
+  if (finfo.symshndxbuf != NULL)
+    free (finfo.symbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5362,6 +5711,8 @@ elf_bfd_final_link (abfd, info)
     free (finfo.internal_relocs);
   if (finfo.external_syms != NULL)
     free (finfo.external_syms);
+  if (finfo.locsym_shndx != NULL)
+    free (finfo.locsym_shndx);
   if (finfo.internal_syms != NULL)
     free (finfo.internal_syms);
   if (finfo.indices != NULL)
@@ -5370,6 +5721,8 @@ elf_bfd_final_link (abfd, info)
     free (finfo.sections);
   if (finfo.symbuf != NULL)
     free (finfo.symbuf);
+  if (finfo.symshndxbuf != NULL)
+    free (finfo.symbuf);
   for (o = abfd->sections; o != NULL; o = o->next)
     {
       if ((o->flags & SEC_RELOC) != 0
@@ -5389,6 +5742,9 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
      Elf_Internal_Sym *elfsym;
      asection *input_sec;
 {
+  Elf_External_Sym *dest;
+  Elf_External_Sym_Shndx *destshndx;
+  
   boolean (*output_symbol_hook) PARAMS ((bfd *,
                                         struct bfd_link_info *info,
                                         const char *,
@@ -5422,8 +5778,11 @@ elf_link_output_sym (finfo, name, elfsym, input_sec)
        return false;
     }
 
-  elf_swap_symbol_out (finfo->output_bfd, elfsym,
-                      (PTR) (finfo->symbuf + finfo->symbuf_count));
+  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;
 
   ++ bfd_get_symcount (finfo->output_bfd);
@@ -5439,18 +5798,31 @@ elf_link_flush_output_syms (finfo)
 {
   if (finfo->symbuf_count > 0)
     {
-      Elf_Internal_Shdr *symtab;
+      Elf_Internal_Shdr *hdr;
       file_ptr pos;
       bfd_size_type amt;
 
-      symtab = &elf_tdata (finfo->output_bfd)->symtab_hdr;
-      pos = symtab->sh_offset + symtab->sh_size;
+      hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr;
+      pos = hdr->sh_offset + hdr->sh_size;
       amt = finfo->symbuf_count * sizeof (Elf_External_Sym);
       if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0
          || bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt)
        return false;
 
-      symtab->sh_size += finfo->symbuf_count * sizeof (Elf_External_Sym);
+      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;
     }
@@ -5471,14 +5843,14 @@ elf_link_sec_merge_syms (h, data)
   if ((h->root.type == bfd_link_hash_defined
        || h->root.type == bfd_link_hash_defweak)
       && ((sec = h->root.u.def.section)->flags & SEC_MERGE)
-      && elf_section_data (sec)->merge_info)
+      && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE)
     {
       bfd *output_bfd = (bfd *) data;
 
       h->root.u.def.value =
        _bfd_merged_section_offset (output_bfd,
                                    &h->root.u.def.section,
-                                   elf_section_data (sec)->merge_info,
+                                   elf_section_data (sec)->sec_info,
                                    h->root.u.def.value, (bfd_vma) 0);
     }
 
@@ -5602,7 +5974,7 @@ elf_link_output_extsym (h, data)
            sym.st_shndx =
              _bfd_elf_section_from_bfd_section (finfo->output_bfd,
                                                 input_sec->output_section);
-           if (sym.st_shndx == (unsigned short) -1)
+           if (sym.st_shndx == SHN_BAD)
              {
                (*_bfd_error_handler)
                  (_("%s: could not find output section %s for input section %s"),
@@ -5715,7 +6087,7 @@ elf_link_output_extsym (h, data)
 
       sym.st_name = h->dynstr_index;
       esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx;
-      elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym);
+      elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym, (PTR) 0);
 
       bucketcount = elf_hash_table (finfo->info)->bucketcount;
       bucket = h->elf_hash_value % bucketcount;
@@ -5887,11 +6259,14 @@ elf_link_input_bfd (finfo, input_bfd)
                                       Elf_Internal_Sym *, asection **));
   bfd *output_bfd;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
   size_t locsymcount;
   size_t extsymoff;
   Elf_External_Sym *external_syms;
   Elf_External_Sym *esym;
   Elf_External_Sym *esymend;
+  Elf_External_Sym_Shndx *shndx_buf;
+  Elf_External_Sym_Shndx *shndx;
   Elf_Internal_Sym *isym;
   long *pindex;
   asection **ppsection;
@@ -5940,20 +6315,31 @@ elf_link_input_bfd (finfo, input_bfd)
        return false;
     }
 
+  shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
+  shndx_buf = NULL;
+  if (shndx_hdr->sh_size != 0 && locsymcount != 0)
+    {
+      bfd_size_type amt = locsymcount * sizeof (Elf_External_Sym_Shndx);
+      shndx_buf = finfo->locsym_shndx;
+      if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+         || bfd_bread (shndx_buf, amt, input_bfd) != amt)
+       return false;
+    }
+
   /* Swap in the local symbols and write out the ones which we know
      are going into the output file.  */
-  esym = external_syms;
-  esymend = esym + locsymcount;
-  isym = finfo->internal_syms;
-  pindex = finfo->indices;
-  ppsection = finfo->sections;
-  for (; esym < esymend; esym++, isym++, pindex++, ppsection++)
+  for (esym = external_syms, esymend = esym + locsymcount,
+        isym = finfo->internal_syms, pindex = finfo->indices,
+        ppsection = finfo->sections, shndx = shndx_buf;
+       esym < esymend;
+       esym++, isym++, pindex++, ppsection++,
+        shndx = (shndx != NULL ? shndx + 1 : NULL))
     {
       asection *isec;
       const char *name;
       Elf_Internal_Sym osym;
 
-      elf_swap_symbol_in (input_bfd, esym, isym);
+      elf_swap_symbol_in (input_bfd, esym, shndx, isym);
       *pindex = -1;
 
       if (elf_bad_symtab (input_bfd))
@@ -5967,14 +6353,16 @@ elf_link_input_bfd (finfo, input_bfd)
 
       if (isym->st_shndx == SHN_UNDEF)
        isec = bfd_und_section_ptr;
-      else if (isym->st_shndx > 0 && isym->st_shndx < SHN_LORESERVE)
+      else if (isym->st_shndx < SHN_LORESERVE
+              || isym->st_shndx > SHN_HIRESERVE)
        {
          isec = section_from_elf_index (input_bfd, isym->st_shndx);
-         if (isec && elf_section_data (isec)->merge_info
+         if (isec
+             && elf_section_data (isec)->sec_info_type == ELF_INFO_TYPE_MERGE
              && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
            isym->st_value =
              _bfd_merged_section_offset (output_bfd, &isec,
-                                         elf_section_data (isec)->merge_info,
+                                         elf_section_data (isec)->sec_info,
                                          isym->st_value, (bfd_vma) 0);
        }
       else if (isym->st_shndx == SHN_ABS)
@@ -6019,8 +6407,7 @@ elf_link_input_bfd (finfo, input_bfd)
          linker_mark is only reliable for sections that have contents.
          For the benefit of the MIPS ELF linker, we check SEC_EXCLUDE
          as well as linker_mark.  */
-      if (isym->st_shndx > 0
-         && isym->st_shndx < SHN_LORESERVE
+      if ((isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE)
          && isec != NULL
          && ((! isec->linker_mark && (isec->flags & SEC_HAS_CONTENTS) != 0)
              || (! finfo->info->relocateable
@@ -6050,7 +6437,7 @@ elf_link_input_bfd (finfo, input_bfd)
       /* Adjust the section index for the output file.  */
       osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
                                                         isec->output_section);
-      if (osym.st_shndx == (unsigned short) -1)
+      if (osym.st_shndx == SHN_BAD)
        return false;
 
       *pindex = bfd_get_symcount (output_bfd);
@@ -6119,117 +6506,116 @@ elf_link_input_bfd (finfo, input_bfd)
              && o->reloc_count > 0)
            return false;
 
-         {
-           Elf_Internal_Rela *rel, *relend;
-           /* Run through the relocs looking for any against symbols
-              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.  */
-           rel = internal_relocs;
-           relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
-           for ( ; rel < relend; rel++)
-             {
-               unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+         /* Run through the relocs looking for any against symbols
+            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.  */
+         if (!finfo->info->relocateable
+             && !elf_section_ignore_discarded_relocs (o))
+           {
+             Elf_Internal_Rela *rel, *relend;
 
-               if (r_symndx >= locsymcount
-                   || (elf_bad_symtab (input_bfd)
-                       && finfo->sections[r_symndx] == NULL))
-                 {
-                   struct elf_link_hash_entry *h;
-
-                   h = sym_hashes[r_symndx - extsymoff];
-                   while (h->root.type == bfd_link_hash_indirect
-                          || h->root.type == bfd_link_hash_warning)
-                     h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-                   /* Complain if the definition comes from a
-                      discarded section.  */
-                   if ((h->root.type == bfd_link_hash_defined
-                        || h->root.type == bfd_link_hash_defweak)
-                       && ! bfd_is_abs_section (h->root.u.def.section)
-                       && bfd_is_abs_section (h->root.u.def.section
-                                              ->output_section))
-                     {
+             rel = internal_relocs;
+             relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
+             for ( ; rel < relend; rel++)
+               {
+                 unsigned long r_symndx = ELF_R_SYM (rel->r_info);
+
+                 if (r_symndx >= locsymcount
+                     || (elf_bad_symtab (input_bfd)
+                         && finfo->sections[r_symndx] == NULL))
+                   {
+                     struct elf_link_hash_entry *h;
+
+                     h = sym_hashes[r_symndx - extsymoff];
+                     while (h->root.type == bfd_link_hash_indirect
+                            || h->root.type == bfd_link_hash_warning)
+                       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+                     /* Complain if the definition comes from a
+                        discarded section.  */
+                     if ((h->root.type == bfd_link_hash_defined
+                          || 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 ((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);
+                             (*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
+                           }
+                         else
 #endif
-                         {
-                           if (! ((*finfo->info->callbacks->undefined_symbol)
-                                   (finfo->info, h->root.root.string,
-                                    input_bfd, o, rel->r_offset,
-                                    true)))
-                             return false;
-                         }
-                     }
-                 }
-               else
-                 {
-                   isym = finfo->internal_syms + r_symndx;
-                   if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
-                     {
-                       asection *sec = finfo->sections[r_symndx];
+                           {
+                             if (! ((*finfo->info->callbacks->undefined_symbol)
+                                    (finfo->info, h->root.root.string,
+                                     input_bfd, o, rel->r_offset,
+                                     true)))
+                               return false;
+                           }
+                       }
+                   }
+                 else
+                   {
+                     asection *sec = finfo->sections[r_symndx];
 
-                       if (sec != NULL
-                           && ! bfd_is_abs_section (sec)
-                           && bfd_is_abs_section (sec->output_section))
-                         {
+                     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 ((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);
+                             (*finfo->info->callbacks->warning)
+                               (finfo->info,
+                                _("warning: relocation against removed section"),
+                                NULL, input_bfd, o, rel->r_offset);
 #endif
-                               memset (rel, 0, sizeof (*rel));
-                             }
-                           else
+                             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
-                                 = _("local symbols in discarded section %s");
-                               bfd_size_type amt
-                                 = strlen (sec->name) + strlen (msg) - 1;
-                               char *buf = (char *) bfd_malloc (amt);
-
-                               if (buf != NULL)
-                                 sprintf (buf, msg, sec->name);
-                               else
-                                 buf = (char *) sec->name;
-                               ok = (*finfo->info->callbacks
-                                     ->undefined_symbol) (finfo->info, buf,
-                                                          input_bfd, o,
-                                                          rel->r_offset,
-                                                          true);
-                               if (buf != sec->name)
-                                 free (buf);
-                               if (!ok)
-                                 return false;
-                             }
-                         }
-                     }
-                 }
-             }
-         }
+                           {
+                             boolean ok;
+                             const char *msg
+                               = _("local symbols in discarded section %s");
+                             bfd_size_type amt
+                               = strlen (sec->name) + strlen (msg) - 1;
+                             char *buf = (char *) bfd_malloc (amt);
+
+                             if (buf != NULL)
+                               sprintf (buf, msg, sec->name);
+                             else
+                               buf = (char *) sec->name;
+                             ok = (*finfo->info->callbacks
+                                   ->undefined_symbol) (finfo->info, buf,
+                                                        input_bfd, o,
+                                                        rel->r_offset,
+                                                        true);
+                             if (buf != sec->name)
+                               free (buf);
+                             if (!ok)
+                               return false;
+                           }
+                       }
+                   }
+               }
+           }
 
          /* Relocate the section by invoking a back end routine.
 
@@ -6385,7 +6771,7 @@ elf_link_input_bfd (finfo, input_bfd)
                          isym->st_shndx =
                            _bfd_elf_section_from_bfd_section (output_bfd,
                                                               osec);
-                         if (isym->st_shndx == (unsigned short) -1)
+                         if (isym->st_shndx == SHN_BAD)
                            return false;
 
                          isym->st_value += sec->output_offset;
@@ -6429,30 +6815,50 @@ elf_link_input_bfd (finfo, input_bfd)
        }
 
       /* Write out the modified section contents.  */
-      if (elf_section_data (o)->stab_info)
+      if (bed->elf_backend_write_section
+         && (*bed->elf_backend_write_section) (output_bfd, o, contents))
        {
-         if (! (_bfd_write_section_stabs
-                (output_bfd, &elf_hash_table (finfo->info)->stab_info,
-                 o, &elf_section_data (o)->stab_info, contents)))
-           return false;
+         /* Section written out.  */
        }
-      else if (elf_section_data (o)->merge_info)
+      else switch (elf_section_data (o)->sec_info_type)
        {
-         if (! (_bfd_write_merged_section
-                (output_bfd, o, elf_section_data (o)->merge_info)))
+       case ELF_INFO_TYPE_STABS:
+         if (! (_bfd_write_section_stabs
+                (output_bfd,
+                 &elf_hash_table (finfo->info)->stab_info,
+                 o, &elf_section_data (o)->sec_info, contents)))
            return false;
-       }
-      else
-       {
-         bfd_size_type sec_size;
-
-         sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
-         if (! (o->flags & SEC_EXCLUDE)
-             && ! bfd_set_section_contents (output_bfd, o->output_section,
-                                            contents,
-                                            (file_ptr) o->output_offset,
-                                            sec_size))
+         break;
+       case ELF_INFO_TYPE_MERGE:
+         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)))
+             return false;
+         }
+         break;
+       default:
+         {
+           bfd_size_type sec_size;
+
+           sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size);
+           if (! (o->flags & SEC_EXCLUDE)
+               && ! bfd_set_section_contents (output_bfd, o->output_section,
+                                              contents,
+                                              (file_ptr) o->output_offset,
+                                              sec_size))
+             return false;
+         }
+         break;
        }
     }
 
@@ -6973,10 +7379,12 @@ elf_gc_mark (info, sec, gc_mark_hook)
     {
       Elf_Internal_Rela *relstart, *rel, *relend;
       Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Shdr *shndx_hdr;
       struct elf_link_hash_entry **sym_hashes;
       size_t nlocsyms;
       size_t extsymoff;
       Elf_External_Sym *locsyms, *freesyms = NULL;
+      Elf_External_Sym_Shndx *locsym_shndx;
       bfd *input_bfd = sec->owner;
       struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
 
@@ -6994,6 +7402,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
        }
       else
        extsymoff = nlocsyms = symtab_hdr->sh_info;
+
       if (symtab_hdr->contents)
        locsyms = (Elf_External_Sym *) symtab_hdr->contents;
       else if (nlocsyms == 0)
@@ -7011,6 +7420,17 @@ elf_gc_mark (info, sec, gc_mark_hook)
            }
        }
 
+      shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
+      locsym_shndx = NULL;
+      if (shndx_hdr->sh_size != 0 && nlocsyms != 0)
+       {
+         bfd_size_type amt = nlocsyms * sizeof (Elf_External_Sym_Shndx);
+         locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+         if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+             || bfd_bread (locsym_shndx, amt, input_bfd) != amt)
+           return false;
+       }
+
       /* Read the relocations.  */
       relstart = (NAME(_bfd_elf,link_read_relocs)
                  (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL,
@@ -7035,7 +7455,10 @@ elf_gc_mark (info, sec, gc_mark_hook)
 
          if (elf_bad_symtab (sec->owner))
            {
-             elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
+             elf_swap_symbol_in (input_bfd,
+                                 locsyms + r_symndx,
+                                 locsym_shndx + (locsym_shndx ? r_symndx : 0),
+                                 &s);
              if (ELF_ST_BIND (s.st_info) == STB_LOCAL)
                rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
              else
@@ -7051,7 +7474,10 @@ elf_gc_mark (info, sec, gc_mark_hook)
            }
          else
            {
-             elf_swap_symbol_in (input_bfd, &locsyms[r_symndx], &s);
+             elf_swap_symbol_in (input_bfd,
+                                 locsyms + r_symndx,
+                                 locsym_shndx + (locsym_shndx ? r_symndx : 0),
+                                 &s);
              rsec = (*gc_mark_hook) (sec->owner, info, rel, NULL, &s);
            }
 
@@ -7594,3 +8020,271 @@ elf_collect_hash_codes (h, data)
 
   return true;
 }
+
+boolean
+elf_reloc_symbol_deleted_p (offset, cookie)
+     bfd_vma offset;
+     PTR cookie;
+{
+  struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *) cookie;
+
+  if (rcookie->bad_symtab)
+    rcookie->rel = rcookie->rels;
+
+  for (; rcookie->rel < rcookie->relend; rcookie->rel++)
+    {
+      unsigned long r_symndx = ELF_R_SYM (rcookie->rel->r_info);
+      Elf_Internal_Sym isym;
+
+      if (! rcookie->bad_symtab)
+       if (rcookie->rel->r_offset > offset)
+         return false;
+      if (rcookie->rel->r_offset != offset)
+       continue;
+
+      if (rcookie->locsyms && r_symndx < rcookie->locsymcount)
+       {
+         Elf_External_Sym *lsym;
+         Elf_External_Sym_Shndx *lshndx;
+
+         lsym = (Elf_External_Sym *) rcookie->locsyms + r_symndx;
+         lshndx = (Elf_External_Sym_Shndx *) rcookie->locsym_shndx;
+         if (lshndx != NULL)
+           lshndx += r_symndx;
+         elf_swap_symbol_in (rcookie->abfd, lsym, lshndx, &isym);
+       }
+
+      if (r_symndx >= rcookie->locsymcount
+         || (rcookie->locsyms
+             && ELF_ST_BIND (isym.st_info) != STB_LOCAL))
+       {
+         struct elf_link_hash_entry *h;
+
+         h = rcookie->sym_hashes[r_symndx - rcookie->extsymoff];
+
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         if ((h->root.type == bfd_link_hash_defined
+              || h->root.type == bfd_link_hash_defweak)
+             && elf_discarded_section (h->root.u.def.section))
+           return true;
+         else
+           return false;
+       }
+      else if (rcookie->locsyms)
+       {
+         /* It's not a relocation against a global symbol,
+            but it could be a relocation against a local
+            symbol for a discarded section.  */
+         asection *isec;
+
+         /* Need to: get the symbol; get the section.  */
+         if (isym.st_shndx < SHN_LORESERVE || isym.st_shndx > SHN_HIRESERVE)
+           {
+             isec = section_from_elf_index (rcookie->abfd, isym.st_shndx);
+             if (isec != NULL && elf_discarded_section (isec))
+               return true;
+           }
+       }
+      return false;
+    }
+  return false;
+}
+
+/* Discard unneeded references to discarded sections.
+   Returns true if any section's size was changed.  */
+/* This function assumes that the relocations are in sorted order,
+   which is true for all known assemblers.  */
+
+boolean
+elf_bfd_discard_info (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  struct elf_reloc_cookie cookie;
+  asection *stab, *eh, *ehdr;
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *shndx_hdr;
+  Elf_External_Sym *freesyms;
+  struct elf_backend_data *bed;
+  bfd *abfd;
+  boolean ret = false;
+  boolean strip = info->strip == strip_all || info->strip == strip_debugger;
+
+  if (info->relocateable
+      || 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)
+       continue;
+
+      bed = get_elf_backend_data (abfd);
+
+      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)
+           eh = NULL;
+       }
+
+      stab = strip ? NULL : bfd_get_section_by_name (abfd, ".stab");
+      if ((! stab || elf_section_data(stab)->sec_info_type != ELF_INFO_TYPE_STABS)
+         && ! eh
+         && (strip || ! bed->elf_backend_discard_info))
+       continue;
+
+      symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+      shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+
+      cookie.abfd = abfd;
+      cookie.sym_hashes = elf_sym_hashes (abfd);
+      cookie.bad_symtab = elf_bad_symtab (abfd);
+      if (cookie.bad_symtab)
+       {
+         cookie.locsymcount =
+           symtab_hdr->sh_size / sizeof (Elf_External_Sym);
+         cookie.extsymoff = 0;
+       }
+      else
+       {
+         cookie.locsymcount = symtab_hdr->sh_info;
+         cookie.extsymoff = symtab_hdr->sh_info;
+       }
+
+      freesyms = NULL;
+      if (symtab_hdr->contents)
+        cookie.locsyms = (void *) symtab_hdr->contents;
+      else if (cookie.locsymcount == 0)
+        cookie.locsyms = NULL;
+      else
+        {
+          bfd_size_type amt = cookie.locsymcount * sizeof (Elf_External_Sym);
+          cookie.locsyms = bfd_malloc (amt);
+          if (cookie.locsyms == NULL)
+           return false;
+         freesyms = cookie.locsyms;
+         if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+              || bfd_bread (cookie.locsyms, amt, abfd) != amt)
+           {
+           error_ret_free_loc:
+             free (cookie.locsyms);
+             return false;
+            }
+        }
+
+      cookie.locsym_shndx = NULL;
+      if (shndx_hdr->sh_size != 0 && cookie.locsymcount != 0)
+       {
+         bfd_size_type amt;
+         amt = cookie.locsymcount * sizeof (Elf_External_Sym_Shndx);
+         cookie.locsym_shndx = bfd_malloc (amt);
+         if (cookie.locsym_shndx == NULL)
+           goto error_ret_free_loc;
+         if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+             || bfd_bread (cookie.locsym_shndx, amt, abfd) != amt)
+           {
+             free (cookie.locsym_shndx);
+             goto error_ret_free_loc;
+           }
+       }
+
+      if (stab)
+       {
+         cookie.rels = (NAME(_bfd_elf,link_read_relocs)
+                        (abfd, stab, (PTR) NULL,
+                         (Elf_Internal_Rela *) NULL,
+                         info->keep_memory));
+         if (cookie.rels)
+           {
+             cookie.rel = cookie.rels;
+             cookie.relend =
+               cookie.rels + stab->reloc_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,
+                                             &cookie))
+               ret = true;
+             if (! info->keep_memory)
+               free (cookie.rels);
+           }
+       }
+
+      if (eh)
+       {
+         cookie.rels = NULL;
+         cookie.rel = NULL;
+         cookie.relend = NULL;
+         if (eh->reloc_count)
+           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,
+                                                elf_reloc_symbol_deleted_p,
+                                                &cookie))
+           ret = true;
+         if (! info->keep_memory)
+           free (cookie.rels);
+       }
+
+      if (bed->elf_backend_discard_info)
+       {
+         if (bed->elf_backend_discard_info (abfd, &cookie, info))
+           ret = true;
+       }
+
+      if (cookie.locsym_shndx != NULL)
+       free (cookie.locsym_shndx);
+
+      if (freesyms != NULL)
+       free (freesyms);
+    }
+
+  if (ehdr
+      && _bfd_elf_discard_section_eh_frame_hdr (output_bfd,
+                                               info, ehdr))
+    ret = true;
+  return ret;
+}
+
+static boolean
+elf_section_ignore_discarded_relocs (sec)
+     asection *sec;
+{
+  switch (elf_section_data (sec)->sec_info_type)
+    {
+    case ELF_INFO_TYPE_STABS:
+    case ELF_INFO_TYPE_EH_FRAME:
+      return true;
+    default:
+      break;
+    }
+  if ((get_elf_backend_data (sec->owner)->elf_backend_ignore_discarded_relocs
+       != NULL)
+      && (*get_elf_backend_data (sec->owner)
+          ->elf_backend_ignore_discarded_relocs) (sec))
+    return true;
+
+  return false;
+}
This page took 0.05124 seconds and 4 git commands to generate.