Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elf.c
index c0c7fef83309bce490cf80466d75aadaf9a18f81..7d0b8a9e9b0322837df5a9743c6cc963014bf894 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,6 +1,6 @@
 /* ELF executable support for BFD.
 
 /* ELF executable support for BFD.
 
-   Copyright (C) 1993-2014 Free Software Foundation, Inc.
+   Copyright (C) 1993-2016 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -42,7 +42,7 @@ SECTION
 #include "elf-bfd.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
 #include "elf-bfd.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
-#include "elf-linux-psinfo.h"
+#include "elf-linux-core.h"
 
 #ifdef CORE_HEADER
 #include CORE_HEADER
 
 #ifdef CORE_HEADER
 #include CORE_HEADER
@@ -51,7 +51,7 @@ SECTION
 static int elf_sort_sections (const void *, const void *);
 static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
 static bfd_boolean prep_headers (bfd *);
 static int elf_sort_sections (const void *, const void *);
 static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
 static bfd_boolean prep_headers (bfd *);
-static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ;
+static bfd_boolean swap_out_syms (bfd *, struct elf_strtab_hash **, int) ;
 static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
 static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
                                    file_ptr offset);
 static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
 static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
                                    file_ptr offset);
@@ -297,13 +297,14 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
       /* Allocate and clear an extra byte at the end, to prevent crashes
         in case the string table is not terminated.  */
       if (shstrtabsize + 1 <= 1
       /* Allocate and clear an extra byte at the end, to prevent crashes
         in case the string table is not terminated.  */
       if (shstrtabsize + 1 <= 1
-         || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL
-         || bfd_seek (abfd, offset, SEEK_SET) != 0)
+         || bfd_seek (abfd, offset, SEEK_SET) != 0
+         || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL)
        shstrtab = NULL;
       else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize)
        {
          if (bfd_get_error () != bfd_error_system_call)
            bfd_set_error (bfd_error_file_truncated);
        shstrtab = NULL;
       else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize)
        {
          if (bfd_get_error () != bfd_error_system_call)
            bfd_set_error (bfd_error_file_truncated);
+         bfd_release (abfd, shstrtab);
          shstrtab = NULL;
          /* Once we've failed to read it, make sure we don't keep
             trying.  Otherwise, we'll keep allocating space for
          shstrtab = NULL;
          /* Once we've failed to read it, make sure we don't keep
             trying.  Otherwise, we'll keep allocating space for
@@ -332,9 +333,19 @@ bfd_elf_string_from_elf_section (bfd *abfd,
 
   hdr = elf_elfsections (abfd)[shindex];
 
 
   hdr = elf_elfsections (abfd)[shindex];
 
-  if (hdr->contents == NULL
-      && bfd_elf_get_str_section (abfd, shindex) == NULL)
-    return NULL;
+  if (hdr->contents == NULL)
+    {
+      if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS)
+       {
+         /* PR 17512: file: f057ec89.  */
+         _bfd_error_handler (_("%B: attempt to load strings from a non-string section (number %d)"),
+                             abfd, shindex);
+         return NULL;
+       }
+
+      if (bfd_elf_get_str_section (abfd, shindex) == NULL)
+       return NULL;
+    }
 
   if (strindex >= hdr->sh_size)
     {
 
   if (strindex >= hdr->sh_size)
     {
@@ -389,8 +400,34 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
   /* Normal syms might have section extension entries.  */
   shndx_hdr = NULL;
 
   /* Normal syms might have section extension entries.  */
   shndx_hdr = NULL;
-  if (symtab_hdr == &elf_tdata (ibfd)->symtab_hdr)
-    shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr;
+  if (elf_symtab_shndx_list (ibfd) != NULL)
+    {
+      elf_section_list * entry;
+      Elf_Internal_Shdr **sections = elf_elfsections (ibfd);
+
+      /* Find an index section that is linked to this symtab section.  */
+      for (entry = elf_symtab_shndx_list (ibfd); entry != NULL; entry = entry->next)
+       {
+         /* PR 20063.  */
+         if (entry->hdr.sh_link >= elf_numsections (ibfd))
+           continue;
+
+         if (sections[entry->hdr.sh_link] == symtab_hdr)
+           {
+             shndx_hdr = & entry->hdr;
+             break;
+           };
+       }
+
+      if (shndx_hdr == NULL)
+       {
+         if (symtab_hdr == & elf_symtab_hdr (ibfd))
+           /* Not really accurate, but this was how the old code used to work.  */
+           shndx_hdr = & elf_symtab_shndx_list (ibfd)->hdr;
+         /* Otherwise we do nothing.  The assumption is that
+            the index table will not be needed.  */
+       }
+    }
 
   /* Read the symbols.  */
   alloc_ext = NULL;
 
   /* Read the symbols.  */
   alloc_ext = NULL;
@@ -398,7 +435,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   alloc_intsym = NULL;
   bed = get_elf_backend_data (ibfd);
   extsym_size = bed->s->sizeof_sym;
   alloc_intsym = NULL;
   bed = get_elf_backend_data (ibfd);
   extsym_size = bed->s->sizeof_sym;
-  amt = symcount * extsym_size;
+  amt = (bfd_size_type) symcount * extsym_size;
   pos = symtab_hdr->sh_offset + symoffset * extsym_size;
   if (extsym_buf == NULL)
     {
   pos = symtab_hdr->sh_offset + symoffset * extsym_size;
   if (extsym_buf == NULL)
     {
@@ -417,7 +454,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
     extshndx_buf = NULL;
   else
     {
     extshndx_buf = NULL;
   else
     {
-      amt = symcount * sizeof (Elf_External_Sym_Shndx);
+      amt = (bfd_size_type) symcount * sizeof (Elf_External_Sym_Shndx);
       pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
       if (extshndx_buf == NULL)
        {
       pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
       if (extshndx_buf == NULL)
        {
@@ -636,6 +673,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                     pointers.  */
                  src = shdr->contents + shdr->sh_size;
                  dest = (Elf_Internal_Group *) (shdr->contents + amt);
                     pointers.  */
                  src = shdr->contents + shdr->sh_size;
                  dest = (Elf_Internal_Group *) (shdr->contents + amt);
+
                  while (1)
                    {
                      unsigned int idx;
                  while (1)
                    {
                      unsigned int idx;
@@ -796,6 +834,14 @@ _bfd_elf_setup_sections (bfd *abfd)
              elf_linked_to_section (s) = linksec;
            }
        }
              elf_linked_to_section (s) = linksec;
            }
        }
+      else if (this_hdr->sh_type == SHT_GROUP
+              && elf_next_in_group (s) == NULL)
+       {
+         (*_bfd_error_handler)
+           (_("%B: SHT_GROUP section [index %d] has no SHF_GROUP sections"),
+            abfd, elf_section_data (s)->this_idx);
+         result = FALSE;
+       }
     }
 
   /* Process section groups.  */
     }
 
   /* Process section groups.  */
@@ -805,8 +851,21 @@ _bfd_elf_setup_sections (bfd *abfd)
   for (i = 0; i < num_group; i++)
     {
       Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
   for (i = 0; i < num_group; i++)
     {
       Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
-      Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents;
-      unsigned int n_elt = shdr->sh_size / 4;
+      Elf_Internal_Group *idx;
+      unsigned int n_elt;
+
+      /* PR binutils/18758: Beware of corrupt binaries with invalid group data.  */
+      if (shdr == NULL || shdr->bfd_section == NULL || shdr->contents == NULL)
+       {
+         (*_bfd_error_handler)
+           (_("%B: section group entry number %u is corrupt"),
+            abfd, i);
+         result = FALSE;
+         continue;
+       }
+
+      idx = (Elf_Internal_Group *) shdr->contents;
+      n_elt = shdr->sh_size / 4;
 
       while (--n_elt != 0)
        if ((++idx)->shdr->bfd_section)
 
       while (--n_elt != 0)
        if ((++idx)->shdr->bfd_section)
@@ -843,6 +902,31 @@ bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
   return elf_next_in_group (sec) != NULL;
 }
 
   return elf_next_in_group (sec) != NULL;
 }
 
+static char *
+convert_debug_to_zdebug (bfd *abfd, const char *name)
+{
+  unsigned int len = strlen (name);
+  char *new_name = bfd_alloc (abfd, len + 2);
+  if (new_name == NULL)
+    return NULL;
+  new_name[0] = '.';
+  new_name[1] = 'z';
+  memcpy (new_name + 2, name + 1, len);
+  return new_name;
+}
+
+static char *
+convert_zdebug_to_debug (bfd *abfd, const char *name)
+{
+  unsigned int len = strlen (name);
+  char *new_name = bfd_alloc (abfd, len);
+  if (new_name == NULL)
+    return NULL;
+  new_name[0] = '.';
+  memcpy (new_name + 1, name + 2, len - 1);
+  return new_name;
+}
+
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -900,9 +984,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
     {
       flags |= SEC_MERGE;
       newsect->entsize = hdr->sh_entsize;
     {
       flags |= SEC_MERGE;
       newsect->entsize = hdr->sh_entsize;
-      if ((hdr->sh_flags & SHF_STRINGS) != 0)
-       flags |= SEC_STRINGS;
     }
     }
+  if ((hdr->sh_flags & SHF_STRINGS) != 0)
+    flags |= SEC_STRINGS;
   if (hdr->sh_flags & SHF_GROUP)
     if (!setup_group (abfd, hdr, newsect))
       return FALSE;
   if (hdr->sh_flags & SHF_GROUP)
     if (!setup_group (abfd, hdr, newsect))
       return FALSE;
@@ -1029,27 +1113,38 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          || (name[1] == 'z' && name[7] == '_')))
     {
       enum { nothing, compress, decompress } action = nothing;
          || (name[1] == 'z' && name[7] == '_')))
     {
       enum { nothing, compress, decompress } action = nothing;
-      char *new_name;
+      int compression_header_size;
+      bfd_size_type uncompressed_size;
+      bfd_boolean compressed
+       = bfd_is_section_compressed_with_header (abfd, newsect,
+                                                &compression_header_size,
+                                                &uncompressed_size);
 
 
-      if (bfd_is_section_compressed (abfd, newsect))
+      if (compressed)
        {
          /* Compressed section.  Check if we should decompress.  */
          if ((abfd->flags & BFD_DECOMPRESS))
            action = decompress;
        }
        {
          /* Compressed section.  Check if we should decompress.  */
          if ((abfd->flags & BFD_DECOMPRESS))
            action = decompress;
        }
-      else
+
+      /* Compress the uncompressed section or convert from/to .zdebug*
+        section.  Check if we should compress.  */
+      if (action == nothing)
        {
        {
-         /* Normal section.  Check if we should compress.  */
-         if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0)
+         if (newsect->size != 0
+             && (abfd->flags & BFD_COMPRESS)
+             && compression_header_size >= 0
+             && uncompressed_size > 0
+             && (!compressed
+                 || ((compression_header_size > 0)
+                     != ((abfd->flags & BFD_COMPRESS_GABI) != 0))))
            action = compress;
            action = compress;
+         else
+           return TRUE;
        }
 
        }
 
-      new_name = NULL;
-      switch (action)
+      if (action == compress)
        {
        {
-       case nothing:
-         break;
-       case compress:
          if (!bfd_init_section_compress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
          if (!bfd_init_section_compress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
@@ -1057,19 +1152,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
                 abfd, name);
              return FALSE;
            }
                 abfd, name);
              return FALSE;
            }
-         if (name[1] != 'z')
-           {
-             unsigned int len = strlen (name);
-
-             new_name = bfd_alloc (abfd, len + 2);
-             if (new_name == NULL)
-               return FALSE;
-             new_name[0] = '.';
-             new_name[1] = 'z';
-             memcpy (new_name + 2, name + 1, len);
-           }
-         break;
-       case decompress:
+       }
+      else
+       {
          if (!bfd_init_section_decompress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
          if (!bfd_init_section_decompress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
@@ -1077,26 +1162,35 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
                 abfd, name);
              return FALSE;
            }
                 abfd, name);
              return FALSE;
            }
-         if (name[1] == 'z')
-           {
-             unsigned int len = strlen (name);
+       }
 
 
-             new_name = bfd_alloc (abfd, len);
+      if (abfd->is_linker_input)
+       {
+         if (name[1] == 'z'
+             && (action == decompress
+                 || (action == compress
+                     && (abfd->flags & BFD_COMPRESS_GABI) != 0)))
+           {
+             /* Convert section name from .zdebug_* to .debug_* so
+                that linker will consider this section as a debug
+                section.  */
+             char *new_name = convert_zdebug_to_debug (abfd, name);
              if (new_name == NULL)
                return FALSE;
              if (new_name == NULL)
                return FALSE;
-             new_name[0] = '.';
-             memcpy (new_name + 1, name + 2, len - 1);
+             bfd_rename_section (abfd, newsect, new_name);
            }
            }
-         break;
        }
        }
-      if (new_name != NULL)
-       bfd_rename_section (abfd, newsect, new_name);
+      else
+       /* For objdump, don't rename the section.  For objcopy, delay
+          section rename to elf_fake_sections.  */
+       newsect->flags |= SEC_ELF_RENAME;
     }
 
   return TRUE;
 }
 
     }
 
   return TRUE;
 }
 
-const char *const bfd_elf_section_type_names[] = {
+const char *const bfd_elf_section_type_names[] =
+{
   "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
   "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
   "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
   "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
   "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
   "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
@@ -1133,14 +1227,160 @@ bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED,
   return bfd_reloc_continue;
 }
 \f
   return bfd_reloc_continue;
 }
 \f
+/* Returns TRUE if section A matches section B.
+   Names, addresses and links may be different, but everything else
+   should be the same.  */
+
+static bfd_boolean
+section_match (const Elf_Internal_Shdr * a,
+              const Elf_Internal_Shdr * b)
+{
+  return
+    a->sh_type         == b->sh_type
+    && (a->sh_flags & ~ SHF_INFO_LINK)
+    == (b->sh_flags & ~ SHF_INFO_LINK)
+    && a->sh_addralign == b->sh_addralign
+    && a->sh_size      == b->sh_size
+    && a->sh_entsize   == b->sh_entsize
+    /* FIXME: Check sh_addr ?  */
+    ;
+}
+
+/* Find a section in OBFD that has the same characteristics
+   as IHEADER.  Return the index of this section or SHN_UNDEF if
+   none can be found.  Check's section HINT first, as this is likely
+   to be the correct section.  */
+
+static unsigned int
+find_link (const bfd * obfd, const Elf_Internal_Shdr * iheader, const unsigned int hint)
+{
+  Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
+  unsigned int i;
+
+  if (section_match (oheaders[hint], iheader))
+    return hint;
+
+  for (i = 1; i < elf_numsections (obfd); i++)
+    {
+      Elf_Internal_Shdr * oheader = oheaders[i];
+
+      if (section_match (oheader, iheader))
+       /* FIXME: Do we care if there is a potential for
+          multiple matches ?  */
+       return i;
+    }
+
+  return SHN_UNDEF;
+}
+
+/* PR 19938: Attempt to set the ELF section header fields of an OS or
+   Processor specific section, based upon a matching input section.
+   Returns TRUE upon success, FALSE otherwise.  */
+   
+static bfd_boolean
+copy_special_section_fields (const bfd *ibfd,
+                            bfd *obfd,
+                            const Elf_Internal_Shdr *iheader,
+                            Elf_Internal_Shdr *oheader,
+                            const unsigned int secnum)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+  const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+  bfd_boolean changed = FALSE;
+  unsigned int sh_link;
+
+  if (oheader->sh_type == SHT_NOBITS)
+    {
+      /* This is a feature for objcopy --only-keep-debug:
+        When a section's type is changed to NOBITS, we preserve
+        the sh_link and sh_info fields so that they can be
+        matched up with the original.
+
+        Note: Strictly speaking these assignments are wrong.
+        The sh_link and sh_info fields should point to the
+        relevent sections in the output BFD, which may not be in
+        the same location as they were in the input BFD.  But
+        the whole point of this action is to preserve the
+        original values of the sh_link and sh_info fields, so
+        that they can be matched up with the section headers in
+        the original file.  So strictly speaking we may be
+        creating an invalid ELF file, but it is only for a file
+        that just contains debug info and only for sections
+        without any contents.  */
+      if (oheader->sh_link == 0)
+       oheader->sh_link = iheader->sh_link;
+      if (oheader->sh_info == 0)
+       oheader->sh_info = iheader->sh_info;
+      return TRUE;
+    }
+
+  /* Allow the target a chance to decide how these fields should be set.  */
+  if (bed->elf_backend_copy_special_section_fields != NULL
+      && bed->elf_backend_copy_special_section_fields
+      (ibfd, obfd, iheader, oheader))
+    return TRUE;
+
+  /* We have an iheader which might match oheader, and which has non-zero
+     sh_info and/or sh_link fields.  Attempt to follow those links and find
+     the section in the output bfd which corresponds to the linked section
+     in the input bfd.  */
+  if (iheader->sh_link != SHN_UNDEF)
+    {
+      sh_link = find_link (obfd, iheaders[iheader->sh_link], iheader->sh_link);
+      if (sh_link != SHN_UNDEF)
+       {
+         oheader->sh_link = sh_link;
+         changed = TRUE;
+       }
+      else
+       /* FIXME: Should we install iheader->sh_link
+          if we could not find a match ?  */
+       (* _bfd_error_handler)
+         (_("%B: Failed to find link section for section %d"), obfd, secnum);
+    }
+
+  if (iheader->sh_info)
+    {
+      /* The sh_info field can hold arbitrary information, but if the
+        SHF_LINK_INFO flag is set then it should be interpreted as a
+        section index.  */
+      if (iheader->sh_flags & SHF_INFO_LINK)
+       {
+         sh_link = find_link (obfd, iheaders[iheader->sh_info],
+                              iheader->sh_info);
+         if (sh_link != SHN_UNDEF)
+           oheader->sh_flags |= SHF_INFO_LINK;
+       }
+      else
+       /* No idea what it means - just copy it.  */
+       sh_link = iheader->sh_info;
+
+      if (sh_link != SHN_UNDEF)
+       {
+         oheader->sh_info = sh_link;
+         changed = TRUE;
+       }
+      else
+       (* _bfd_error_handler)
+         (_("%B: Failed to find info section for section %d"), obfd, secnum);
+    }
+
+  return changed;
+}
+  
 /* Copy the program header and other data from one object module to
    another.  */
 
 bfd_boolean
 _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 {
 /* Copy the program header and other data from one object module to
    another.  */
 
 bfd_boolean
 _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 {
+  const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+  Elf_Internal_Shdr **oheaders = elf_elfsections (obfd);
+  const struct elf_backend_data *bed;
+  unsigned int i;
+
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return TRUE;
 
   if (!elf_flags_init (obfd))
     return TRUE;
 
   if (!elf_flags_init (obfd))
@@ -1155,8 +1395,105 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   elf_elfheader (obfd)->e_ident[EI_OSABI] =
     elf_elfheader (ibfd)->e_ident[EI_OSABI];
 
   elf_elfheader (obfd)->e_ident[EI_OSABI] =
     elf_elfheader (ibfd)->e_ident[EI_OSABI];
 
+  /* If set, copy the EI_ABIVERSION field.  */
+  if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION])
+    elf_elfheader (obfd)->e_ident[EI_ABIVERSION]
+      = elf_elfheader (ibfd)->e_ident[EI_ABIVERSION];
+  
   /* Copy object attributes.  */
   _bfd_elf_copy_obj_attributes (ibfd, obfd);
   /* Copy object attributes.  */
   _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+  if (iheaders == NULL || oheaders == NULL)
+    return TRUE;
+
+  bed = get_elf_backend_data (obfd);
+
+  /* Possibly copy other fields in the section header.  */
+  for (i = 1; i < elf_numsections (obfd); i++)
+    {
+      unsigned int j;
+      Elf_Internal_Shdr * oheader = oheaders[i];
+
+      /* Ignore ordinary sections.  SHT_NOBITS sections are considered however
+        because of a special case need for generating separate debug info
+        files.  See below for more details.  */
+      if (oheader == NULL
+         || (oheader->sh_type != SHT_NOBITS
+             && oheader->sh_type < SHT_LOOS))
+       continue;
+
+      /* Ignore empty sections, and sections whose
+        fields have already been initialised.  */
+      if (oheader->sh_size == 0
+         || (oheader->sh_info != 0 && oheader->sh_link != 0))
+       continue;
+
+      /* Scan for the matching section in the input bfd.
+        First we try for a direct mapping between the input and output sections.  */
+      for (j = 1; j < elf_numsections (ibfd); j++)
+       {
+         const Elf_Internal_Shdr * iheader = iheaders[j];
+
+         if (iheader == NULL)
+           continue;
+
+         if (oheader->bfd_section != NULL
+             && iheader->bfd_section != NULL
+             && iheader->bfd_section->output_section != NULL
+             && iheader->bfd_section->output_section == oheader->bfd_section)
+           {
+             /* We have found a connection from the input section to the
+                output section.  Attempt to copy the header fields.  If
+                this fails then do not try any further sections - there
+                should only be a one-to-one mapping between input and output. */
+             if (! copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+               j = elf_numsections (ibfd);
+             break;
+           }
+       }
+
+      if (j < elf_numsections (ibfd))
+       continue;
+
+      /* That failed.  So try to deduce the corresponding input section.
+        Unfortunately we cannot compare names as the output string table
+        is empty, so instead we check size, address and type.  */
+      for (j = 1; j < elf_numsections (ibfd); j++)
+       {
+         const Elf_Internal_Shdr * iheader = iheaders[j];
+
+         if (iheader == NULL)
+           continue;
+
+         /* Try matching fields in the input section's header.
+            Since --only-keep-debug turns all non-debug sections into
+            SHT_NOBITS sections, the output SHT_NOBITS type matches any
+            input type.  */
+         if ((oheader->sh_type == SHT_NOBITS
+              || iheader->sh_type == oheader->sh_type)
+             && (iheader->sh_flags & ~ SHF_INFO_LINK)
+             == (oheader->sh_flags & ~ SHF_INFO_LINK)
+             && iheader->sh_addralign == oheader->sh_addralign
+             && iheader->sh_entsize == oheader->sh_entsize
+             && iheader->sh_size == oheader->sh_size
+             && iheader->sh_addr == oheader->sh_addr
+             && (iheader->sh_info != oheader->sh_info
+                 || iheader->sh_link != oheader->sh_link))
+           {
+             if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+               break;
+           }
+       }
+
+      if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS)
+       {
+         /* Final attempt.  Call the backend copy function
+            with a NULL input section.  */
+         if (bed->elf_backend_copy_special_section_fields != NULL)
+           bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader);
+       }
+    }
+
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -1253,8 +1590,13 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
       extdyn = dynbuf;
       swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
       extdyn = dynbuf;
+      /* PR 17512: file: 6f427532.  */
+      if (s->size < extdynsize)
+       goto error_return;
       extdynend = extdyn + s->size;
       extdynend = extdyn + s->size;
-      for (; extdyn < extdynend; extdyn += extdynsize)
+      /* PR 17512: file: id:000006,sig:06,src:000000,op:flip4,pos:5664.
+         Fix range check.  */
+      for (; extdyn <= (extdynend - extdynsize); extdyn += extdynsize)
        {
          Elf_Internal_Dyn dyn;
          const char *name = "";
        {
          Elf_Internal_Dyn dyn;
          const char *name = "";
@@ -1425,8 +1767,8 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
 /* Get version string.  */
 
 const char *
 /* Get version string.  */
 
 const char *
-bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
-                                  bfd_boolean *hidden)
+_bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
+                                   bfd_boolean *hidden)
 {
   const char *version_string = NULL;
   if (elf_dynversym (abfd) != 0
 {
   const char *version_string = NULL;
   if (elf_dynversym (abfd) != 0
@@ -1522,9 +1864,9 @@ bfd_elf_print_symbol (bfd *abfd,
        bfd_fprintf_vma (abfd, file, val);
 
        /* If we have version information, print it.  */
        bfd_fprintf_vma (abfd, file, val);
 
        /* If we have version information, print it.  */
-       version_string = bfd_elf_get_symbol_version_string (abfd,
-                                                           symbol,
-                                                           &hidden);
+       version_string = _bfd_elf_get_symbol_version_string (abfd,
+                                                            symbol,
+                                                            &hidden);
        if (version_string)
          {
            if (!hidden)
        if (version_string)
          {
            if (!hidden)
@@ -1559,29 +1901,6 @@ bfd_elf_print_symbol (bfd *abfd,
       break;
     }
 }
       break;
     }
 }
-
-/* Allocate an ELF string table--force the first byte to be zero.  */
-
-struct bfd_strtab_hash *
-_bfd_elf_stringtab_init (void)
-{
-  struct bfd_strtab_hash *ret;
-
-  ret = _bfd_stringtab_init ();
-  if (ret != NULL)
-    {
-      bfd_size_type loc;
-
-      loc = _bfd_stringtab_add (ret, "", TRUE, FALSE);
-      BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1);
-      if (loc == (bfd_size_type) -1)
-       {
-         _bfd_stringtab_free (ret);
-         ret = NULL;
-       }
-    }
-  return ret;
-}
 \f
 /* ELF .o/exec file reading */
 
 \f
 /* ELF .o/exec file reading */
 
@@ -1605,7 +1924,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
   if (++ nesting > 3)
     {
       /* PR17512: A corrupt ELF binary might contain a recursive group of
   if (++ nesting > 3)
     {
       /* PR17512: A corrupt ELF binary might contain a recursive group of
-        sections, each the string indicies pointing to the next in the
+        sections, with each the string indicies pointing to the next in the
         loop.  Detect this here, by refusing to load a section that we are
         already in the process of loading.  We only trigger this test if
         we have nested at least three sections deep as normal ELF binaries
         loop.  Detect this here, by refusing to load a section that we are
         already in the process of loading.  We only trigger this test if
         we have nested at least three sections deep as normal ELF binaries
@@ -1728,10 +2047,18 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          goto success;
        }
 
          goto success;
        }
 
-      BFD_ASSERT (elf_onesymtab (abfd) == 0);
+      /* PR 18854: A binary might contain more than one symbol table.
+        Unusual, but possible.  Warn, but continue.  */
+      if (elf_onesymtab (abfd) != 0)
+       {
+         (*_bfd_error_handler)
+           (_("%B: warning: multiple symbol tables detected - ignoring the table in section %u"),
+            abfd, shindex);
+         goto success;
+       }
       elf_onesymtab (abfd) = shindex;
       elf_onesymtab (abfd) = shindex;
-      elf_tdata (abfd)->symtab_hdr = *hdr;
-      elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr;
+      elf_symtab_hdr (abfd) = *hdr;
+      elf_elfsections (abfd)[shindex] = hdr = & elf_symtab_hdr (abfd);
       abfd->flags |= HAS_SYMS;
 
       /* Sometimes a shared object will map in the symbol table.  If
       abfd->flags |= HAS_SYMS;
 
       /* Sometimes a shared object will map in the symbol table.  If
@@ -1749,30 +2076,39 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we
         can't read symbols without that section loaded as well.  It
         is most likely specified by the next section header.  */
       /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we
         can't read symbols without that section loaded as well.  It
         is most likely specified by the next section header.  */
-      if (elf_elfsections (abfd)[elf_symtab_shndx (abfd)]->sh_link != shindex)
-       {
-         unsigned int i, num_sec;
+      {
+       elf_section_list * entry;
+       unsigned int i, num_sec;
 
 
-         num_sec = elf_numsections (abfd);
-         for (i = shindex + 1; i < num_sec; i++)
+       for (entry = elf_symtab_shndx_list (abfd); entry != NULL; entry = entry->next)
+         if (entry->hdr.sh_link == shindex)
+           goto success;
+
+       num_sec = elf_numsections (abfd);
+       for (i = shindex + 1; i < num_sec; i++)
+         {
+           Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+
+           if (hdr2->sh_type == SHT_SYMTAB_SHNDX
+               && hdr2->sh_link == shindex)
+             break;
+         }
+
+       if (i == num_sec)
+         for (i = 1; i < shindex; i++)
            {
              Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
            {
              Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+
              if (hdr2->sh_type == SHT_SYMTAB_SHNDX
                  && hdr2->sh_link == shindex)
                break;
            }
              if (hdr2->sh_type == SHT_SYMTAB_SHNDX
                  && hdr2->sh_link == shindex)
                break;
            }
-         if (i == num_sec)
-           for (i = 1; i < shindex; i++)
-             {
-               Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
-               if (hdr2->sh_type == SHT_SYMTAB_SHNDX
-                   && hdr2->sh_link == shindex)
-                 break;
-             }
-         if (i != shindex)
-           ret = bfd_section_from_shdr (abfd, i);
-       }
-      goto success;
+
+       if (i != shindex)
+         ret = bfd_section_from_shdr (abfd, i);
+       /* else FIXME: we have failed to find the symbol table - should we issue an error ? */
+       goto success;
+      }
 
     case SHT_DYNSYM:           /* A dynamic symbol table.  */
       if (elf_dynsymtab (abfd) == shindex)
 
     case SHT_DYNSYM:           /* A dynamic symbol table.  */
       if (elf_dynsymtab (abfd) == shindex)
@@ -1793,7 +2129,15 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          goto success;
        }
 
          goto success;
        }
 
-      BFD_ASSERT (elf_dynsymtab (abfd) == 0);
+      /* PR 18854: A binary might contain more than one dynamic symbol table.
+        Unusual, but possible.  Warn, but continue.  */
+      if (elf_dynsymtab (abfd) != 0)
+       {
+         (*_bfd_error_handler)
+           (_("%B: warning: multiple dynamic symbol tables detected - ignoring the table in section %u"),
+            abfd, shindex);
+         goto success;
+       }
       elf_dynsymtab (abfd) = shindex;
       elf_tdata (abfd)->dynsymtab_hdr = *hdr;
       elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr;
       elf_dynsymtab (abfd) = shindex;
       elf_tdata (abfd)->dynsymtab_hdr = *hdr;
       elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr;
@@ -1805,14 +2149,23 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       goto success;
 
     case SHT_SYMTAB_SHNDX:     /* Symbol section indices when >64k sections.  */
       goto success;
 
     case SHT_SYMTAB_SHNDX:     /* Symbol section indices when >64k sections.  */
-      if (elf_symtab_shndx (abfd) == shindex)
-       goto success;
+      {
+       elf_section_list * entry;
 
 
-      BFD_ASSERT (elf_symtab_shndx (abfd) == 0);
-      elf_symtab_shndx (abfd) = shindex;
-      elf_tdata (abfd)->symtab_shndx_hdr = *hdr;
-      elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr;
-      goto success;
+       for (entry = elf_symtab_shndx_list (abfd); entry != NULL; entry = entry->next)
+         if (entry->ndx == shindex)
+           goto success;
+       
+       entry = bfd_alloc (abfd, sizeof * entry);
+       if (entry == NULL)
+         goto fail;
+       entry->ndx = shindex;
+       entry->hdr = * hdr;
+       entry->next = elf_symtab_shndx_list (abfd);
+       elf_symtab_shndx_list (abfd) = entry;
+       elf_elfsections (abfd)[shindex] = & entry->hdr;
+       goto success;
+      }
 
     case SHT_STRTAB:           /* A string table.  */
       if (hdr->bfd_section != NULL)
 
     case SHT_STRTAB:           /* A string table.  */
       if (hdr->bfd_section != NULL)
@@ -1882,7 +2235,6 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        Elf_Internal_Shdr *hdr2, **p_hdr;
        unsigned int num_sec = elf_numsections (abfd);
        struct bfd_elf_section_data *esdt;
        Elf_Internal_Shdr *hdr2, **p_hdr;
        unsigned int num_sec = elf_numsections (abfd);
        struct bfd_elf_section_data *esdt;
-       bfd_size_type amt;
 
        if (hdr->sh_entsize
            != (bfd_size_type) (hdr->sh_type == SHT_REL
 
        if (hdr->sh_entsize
            != (bfd_size_type) (hdr->sh_type == SHT_REL
@@ -1972,9 +2324,10 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        else
          p_hdr = &esdt->rel.hdr;
 
        else
          p_hdr = &esdt->rel.hdr;
 
-       BFD_ASSERT (*p_hdr == NULL);
-       amt = sizeof (*hdr2);
-       hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt);
+       /* PR 17512: file: 0b4f81b7.  */
+       if (*p_hdr != NULL)
+         goto fail;
+       hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
        if (hdr2 == NULL)
          goto fail;
        *hdr2 = *hdr;
        if (hdr2 == NULL)
          goto fail;
        *hdr2 = *hdr;
@@ -2029,15 +2382,18 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       if (hdr->contents != NULL)
        {
          Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents;
       if (hdr->contents != NULL)
        {
          Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents;
-         unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE;
+         unsigned int n_elt = hdr->sh_size / sizeof (* idx);
          asection *s;
 
          asection *s;
 
+         if (n_elt == 0)
+           goto fail;
          if (idx->flags & GRP_COMDAT)
            hdr->bfd_section->flags
              |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
          /* We try to keep the same section order as it comes in.  */
          idx += n_elt;
          if (idx->flags & GRP_COMDAT)
            hdr->bfd_section->flags
              |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
          /* We try to keep the same section order as it comes in.  */
          idx += n_elt;
+
          while (--n_elt != 0)
            {
              --idx;
          while (--n_elt != 0)
            {
              --idx;
@@ -2636,6 +2992,27 @@ _bfd_elf_single_rel_hdr (asection *sec)
     return elf_section_data (sec)->rela.hdr;
 }
 
     return elf_section_data (sec)->rela.hdr;
 }
 
+static bfd_boolean
+_bfd_elf_set_reloc_sh_name (bfd *abfd,
+                           Elf_Internal_Shdr *rel_hdr,
+                           const char *sec_name,
+                           bfd_boolean use_rela_p)
+{
+  char *name = (char *) bfd_alloc (abfd,
+                                  sizeof ".rela" + strlen (sec_name));
+  if (name == NULL)
+    return FALSE;
+
+  sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", sec_name);
+  rel_hdr->sh_name =
+    (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
+                                       FALSE);
+  if (rel_hdr->sh_name == (unsigned int) -1)
+    return FALSE;
+
+  return TRUE;
+}
+
 /* Allocate and initialize a section-header for a new reloc section,
    containing relocations against ASECT.  It is stored in RELDATA.  If
    USE_RELA_P is TRUE, we use RELA relocations; otherwise, we use REL
 /* Allocate and initialize a section-header for a new reloc section,
    containing relocations against ASECT.  It is stored in RELDATA.  If
    USE_RELA_P is TRUE, we use RELA relocations; otherwise, we use REL
@@ -2644,28 +3021,21 @@ _bfd_elf_single_rel_hdr (asection *sec)
 static bfd_boolean
 _bfd_elf_init_reloc_shdr (bfd *abfd,
                          struct bfd_elf_section_reloc_data *reldata,
 static bfd_boolean
 _bfd_elf_init_reloc_shdr (bfd *abfd,
                          struct bfd_elf_section_reloc_data *reldata,
-                         asection *asect,
-                         bfd_boolean use_rela_p)
+                         const char *sec_name,
+                         bfd_boolean use_rela_p,
+                         bfd_boolean delay_st_name_p)
 {
   Elf_Internal_Shdr *rel_hdr;
 {
   Elf_Internal_Shdr *rel_hdr;
-  char *name;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  bfd_size_type amt;
 
 
-  amt = sizeof (Elf_Internal_Shdr);
   BFD_ASSERT (reldata->hdr == NULL);
   BFD_ASSERT (reldata->hdr == NULL);
-  rel_hdr = bfd_zalloc (abfd, amt);
+  rel_hdr = bfd_zalloc (abfd, sizeof (*rel_hdr));
   reldata->hdr = rel_hdr;
 
   reldata->hdr = rel_hdr;
 
-  amt = sizeof ".rela" + strlen (asect->name);
-  name = (char *) bfd_alloc (abfd, amt);
-  if (name == NULL)
-    return FALSE;
-  sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
-  rel_hdr->sh_name =
-    (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
-                                       FALSE);
-  if (rel_hdr->sh_name == (unsigned int) -1)
+  if (delay_st_name_p)
+    rel_hdr->sh_name = (unsigned int) -1;
+  else if (!_bfd_elf_set_reloc_sh_name (abfd, rel_hdr, sec_name,
+                                       use_rela_p))
     return FALSE;
   rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
   rel_hdr->sh_entsize = (use_rela_p
     return FALSE;
   rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
   rel_hdr->sh_entsize = (use_rela_p
@@ -2707,6 +3077,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
   struct bfd_elf_section_data *esd = elf_section_data (asect);
   Elf_Internal_Shdr *this_hdr;
   unsigned int sh_type;
   struct bfd_elf_section_data *esd = elf_section_data (asect);
   Elf_Internal_Shdr *this_hdr;
   unsigned int sh_type;
+  const char *name = asect->name;
+  bfd_boolean delay_st_name_p = FALSE;
 
   if (arg->failed)
     {
 
   if (arg->failed)
     {
@@ -2717,12 +3089,72 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
 
   this_hdr = &esd->this_hdr;
 
 
   this_hdr = &esd->this_hdr;
 
-  this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
-                                                         asect->name, FALSE);
-  if (this_hdr->sh_name == (unsigned int) -1)
+  if (arg->link_info)
     {
     {
-      arg->failed = TRUE;
-      return;
+      /* ld: compress DWARF debug sections with names: .debug_*.  */
+      if ((arg->link_info->compress_debug & COMPRESS_DEBUG)
+         && (asect->flags & SEC_DEBUGGING)
+         && name[1] == 'd'
+         && name[6] == '_')
+       {
+         /* Set SEC_ELF_COMPRESS to indicate this section should be
+            compressed.  */
+         asect->flags |= SEC_ELF_COMPRESS;
+
+         /* If this section will be compressed, delay adding section
+            name to section name section after it is compressed in
+            _bfd_elf_assign_file_positions_for_non_load.  */
+         delay_st_name_p = TRUE;
+       }
+    }
+  else if ((asect->flags & SEC_ELF_RENAME))
+    {
+      /* objcopy: rename output DWARF debug section.  */
+      if ((abfd->flags & (BFD_DECOMPRESS | BFD_COMPRESS_GABI)))
+       {
+         /* When we decompress or compress with SHF_COMPRESSED,
+            convert section name from .zdebug_* to .debug_* if
+            needed.  */
+         if (name[1] == 'z')
+           {
+             char *new_name = convert_zdebug_to_debug (abfd, name);
+             if (new_name == NULL)
+               {
+                 arg->failed = TRUE;
+                 return;
+               }
+             name = new_name;
+           }
+       }
+      else if (asect->compress_status == COMPRESS_SECTION_DONE)
+       {
+         /* PR binutils/18087: Compression does not always make a
+            section smaller.  So only rename the section when
+            compression has actually taken place.  If input section
+            name is .zdebug_*, we should never compress it again.  */
+         char *new_name = convert_debug_to_zdebug (abfd, name);
+         if (new_name == NULL)
+           {
+             arg->failed = TRUE;
+             return;
+           }
+         BFD_ASSERT (name[1] != 'z');
+         name = new_name;
+       }
+    }
+
+  if (delay_st_name_p)
+    this_hdr->sh_name = (unsigned int) -1;
+  else
+    {
+      this_hdr->sh_name
+       = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+                                             name, FALSE);
+      if (this_hdr->sh_name == (unsigned int) -1)
+       {
+         arg->failed = TRUE;
+         return;
+       }
     }
 
   /* Don't clear sh_flags. Assembler may set additional bits.  */
     }
 
   /* Don't clear sh_flags. Assembler may set additional bits.  */
@@ -2736,6 +3168,15 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
   this_hdr->sh_offset = 0;
   this_hdr->sh_size = asect->size;
   this_hdr->sh_link = 0;
   this_hdr->sh_offset = 0;
   this_hdr->sh_size = asect->size;
   this_hdr->sh_link = 0;
+  /* PR 17512: file: 0eb809fe, 8b0535ee.  */
+  if (asect->alignment_power >= (sizeof (bfd_vma) * 8) - 1)
+    {
+      (*_bfd_error_handler)
+       (_("%B: error: Alignment power %d of section `%A' is too big"),
+        abfd, asect, asect->alignment_power);
+      arg->failed = TRUE;
+      return;
+    }
   this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power;
   /* The sh_entsize and sh_info fields may have been set already by
      copy_private_section_data.  */
   this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power;
   /* The sh_entsize and sh_info fields may have been set already by
      copy_private_section_data.  */
@@ -2771,14 +3212,17 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
       break;
 
     case SHT_STRTAB:
       break;
 
     case SHT_STRTAB:
-    case SHT_INIT_ARRAY:
-    case SHT_FINI_ARRAY:
-    case SHT_PREINIT_ARRAY:
     case SHT_NOTE:
     case SHT_NOBITS:
     case SHT_PROGBITS:
       break;
 
     case SHT_NOTE:
     case SHT_NOBITS:
     case SHT_PROGBITS:
       break;
 
+    case SHT_INIT_ARRAY:
+    case SHT_FINI_ARRAY:
+    case SHT_PREINIT_ARRAY:
+      this_hdr->sh_entsize = bed->s->arch_size / 8;
+      break;
+
     case SHT_HASH:
       this_hdr->sh_entsize = bed->s->sizeof_hash_entry;
       break;
     case SHT_HASH:
       this_hdr->sh_entsize = bed->s->sizeof_hash_entry;
       break;
@@ -2848,9 +3292,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
     {
       this_hdr->sh_flags |= SHF_MERGE;
       this_hdr->sh_entsize = asect->entsize;
     {
       this_hdr->sh_flags |= SHF_MERGE;
       this_hdr->sh_entsize = asect->entsize;
-      if ((asect->flags & SEC_STRINGS) != 0)
-       this_hdr->sh_flags |= SHF_STRINGS;
     }
     }
+  if ((asect->flags & SEC_STRINGS) != 0)
+    this_hdr->sh_flags |= SHF_STRINGS;
   if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
     this_hdr->sh_flags |= SHF_GROUP;
   if ((asect->flags & SEC_THREAD_LOCAL) != 0)
   if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
     this_hdr->sh_flags |= SHF_GROUP;
   if ((asect->flags & SEC_THREAD_LOCAL) != 0)
@@ -2884,16 +3328,19 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
       if (arg->link_info
          /* Do the normal setup if we wouldn't create any sections here.  */
          && esd->rel.count + esd->rela.count > 0
       if (arg->link_info
          /* Do the normal setup if we wouldn't create any sections here.  */
          && esd->rel.count + esd->rela.count > 0
-         && (arg->link_info->relocatable || arg->link_info->emitrelocations))
+         && (bfd_link_relocatable (arg->link_info)
+             || arg->link_info->emitrelocations))
        {
          if (esd->rel.count && esd->rel.hdr == NULL
        {
          if (esd->rel.count && esd->rel.hdr == NULL
-             && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, asect, FALSE))
+             && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, name, FALSE,
+                                           delay_st_name_p))
            {
              arg->failed = TRUE;
              return;
            }
          if (esd->rela.count && esd->rela.hdr == NULL
            {
              arg->failed = TRUE;
              return;
            }
          if (esd->rela.count && esd->rela.hdr == NULL
-             && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, asect, TRUE))
+             && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, name, TRUE,
+                                           delay_st_name_p))
            {
              arg->failed = TRUE;
              return;
            {
              arg->failed = TRUE;
              return;
@@ -2902,8 +3349,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
       else if (!_bfd_elf_init_reloc_shdr (abfd,
                                          (asect->use_rela_p
                                           ? &esd->rela : &esd->rel),
       else if (!_bfd_elf_init_reloc_shdr (abfd,
                                          (asect->use_rela_p
                                           ? &esd->rela : &esd->rel),
-                                         asect,
-                                         asect->use_rela_p))
+                                         name,
+                                         asect->use_rela_p,
+                                         delay_st_name_p))
          arg->failed = TRUE;
     }
 
          arg->failed = TRUE;
     }
 
@@ -2963,12 +3411,19 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
       /* The ELF backend linker sets sh_info to -2 when the group
         signature symbol is global, and thus the index can't be
         set until all local symbols are output.  */
       /* The ELF backend linker sets sh_info to -2 when the group
         signature symbol is global, and thus the index can't be
         set until all local symbols are output.  */
-      asection *igroup = elf_sec_group (elf_next_in_group (sec));
-      struct bfd_elf_section_data *sec_data = elf_section_data (igroup);
-      unsigned long symndx = sec_data->this_hdr.sh_info;
-      unsigned long extsymoff = 0;
+      asection *igroup;
+      struct bfd_elf_section_data *sec_data;
+      unsigned long symndx;
+      unsigned long extsymoff;
       struct elf_link_hash_entry *h;
 
       struct elf_link_hash_entry *h;
 
+      /* The point of this little dance to the first SHF_GROUP section
+        then back to the SHT_GROUP section is that this gets us to
+        the SHT_GROUP in the input object.  */
+      igroup = elf_sec_group (elf_next_in_group (sec));
+      sec_data = elf_section_data (igroup);
+      symndx = sec_data->this_hdr.sh_info;
+      extsymoff = 0;
       if (!elf_bad_symtab (igroup->owner))
        {
          Elf_Internal_Shdr *symtab_hdr;
       if (!elf_bad_symtab (igroup->owner))
        {
          Elf_Internal_Shdr *symtab_hdr;
@@ -3037,16 +3492,58 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 }
 
   H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 }
 
-/* Assign all ELF section numbers.  The dummy first section is handled here
-   too.  The link/info pointers for the standard section types are filled
-   in here too, while we're at it.  */
+/* Return the section which RELOC_SEC applies to.  */
 
 
-static bfd_boolean
+asection *
+_bfd_elf_get_reloc_section (asection *reloc_sec)
+{
+  const char *name;
+  unsigned int type;
+  bfd *abfd;
+
+  if (reloc_sec == NULL)
+    return NULL;
+
+  type = elf_section_data (reloc_sec)->this_hdr.sh_type;
+  if (type != SHT_REL && type != SHT_RELA)
+    return NULL;
+
+  /* We look up the section the relocs apply to by name.  */
+  name = reloc_sec->name;
+  if (type == SHT_REL)
+    name += 4;
+  else
+    name += 5;
+
+  /* If a target needs .got.plt section, relocations in rela.plt/rel.plt
+     section apply to .got.plt section.  */
+  abfd = reloc_sec->owner;
+  if (get_elf_backend_data (abfd)->want_got_plt
+      && strcmp (name, ".plt") == 0)
+    {
+      /* .got.plt is a linker created input section.  It may be mapped
+        to some other output section.  Try two likely sections.  */
+      name = ".got.plt";
+      reloc_sec = bfd_get_section_by_name (abfd, name);
+      if (reloc_sec != NULL)
+       return reloc_sec;
+      name = ".got";
+    }
+
+  reloc_sec = bfd_get_section_by_name (abfd, name);
+  return reloc_sec;
+}
+
+/* Assign all ELF section numbers.  The dummy first section is handled here
+   too.  The link/info pointers for the standard section types are filled
+   in here too, while we're at it.  */
+
+static bfd_boolean
 assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 {
   struct elf_obj_tdata *t = elf_tdata (abfd);
   asection *sec;
 assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 {
   struct elf_obj_tdata *t = elf_tdata (abfd);
   asection *sec;
-  unsigned int section_number, secn;
+  unsigned int section_number;
   Elf_Internal_Shdr **i_shdrp;
   struct bfd_elf_section_data *d;
   bfd_boolean need_symtab;
   Elf_Internal_Shdr **i_shdrp;
   struct bfd_elf_section_data *d;
   bfd_boolean need_symtab;
@@ -3056,8 +3553,10 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
 
   /* SHT_GROUP sections are in relocatable files only.  */
   _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
 
   /* SHT_GROUP sections are in relocatable files only.  */
-  if (link_info == NULL || link_info->relocatable)
+  if (link_info == NULL || bfd_link_relocatable (link_info))
     {
     {
+      size_t reloc_count = 0;
+
       /* Put SHT_GROUP sections first.  */
       for (sec = abfd->sections; sec != NULL; sec = sec->next)
        {
       /* Put SHT_GROUP sections first.  */
       for (sec = abfd->sections; sec != NULL; sec = sec->next)
        {
@@ -3074,7 +3573,14 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
              else
                d->this_idx = section_number++;
            }
              else
                d->this_idx = section_number++;
            }
+
+         /* Count relocations.  */
+         reloc_count += sec->reloc_count;
        }
        }
+
+      /* Clear HAS_RELOC if there are no relocations.  */
+      if (reloc_count == 0)
+       abfd->flags &= ~HAS_RELOC;
     }
 
   for (sec = abfd->sections; sec; sec = sec->next)
     }
 
   for (sec = abfd->sections; sec; sec = sec->next)
@@ -3083,11 +3589,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 
       if (d->this_hdr.sh_type != SHT_GROUP)
        d->this_idx = section_number++;
 
       if (d->this_hdr.sh_type != SHT_GROUP)
        d->this_idx = section_number++;
-      _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
+      if (d->this_hdr.sh_name != (unsigned int) -1)
+       _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
       if (d->rel.hdr)
        {
          d->rel.idx = section_number++;
       if (d->rel.hdr)
        {
          d->rel.idx = section_number++;
-         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name);
+         if (d->rel.hdr->sh_name != (unsigned int) -1)
+           _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name);
        }
       else
        d->rel.idx = 0;
        }
       else
        d->rel.idx = 0;
@@ -3095,16 +3603,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       if (d->rela.hdr)
        {
          d->rela.idx = section_number++;
       if (d->rela.hdr)
        {
          d->rela.idx = section_number++;
-         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name);
+         if (d->rela.hdr->sh_name != (unsigned int) -1)
+           _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name);
        }
       else
        d->rela.idx = 0;
     }
 
        }
       else
        d->rela.idx = 0;
     }
 
-  elf_shstrtab_sec (abfd) = section_number++;
-  _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
-  elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd);
-
   need_symtab = (bfd_get_symcount (abfd) > 0
                || (link_info == NULL
                    && ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
   need_symtab = (bfd_get_symcount (abfd) > 0
                || (link_info == NULL
                    && ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
@@ -3115,17 +3620,27 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
       if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF))
        {
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
       if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF))
        {
-         elf_symtab_shndx (abfd) = section_number++;
-         t->symtab_shndx_hdr.sh_name
+         elf_section_list * entry;
+
+         BFD_ASSERT (elf_symtab_shndx_list (abfd) == NULL);
+
+         entry = bfd_zalloc (abfd, sizeof * entry);
+         entry->ndx = section_number++;
+         elf_symtab_shndx_list (abfd) = entry;
+         entry->hdr.sh_name
            = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
                                                  ".symtab_shndx", FALSE);
            = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
                                                  ".symtab_shndx", FALSE);
-         if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1)
+         if (entry->hdr.sh_name == (unsigned int) -1)
            return FALSE;
        }
       elf_strtab_sec (abfd) = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
            return FALSE;
        }
       elf_strtab_sec (abfd) = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
+  elf_shstrtab_sec (abfd) = section_number++;
+  _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
+  elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd);
+
   if (section_number >= SHN_LORESERVE)
     {
       _bfd_error_handler (_("%B: too many sections: %u"),
   if (section_number >= SHN_LORESERVE)
     {
       _bfd_error_handler (_("%B: too many sections: %u"),
@@ -3133,9 +3648,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       return FALSE;
     }
 
       return FALSE;
     }
 
-  _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
-  t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
-
   elf_numsections (abfd) = section_number;
   elf_elfheader (abfd)->e_shnum = section_number;
 
   elf_numsections (abfd) = section_number;
   elf_elfheader (abfd)->e_shnum = section_number;
 
@@ -3162,8 +3674,10 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       i_shdrp[elf_onesymtab (abfd)] = &t->symtab_hdr;
       if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
        {
       i_shdrp[elf_onesymtab (abfd)] = &t->symtab_hdr;
       if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
        {
-         i_shdrp[elf_symtab_shndx (abfd)] = &t->symtab_shndx_hdr;
-         t->symtab_shndx_hdr.sh_link = elf_onesymtab (abfd);
+         elf_section_list * entry = elf_symtab_shndx_list (abfd);
+         BFD_ASSERT (entry != NULL);
+         i_shdrp[entry->ndx] = & entry->hdr;
+         entry->hdr.sh_link = elf_onesymtab (abfd);
        }
       i_shdrp[elf_strtab_sec (abfd)] = &t->strtab_hdr;
       t->symtab_hdr.sh_link = elf_strtab_sec (abfd);
        }
       i_shdrp[elf_strtab_sec (abfd)] = &t->strtab_hdr;
       t->symtab_hdr.sh_link = elf_strtab_sec (abfd);
@@ -3172,7 +3686,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       asection *s;
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       asection *s;
-      const char *name;
 
       d = elf_section_data (sec);
 
 
       d = elf_section_data (sec);
 
@@ -3276,13 +3789,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
          if (s != NULL)
            d->this_hdr.sh_link = elf_section_data (s)->this_idx;
 
          if (s != NULL)
            d->this_hdr.sh_link = elf_section_data (s)->this_idx;
 
-         /* We look up the section the relocs apply to by name.  */
-         name = sec->name;
-         if (d->this_hdr.sh_type == SHT_REL)
-           name += 4;
-         else
-           name += 5;
-         s = bfd_get_section_by_name (abfd, name);
+         s = get_elf_backend_data (abfd)->get_reloc_section (sec);
          if (s != NULL)
            {
              d->this_hdr.sh_info = elf_section_data (s)->this_idx;
          if (s != NULL)
            {
              d->this_hdr.sh_info = elf_section_data (s)->this_idx;
@@ -3358,12 +3865,10 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
        }
     }
 
        }
     }
 
-  for (secn = 1; secn < section_number; ++secn)
-    if (i_shdrp[secn] == NULL)
-      i_shdrp[secn] = i_shdrp[0];
-    else
-      i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
-                                                      i_shdrp[secn]->sh_name);
+  /* Delay setting sh_name to _bfd_elf_write_object_contents so that
+     _bfd_elf_assign_file_positions_for_non_load can convert DWARF
+     debug section name from .debug_* to .zdebug_* if needed.  */
+
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -3380,6 +3885,44 @@ sym_is_global (bfd *abfd, asymbol *sym)
          || bfd_is_com_section (bfd_get_section (sym)));
 }
 
          || bfd_is_com_section (bfd_get_section (sym)));
 }
 
+/* Filter global symbols of ABFD to include in the import library.  All
+   SYMCOUNT symbols of ABFD can be examined from their pointers in
+   SYMS.  Pointers of symbols to keep should be stored contiguously at
+   the beginning of that array.
+
+   Returns the number of symbols to keep.  */
+
+unsigned int
+_bfd_elf_filter_global_symbols (bfd *abfd, struct bfd_link_info *info,
+                               asymbol **syms, long symcount)
+{
+  long src_count, dst_count = 0;
+
+  for (src_count = 0; src_count < symcount; src_count++)
+    {
+      asymbol *sym = syms[src_count];
+      char *name = (char *) bfd_asymbol_name (sym);
+      struct bfd_link_hash_entry *h;
+
+      if (!sym_is_global (abfd, sym))
+       continue;
+
+      h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
+      if (h == NULL)
+       continue;
+      if (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)
+       continue;
+      if (h->linker_def || h->ldscript_def)
+       continue;
+
+      syms[dst_count++] = sym;
+    }
+
+  syms[dst_count] = NULL;
+
+  return dst_count;
+}
+
 /* Don't output section symbols for sections that are not going to be
    output, that are duplicates or there is no BFD section.  */
 
 /* Don't output section symbols for sections that are not going to be
    output, that are duplicates or there is no BFD section.  */
 
@@ -3414,7 +3957,7 @@ elf_map_symbols (bfd *abfd, unsigned int *pnum_locals)
   unsigned int num_globals = 0;
   unsigned int num_locals2 = 0;
   unsigned int num_globals2 = 0;
   unsigned int num_globals = 0;
   unsigned int num_locals2 = 0;
   unsigned int num_globals2 = 0;
-  int max_index = 0;
+  unsigned int max_index = 0;
   unsigned int idx;
   asection *asect;
   asymbol **new_syms;
   unsigned int idx;
   asection *asect;
   asymbol **new_syms;
@@ -3563,7 +4106,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct fake_section_arg fsargs;
   bfd_boolean failed;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct fake_section_arg fsargs;
   bfd_boolean failed;
-  struct bfd_strtab_hash *strtab = NULL;
+  struct elf_strtab_hash *strtab = NULL;
   Elf_Internal_Shdr *shstrtab_hdr;
   bfd_boolean need_symtab;
 
   Elf_Internal_Shdr *shstrtab_hdr;
   bfd_boolean need_symtab;
 
@@ -3614,13 +4157,13 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
   /* sh_name was set in prep_headers.  */
   shstrtab_hdr->sh_type = SHT_STRTAB;
   shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
   /* sh_name was set in prep_headers.  */
   shstrtab_hdr->sh_type = SHT_STRTAB;
-  shstrtab_hdr->sh_flags = 0;
+  shstrtab_hdr->sh_flags = bed->elf_strtab_flags;
   shstrtab_hdr->sh_addr = 0;
   shstrtab_hdr->sh_addr = 0;
-  shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
+  /* sh_size is set in _bfd_elf_assign_file_positions_for_non_load.  */
   shstrtab_hdr->sh_entsize = 0;
   shstrtab_hdr->sh_link = 0;
   shstrtab_hdr->sh_info = 0;
   shstrtab_hdr->sh_entsize = 0;
   shstrtab_hdr->sh_link = 0;
   shstrtab_hdr->sh_info = 0;
-  /* sh_offset is set in assign_file_positions_except_relocs.  */
+  /* sh_offset is set in _bfd_elf_assign_file_positions_for_non_load.  */
   shstrtab_hdr->sh_addralign = 1;
 
   if (!assign_file_positions_except_relocs (abfd, link_info))
   shstrtab_hdr->sh_addralign = 1;
 
   if (!assign_file_positions_except_relocs (abfd, link_info))
@@ -3633,12 +4176,16 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
 
       off = elf_next_file_pos (abfd);
 
 
       off = elf_next_file_pos (abfd);
 
-      hdr = &elf_tdata (abfd)->symtab_hdr;
+      hdr = & elf_symtab_hdr (abfd);
       off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
 
       off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
 
-      hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-      if (hdr->sh_size != 0)
-       off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
+      if (elf_symtab_shndx_list (abfd) != NULL)
+       {
+         hdr = & elf_symtab_shndx_list (abfd)->hdr;
+         if (hdr->sh_size != 0)
+           off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
+         /* FIXME: What about other symtab_shndx sections in the list ?  */
+       }
 
       hdr = &elf_tdata (abfd)->strtab_hdr;
       off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
 
       hdr = &elf_tdata (abfd)->strtab_hdr;
       off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
@@ -3648,9 +4195,9 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
       /* Now that we know where the .strtab section goes, write it
         out.  */
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
       /* Now that we know where the .strtab section goes, write it
         out.  */
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
-         || ! _bfd_stringtab_emit (abfd, strtab))
+         || ! _bfd_elf_strtab_emit (abfd, strtab))
        return FALSE;
        return FALSE;
-      _bfd_stringtab_free (strtab);
+      _bfd_elf_strtab_free (strtab);
     }
 
   abfd->output_has_begun = TRUE;
     }
 
   abfd->output_has_begun = TRUE;
@@ -3989,6 +4536,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       last_size = 0;
       phdr_index = 0;
       maxpagesize = bed->maxpagesize;
       last_size = 0;
       phdr_index = 0;
       maxpagesize = bed->maxpagesize;
+      /* PR 17512: file: c8455299.
+        Avoid divide-by-zero errors later on.
+        FIXME: Should we abort if the maxpagesize is zero ?  */
+      if (maxpagesize == 0)
+       maxpagesize = 1;
       writable = FALSE;
       dynsec = bfd_get_section_by_name (abfd, ".dynamic");
       if (dynsec != NULL
       writable = FALSE;
       dynsec = bfd_get_section_by_name (abfd, ".dynamic");
       if (dynsec != NULL
@@ -4059,11 +4611,18 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
              new_segment = TRUE;
            }
          else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
              new_segment = TRUE;
            }
          else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
-                  && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+                  && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0
+                  && ((abfd->flags & D_PAGED) == 0
+                      || (((last_hdr->lma + last_size - 1) & -maxpagesize)
+                          != (hdr->lma & -maxpagesize))))
            {
            {
-             /* We don't want to put a loadable section after a
-                nonloadable section in the same segment.
-                Consider .tbss sections as loadable for this purpose.  */
+             /* We don't want to put a loaded section after a
+                nonloaded (ie. bss style) section in the same segment
+                as that will force the non-loaded section to be loaded.
+                Consider .tbss sections as loaded for this purpose.
+                However, like the writable/non-writable case below,
+                if they are on the same page then they must be put
+                in the same segment.  */
              new_segment = TRUE;
            }
          else if ((abfd->flags & D_PAGED) == 0)
              new_segment = TRUE;
            }
          else if ((abfd->flags & D_PAGED) == 0)
@@ -4334,9 +4893,6 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
                goto error_return;
              m->next = NULL;
              m->p_type = PT_GNU_RELRO;
                goto error_return;
              m->next = NULL;
              m->p_type = PT_GNU_RELRO;
-             m->p_flags = PF_R;
-             m->p_flags_valid = 1;
-
              *pm = m;
              pm = &m->next;
            }
              *pm = m;
              pm = &m->next;
            }
@@ -4731,7 +5287,9 @@ assign_file_positions_for_load_sections (bfd *abfd,
          p->p_memsz = bed->s->sizeof_ehdr;
          if (m->count > 0)
            {
          p->p_memsz = bed->s->sizeof_ehdr;
          if (m->count > 0)
            {
-             if (p->p_vaddr < (bfd_vma) off)
+             if (p->p_vaddr < (bfd_vma) off
+                 || (!m->p_paddr_valid
+                     && p->p_paddr < (bfd_vma) off))
                {
                  (*_bfd_error_handler)
                    (_("%B: Not enough room for program headers, try linking with -N"),
                {
                  (*_bfd_error_handler)
                    (_("%B: Not enough room for program headers, try linking with -N"),
@@ -4976,7 +5534,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   Elf_Internal_Shdr **i_shdrpp;
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   Elf_Internal_Shdr **i_shdrpp;
-  Elf_Internal_Shdr **hdrpp;
+  Elf_Internal_Shdr **hdrpp, **end_hdrpp;
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   struct elf_segment_map *m;
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   struct elf_segment_map *m;
@@ -4984,14 +5542,12 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   file_ptr off;
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   file_ptr off;
-  unsigned int num_sec;
-  unsigned int i;
   unsigned int count;
 
   i_shdrpp = elf_elfsections (abfd);
   unsigned int count;
 
   i_shdrpp = elf_elfsections (abfd);
-  num_sec = elf_numsections (abfd);
+  end_hdrpp = i_shdrpp + elf_numsections (abfd);
   off = elf_next_file_pos (abfd);
   off = elf_next_file_pos (abfd);
-  for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++)
+  for (hdrpp = i_shdrpp + 1; hdrpp < end_hdrpp; hdrpp++)
     {
       Elf_Internal_Shdr *hdr;
 
     {
       Elf_Internal_Shdr *hdr;
 
@@ -5022,9 +5578,14 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        }
       else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
                && hdr->bfd_section == NULL)
        }
       else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
                && hdr->bfd_section == NULL)
+              || (hdr->bfd_section != NULL
+                  && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
+                  /* Compress DWARF debug sections.  */
               || hdr == i_shdrpp[elf_onesymtab (abfd)]
               || hdr == i_shdrpp[elf_onesymtab (abfd)]
-              || hdr == i_shdrpp[elf_symtab_shndx (abfd)]
-              || hdr == i_shdrpp[elf_strtab_sec (abfd)])
+              || (elf_symtab_shndx_list (abfd) != NULL
+                  && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
+              || hdr == i_shdrpp[elf_strtab_sec (abfd)]
+              || hdr == i_shdrpp[elf_shstrtab_sec (abfd)])
        hdr->sh_offset = -1;
       else
        off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
        hdr->sh_offset = -1;
       else
        off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
@@ -5165,7 +5726,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
              if (!m->p_align_valid)
                p->p_align = 1;
              if (!m->p_flags_valid)
              if (!m->p_align_valid)
                p->p_align = 1;
              if (!m->p_flags_valid)
-               p->p_flags = (lp->p_flags & ~PF_W);
+               p->p_flags = PF_R;
            }
          else
            {
            }
          else
            {
@@ -5180,11 +5741,19 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        }
       else if (m->count != 0)
        {
        }
       else if (m->count != 0)
        {
+         unsigned int i;
          if (p->p_type != PT_LOAD
              && (p->p_type != PT_NOTE
                  || bfd_get_format (abfd) != bfd_core))
            {
          if (p->p_type != PT_LOAD
              && (p->p_type != PT_NOTE
                  || bfd_get_format (abfd) != bfd_core))
            {
-             BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+             if (m->includes_filehdr || m->includes_phdrs)
+               {
+                 /* PR 17512: file: 2195325e.  */
+                 (*_bfd_error_handler)
+                   (_("%B: warning: non-load segment includes file header and/or program header"),
+                    abfd);
+                 return FALSE;
+               }
 
              p->p_filesz = 0;
              p->p_offset = m->sections[0]->filepos;
 
              p->p_filesz = 0;
              p->p_offset = m->sections[0]->filepos;
@@ -5220,6 +5789,15 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   return TRUE;
 }
 
   return TRUE;
 }
 
+static elf_section_list *
+find_section_in_list (unsigned int i, elf_section_list * list)
+{
+  for (;list != NULL; list = list->next)
+    if (list->ndx == i)
+      break;
+  return list;
+}
+
 /* Work out the file positions of all the sections.  This is called by
    _bfd_elf_compute_section_file_positions.  All the section sizes and
    VMAs must be known before this is called.
 /* Work out the file positions of all the sections.  This is called by
    _bfd_elf_compute_section_file_positions.  All the section sizes and
    VMAs must be known before this is called.
@@ -5264,9 +5842,14 @@ assign_file_positions_except_relocs (bfd *abfd,
          hdr = *hdrpp;
          if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
               && hdr->bfd_section == NULL)
          hdr = *hdrpp;
          if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
               && hdr->bfd_section == NULL)
+             || (hdr->bfd_section != NULL
+                 && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
+                 /* Compress DWARF debug sections.  */
              || i == elf_onesymtab (abfd)
              || i == elf_onesymtab (abfd)
-             || i == elf_symtab_shndx (abfd)
-             || i == elf_strtab_sec (abfd))
+             || (elf_symtab_shndx_list (abfd) != NULL
+                 && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
+             || i == elf_strtab_sec (abfd)
+             || i == elf_shstrtab_sec (abfd))
            {
              hdr->sh_offset = -1;
            }
            {
              hdr->sh_offset = -1;
            }
@@ -5296,9 +5879,7 @@ assign_file_positions_except_relocs (bfd *abfd,
        }
 
       /* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=.  */
        }
 
       /* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=.  */
-      if (link_info != NULL
-         && link_info->executable
-         && link_info->shared)
+      if (link_info != NULL && bfd_link_pie (link_info))
        {
          unsigned int num_segments = elf_elfheader (abfd)->e_phnum;
          Elf_Internal_Phdr *segment = elf_tdata (abfd)->phdr;
        {
          unsigned int num_segments = elf_elfheader (abfd)->e_phnum;
          Elf_Internal_Phdr *segment = elf_tdata (abfd)->phdr;
@@ -5417,35 +5998,99 @@ prep_headers (bfd *abfd)
 /* Assign file positions for all the reloc sections which are not part
    of the loadable file image, and the file position of section headers.  */
 
 /* Assign file positions for all the reloc sections which are not part
    of the loadable file image, and the file position of section headers.  */
 
-static void
-_bfd_elf_assign_file_positions_for_relocs (bfd *abfd)
+static bfd_boolean
+_bfd_elf_assign_file_positions_for_non_load (bfd *abfd)
 {
   file_ptr off;
 {
   file_ptr off;
-  unsigned int i, num_sec;
-  Elf_Internal_Shdr **shdrpp;
+  Elf_Internal_Shdr **shdrpp, **end_shdrpp;
+  Elf_Internal_Shdr *shdrp;
   Elf_Internal_Ehdr *i_ehdrp;
   const struct elf_backend_data *bed;
 
   off = elf_next_file_pos (abfd);
 
   Elf_Internal_Ehdr *i_ehdrp;
   const struct elf_backend_data *bed;
 
   off = elf_next_file_pos (abfd);
 
-  num_sec = elf_numsections (abfd);
-  for (i = 1, shdrpp = elf_elfsections (abfd) + 1; i < num_sec; i++, shdrpp++)
+  shdrpp = elf_elfsections (abfd);
+  end_shdrpp = shdrpp + elf_numsections (abfd);
+  for (shdrpp++; shdrpp < end_shdrpp; shdrpp++)
     {
     {
-      Elf_Internal_Shdr *shdrp;
-
       shdrp = *shdrpp;
       shdrp = *shdrpp;
-      if ((shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA)
-         && shdrp->sh_offset == -1)
-       off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE);
+      if (shdrp->sh_offset == -1)
+       {
+         asection *sec = shdrp->bfd_section;
+         bfd_boolean is_rel = (shdrp->sh_type == SHT_REL
+                               || shdrp->sh_type == SHT_RELA);
+         if (is_rel
+             || (sec != NULL && (sec->flags & SEC_ELF_COMPRESS)))
+           {
+             if (!is_rel)
+               {
+                 const char *name = sec->name;
+                 struct bfd_elf_section_data *d;
+
+                 /* Compress DWARF debug sections.  */
+                 if (!bfd_compress_section (abfd, sec,
+                                            shdrp->contents))
+                   return FALSE;
+
+                 if (sec->compress_status == COMPRESS_SECTION_DONE
+                     && (abfd->flags & BFD_COMPRESS_GABI) == 0)
+                   {
+                     /* If section is compressed with zlib-gnu, convert
+                        section name from .debug_* to .zdebug_*.  */
+                     char *new_name
+                       = convert_debug_to_zdebug (abfd, name);
+                     if (new_name == NULL)
+                       return FALSE;
+                     name = new_name;
+                   }
+                 /* Add section name to section name section.  */
+                 if (shdrp->sh_name != (unsigned int) -1)
+                   abort ();
+                 shdrp->sh_name
+                   = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+                                                         name, FALSE);
+                 d = elf_section_data (sec);
+
+                 /* Add reloc section name to section name section.  */
+                 if (d->rel.hdr
+                     && !_bfd_elf_set_reloc_sh_name (abfd,
+                                                     d->rel.hdr,
+                                                     name, FALSE))
+                   return FALSE;
+                 if (d->rela.hdr
+                     && !_bfd_elf_set_reloc_sh_name (abfd,
+                                                     d->rela.hdr,
+                                                     name, TRUE))
+                   return FALSE;
+
+                 /* Update section size and contents.  */
+                 shdrp->sh_size = sec->size;
+                 shdrp->contents = sec->contents;
+                 shdrp->bfd_section->contents = NULL;
+               }
+             off = _bfd_elf_assign_file_position_for_section (shdrp,
+                                                              off,
+                                                              TRUE);
+           }
+       }
     }
 
     }
 
-/* Place the section headers.  */
+  /* Place section name section after DWARF debug sections have been
+     compressed.  */
+  _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
+  shdrp = &elf_tdata (abfd)->shstrtab_hdr;
+  shdrp->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
+  off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE);
+
+  /* Place the section headers.  */
   i_ehdrp = elf_elfheader (abfd);
   bed = get_elf_backend_data (abfd);
   off = align_file_position (off, 1 << bed->s->log_file_align);
   i_ehdrp->e_shoff = off;
   off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
   elf_next_file_pos (abfd) = off;
   i_ehdrp = elf_elfheader (abfd);
   bed = get_elf_backend_data (abfd);
   off = align_file_position (off, 1 << bed->s->log_file_align);
   i_ehdrp->e_shoff = off;
   off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
   elf_next_file_pos (abfd) = off;
+
+  return TRUE;
 }
 
 bfd_boolean
 }
 
 bfd_boolean
@@ -5468,12 +6113,16 @@ _bfd_elf_write_object_contents (bfd *abfd)
   if (failed)
     return FALSE;
 
   if (failed)
     return FALSE;
 
-  _bfd_elf_assign_file_positions_for_relocs (abfd);
+  if (!_bfd_elf_assign_file_positions_for_non_load (abfd))
+    return FALSE;
 
   /* After writing the headers, we need to write the sections too...  */
   num_sec = elf_numsections (abfd);
   for (count = 1; count < num_sec; count++)
     {
 
   /* After writing the headers, we need to write the sections too...  */
   num_sec = elf_numsections (abfd);
   for (count = 1; count < num_sec; count++)
     {
+      i_shdrp[count]->sh_name
+       = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
+                                 i_shdrp[count]->sh_name);
       if (bed->elf_backend_section_processing)
        (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]);
       if (i_shdrp[count]->contents)
       if (bed->elf_backend_section_processing)
        (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]);
       if (i_shdrp[count]->contents)
@@ -5925,8 +6574,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
             something.  They are allowed by the ELF spec however, so only
             a warning is produced.  */
          if (segment->p_type == PT_LOAD)
             something.  They are allowed by the ELF spec however, so only
             a warning is produced.  */
          if (segment->p_type == PT_LOAD)
-           (*_bfd_error_handler) (_("%B: warning: Empty loadable segment"
-                                    " detected, is this intentional ?\n"),
+           (*_bfd_error_handler) (_("\
+%B: warning: Empty loadable segment detected, is this intentional ?"),
                                   ibfd);
 
          map->count = 0;
                                   ibfd);
 
          map->count = 0;
@@ -5980,13 +6629,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       first_matching_lma = TRUE;
       first_suggested_lma = TRUE;
 
       first_matching_lma = TRUE;
       first_suggested_lma = TRUE;
 
-      for (section = ibfd->sections;
+      for (section = first_section, j = 0;
           section != NULL;
           section = section->next)
           section != NULL;
           section = section->next)
-       if (section == first_section)
-         break;
-
-      for (j = 0; section != NULL; section = section->next)
        {
          if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
            {
        {
          if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
            {
@@ -6539,7 +7184,15 @@ rewrite:
           i++, segment++)
        if (segment->p_type == PT_LOAD
            && maxpagesize < segment->p_align)
           i++, segment++)
        if (segment->p_type == PT_LOAD
            && maxpagesize < segment->p_align)
-         maxpagesize = segment->p_align;
+         {
+           /* PR 17512: file: f17299af.  */
+           if (segment->p_align > (bfd_vma) 1 << ((sizeof (bfd_vma) * 8) - 2))
+             (*_bfd_error_handler) (_("\
+%B: warning: segment alignment of 0x%llx is too large"),
+                                    ibfd, (long long) segment->p_align);
+           else
+             maxpagesize = segment->p_align;
+         }
 
       if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize)
        bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize);
 
       if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize)
        bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize);
@@ -6559,7 +7212,8 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
 
 {
   Elf_Internal_Shdr *ihdr, *ohdr;
 
 {
   Elf_Internal_Shdr *ihdr, *ohdr;
-  bfd_boolean final_link = link_info != NULL && !link_info->relocatable;
+  bfd_boolean final_link = (link_info != NULL
+                           && !bfd_link_relocatable (link_info));
 
   if (ibfd->xvec->flavour != bfd_target_elf_flavour
       || obfd->xvec->flavour != bfd_target_elf_flavour)
 
   if (ibfd->xvec->flavour != bfd_target_elf_flavour
       || obfd->xvec->flavour != bfd_target_elf_flavour)
@@ -6596,6 +7250,11 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
          elf_next_in_group (osec) = elf_next_in_group (isec);
          elf_section_data (osec)->group = elf_section_data (isec)->group;
        }
          elf_next_in_group (osec) = elf_next_in_group (isec);
          elf_section_data (osec)->group = elf_section_data (isec)->group;
        }
+
+      /* If not decompress, preserve SHF_COMPRESSED.  */
+      if ((ibfd->flags & BFD_DECOMPRESS) == 0)
+       elf_section_flags (osec) |= (elf_section_flags (isec)
+                                    & SHF_COMPRESSED);
     }
 
   ihdr = &elf_section_data (isec)->this_hdr;
     }
 
   ihdr = &elf_section_data (isec)->this_hdr;
@@ -6774,7 +7433,7 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd,
        shndx = MAP_STRTAB;
       else if (shndx == elf_shstrtab_sec (ibfd))
        shndx = MAP_SHSTRTAB;
        shndx = MAP_STRTAB;
       else if (shndx == elf_shstrtab_sec (ibfd))
        shndx = MAP_SHSTRTAB;
-      else if (shndx == elf_symtab_shndx (ibfd))
+      else if (find_section_in_list (shndx, elf_symtab_shndx_list (ibfd)))
        shndx = MAP_SYM_SHNDX;
       osym->internal_elf_sym.st_shndx = shndx;
     }
        shndx = MAP_SYM_SHNDX;
       osym->internal_elf_sym.st_shndx = shndx;
     }
@@ -6786,18 +7445,21 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd,
 
 static bfd_boolean
 swap_out_syms (bfd *abfd,
 
 static bfd_boolean
 swap_out_syms (bfd *abfd,
-              struct bfd_strtab_hash **sttp,
+              struct elf_strtab_hash **sttp,
               int relocatable_p)
 {
   const struct elf_backend_data *bed;
   int symcount;
   asymbol **syms;
               int relocatable_p)
 {
   const struct elf_backend_data *bed;
   int symcount;
   asymbol **syms;
-  struct bfd_strtab_hash *stt;
+  struct elf_strtab_hash *stt;
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
+  struct elf_sym_strtab *symstrtab;
   bfd_byte *outbound_syms;
   bfd_byte *outbound_shndx;
   bfd_byte *outbound_syms;
   bfd_byte *outbound_shndx;
+  unsigned long outbound_syms_index;
+  unsigned long outbound_shndx_index;
   int idx;
   unsigned int num_locals;
   bfd_size_type amt;
   int idx;
   unsigned int num_locals;
   bfd_size_type amt;
@@ -6807,7 +7469,7 @@ swap_out_syms (bfd *abfd,
     return FALSE;
 
   /* Dump out the symtabs.  */
     return FALSE;
 
   /* Dump out the symtabs.  */
-  stt = _bfd_elf_stringtab_init ();
+  stt = _bfd_elf_strtab_init ();
   if (stt == NULL)
     return FALSE;
 
   if (stt == NULL)
     return FALSE;
 
@@ -6823,33 +7485,48 @@ swap_out_syms (bfd *abfd,
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
 
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
 
+  /* Allocate buffer to swap out the .strtab section.  */
+  symstrtab = (struct elf_sym_strtab *) bfd_malloc ((symcount + 1)
+                                                   * sizeof (*symstrtab));
+  if (symstrtab == NULL)
+    {
+      _bfd_elf_strtab_free (stt);
+      return FALSE;
+    }
+
   outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount,
                                            bed->s->sizeof_sym);
   if (outbound_syms == NULL)
     {
   outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount,
                                            bed->s->sizeof_sym);
   if (outbound_syms == NULL)
     {
-      _bfd_stringtab_free (stt);
+error_return:
+      _bfd_elf_strtab_free (stt);
+      free (symstrtab);
       return FALSE;
     }
   symtab_hdr->contents = outbound_syms;
       return FALSE;
     }
   symtab_hdr->contents = outbound_syms;
+  outbound_syms_index = 0;
 
   outbound_shndx = NULL;
 
   outbound_shndx = NULL;
-  symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
-  if (symtab_shndx_hdr->sh_name != 0)
+  outbound_shndx_index = 0;
+
+  if (elf_symtab_shndx_list (abfd))
     {
     {
-      amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
-      outbound_shndx =  (bfd_byte *)
-          bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx));
-      if (outbound_shndx == NULL)
+      symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr;
+      if (symtab_shndx_hdr->sh_name != 0)
        {
        {
-         _bfd_stringtab_free (stt);
-         return FALSE;
-       }
+         amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
+         outbound_shndx =  (bfd_byte *)
+           bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx));
+         if (outbound_shndx == NULL)
+           goto error_return;
 
 
-      symtab_shndx_hdr->contents = outbound_shndx;
-      symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
-      symtab_shndx_hdr->sh_size = amt;
-      symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
-      symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+         symtab_shndx_hdr->contents = outbound_shndx;
+         symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+         symtab_shndx_hdr->sh_size = amt;
+         symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+         symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+       }
+      /* FIXME: What about any other headers in the list ?  */
     }
 
   /* Now generate the data (for "contents").  */
     }
 
   /* Now generate the data (for "contents").  */
@@ -6863,10 +7540,12 @@ swap_out_syms (bfd *abfd,
     sym.st_other = 0;
     sym.st_shndx = SHN_UNDEF;
     sym.st_target_internal = 0;
     sym.st_other = 0;
     sym.st_shndx = SHN_UNDEF;
     sym.st_target_internal = 0;
-    bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
-    outbound_syms += bed->s->sizeof_sym;
+    symstrtab[0].sym = sym;
+    symstrtab[0].dest_index = outbound_syms_index;
+    symstrtab[0].destshndx_index = outbound_shndx_index;
+    outbound_syms_index++;
     if (outbound_shndx != NULL)
     if (outbound_shndx != NULL)
-      outbound_shndx += sizeof (Elf_External_Sym_Shndx);
+      outbound_shndx_index++;
   }
 
   name_local_sections
   }
 
   name_local_sections
@@ -6874,7 +7553,7 @@ swap_out_syms (bfd *abfd,
        && bed->elf_backend_name_local_section_symbols (abfd));
 
   syms = bfd_get_outsymbols (abfd);
        && bed->elf_backend_name_local_section_symbols (abfd));
 
   syms = bfd_get_outsymbols (abfd);
-  for (idx = 0; idx < symcount; idx++)
+  for (idx = 0; idx < symcount;)
     {
       Elf_Internal_Sym sym;
       bfd_vma value = syms[idx]->value;
     {
       Elf_Internal_Sym sym;
       bfd_vma value = syms[idx]->value;
@@ -6886,18 +7565,17 @@ swap_out_syms (bfd *abfd,
          && (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
        {
          /* Local section symbols have no name.  */
          && (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
        {
          /* Local section symbols have no name.  */
-         sym.st_name = 0;
+         sym.st_name = (unsigned long) -1;
        }
       else
        {
        }
       else
        {
-         sym.st_name = (unsigned long) _bfd_stringtab_add (stt,
-                                                           syms[idx]->name,
-                                                           TRUE, FALSE);
+         /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
+            to get the final offset for st_name.  */
+         sym.st_name
+           = (unsigned long) _bfd_elf_strtab_add (stt, syms[idx]->name,
+                                                  FALSE);
          if (sym.st_name == (unsigned long) -1)
          if (sym.st_name == (unsigned long) -1)
-           {
-             _bfd_stringtab_free (stt);
-             return FALSE;
-           }
+           goto error_return;
        }
 
       type_ptr = elf_symbol_from (abfd, syms[idx]);
        }
 
       type_ptr = elf_symbol_from (abfd, syms[idx]);
@@ -6957,7 +7635,8 @@ swap_out_syms (bfd *abfd,
                  shndx = elf_shstrtab_sec (abfd);
                  break;
                case MAP_SYM_SHNDX:
                  shndx = elf_shstrtab_sec (abfd);
                  break;
                case MAP_SYM_SHNDX:
-                 shndx = elf_symtab_shndx (abfd);
+                 if (elf_symtab_shndx_list (abfd))
+                   shndx = elf_symtab_shndx_list (abfd)->ndx;
                  break;
                default:
                  shndx = SHN_ABS;
                  break;
                default:
                  shndx = SHN_ABS;
@@ -6980,19 +7659,17 @@ swap_out_syms (bfd *abfd,
                     section of a symbol to be a section that is
                     actually in the output file.  */
                  sec2 = bfd_get_section_by_name (abfd, sec->name);
                     section of a symbol to be a section that is
                     actually in the output file.  */
                  sec2 = bfd_get_section_by_name (abfd, sec->name);
-                 if (sec2 == NULL)
+                 if (sec2 != NULL)
+                   shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
+                 if (shndx == SHN_BAD)
                    {
                      _bfd_error_handler (_("\
 Unable to find equivalent output section for symbol '%s' from section '%s'"),
                                          syms[idx]->name ? syms[idx]->name : "<Local sym>",
                                          sec->name);
                      bfd_set_error (bfd_error_invalid_operation);
                    {
                      _bfd_error_handler (_("\
 Unable to find equivalent output section for symbol '%s' from section '%s'"),
                                          syms[idx]->name ? syms[idx]->name : "<Local sym>",
                                          sec->name);
                      bfd_set_error (bfd_error_invalid_operation);
-                     _bfd_stringtab_free (stt);
-                     return FALSE;
+                     goto error_return;
                    }
                    }
-
-                 shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
-                 BFD_ASSERT (shndx != SHN_BAD);
                }
            }
 
                }
            }
 
@@ -7032,12 +7709,16 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
        }
       else if (bfd_is_com_section (syms[idx]->section))
        {
        }
       else if (bfd_is_com_section (syms[idx]->section))
        {
-#ifdef USE_STT_COMMON
-         if (type == STT_OBJECT)
-           sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON);
-         else
-#endif
-           sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+         if (type != STT_TLS)
+           {
+             if ((abfd->flags & BFD_CONVERT_ELF_COMMON))
+               type = ((abfd->flags & BFD_USE_ELF_STT_COMMON)
+                       ? STT_COMMON : STT_OBJECT);
+             else
+               type = ((flags & BSF_ELF_COMMON) != 0
+                       ? STT_COMMON : STT_OBJECT);
+           }
+         sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
        }
       else if (bfd_is_und_section (syms[idx]->section))
        sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
        }
       else if (bfd_is_und_section (syms[idx]->section))
        sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
@@ -7074,17 +7755,42 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
          sym.st_target_internal = 0;
        }
 
          sym.st_target_internal = 0;
        }
 
-      bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
-      outbound_syms += bed->s->sizeof_sym;
+      idx++;
+      symstrtab[idx].sym = sym;
+      symstrtab[idx].dest_index = outbound_syms_index;
+      symstrtab[idx].destshndx_index = outbound_shndx_index;
+
+      outbound_syms_index++;
       if (outbound_shndx != NULL)
       if (outbound_shndx != NULL)
-       outbound_shndx += sizeof (Elf_External_Sym_Shndx);
+       outbound_shndx_index++;
     }
 
     }
 
+  /* Finalize the .strtab section.  */
+  _bfd_elf_strtab_finalize (stt);
+
+  /* Swap out the .strtab section.  */
+  for (idx = 0; idx <= symcount; idx++)
+    {
+      struct elf_sym_strtab *elfsym = &symstrtab[idx];
+      if (elfsym->sym.st_name == (unsigned long) -1)
+       elfsym->sym.st_name = 0;
+      else
+       elfsym->sym.st_name = _bfd_elf_strtab_offset (stt,
+                                                     elfsym->sym.st_name);
+      bed->s->swap_symbol_out (abfd, &elfsym->sym,
+                              (outbound_syms
+                               + (elfsym->dest_index
+                                  * bed->s->sizeof_sym)),
+                              (outbound_shndx
+                               + (elfsym->destshndx_index
+                                  * sizeof (Elf_External_Sym_Shndx))));
+    }
+  free (symstrtab);
+
   *sttp = stt;
   *sttp = stt;
-  symstrtab_hdr->sh_size = _bfd_stringtab_size (stt);
+  symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt);
   symstrtab_hdr->sh_type = SHT_STRTAB;
   symstrtab_hdr->sh_type = SHT_STRTAB;
-
-  symstrtab_hdr->sh_flags = 0;
+  symstrtab_hdr->sh_flags = bed->elf_strtab_flags;
   symstrtab_hdr->sh_addr = 0;
   symstrtab_hdr->sh_entsize = 0;
   symstrtab_hdr->sh_link = 0;
   symstrtab_hdr->sh_addr = 0;
   symstrtab_hdr->sh_entsize = 0;
   symstrtab_hdr->sh_link = 0;
@@ -7285,30 +7991,30 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver)
 
       hdr = &elf_tdata (abfd)->dynverref_hdr;
 
 
       hdr = &elf_tdata (abfd)->dynverref_hdr;
 
-      if (hdr->sh_info)
-       elf_tdata (abfd)->verref = (Elf_Internal_Verneed *)
-          bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed));
-      else
-       elf_tdata (abfd)->verref = NULL;
-       
-      if (elf_tdata (abfd)->verref == NULL)
-       goto error_return;
-
-      elf_tdata (abfd)->cverrefs = hdr->sh_info;
-
-      contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
-      if (contents == NULL)
+      if (hdr->sh_info == 0 || hdr->sh_size < sizeof (Elf_External_Verneed))
        {
        {
+error_return_bad_verref:
+         (*_bfd_error_handler)
+           (_("%B: .gnu.version_r invalid entry"), abfd);
+         bfd_set_error (bfd_error_bad_value);
 error_return_verref:
          elf_tdata (abfd)->verref = NULL;
          elf_tdata (abfd)->cverrefs = 0;
          goto error_return;
        }
 error_return_verref:
          elf_tdata (abfd)->verref = NULL;
          elf_tdata (abfd)->cverrefs = 0;
          goto error_return;
        }
+
+      contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+      if (contents == NULL)
+       goto error_return_verref;
+
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
        goto error_return_verref;
 
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
        goto error_return_verref;
 
-      if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed))
+      elf_tdata (abfd)->verref = (Elf_Internal_Verneed *)
+       bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed));
+
+      if (elf_tdata (abfd)->verref == NULL)
        goto error_return_verref;
 
       BFD_ASSERT (sizeof (Elf_External_Verneed)
        goto error_return_verref;
 
       BFD_ASSERT (sizeof (Elf_External_Verneed)
@@ -7330,7 +8036,7 @@ error_return_verref:
            bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                             iverneed->vn_file);
          if (iverneed->vn_filename == NULL)
            bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                             iverneed->vn_file);
          if (iverneed->vn_filename == NULL)
-           goto error_return_verref;
+           goto error_return_bad_verref;
 
          if (iverneed->vn_cnt == 0)
            iverneed->vn_auxptr = NULL;
 
          if (iverneed->vn_cnt == 0)
            iverneed->vn_auxptr = NULL;
@@ -7345,7 +8051,7 @@ error_return_verref:
 
          if (iverneed->vn_aux
              > (size_t) (contents_end - (bfd_byte *) everneed))
 
          if (iverneed->vn_aux
              > (size_t) (contents_end - (bfd_byte *) everneed))
-           goto error_return_verref;
+           goto error_return_bad_verref;
 
          evernaux = ((Elf_External_Vernaux *)
                      ((bfd_byte *) everneed + iverneed->vn_aux));
 
          evernaux = ((Elf_External_Vernaux *)
                      ((bfd_byte *) everneed + iverneed->vn_aux));
@@ -7358,36 +8064,42 @@ error_return_verref:
                bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                                 ivernaux->vna_name);
              if (ivernaux->vna_nodename == NULL)
                bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                                 ivernaux->vna_name);
              if (ivernaux->vna_nodename == NULL)
-               goto error_return_verref;
+               goto error_return_bad_verref;
+
+             if (ivernaux->vna_other > freeidx)
+               freeidx = ivernaux->vna_other;
 
 
+             ivernaux->vna_nextptr = NULL;
+             if (ivernaux->vna_next == 0)
+               {
+                 iverneed->vn_cnt = j + 1;
+                 break;
+               }
              if (j + 1 < iverneed->vn_cnt)
                ivernaux->vna_nextptr = ivernaux + 1;
              if (j + 1 < iverneed->vn_cnt)
                ivernaux->vna_nextptr = ivernaux + 1;
-             else
-               ivernaux->vna_nextptr = NULL;
 
              if (ivernaux->vna_next
                  > (size_t) (contents_end - (bfd_byte *) evernaux))
 
              if (ivernaux->vna_next
                  > (size_t) (contents_end - (bfd_byte *) evernaux))
-               goto error_return_verref;
+               goto error_return_bad_verref;
 
              evernaux = ((Elf_External_Vernaux *)
                          ((bfd_byte *) evernaux + ivernaux->vna_next));
 
              evernaux = ((Elf_External_Vernaux *)
                          ((bfd_byte *) evernaux + ivernaux->vna_next));
-
-             if (ivernaux->vna_other > freeidx)
-               freeidx = ivernaux->vna_other;
            }
 
            }
 
+         iverneed->vn_nextref = NULL;
+         if (iverneed->vn_next == 0)
+           break;
          if (i + 1 < hdr->sh_info)
            iverneed->vn_nextref = iverneed + 1;
          if (i + 1 < hdr->sh_info)
            iverneed->vn_nextref = iverneed + 1;
-         else
-           iverneed->vn_nextref = NULL;
 
          if (iverneed->vn_next
              > (size_t) (contents_end - (bfd_byte *) everneed))
 
          if (iverneed->vn_next
              > (size_t) (contents_end - (bfd_byte *) everneed))
-           goto error_return_verref;
+           goto error_return_bad_verref;
 
          everneed = ((Elf_External_Verneed *)
                      ((bfd_byte *) everneed + iverneed->vn_next));
        }
 
          everneed = ((Elf_External_Verneed *)
                      ((bfd_byte *) everneed + iverneed->vn_next));
        }
+      elf_tdata (abfd)->cverrefs = i;
 
       free (contents);
       contents = NULL;
 
       free (contents);
       contents = NULL;
@@ -7406,15 +8118,24 @@ error_return_verref:
 
       hdr = &elf_tdata (abfd)->dynverdef_hdr;
 
 
       hdr = &elf_tdata (abfd)->dynverdef_hdr;
 
+      if (hdr->sh_info == 0 || hdr->sh_size < sizeof (Elf_External_Verdef))
+       {
+       error_return_bad_verdef:
+         (*_bfd_error_handler)
+           (_("%B: .gnu.version_d invalid entry"), abfd);
+         bfd_set_error (bfd_error_bad_value);
+       error_return_verdef:
+         elf_tdata (abfd)->verdef = NULL;
+         elf_tdata (abfd)->cverdefs = 0;
+         goto error_return;
+       }
+
       contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
       if (contents == NULL)
       contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
       if (contents == NULL)
-       goto error_return;
+       goto error_return_verdef;
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
          || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
-       goto error_return;
-
-      if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef))
-       goto error_return;
+       goto error_return_verdef;
 
       BFD_ASSERT (sizeof (Elf_External_Verdef)
                  >= sizeof (Elf_External_Verdaux));
 
       BFD_ASSERT (sizeof (Elf_External_Verdef)
                  >= sizeof (Elf_External_Verdaux));
@@ -7432,12 +8153,17 @@ error_return_verref:
        {
          _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
 
        {
          _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
 
+         if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) == 0)
+           goto error_return_bad_verdef;
          if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx)
            maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION);
 
          if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx)
            maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION);
 
+         if (iverdefmem.vd_next == 0)
+           break;
+
          if (iverdefmem.vd_next
              > (size_t) (contents_end_def - (bfd_byte *) everdef))
          if (iverdefmem.vd_next
              > (size_t) (contents_end_def - (bfd_byte *) everdef))
-           goto error_return;
+           goto error_return_bad_verdef;
 
          everdef = ((Elf_External_Verdef *)
                     ((bfd_byte *) everdef + iverdefmem.vd_next));
 
          everdef = ((Elf_External_Verdef *)
                     ((bfd_byte *) everdef + iverdefmem.vd_next));
@@ -7450,14 +8176,11 @@ error_return_verref:
          else
            freeidx = ++maxidx;
        }
          else
            freeidx = ++maxidx;
        }
-      if (maxidx)
-       elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *)
-          bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef));
-      else
-       elf_tdata (abfd)->verdef = NULL;
 
 
+      elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *)
+       bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef));
       if (elf_tdata (abfd)->verdef == NULL)
       if (elf_tdata (abfd)->verdef == NULL)
-       goto error_return;
+       goto error_return_verdef;
 
       elf_tdata (abfd)->cverdefs = maxidx;
 
 
       elf_tdata (abfd)->cverdefs = maxidx;
 
@@ -7472,15 +8195,10 @@ error_return_verref:
          _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
 
          if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0)
          _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
 
          if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0)
-           {
-error_return_verdef:
-             elf_tdata (abfd)->verdef = NULL;
-             elf_tdata (abfd)->cverdefs = 0;
-             goto error_return;
-           }
+           goto error_return_bad_verdef;
 
          iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1];
 
          iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1];
-         memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef));
+         memcpy (iverdef, &iverdefmem, offsetof (Elf_Internal_Verdef, vd_bfd));
 
          iverdef->vd_bfd = abfd;
 
 
          iverdef->vd_bfd = abfd;
 
@@ -7497,7 +8215,7 @@ error_return_verdef:
 
          if (iverdef->vd_aux
              > (size_t) (contents_end_aux - (bfd_byte *) everdef))
 
          if (iverdef->vd_aux
              > (size_t) (contents_end_aux - (bfd_byte *) everdef))
-           goto error_return_verdef;
+           goto error_return_bad_verdef;
 
          everdaux = ((Elf_External_Verdaux *)
                      ((bfd_byte *) everdef + iverdef->vd_aux));
 
          everdaux = ((Elf_External_Verdaux *)
                      ((bfd_byte *) everdef + iverdef->vd_aux));
@@ -7510,28 +8228,34 @@ error_return_verdef:
                bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                                 iverdaux->vda_name);
              if (iverdaux->vda_nodename == NULL)
                bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                                 iverdaux->vda_name);
              if (iverdaux->vda_nodename == NULL)
-               goto error_return_verdef;
+               goto error_return_bad_verdef;
 
 
+             iverdaux->vda_nextptr = NULL;
+             if (iverdaux->vda_next == 0)
+               {
+                 iverdef->vd_cnt = j + 1;
+                 break;
+               }
              if (j + 1 < iverdef->vd_cnt)
                iverdaux->vda_nextptr = iverdaux + 1;
              if (j + 1 < iverdef->vd_cnt)
                iverdaux->vda_nextptr = iverdaux + 1;
-             else
-               iverdaux->vda_nextptr = NULL;
 
              if (iverdaux->vda_next
                  > (size_t) (contents_end_aux - (bfd_byte *) everdaux))
 
              if (iverdaux->vda_next
                  > (size_t) (contents_end_aux - (bfd_byte *) everdaux))
-               goto error_return_verdef;
+               goto error_return_bad_verdef;
 
              everdaux = ((Elf_External_Verdaux *)
                          ((bfd_byte *) everdaux + iverdaux->vda_next));
            }
 
 
              everdaux = ((Elf_External_Verdaux *)
                          ((bfd_byte *) everdaux + iverdaux->vda_next));
            }
 
+         iverdef->vd_nodename = NULL;
          if (iverdef->vd_cnt)
            iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
 
          if (iverdef->vd_cnt)
            iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
 
+         iverdef->vd_nextdef = NULL;
+         if (iverdef->vd_next == 0)
+           break;
          if ((size_t) (iverdef - iverdefarr) + 1 < maxidx)
            iverdef->vd_nextdef = iverdef + 1;
          if ((size_t) (iverdef - iverdefarr) + 1 < maxidx)
            iverdef->vd_nextdef = iverdef + 1;
-         else
-           iverdef->vd_nextdef = NULL;
 
          everdef = ((Elf_External_Verdef *)
                     ((bfd_byte *) everdef + iverdef->vd_next));
 
          everdef = ((Elf_External_Verdef *)
                     ((bfd_byte *) everdef + iverdef->vd_next));
@@ -7574,14 +8298,13 @@ error_return_verdef:
       if (iverdef->vd_nodename == NULL)
        goto error_return_verdef;
       iverdef->vd_nextdef = NULL;
       if (iverdef->vd_nodename == NULL)
        goto error_return_verdef;
       iverdef->vd_nextdef = NULL;
-      iverdef->vd_auxptr = (struct elf_internal_verdaux *)
-          bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux));
+      iverdef->vd_auxptr = ((struct elf_internal_verdaux *)
+                           bfd_zalloc (abfd, sizeof (Elf_Internal_Verdaux)));
       if (iverdef->vd_auxptr == NULL)
        goto error_return_verdef;
 
       iverdaux = iverdef->vd_auxptr;
       iverdaux->vda_nodename = iverdef->vd_nodename;
       if (iverdef->vd_auxptr == NULL)
        goto error_return_verdef;
 
       iverdaux = iverdef->vd_auxptr;
       iverdaux->vda_nodename = iverdef->vd_nodename;
-      iverdaux->vda_nextptr = NULL;
     }
 
   return TRUE;
     }
 
   return TRUE;
@@ -7638,6 +8361,47 @@ _bfd_elf_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED,
   if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
     return TRUE;
 
   if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
     return TRUE;
 
+  /* Treat assembler generated fake symbols, dollar local labels and
+     forward-backward labels (aka local labels) as locals.
+     These labels have the form:
+
+       L0^A.*                                  (fake symbols)
+
+       [.]?L[0123456789]+{^A|^B}[0123456789]*  (local labels)
+
+     Versions which start with .L will have already been matched above,
+     so we only need to match the rest.  */
+  if (name[0] == 'L' && ISDIGIT (name[1]))
+    {
+      bfd_boolean ret = FALSE;
+      const char * p;
+      char c;
+
+      for (p = name + 2; (c = *p); p++)
+       {
+         if (c == 1 || c == 2)
+           {
+             if (c == 1 && p == name + 2)
+               /* A fake symbol.  */
+               return TRUE;
+
+             /* FIXME: We are being paranoid here and treating symbols like
+                L0^Bfoo as if there were non-local, on the grounds that the
+                assembler will never generate them.  But can any symbol
+                containing an ASCII value in the range 1-31 ever be anything
+                other than some kind of local ?  */
+             ret = TRUE;
+           }
+
+         if (! ISDIGIT (c))
+           {
+             ret = FALSE;
+             break;
+           }
+       }
+      return ret;
+    }
+
   return FALSE;
 }
 
   return FALSE;
 }
 
@@ -7664,109 +8428,6 @@ _bfd_elf_set_arch_mach (bfd *abfd,
   return bfd_default_set_arch_mach (abfd, arch, machine);
 }
 
   return bfd_default_set_arch_mach (abfd, arch, machine);
 }
 
-/* Find the function to a particular section and offset,
-   for error reporting.  */
-
-static bfd_boolean
-elf_find_function (bfd *abfd,
-                  asymbol **symbols,
-                  asection *section,
-                  bfd_vma offset,
-                  const char **filename_ptr,
-                  const char **functionname_ptr)
-{
-  struct elf_find_function_cache
-  {
-    asection *last_section;
-    asymbol *func;
-    const char *filename;
-    bfd_size_type func_size;
-  } *cache;
-
-  if (symbols == NULL)
-    return FALSE;
-
-  cache = elf_tdata (abfd)->elf_find_function_cache;
-  if (cache == NULL)
-    {
-      cache = bfd_zalloc (abfd, sizeof (*cache));
-      elf_tdata (abfd)->elf_find_function_cache = cache;
-      if (cache == NULL)
-       return FALSE;
-    }
-  if (cache->last_section != section
-      || cache->func == NULL
-      || offset < cache->func->value
-      || offset >= cache->func->value + cache->func_size)
-    {
-      asymbol *file;
-      bfd_vma low_func;
-      asymbol **p;
-      /* ??? Given multiple file symbols, it is impossible to reliably
-        choose the right file name for global symbols.  File symbols are
-        local symbols, and thus all file symbols must sort before any
-        global symbols.  The ELF spec may be interpreted to say that a
-        file symbol must sort before other local symbols, but currently
-        ld -r doesn't do this.  So, for ld -r output, it is possible to
-        make a better choice of file name for local symbols by ignoring
-        file symbols appearing after a given local symbol.  */
-      enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
-      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-
-      file = NULL;
-      low_func = 0;
-      state = nothing_seen;
-      cache->filename = NULL;
-      cache->func = NULL;
-      cache->func_size = 0;
-      cache->last_section = section;
-
-      for (p = symbols; *p != NULL; p++)
-       {
-         asymbol *sym = *p;
-         bfd_vma code_off;
-         bfd_size_type size;
-
-         if ((sym->flags & BSF_FILE) != 0)
-           {
-             file = sym;
-             if (state == symbol_seen)
-               state = file_after_symbol_seen;
-             continue;
-           }
-
-         size = bed->maybe_function_sym (sym, section, &code_off);
-         if (size != 0
-             && code_off <= offset
-             && (code_off > low_func
-                 || (code_off == low_func
-                     && size > cache->func_size)))
-           {
-             cache->func = sym;
-             cache->func_size = size;
-             cache->filename = NULL;
-             low_func = code_off;
-             if (file != NULL
-                 && ((sym->flags & BSF_LOCAL) != 0
-                     || state != file_after_symbol_seen))
-               cache->filename = bfd_asymbol_name (file);
-           }
-         if (state == nothing_seen)
-           state = symbol_seen;
-       }
-    }
-
-  if (cache->func == NULL)
-    return FALSE;
-
-  if (filename_ptr)
-    *filename_ptr = cache->filename;
-  if (functionname_ptr)
-    *functionname_ptr = bfd_asymbol_name (cache->func);
-
-  return TRUE;
-}
-
 /* Find the nearest line to a particular section and offset,
    for error reporting.  */
 
 /* Find the nearest line to a particular section and offset,
    for error reporting.  */
 
@@ -7786,24 +8447,15 @@ _bfd_elf_find_nearest_line (bfd *abfd,
                                     filename_ptr, functionname_ptr,
                                     line_ptr, discriminator_ptr,
                                     dwarf_debug_sections, 0,
                                     filename_ptr, functionname_ptr,
                                     line_ptr, discriminator_ptr,
                                     dwarf_debug_sections, 0,
-                                    &elf_tdata (abfd)->dwarf2_find_line_info))
+                                    &elf_tdata (abfd)->dwarf2_find_line_info)
+      || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+                                       filename_ptr, functionname_ptr,
+                                       line_ptr))
     {
       if (!*functionname_ptr)
     {
       if (!*functionname_ptr)
-       elf_find_function (abfd, symbols, section, offset,
-                          *filename_ptr ? NULL : filename_ptr,
-                          functionname_ptr);
-
-      return TRUE;
-    }
-
-  if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
-                                    filename_ptr, functionname_ptr, line_ptr))
-    {
-      if (!*functionname_ptr)
-       elf_find_function (abfd, symbols, section, offset,
-                          *filename_ptr ? NULL : filename_ptr,
-                          functionname_ptr);
-
+       _bfd_elf_find_function (abfd, symbols, section, offset,
+                               *filename_ptr ? NULL : filename_ptr,
+                               functionname_ptr);
       return TRUE;
     }
 
       return TRUE;
     }
 
@@ -7818,8 +8470,8 @@ _bfd_elf_find_nearest_line (bfd *abfd,
   if (symbols == NULL)
     return FALSE;
 
   if (symbols == NULL)
     return FALSE;
 
-  if (! elf_find_function (abfd, symbols, section, offset,
-                          filename_ptr, functionname_ptr))
+  if (! _bfd_elf_find_function (abfd, symbols, section, offset,
+                               filename_ptr, functionname_ptr))
     return FALSE;
 
   *line_ptr = 0;
     return FALSE;
 
   *line_ptr = 0;
@@ -7863,7 +8515,7 @@ _bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info)
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   int ret = bed->s->sizeof_ehdr;
 
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   int ret = bed->s->sizeof_ehdr;
 
-  if (!info->relocatable)
+  if (!bfd_link_relocatable (info))
     {
       bfd_size_type phdr_size = elf_program_header_size (abfd);
 
     {
       bfd_size_type phdr_size = elf_program_header_size (abfd);
 
@@ -7900,7 +8552,21 @@ _bfd_elf_set_section_contents (bfd *abfd,
       && ! _bfd_elf_compute_section_file_positions (abfd, NULL))
     return FALSE;
 
       && ! _bfd_elf_compute_section_file_positions (abfd, NULL))
     return FALSE;
 
+  if (!count)
+    return TRUE;
+
   hdr = &elf_section_data (section)->this_hdr;
   hdr = &elf_section_data (section)->this_hdr;
+  if (hdr->sh_offset == (file_ptr) -1)
+    {
+      /* We must compress this section.  Write output to the buffer.  */
+      unsigned char *contents = hdr->contents;
+      if ((offset + count) > hdr->sh_size
+         || (section->flags & SEC_ELF_COMPRESS) == 0
+         || contents == NULL)
+       abort ();
+      memcpy (contents + offset, location, count);
+      return TRUE;
+    }
   pos = hdr->sh_offset + offset;
   if (bfd_seek (abfd, pos, SEEK_SET) != 0
       || bfd_bwrite (location, count, abfd) != count)
   pos = hdr->sh_offset + offset;
   if (bfd_seek (abfd, pos, SEEK_SET) != 0
       || bfd_bwrite (location, count, abfd) != count)
@@ -8319,6 +8985,18 @@ elfcore_grok_s390_tdb (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-s390-tdb", note);
 }
 
   return elfcore_make_note_pseudosection (abfd, ".reg-s390-tdb", note);
 }
 
+static bfd_boolean
+elfcore_grok_s390_vxrs_low (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-vxrs-low", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_vxrs_high (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-vxrs-high", note);
+}
+
 static bfd_boolean
 elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
 {
 static bfd_boolean
 elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -8783,6 +9461,20 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
         return TRUE;
 
       else
         return TRUE;
 
+    case NT_S390_VXRS_LOW:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_s390_vxrs_low (abfd, note);
+      else
+       return TRUE;
+
+    case NT_S390_VXRS_HIGH:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_s390_vxrs_high (abfd, note);
+      else
+       return TRUE;
+
     case NT_ARM_VFP:
       if (note->namesz == 6
          && strcmp (note->namedata, "LINUX") == 0)
     case NT_ARM_VFP:
       if (note->namesz == 6
          && strcmp (note->namedata, "LINUX") == 0)
@@ -8843,24 +9535,25 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
     case NT_SIGINFO:
       return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
                                              note);
     case NT_SIGINFO:
       return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
                                              note);
+
     }
 }
 
 static bfd_boolean
 elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
 {
     }
 }
 
 static bfd_boolean
 elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
 {
-  struct elf_obj_tdata *t;
+  struct bfd_build_id* build_id;
 
   if (note->descsz == 0)
     return FALSE;
 
 
   if (note->descsz == 0)
     return FALSE;
 
-  t = elf_tdata (abfd);
-  t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz);
-  if (t->build_id == NULL)
+  build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) - 1 + note->descsz);
+  if (build_id == NULL)
     return FALSE;
 
     return FALSE;
 
-  t->build_id->size = note->descsz;
-  memcpy (t->build_id->data, note->descdata, note->descsz);
+  build_id->size = note->descsz;
+  memcpy (build_id->data, note->descdata, note->descsz);
+  abfd->build_id = build_id;
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -8907,6 +9600,168 @@ elfobj_grok_stapsdt_note (bfd *abfd, Elf_Internal_Note *note)
     }
 }
 
     }
 }
 
+static bfd_boolean
+elfcore_grok_freebsd_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+  size_t offset;
+
+  switch (abfd->arch_info->bits_per_word)
+    {
+    case 32:
+      if (note->descsz < 108)
+       return FALSE;
+      break;
+
+    case 64:
+      if (note->descsz < 120)
+       return FALSE;
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  /* Check for version 1 in pr_version.  */
+  if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+    return FALSE;
+  offset = 4;
+
+  /* Skip over pr_psinfosz. */
+  if (abfd->arch_info->bits_per_word == 32)
+    offset += 4;
+  else
+    {
+      offset += 4;     /* Padding before pr_psinfosz. */
+      offset += 8;
+    }
+
+  /* pr_fname is PRFNAMESZ (16) + 1 bytes in size.  */
+  elf_tdata (abfd)->core->program
+    = _bfd_elfcore_strndup (abfd, note->descdata + offset, 17);
+  offset += 17;
+
+  /* pr_psargs is PRARGSZ (80) + 1 bytes in size.  */
+  elf_tdata (abfd)->core->command
+    = _bfd_elfcore_strndup (abfd, note->descdata + offset, 81);
+  offset += 81;
+
+  /* Padding before pr_pid.  */
+  offset += 2;
+
+  /* The pr_pid field was added in version "1a".  */
+  if (note->descsz < offset + 4)
+    return TRUE;
+
+  elf_tdata (abfd)->core->pid
+    = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+
+  return TRUE;
+}
+
+static bfd_boolean
+elfcore_grok_freebsd_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+  size_t offset;
+  size_t size;
+
+  /* Check for version 1 in pr_version. */
+  if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+    return FALSE;
+  offset = 4;
+
+  /* Skip over pr_statussz.  */
+  switch (abfd->arch_info->bits_per_word)
+    {
+    case 32:
+      offset += 4;
+      break;
+
+    case 64:
+      offset += 4;     /* Padding before pr_statussz. */
+      offset += 8;
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  /* Extract size of pr_reg from pr_gregsetsz.  */
+  if (abfd->arch_info->bits_per_word == 32)
+    size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+  else
+    size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset);
+
+  /* Skip over pr_gregsetsz and pr_fpregsetsz. */
+  offset += (abfd->arch_info->bits_per_word / 8) * 2;
+
+  /* Skip over pr_osreldate. */
+  offset += 4;
+
+  /* Read signal from pr_cursig. */
+  if (elf_tdata (abfd)->core->signal == 0)
+    elf_tdata (abfd)->core->signal
+      = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+  offset += 4;
+
+  /* Read TID from pr_pid. */
+  elf_tdata (abfd)->core->lwpid
+      = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+  offset += 4;
+
+  /* Padding before pr_reg. */
+  if (abfd->arch_info->bits_per_word == 64)
+    offset += 4;
+
+  /* Make a ".reg/999" section and a ".reg" section.  */
+  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+                                         size, note->descpos + offset);
+}
+
+static bfd_boolean
+elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note)
+{
+  switch (note->type)
+    {
+    case NT_PRSTATUS:
+      return elfcore_grok_freebsd_prstatus (abfd, note);
+
+    case NT_FPREGSET:
+      return elfcore_grok_prfpreg (abfd, note);
+
+    case NT_PRPSINFO:
+      return elfcore_grok_freebsd_psinfo (abfd, note);
+
+    case NT_FREEBSD_THRMISC:
+      if (note->namesz == 8)
+       return elfcore_make_note_pseudosection (abfd, ".thrmisc", note);
+      else
+       return TRUE;
+
+    case NT_FREEBSD_PROCSTAT_AUXV:
+      {
+       asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv",
+                                                            SEC_HAS_CONTENTS);
+
+       if (sect == NULL)
+         return FALSE;
+       sect->size = note->descsz - 4;
+       sect->filepos = note->descpos + 4;
+       sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+       return TRUE;
+      }
+
+    case NT_X86_XSTATE:
+      if (note->namesz == 8)
+       return elfcore_grok_xstatereg (abfd, note);
+      else
+       return TRUE;
+
+    default:
+      return TRUE;
+    }
+}
+
 static bfd_boolean
 elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
 {
 static bfd_boolean
 elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
 {
@@ -9340,9 +10195,7 @@ elfcore_write_linux_prpsinfo32
 {
   struct elf_external_linux_prpsinfo32 data;
 
 {
   struct elf_external_linux_prpsinfo32 data;
 
-  memset (&data, 0, sizeof (data));
-  LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
-
+  swap_linux_prpsinfo32_out (abfd, prpsinfo, &data);
   return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
                             &data, sizeof (data));
 }
   return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
                             &data, sizeof (data));
 }
@@ -9354,9 +10207,7 @@ elfcore_write_linux_prpsinfo64
 {
   struct elf_external_linux_prpsinfo64 data;
 
 {
   struct elf_external_linux_prpsinfo64 data;
 
-  memset (&data, 0, sizeof (data));
-  LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data);
-
+  swap_linux_prpsinfo64_out (abfd, prpsinfo, &data);
   return elfcore_write_note (abfd, buf, bufsiz,
                             "CORE", NT_PRPSINFO, &data, sizeof (data));
 }
   return elfcore_write_note (abfd, buf, bufsiz,
                             "CORE", NT_PRPSINFO, &data, sizeof (data));
 }
@@ -9508,7 +10359,11 @@ char *
 elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz,
                         const void *xfpregs, int size)
 {
 elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz,
                         const void *xfpregs, int size)
 {
-  char *note_name = "LINUX";
+  char *note_name;
+  if (get_elf_backend_data (abfd)->elf_osabi == ELFOSABI_FREEBSD)
+    note_name = "FreeBSD";
+  else
+    note_name = "LINUX";
   return elfcore_write_note (abfd, buf, bufsiz,
                             note_name, NT_X86_XSTATE, xfpregs, size);
 }
   return elfcore_write_note (abfd, buf, bufsiz,
                             note_name, NT_X86_XSTATE, xfpregs, size);
 }
@@ -9648,6 +10503,31 @@ elfcore_write_s390_tdb (bfd *abfd,
                              note_name, NT_S390_TDB, s390_tdb, size);
 }
 
                              note_name, NT_S390_TDB, s390_tdb, size);
 }
 
+char *
+elfcore_write_s390_vxrs_low (bfd *abfd,
+                            char *buf,
+                            int *bufsiz,
+                            const void *s390_vxrs_low,
+                            int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_S390_VXRS_LOW, s390_vxrs_low, size);
+}
+
+char *
+elfcore_write_s390_vxrs_high (bfd *abfd,
+                            char *buf,
+                            int *bufsiz,
+                            const void *s390_vxrs_high,
+                            int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_S390_VXRS_HIGH,
+                            s390_vxrs_high, size);
+}
+
 char *
 elfcore_write_arm_vfp (bfd *abfd,
                       char *buf,
 char *
 elfcore_write_arm_vfp (bfd *abfd,
                       char *buf,
@@ -9732,6 +10612,10 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-s390-tdb") == 0)
     return elfcore_write_s390_tdb (abfd, buf, bufsiz, data, size);
     return elfcore_write_s390_system_call (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-s390-tdb") == 0)
     return elfcore_write_s390_tdb (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-vxrs-low") == 0)
+    return elfcore_write_s390_vxrs_low (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-vxrs-high") == 0)
+    return elfcore_write_s390_vxrs_high (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-arm-vfp") == 0)
     return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-aarch-tls") == 0)
   if (strcmp (section, ".reg-arm-vfp") == 0)
     return elfcore_write_arm_vfp (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-aarch-tls") == 0)
@@ -9779,32 +10663,39 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
          return TRUE;
 
        case bfd_core:
          return TRUE;
 
        case bfd_core:
-         if (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
-           {
-             if (! elfcore_grok_netbsd_note (abfd, &in))
-               return FALSE;
-           }
-         else if (CONST_STRNEQ (in.namedata, "OpenBSD"))
-           {
-             if (! elfcore_grok_openbsd_note (abfd, &in))
-               return FALSE;
-           }
-         else if (CONST_STRNEQ (in.namedata, "QNX"))
-           {
-             if (! elfcore_grok_nto_note (abfd, &in))
-               return FALSE;
-           }
-         else if (CONST_STRNEQ (in.namedata, "SPU/"))
+         {
+#define GROKER_ELEMENT(S,F) {S, sizeof (S) - 1, F}
+           struct
            {
            {
-             if (! elfcore_grok_spu_note (abfd, &in))
-               return FALSE;
+             const char * string;
+             size_t len;
+             bfd_boolean (* func)(bfd *, Elf_Internal_Note *);
            }
            }
-         else
+           grokers[] =
            {
            {
-             if (! elfcore_grok_note (abfd, &in))
-               return FALSE;
-           }
-         break;
+             GROKER_ELEMENT ("", elfcore_grok_note),
+             GROKER_ELEMENT ("FreeBSD", elfcore_grok_freebsd_note),
+             GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note),
+             GROKER_ELEMENT ( "OpenBSD", elfcore_grok_openbsd_note),
+             GROKER_ELEMENT ("QNX", elfcore_grok_nto_note),
+             GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note)
+           };
+#undef GROKER_ELEMENT
+           int i;
+
+           for (i = ARRAY_SIZE (grokers); i--;)
+             {
+               if (in.namesz >= grokers[i].len
+                   && strncmp (in.namedata, grokers[i].string,
+                               grokers[i].len) == 0)
+                 {
+                   if (! grokers[i].func (abfd, & in))
+                     return FALSE;
+                   break;
+                 }
+             }
+           break;
+         }
 
        case bfd_object:
          if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
 
        case bfd_object:
          if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
@@ -9838,10 +10729,14 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
   if (bfd_seek (abfd, offset, SEEK_SET) != 0)
     return FALSE;
 
   if (bfd_seek (abfd, offset, SEEK_SET) != 0)
     return FALSE;
 
-  buf = (char *) bfd_malloc (size);
+  buf = (char *) bfd_malloc (size + 1);
   if (buf == NULL)
     return FALSE;
 
   if (buf == NULL)
     return FALSE;
 
+  /* PR 17512: file: ec08f814
+     0-termintate the buffer so that string searches will not overflow.  */
+  buf[size] = 0;
+
   if (bfd_bread (buf, size, abfd) != size
       || !elf_parse_notes (abfd, buf, size, offset))
     {
   if (bfd_bread (buf, size, abfd) != size
       || !elf_parse_notes (abfd, buf, size, offset))
     {
@@ -9961,6 +10856,12 @@ _bfd_elf_rel_local_sym (bfd *abfd,
                                     sym->st_value + addend);
 }
 
                                     sym->st_value + addend);
 }
 
+/* Adjust an address within a section.  Given OFFSET within SEC, return
+   the new offset within the section, based upon changes made to the
+   section.  Returns -1 if the offset is now invalid.
+   The offset (in abnd out) is in target sized bytes, however big a
+   byte may be.  */
+
 bfd_vma
 _bfd_elf_section_offset (bfd *abfd,
                         struct bfd_link_info *info,
 bfd_vma
 _bfd_elf_section_offset (bfd *abfd,
                         struct bfd_link_info *info,
@@ -9974,12 +10875,17 @@ _bfd_elf_section_offset (bfd *abfd,
                                       offset);
     case SEC_INFO_TYPE_EH_FRAME:
       return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
                                       offset);
     case SEC_INFO_TYPE_EH_FRAME:
       return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
+
     default:
       if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0)
        {
     default:
       if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0)
        {
+         /* Reverse the offset.  */
          const struct elf_backend_data *bed = get_elf_backend_data (abfd);
          bfd_size_type address_size = bed->s->arch_size / 8;
          const struct elf_backend_data *bed = get_elf_backend_data (abfd);
          bfd_size_type address_size = bed->s->arch_size / 8;
-         offset = sec->size - offset - address_size;
+
+         /* address_size and sec->size are in octets.  Convert
+            to bytes before subtracting the original offset.  */
+         offset = (sec->size - address_size) / bfd_octets_per_byte (abfd) - offset;
        }
       return offset;
     }
        }
       return offset;
     }
This page took 0.060037 seconds and 4 git commands to generate.