PR binutils/15106
[deliverable/binutils-gdb.git] / bfd / elf.c
index f27c607ab2b2a55387f7d305ef98bf46cb4cb8f1..380f6eff2a696f8e0b628efb53c3740e97c4a4d8 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,7 +1,8 @@
 /* ELF executable support for BFD.
 
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
+   2013
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -44,6 +45,11 @@ SECTION
 #include "elf-bfd.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
+#include "elf-linux-psinfo.h"
+
+#ifdef CORE_HEADER
+#include CORE_HEADER
+#endif
 
 static int elf_sort_sections (const void *, const void *);
 static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
@@ -232,7 +238,7 @@ bfd_elf_gnu_hash (const char *namearg)
 bfd_boolean
 bfd_elf_allocate_object (bfd *abfd,
                         size_t object_size,
-                        enum elf_object_id object_id)
+                        enum elf_target_id object_id)
 {
   BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata));
   abfd->tdata.any = bfd_zalloc (abfd, object_size);
@@ -246,17 +252,18 @@ bfd_elf_allocate_object (bfd *abfd,
 
 
 bfd_boolean
-bfd_elf_make_generic_object (bfd *abfd)
+bfd_elf_make_object (bfd *abfd)
 {
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
-                                 GENERIC_ELF_TDATA);
+                                 bed->target_id);
 }
 
 bfd_boolean
 bfd_elf_mkcorefile (bfd *abfd)
 {
   /* I think this can be done just like an object file.  */
-  return bfd_elf_make_generic_object (abfd);
+  return abfd->xvec->_bfd_set_format[(int) bfd_object] (abfd);
 }
 
 static char *
@@ -283,7 +290,7 @@ 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
-         || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL
+         || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL
          || bfd_seek (abfd, offset, SEEK_SET) != 0)
        shstrtab = NULL;
       else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize)
@@ -331,7 +338,7 @@ bfd_elf_string_from_elf_section (bfd *abfd,
         (shindex == shstrndx && strindex == hdr->sh_name
          ? ".shstrtab"
          : bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name)));
-      return "";
+      return NULL;
     }
 
   return ((char *) hdr->contents) + strindex;
@@ -407,8 +414,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
       pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
       if (extshndx_buf == NULL)
        {
-         alloc_extshndx = bfd_malloc2 (symcount,
-                                       sizeof (Elf_External_Sym_Shndx));
+         alloc_extshndx = (Elf_External_Sym_Shndx *)
+              bfd_malloc2 (symcount, sizeof (Elf_External_Sym_Shndx));
          extshndx_buf = alloc_extshndx;
        }
       if (extshndx_buf == NULL
@@ -422,7 +429,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
   if (intsym_buf == NULL)
     {
-      alloc_intsym = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
+      alloc_intsym = (Elf_Internal_Sym *)
+          bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
       intsym_buf = alloc_intsym;
       if (intsym_buf == NULL)
        goto out;
@@ -430,7 +438,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
   /* Convert the symbols to internal form.  */
   isymend = intsym_buf + symcount;
-  for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf;
+  for (esym = (const bfd_byte *) extsym_buf, isym = intsym_buf,
+           shndx = extshndx_buf;
        isym < isymend;
        esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL)
     if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym))
@@ -538,9 +547,9 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
       shnum = elf_numsections (abfd);
       num_group = 0;
 
-#define IS_VALID_GROUP_SECTION_HEADER(shdr)            \
+#define IS_VALID_GROUP_SECTION_HEADER(shdr, minsize)   \
        (   (shdr)->sh_type == SHT_GROUP                \
-        && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE)     \
+        && (shdr)->sh_size >= minsize                  \
         && (shdr)->sh_entsize == GRP_ENTRY_SIZE        \
         && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0)
 
@@ -548,7 +557,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
        {
          Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
 
-         if (IS_VALID_GROUP_SECTION_HEADER (shdr))
+         if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
            num_group += 1;
        }
 
@@ -564,8 +573,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
          bfd_size_type amt;
 
          elf_tdata (abfd)->num_group = num_group;
-         elf_tdata (abfd)->group_sect_ptr
-           = bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *));
+         elf_tdata (abfd)->group_sect_ptr = (Elf_Internal_Shdr **)
+              bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *));
          if (elf_tdata (abfd)->group_sect_ptr == NULL)
            return FALSE;
 
@@ -574,7 +583,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
            {
              Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
 
-             if (IS_VALID_GROUP_SECTION_HEADER (shdr))
+             if (IS_VALID_GROUP_SECTION_HEADER (shdr, 2 * GRP_ENTRY_SIZE))
                {
                  unsigned char *src;
                  Elf_Internal_Group *dest;
@@ -586,8 +595,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                  /* Read the raw contents.  */
                  BFD_ASSERT (sizeof (*dest) >= 4);
                  amt = shdr->sh_size * sizeof (*dest) / 4;
-                 shdr->contents = bfd_alloc2 (abfd, shdr->sh_size,
-                                              sizeof (*dest) / 4);
+                 shdr->contents = (unsigned char *)
+                      bfd_alloc2 (abfd, shdr->sh_size, sizeof (*dest) / 4);
                  /* PR binutils/4110: Handle corrupt group headers.  */
                  if (shdr->contents == NULL)
                    {
@@ -732,18 +741,18 @@ _bfd_elf_setup_sections (bfd *abfd)
            }
          else
            {
-             asection *link = NULL;
+             asection *linksec = NULL;
 
              if (elfsec < elf_numsections (abfd))
                {
                  this_hdr = elf_elfsections (abfd)[elfsec];
-                 link = this_hdr->bfd_section;
+                 linksec = this_hdr->bfd_section;
                }
 
              /* PR 1991, 2008:
                 Some strip/objcopy may leave an incorrect value in
                 sh_link.  We don't want to proceed.  */
-             if (link == NULL)
+             if (linksec == NULL)
                {
                  (*_bfd_error_handler)
                    (_("%B: sh_link [%d] in section `%A' is incorrect"),
@@ -751,7 +760,7 @@ _bfd_elf_setup_sections (bfd *abfd)
                  result = FALSE;
                }
 
-             elf_linked_to_section (s) = link;
+             elf_linked_to_section (s) = linksec;
            }
        }
     }
@@ -815,11 +824,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   const struct elf_backend_data *bed;
 
   if (hdr->bfd_section != NULL)
-    {
-      BFD_ASSERT (strcmp (name,
-                         bfd_get_section_name (abfd, hdr->bfd_section)) == 0);
-      return TRUE;
-    }
+    return TRUE;
 
   newsect = bfd_make_section_anyway (abfd, name);
   if (newsect == NULL)
@@ -870,50 +875,32 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       return FALSE;
   if ((hdr->sh_flags & SHF_TLS) != 0)
     flags |= SEC_THREAD_LOCAL;
+  if ((hdr->sh_flags & SHF_EXCLUDE) != 0)
+    flags |= SEC_EXCLUDE;
 
   if ((flags & SEC_ALLOC) == 0)
     {
       /* The debugging sections appear to be recognized only by name,
         not any sort of flag.  Their SEC_ALLOC bits are cleared.  */
-      static const struct
-       {
-         const char *name;
-         int len;
-       } debug_sections [] =
-       {
-         { STRING_COMMA_LEN ("debug") },       /* 'd' */
-         { NULL,                0  },  /* 'e' */
-         { NULL,                0  },  /* 'f' */
-         { STRING_COMMA_LEN ("gnu.linkonce.wi.") },    /* 'g' */
-         { NULL,                0  },  /* 'h' */
-         { NULL,                0  },  /* 'i' */
-         { NULL,                0  },  /* 'j' */
-         { NULL,                0  },  /* 'k' */
-         { STRING_COMMA_LEN ("line") },        /* 'l' */
-         { NULL,                0  },  /* 'm' */
-         { NULL,                0  },  /* 'n' */
-         { NULL,                0  },  /* 'o' */
-         { NULL,                0  },  /* 'p' */
-         { NULL,                0  },  /* 'q' */
-         { NULL,                0  },  /* 'r' */
-         { STRING_COMMA_LEN ("stab") },        /* 's' */
-         { NULL,                0  },  /* 't' */
-         { NULL,                0  },  /* 'u' */
-         { NULL,                0  },  /* 'v' */
-         { NULL,                0  },  /* 'w' */
-         { NULL,                0  },  /* 'x' */
-         { NULL,                0  },  /* 'y' */
-         { STRING_COMMA_LEN ("zdebug") }       /* 'z' */
-       };
-
       if (name [0] == '.')
        {
-         int i = name [1] - 'd';
-         if (i >= 0
-             && i < (int) ARRAY_SIZE (debug_sections)
-             && debug_sections [i].name != NULL
-             && strncmp (&name [1], debug_sections [i].name,
-                         debug_sections [i].len) == 0)
+         const char *p;
+         int n;
+         if (name[1] == 'd')
+           p = ".debug", n = 6;
+         else if (name[1] == 'g' && name[2] == 'n')
+           p = ".gnu.linkonce.wi.", n = 17;
+         else if (name[1] == 'g' && name[2] == 'd')
+           p = ".gdb_index", n = 11; /* yes we really do mean 11.  */
+         else if (name[1] == 'l')
+           p = ".line", n = 5;
+         else if (name[1] == 's')
+           p = ".stab", n = 5;
+         else if (name[1] == 'z')
+           p = ".zdebug", n = 7;
+         else
+           p = NULL, n = 0;
+         if (p != NULL && strncmp (name, p, n) == 0)
            flags |= SEC_DEBUGGING;
        }
     }
@@ -971,25 +958,10 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       phdr = elf_tdata (abfd)->phdr;
       for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
        {
-         /* This section is part of this segment if its file
-            offset plus size lies within the segment's memory
-            span and, if the section is loaded, the extent of the
-            loaded data lies within the extent of the segment.
-
-            Note - we used to check the p_paddr field as well, and
-            refuse to set the LMA if it was 0.  This is wrong
-            though, as a perfectly valid initialised segment can
-            have a p_paddr of zero.  Some architectures, eg ARM,
-            place special significance on the address 0 and
-            executables need to be able to have a segment which
-            covers this address.  */
-         if (phdr->p_type == PT_LOAD
-             && (bfd_vma) hdr->sh_offset >= phdr->p_offset
-             && (hdr->sh_offset + hdr->sh_size
-                 <= phdr->p_offset + phdr->p_memsz)
-             && ((flags & SEC_LOAD) == 0
-                 || (hdr->sh_offset + hdr->sh_size
-                     <= phdr->p_offset + phdr->p_filesz)))
+         if (((phdr->p_type == PT_LOAD
+               && (hdr->sh_flags & SHF_TLS) == 0)
+              || phdr->p_type == PT_TLS)
+             && ELF_SECTION_IN_SEGMENT (hdr, phdr))
            {
              if ((flags & SEC_LOAD) == 0)
                newsect->lma = (phdr->p_paddr
@@ -1017,6 +989,77 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
        }
     }
 
+  /* Compress/decompress DWARF debug sections with names: .debug_* and
+     .zdebug_*, after the section flags is set.  */
+  if ((flags & SEC_DEBUGGING)
+      && ((name[1] == 'd' && name[6] == '_')
+         || (name[1] == 'z' && name[7] == '_')))
+    {
+      enum { nothing, compress, decompress } action = nothing;
+      char *new_name;
+
+      if (bfd_is_section_compressed (abfd, newsect))
+       {
+         /* Compressed section.  Check if we should decompress.  */
+         if ((abfd->flags & BFD_DECOMPRESS))
+           action = decompress;
+       }
+      else
+       {
+         /* Normal section.  Check if we should compress.  */
+         if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0)
+           action = compress;
+       }
+
+      new_name = NULL;
+      switch (action)
+       {
+       case nothing:
+         break;
+       case compress:
+         if (!bfd_init_section_compress_status (abfd, newsect))
+           {
+             (*_bfd_error_handler)
+               (_("%B: unable to initialize compress status for section %s"),
+                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:
+         if (!bfd_init_section_decompress_status (abfd, newsect))
+           {
+             (*_bfd_error_handler)
+               (_("%B: unable to initialize decompress status for section %s"),
+                abfd, name);
+             return FALSE;
+           }
+         if (name[1] == 'z')
+           {
+             unsigned int len = strlen (name);
+
+             new_name = bfd_alloc (abfd, len);
+             if (new_name == NULL)
+               return FALSE;
+             new_name[0] = '.';
+             memcpy (new_name + 1, name + 2, len - 1);
+           }
+         break;
+       }
+      if (new_name != NULL)
+       bfd_rename_section (abfd, newsect, new_name);
+    }
+
   return TRUE;
 }
 
@@ -1077,7 +1120,6 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
   /* Copy object attributes.  */
   _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
   return TRUE;
 }
 
@@ -1108,7 +1150,7 @@ get_segment_type (unsigned int p_type)
 bfd_boolean
 _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
 {
-  FILE *f = farg;
+  FILE *f = (FILE *) farg;
   Elf_Internal_Phdr *p;
   asection *s;
   bfd_byte *dynbuf = NULL;
@@ -1351,7 +1393,7 @@ bfd_elf_print_symbol (bfd *abfd,
                      asymbol *symbol,
                      bfd_print_symbol_type how)
 {
-  FILE *file = filep;
+  FILE *file = (FILE *) filep;
   switch (how)
     {
     case bfd_print_symbol_name:
@@ -1531,10 +1573,25 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
     case SHT_DYNAMIC:  /* Dynamic linking information.  */
       if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
        return FALSE;
-      if (hdr->sh_link > elf_numsections (abfd)
-         || elf_elfsections (abfd)[hdr->sh_link] == NULL)
+      if (hdr->sh_link > elf_numsections (abfd))
+       {
+         /* PR 10478: Accept Solaris binaries with a sh_link
+            field set to SHN_BEFORE or SHN_AFTER.  */
+         switch (bfd_get_arch (abfd))
+           {
+           case bfd_arch_i386:
+           case bfd_arch_sparc:
+             if (hdr->sh_link == (SHN_LORESERVE & 0xffff) /* SHN_BEFORE */
+                 || hdr->sh_link == ((SHN_LORESERVE + 1) & 0xffff) /* SHN_AFTER */)
+               break;
+             /* Otherwise fall through.  */
+           default:
+             return FALSE;
+           }
+       }
+      else if (elf_elfsections (abfd)[hdr->sh_link] == NULL)
        return FALSE;
-      if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB)
+      else if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB)
        {
          Elf_Internal_Shdr *dynsymhdr;
 
@@ -1571,7 +1628,15 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       if (hdr->sh_entsize != bed->s->sizeof_sym)
        return FALSE;
       if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
-       return FALSE;
+       {
+         if (hdr->sh_size != 0)
+           return FALSE;
+         /* Some assemblers erroneously set sh_info to one with a
+            zero sh_size.  ld sees this as a global symbol count
+            of (unsigned) -1.  Fix it here.  */
+         hdr->sh_info = 0;
+         return TRUE;
+       }
       BFD_ASSERT (elf_onesymtab (abfd) == 0);
       elf_onesymtab (abfd) = shindex;
       elf_tdata (abfd)->symtab_hdr = *hdr;
@@ -1624,6 +1689,16 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
 
       if (hdr->sh_entsize != bed->s->sizeof_sym)
        return FALSE;
+      if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
+       {
+         if (hdr->sh_size != 0)
+           return FALSE;
+         /* Some linkers erroneously set sh_info to one with a
+            zero sh_size.  ld sees this as a global symbol count
+            of (unsigned) -1.  Fix it here.  */
+         hdr->sh_info = 0;
+         return TRUE;
+       }
       BFD_ASSERT (elf_dynsymtab (abfd) == 0);
       elf_dynsymtab (abfd) = shindex;
       elf_tdata (abfd)->dynsymtab_hdr = *hdr;
@@ -1704,8 +1779,10 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       /* *These* do a lot of work -- but build no sections!  */
       {
        asection *target_sect;
-       Elf_Internal_Shdr *hdr2;
+       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
@@ -1784,20 +1861,19 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        if (target_sect == NULL)
          return FALSE;
 
-       if ((target_sect->flags & SEC_RELOC) == 0
-           || target_sect->reloc_count == 0)
-         hdr2 = &elf_section_data (target_sect)->rel_hdr;
+       esdt = elf_section_data (target_sect);
+       if (hdr->sh_type == SHT_RELA)
+         p_hdr = &esdt->rela.hdr;
        else
-         {
-           bfd_size_type amt;
-           BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
-           amt = sizeof (*hdr2);
-           hdr2 = bfd_alloc (abfd, amt);
-           if (hdr2 == NULL)
-             return FALSE;
-           elf_section_data (target_sect)->rel_hdr2 = hdr2;
-         }
+         p_hdr = &esdt->rel.hdr;
+
+       BFD_ASSERT (*p_hdr == NULL);
+       amt = sizeof (*hdr2);
+       hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt);
+       if (hdr2 == NULL)
+         return FALSE;
        *hdr2 = *hdr;
+       *p_hdr = hdr2;
        elf_elfsections (abfd)[shindex] = hdr2;
        target_sect->reloc_count += NUM_SHDR_ENTRIES (hdr);
        target_sect->flags |= SEC_RELOC;
@@ -1806,7 +1882,10 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        /* In the section to which the relocations apply, mark whether
           its relocations are of the REL or RELA variety.  */
        if (hdr->sh_size != 0)
-         target_sect->use_rela_p = hdr->sh_type == SHT_RELA;
+         {
+           if (hdr->sh_type == SHT_RELA)
+             target_sect->use_rela_p = 1;
+         }
        abfd->flags |= HAS_RELOC;
        return TRUE;
       }
@@ -1832,7 +1911,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       return TRUE;
 
     case SHT_GROUP:
-      if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
+      if (! IS_VALID_GROUP_SECTION_HEADER (hdr, GRP_ENTRY_SIZE))
        return FALSE;
       if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
        return FALSE;
@@ -1961,11 +2040,11 @@ bfd_sym_from_r_symndx (struct sym_cache *cache,
    section.  */
 
 asection *
-bfd_section_from_elf_index (bfd *abfd, unsigned int index)
+bfd_section_from_elf_index (bfd *abfd, unsigned int sec_index)
 {
-  if (index >= elf_numsections (abfd))
+  if (sec_index >= elf_numsections (abfd))
     return NULL;
-  return elf_elfsections (abfd)[index]->bfd_section;
+  return elf_elfsections (abfd)[sec_index]->bfd_section;
 }
 
 static const struct bfd_elf_special_section special_sections_b[] =
@@ -1984,6 +2063,9 @@ static const struct bfd_elf_special_section special_sections_d[] =
 {
   { STRING_COMMA_LEN (".data"),         -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { STRING_COMMA_LEN (".data1"),         0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  /* There are more DWARF sections than these, but they needn't be added here
+     unless you have to cope with broken compilers that don't emit section
+     attributes or you want to help the user writing assembler.  */
   { STRING_COMMA_LEN (".debug"),         0, SHT_PROGBITS, 0 },
   { STRING_COMMA_LEN (".debug_line"),    0, SHT_PROGBITS, 0 },
   { STRING_COMMA_LEN (".debug_info"),    0, SHT_PROGBITS, 0 },
@@ -2005,6 +2087,7 @@ static const struct bfd_elf_special_section special_sections_f[] =
 static const struct bfd_elf_special_section special_sections_g[] =
 {
   { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS,      SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".gnu.lto_"),       -1, SHT_PROGBITS,    SHF_EXCLUDE },
   { STRING_COMMA_LEN (".got"),             0, SHT_PROGBITS,    SHF_ALLOC + SHF_WRITE },
   { STRING_COMMA_LEN (".gnu.version"),     0, SHT_GNU_versym,  0 },
   { STRING_COMMA_LEN (".gnu.version_d"),   0, SHT_GNU_verdef,  0 },
@@ -2086,7 +2169,7 @@ static const struct bfd_elf_special_section special_sections_z[] =
   { NULL,                     0,  0, 0,            0 }
 };
 
-static const struct bfd_elf_special_section *special_sections[] =
+static const struct bfd_elf_special_section * const special_sections[] =
 {
   special_sections_b,          /* 'b' */
   special_sections_c,          /* 'c' */
@@ -2210,7 +2293,8 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
   sdata = (struct bfd_elf_section_data *) sec->used_by_bfd;
   if (sdata == NULL)
     {
-      sdata = bfd_zalloc (abfd, sizeof (*sdata));
+      sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd,
+                                                          sizeof (*sdata));
       if (sdata == NULL)
        return FALSE;
       sec->used_by_bfd = sdata;
@@ -2225,12 +2309,19 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
      anyway.  We will set ELF section type and flags for all linker
      created sections.  If user specifies BFD section flags, we will
      set ELF section type and flags based on BFD section flags in
-     elf_fake_sections.  */
-  if ((!sec->flags && abfd->direction != read_direction)
+     elf_fake_sections.  Special handling for .init_array/.fini_array
+     output sections since they may contain .ctors/.dtors input
+     sections.  We don't want _bfd_elf_init_private_section_data to
+     copy ELF section type from .ctors/.dtors input sections.  */
+  if (abfd->direction != read_direction
       || (sec->flags & SEC_LINKER_CREATED) != 0)
     {
       ssect = (*bed->get_sec_type_attr) (abfd, sec);
-      if (ssect != NULL)
+      if (ssect != NULL
+         && (!sec->flags
+             || (sec->flags & SEC_LINKER_CREATED) != 0
+             || ssect->type == SHT_INIT_ARRAY
+             || ssect->type == SHT_FINI_ARRAY))
        {
          elf_section_type (sec) = ssect->type;
          elf_section_flags (sec) = ssect->attr;
@@ -2265,8 +2356,8 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
 bfd_boolean
 _bfd_elf_make_section_from_phdr (bfd *abfd,
                                 Elf_Internal_Phdr *hdr,
-                                int index,
-                                const char *typename)
+                                int hdr_index,
+                                const char *type_name)
 {
   asection *newsect;
   char *name;
@@ -2280,9 +2371,9 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
 
   if (hdr->p_filesz > 0)
     {
-      sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
+      sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "a" : "");
       len = strlen (namebuf) + 1;
-      name = bfd_alloc (abfd, len);
+      name = (char *) bfd_alloc (abfd, len);
       if (!name)
        return FALSE;
       memcpy (name, namebuf, len);
@@ -2316,9 +2407,9 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
     {
       bfd_vma align;
 
-      sprintf (namebuf, "%s%d%s", typename, index, split ? "b" : "");
+      sprintf (namebuf, "%s%d%s", type_name, hdr_index, split ? "b" : "");
       len = strlen (namebuf) + 1;
-      name = bfd_alloc (abfd, len);
+      name = (char *) bfd_alloc (abfd, len);
       if (!name)
        return FALSE;
       memcpy (name, namebuf, len);
@@ -2355,69 +2446,92 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
 }
 
 bfd_boolean
-bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index)
+bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
 {
   const struct elf_backend_data *bed;
 
   switch (hdr->p_type)
     {
     case PT_NULL:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "null");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "null");
 
     case PT_LOAD:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "load");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load");
 
     case PT_DYNAMIC:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "dynamic");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "dynamic");
 
     case PT_INTERP:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "interp");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "interp");
 
     case PT_NOTE:
-      if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note"))
+      if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "note"))
        return FALSE;
       if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
        return FALSE;
       return TRUE;
 
     case PT_SHLIB:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "shlib");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "shlib");
 
     case PT_PHDR:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "phdr");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "phdr");
 
     case PT_GNU_EH_FRAME:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index,
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index,
                                              "eh_frame_hdr");
 
     case PT_GNU_STACK:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "stack");
 
     case PT_GNU_RELRO:
-      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro");
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro");
 
     default:
       /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
-      return bed->elf_backend_section_from_phdr (abfd, hdr, index, "proc");
+      return bed->elf_backend_section_from_phdr (abfd, hdr, hdr_index, "proc");
+    }
+}
+
+/* Return the REL_HDR for SEC, assuming there is only a single one, either
+   REL or RELA.  */
+
+Elf_Internal_Shdr *
+_bfd_elf_single_rel_hdr (asection *sec)
+{
+  if (elf_section_data (sec)->rel.hdr)
+    {
+      BFD_ASSERT (elf_section_data (sec)->rela.hdr == NULL);
+      return elf_section_data (sec)->rel.hdr;
     }
+  else
+    return elf_section_data (sec)->rela.hdr;
 }
 
-/* Initialize REL_HDR, the section-header for new section, containing
-   relocations against ASECT.  If USE_RELA_P is TRUE, we use RELA
-   relocations; otherwise, we use REL relocations.  */
+/* 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
+   relocations.  */
 
 bfd_boolean
 _bfd_elf_init_reloc_shdr (bfd *abfd,
-                         Elf_Internal_Shdr *rel_hdr,
+                         struct bfd_elf_section_reloc_data *reldata,
                          asection *asect,
                          bfd_boolean use_rela_p)
 {
+  Elf_Internal_Shdr *rel_hdr;
   char *name;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  bfd_size_type amt = sizeof ".rela" + strlen (asect->name);
+  bfd_size_type amt;
+
+  amt = sizeof (Elf_Internal_Shdr);
+  BFD_ASSERT (reldata->hdr == NULL);
+  rel_hdr = bfd_zalloc (abfd, amt);
+  reldata->hdr = rel_hdr;
 
-  name = bfd_alloc (abfd, amt);
+  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);
@@ -2439,30 +2553,48 @@ _bfd_elf_init_reloc_shdr (bfd *abfd,
   return TRUE;
 }
 
+/* Return the default section type based on the passed in section flags.  */
+
+int
+bfd_elf_get_default_section_type (flagword flags)
+{
+  if ((flags & SEC_ALLOC) != 0
+      && (flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+    return SHT_NOBITS;
+  return SHT_PROGBITS;
+}
+
+struct fake_section_arg
+{
+  struct bfd_link_info *link_info;
+  bfd_boolean failed;
+};
+
 /* Set up an ELF internal section header for a section.  */
 
 static void
-elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
+elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)
 {
+  struct fake_section_arg *arg = (struct fake_section_arg *)fsarg;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  bfd_boolean *failedptr = failedptrarg;
+  struct bfd_elf_section_data *esd = elf_section_data (asect);
   Elf_Internal_Shdr *this_hdr;
   unsigned int sh_type;
 
-  if (*failedptr)
+  if (arg->failed)
     {
       /* We already failed; just get out of the bfd_map_over_sections
         loop.  */
       return;
     }
 
-  this_hdr = &elf_section_data (asect)->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)
     {
-      *failedptr = TRUE;
+      arg->failed = TRUE;
       return;
     }
 
@@ -2488,12 +2620,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
      asect->flags.  */
   if ((asect->flags & SEC_GROUP) != 0)
     sh_type = SHT_GROUP;
-  else if ((asect->flags & SEC_ALLOC) != 0
-          && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
-              || (asect->flags & SEC_NEVER_LOAD) != 0))
-    sh_type = SHT_NOBITS;
   else
-    sh_type = SHT_PROGBITS;
+    sh_type = bfd_elf_get_default_section_type (asect->flags);
 
   if (this_hdr->sh_type == SHT_NULL)
     this_hdr->sh_type = sh_type;
@@ -2615,12 +2743,48 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
            }
        }
     }
+  if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE)
+    this_hdr->sh_flags |= SHF_EXCLUDE;
+
+  /* If the section has relocs, set up a section header for the
+     SHT_REL[A] section.  If two relocation sections are required for
+     this section, it is up to the processor-specific back-end to
+     create the other.  */
+  if ((asect->flags & SEC_RELOC) != 0)
+    {
+      /* When doing a relocatable link, create both REL and RELA sections if
+        needed.  */
+      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))
+       {
+         if (esd->rel.count && esd->rel.hdr == NULL
+             && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, asect, FALSE))
+           {
+             arg->failed = TRUE;
+             return;
+           }
+         if (esd->rela.count && esd->rela.hdr == NULL
+             && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, asect, TRUE))
+           {
+             arg->failed = TRUE;
+             return;
+           }
+       }
+      else if (!_bfd_elf_init_reloc_shdr (abfd,
+                                         (asect->use_rela_p
+                                          ? &esd->rela : &esd->rel),
+                                         asect,
+                                         asect->use_rela_p))
+         arg->failed = TRUE;
+    }
 
   /* Check for processor-specific section types.  */
   sh_type = this_hdr->sh_type;
   if (bed->elf_backend_fake_sections
       && !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect))
-    *failedptr = TRUE;
+    arg->failed = TRUE;
 
   if (sh_type == SHT_NOBITS && asect->size != 0)
     {
@@ -2628,17 +2792,6 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
         called for objcopy --only-keep-debug.  */
       this_hdr->sh_type = sh_type;
     }
-
-  /* If the section has relocs, set up a section header for the
-     SHT_REL[A] section.  If two relocation sections are required for
-     this section, it is up to the processor-specific back-end to
-     create the other.  */
-  if ((asect->flags & SEC_RELOC) != 0
-      && !_bfd_elf_init_reloc_shdr (abfd,
-                                   &elf_section_data (asect)->rel_hdr,
-                                   asect,
-                                   asect->use_rela_p))
-    *failedptr = TRUE;
 }
 
 /* Fill in the contents of a SHT_GROUP section.  Called from
@@ -2649,7 +2802,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
 void
 bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
 {
-  bfd_boolean *failedptr = failedptrarg;
+  bfd_boolean *failedptr = (bfd_boolean *) failedptrarg;
   asection *elt, *first;
   unsigned char *loc;
   bfd_boolean gas;
@@ -2709,7 +2862,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   if (sec->contents == NULL)
     {
       gas = FALSE;
-      sec->contents = bfd_alloc (abfd, sec->size);
+      sec->contents = (unsigned char *) bfd_alloc (abfd, sec->size);
 
       /* Arrange for the section to be written out.  */
       elf_section_data (sec)->this_hdr.contents = sec->contents;
@@ -2734,17 +2887,16 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   while (elt != NULL)
     {
       asection *s;
-      unsigned int idx;
 
       s = elt;
-      if (! elf_discarded_section (s))
+      if (!gas)
+       s = s->output_section;
+      if (s != NULL
+         && !bfd_is_abs_section (s))
        {
+         unsigned int idx = elf_section_data (s)->this_idx;
+
          loc -= 4;
-         if (!gas)
-           s = s->output_section;
-         idx = 0;
-         if (s != NULL)
-           idx = elf_section_data (s)->this_idx;
          H_PUT_32 (abfd, idx, loc);
        }
       elt = elf_next_in_group (elt);
@@ -2805,21 +2957,21 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       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 ((sec->flags & SEC_RELOC) == 0)
-       d->rel_idx = 0;
-      else
+      if (d->rel.hdr)
        {
-         d->rel_idx = section_number++;
-         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name);
+         d->rel.idx = section_number++;
+         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name);
        }
+      else
+       d->rel.idx = 0;
 
-      if (d->rel_hdr2)
+      if (d->rela.hdr)
        {
-         d->rel_idx2 = section_number++;
-         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name);
+         d->rela.idx = section_number++;
+         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name);
        }
       else
-       d->rel_idx2 = 0;
+       d->rela.idx = 0;
     }
 
   t->shstrtab_section = section_number++;
@@ -2847,6 +2999,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
+  if (section_number >= SHN_LORESERVE)
+    {
+      _bfd_error_handler (_("%B: too many sections: %u"),
+                         abfd, section_number);
+      return FALSE;
+    }
+
   _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
   t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
 
@@ -2855,11 +3014,13 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 
   /* Set up the list of section header pointers, in agreement with the
      indices.  */
-  i_shdrp = bfd_zalloc2 (abfd, section_number, sizeof (Elf_Internal_Shdr *));
+  i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc2 (abfd, section_number,
+                                                sizeof (Elf_Internal_Shdr *));
   if (i_shdrp == NULL)
     return FALSE;
 
-  i_shdrp[0] = bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr));
+  i_shdrp[0] = (Elf_Internal_Shdr *) bfd_zalloc (abfd,
+                                                 sizeof (Elf_Internal_Shdr));
   if (i_shdrp[0] == NULL)
     {
       bfd_release (abfd, i_shdrp);
@@ -2883,30 +3044,31 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 
   for (sec = abfd->sections; sec; sec = sec->next)
     {
-      struct bfd_elf_section_data *d = elf_section_data (sec);
       asection *s;
       const char *name;
 
+      d = elf_section_data (sec);
+
       i_shdrp[d->this_idx] = &d->this_hdr;
-      if (d->rel_idx != 0)
-       i_shdrp[d->rel_idx] = &d->rel_hdr;
-      if (d->rel_idx2 != 0)
-       i_shdrp[d->rel_idx2] = d->rel_hdr2;
+      if (d->rel.idx != 0)
+       i_shdrp[d->rel.idx] = d->rel.hdr;
+      if (d->rela.idx != 0)
+       i_shdrp[d->rela.idx] = d->rela.hdr;
 
       /* Fill in the sh_link and sh_info fields while we're at it.  */
 
       /* sh_link of a reloc section is the section index of the symbol
         table.  sh_info is the section index of the section to which
         the relocation entries apply.  */
-      if (d->rel_idx != 0)
+      if (d->rel.idx != 0)
        {
-         d->rel_hdr.sh_link = t->symtab_section;
-         d->rel_hdr.sh_info = d->this_idx;
+         d->rel.hdr->sh_link = t->symtab_section;
+         d->rel.hdr->sh_info = d->this_idx;
        }
-      if (d->rel_idx2 != 0)
+      if (d->rela.idx != 0)
        {
-         d->rel_hdr2->sh_link = t->symtab_section;
-         d->rel_hdr2->sh_info = d->this_idx;
+         d->rela.hdr->sh_link = t->symtab_section;
+         d->rela.hdr->sh_info = d->this_idx;
        }
 
       /* We need to set up sh_link for SHF_LINK_ORDER.  */
@@ -2919,7 +3081,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
              if (link_info != NULL)
                {
                  /* Check discarded linkonce section.  */
-                 if (elf_discarded_section (s))
+                 if (discarded_section (s))
                    {
                      asection *kept;
                      (*_bfd_error_handler)
@@ -3008,7 +3170,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
              char *alc;
 
              len = strlen (sec->name);
-             alc = bfd_malloc (len - 2);
+             alc = (char *) bfd_malloc (len - 2);
              if (alc == NULL)
                return FALSE;
              memcpy (alc, sec->name, len - 3);
@@ -3073,9 +3235,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   return TRUE;
 }
 
-/* Map symbol from it's internal number to the external number, moving
-   all local symbols to be at the head of the list.  */
-
 static bfd_boolean
 sym_is_global (bfd *abfd, asymbol *sym)
 {
@@ -3084,23 +3243,35 @@ sym_is_global (bfd *abfd, asymbol *sym)
   if (bed->elf_backend_sym_is_global)
     return (*bed->elf_backend_sym_is_global) (abfd, sym);
 
-  return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+  return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0
          || bfd_is_und_section (bfd_get_section (sym))
          || bfd_is_com_section (bfd_get_section (sym)));
 }
 
 /* Don't output section symbols for sections that are not going to be
-   output.  */
+   output, that are duplicates or there is no BFD section.  */
 
 static bfd_boolean
 ignore_section_sym (bfd *abfd, asymbol *sym)
 {
-  return ((sym->flags & BSF_SECTION_SYM) != 0
-         && !(sym->section->owner == abfd
+  elf_symbol_type *type_ptr;
+
+  if ((sym->flags & BSF_SECTION_SYM) == 0)
+    return FALSE;
+
+  type_ptr = elf_symbol_from (abfd, sym);
+  return ((type_ptr != NULL
+          && type_ptr->internal_elf_sym.st_shndx != 0
+          && bfd_is_abs_section (sym->section))
+         || !(sym->section->owner == abfd
               || (sym->section->output_section->owner == abfd
-                  && sym->section->output_offset == 0)));
+                  && sym->section->output_offset == 0)
+              || bfd_is_abs_section (sym->section)));
 }
 
+/* Map symbol from it's internal number to the external number, moving
+   all local symbols to be at the head of the list.  */
+
 static bfd_boolean
 elf_map_symbols (bfd *abfd)
 {
@@ -3128,7 +3299,7 @@ elf_map_symbols (bfd *abfd)
     }
 
   max_index++;
-  sect_syms = bfd_zalloc2 (abfd, max_index, sizeof (asymbol *));
+  sect_syms = (asymbol **) bfd_zalloc2 (abfd, max_index, sizeof (asymbol *));
   if (sect_syms == NULL)
     return FALSE;
   elf_section_syms (abfd) = sect_syms;
@@ -3142,7 +3313,8 @@ elf_map_symbols (bfd *abfd)
 
       if ((sym->flags & BSF_SECTION_SYM) != 0
          && sym->value == 0
-         && !ignore_section_sym (abfd, sym))
+         && !ignore_section_sym (abfd, sym)
+         && !bfd_is_abs_section (sym->section))
        {
          asection *sec = sym->section;
 
@@ -3156,12 +3328,10 @@ elf_map_symbols (bfd *abfd)
   /* Classify all of the symbols.  */
   for (idx = 0; idx < symcount; idx++)
     {
-      if (ignore_section_sym (abfd, syms[idx]))
-       continue;
-      if (!sym_is_global (abfd, syms[idx]))
-       num_locals++;
-      else
+      if (sym_is_global (abfd, syms[idx]))
        num_globals++;
+      else if (!ignore_section_sym (abfd, syms[idx]))
+       num_locals++;
     }
 
   /* We will be adding a section symbol for each normal BFD section.  Most
@@ -3180,7 +3350,8 @@ elf_map_symbols (bfd *abfd)
     }
 
   /* Now sort the symbols so the local symbols are first.  */
-  new_syms = bfd_alloc2 (abfd, num_locals + num_globals, sizeof (asymbol *));
+  new_syms = (asymbol **) bfd_alloc2 (abfd, num_locals + num_globals,
+                                      sizeof (asymbol *));
 
   if (new_syms == NULL)
     return FALSE;
@@ -3190,12 +3361,12 @@ elf_map_symbols (bfd *abfd)
       asymbol *sym = syms[idx];
       unsigned int i;
 
-      if (ignore_section_sym (abfd, sym))
-       continue;
-      if (!sym_is_global (abfd, sym))
+      if (sym_is_global (abfd, sym))
+       i = num_locals + num_globals2++;
+      else if (!ignore_section_sym (abfd, sym))
        i = num_locals2++;
       else
-       i = num_locals + num_globals2++;
+       continue;
       new_syms[i] = sym;
       sym->udata.i = i + 1;
     }
@@ -3259,6 +3430,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
                                         struct bfd_link_info *link_info)
 {
   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;
   Elf_Internal_Shdr *shstrtab_hdr;
@@ -3278,9 +3450,10 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   if (bed->elf_backend_post_process_headers)
     (*bed->elf_backend_post_process_headers) (abfd, link_info);
 
-  failed = FALSE;
-  bfd_map_over_sections (abfd, elf_fake_sections, &failed);
-  if (failed)
+  fsargs.failed = FALSE;
+  fsargs.link_info = link_info;
+  bfd_map_over_sections (abfd, elf_fake_sections, &fsargs);
+  if (fsargs.failed)
     return FALSE;
 
   if (!assign_section_numbers (abfd, link_info))
@@ -3300,6 +3473,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
        return FALSE;
     }
 
+  failed = FALSE;
   if (link_info == NULL)
     {
       bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
@@ -3489,7 +3663,7 @@ make_mapping (bfd *abfd,
 
   amt = sizeof (struct elf_segment_map);
   amt += (to - from - 1) * sizeof (asection *);
-  m = bfd_zalloc (abfd, amt);
+  m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
   if (m == NULL)
     return NULL;
   m->next = NULL;
@@ -3516,7 +3690,8 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
 {
   struct elf_segment_map *m;
 
-  m = bfd_zalloc (abfd, sizeof (struct elf_segment_map));
+  m = (struct elf_segment_map *) bfd_zalloc (abfd,
+                                             sizeof (struct elf_segment_map));
   if (m == NULL)
     return NULL;
   m->next = NULL;
@@ -3587,6 +3762,10 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
   bfd_boolean no_user_phdrs;
 
   no_user_phdrs = elf_tdata (abfd)->segment_map == NULL;
+
+  if (info != NULL)
+    info->user_phdrs = !no_user_phdrs;
+
   if (no_user_phdrs && bfd_count_sections (abfd) != 0)
     {
       asection *s;
@@ -3604,13 +3783,21 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       asection *first_tls = NULL;
       asection *dynsec, *eh_frame_hdr;
       bfd_size_type amt;
+      bfd_vma addr_mask, wrap_to = 0;
 
       /* Select the allocated sections, and sort them.  */
 
-      sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
+      sections = (asection **) bfd_malloc2 (bfd_count_sections (abfd),
+                                            sizeof (asection *));
       if (sections == NULL)
        goto error_return;
 
+      /* Calculate top address, avoiding undefined behaviour of shift
+        left operator when shift count is equal to size of type
+        being shifted.  */
+      addr_mask = ((bfd_vma) 1 << (bfd_arch_bits_per_address (abfd) - 1)) - 1;
+      addr_mask = (addr_mask << 1) + 1;
+
       i = 0;
       for (s = abfd->sections; s != NULL; s = s->next)
        {
@@ -3618,6 +3805,9 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
            {
              sections[i] = s;
              ++i;
+             /* A wrapping section potentially clashes with header.  */
+             if (((s->lma + s->size) & addr_mask) < (s->lma & addr_mask))
+               wrap_to = (s->lma + s->size) & addr_mask;
            }
        }
       BFD_ASSERT (i <= bfd_count_sections (abfd));
@@ -3637,7 +3827,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       if (s != NULL && (s->flags & SEC_LOAD) != 0)
        {
          amt = sizeof (struct elf_segment_map);
-         m = bfd_zalloc (abfd, amt);
+         m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
          if (m == NULL)
            goto error_return;
          m->next = NULL;
@@ -3651,7 +3841,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          pm = &m->next;
 
          amt = sizeof (struct elf_segment_map);
-         m = bfd_zalloc (abfd, amt);
+         m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
          if (m == NULL)
            goto error_return;
          m->next = NULL;
@@ -3686,9 +3876,12 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 
          if (phdr_size == (bfd_size_type) -1)
            phdr_size = get_program_header_size (abfd, info);
+         phdr_size += bed->s->sizeof_ehdr;
          if ((abfd->flags & D_PAGED) == 0
-             || sections[0]->lma < phdr_size
-             || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
+             || (sections[0]->lma & addr_mask) < phdr_size
+             || ((sections[0]->lma & addr_mask) % maxpagesize
+                 < phdr_size % maxpagesize)
+             || (sections[0]->lma & addr_mask & -maxpagesize) < wrap_to)
            phdr_in_segment = FALSE;
        }
 
@@ -3715,6 +3908,13 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
                 segment.  */
              new_segment = TRUE;
            }
+         else if (hdr->lma < last_hdr->lma + last_size
+                  || last_hdr->lma + last_size < last_hdr->lma)
+           {
+             /* If this section has a load address that makes it overlap
+                the previous section, then we need a new segment.  */
+             new_segment = TRUE;
+           }
          /* In the next test we have to be careful when last_hdr->lma is close
             to the end of the address space.  If the aligned address wraps
             around to the start of the address space, then there are no more
@@ -3746,9 +3946,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
            }
          else if (! writable
                   && (hdr->flags & SEC_READONLY) == 0
-                  && (((last_hdr->lma + last_size - 1)
-                       & ~(maxpagesize - 1))
-                      != (hdr->lma & ~(maxpagesize - 1))))
+                  && (((last_hdr->lma + last_size - 1) & -maxpagesize)
+                      != (hdr->lma & -maxpagesize)))
            {
              /* We don't want to put a writable section in a read only
                 segment, unless they are on the same page in memory
@@ -3813,8 +4012,12 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          phdr_in_segment = FALSE;
        }
 
-      /* Create a final PT_LOAD program segment.  */
-      if (last_hdr != NULL)
+      /* Create a final PT_LOAD program segment, but not if it's just
+        for .tbss.  */
+      if (last_hdr != NULL
+         && (i - phdr_index != 1
+             || ((last_hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
+                 != SEC_THREAD_LOCAL)))
        {
          m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
          if (m == NULL)
@@ -3846,7 +4049,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
              && CONST_STRNEQ (s->name, ".note"))
            {
              asection *s2;
-             unsigned count = 1;
+
+             count = 1;
              amt = sizeof (struct elf_segment_map);
              if (s->alignment_power == 2)
                for (s2 = s; s2->next != NULL; s2 = s2->next)
@@ -3854,14 +4058,14 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
                    if (s2->next->alignment_power == 2
                        && (s2->next->flags & SEC_LOAD) != 0
                        && CONST_STRNEQ (s2->next->name, ".note")
-                       && align_power (s2->vma + s2->size, 2)
-                          == s2->next->vma)
+                       && align_power (s2->lma + s2->size, 2)
+                          == s2->next->lma)
                      count++;
                    else
                      break;
                  }
              amt += (count - 1) * sizeof (asection *);
-             m = bfd_zalloc (abfd, amt);
+             m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
              if (m == NULL)
                goto error_return;
              m->next = NULL;
@@ -3889,11 +4093,9 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       /* If there are any SHF_TLS output sections, add PT_TLS segment.  */
       if (tls_count > 0)
        {
-         int i;
-
          amt = sizeof (struct elf_segment_map);
          amt += (tls_count - 1) * sizeof (asection *);
-         m = bfd_zalloc (abfd, amt);
+         m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
          if (m == NULL)
            goto error_return;
          m->next = NULL;
@@ -3902,7 +4104,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          /* Mandated PF_R.  */
          m->p_flags = PF_R;
          m->p_flags_valid = 1;
-         for (i = 0; i < tls_count; ++i)
+         for (i = 0; i < (unsigned int) tls_count; ++i)
            {
              BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
              m->sections[i] = first_tls;
@@ -3920,7 +4122,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0)
        {
          amt = sizeof (struct elf_segment_map);
-         m = bfd_zalloc (abfd, amt);
+         m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
          if (m == NULL)
            goto error_return;
          m->next = NULL;
@@ -3935,13 +4137,20 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       if (elf_tdata (abfd)->stack_flags)
        {
          amt = sizeof (struct elf_segment_map);
-         m = bfd_zalloc (abfd, amt);
+         m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
          if (m == NULL)
            goto error_return;
          m->next = NULL;
          m->p_type = PT_GNU_STACK;
          m->p_flags = elf_tdata (abfd)->stack_flags;
+         m->p_align = bed->stack_align;
          m->p_flags_valid = 1;
+         m->p_align_valid = m->p_align != 0;
+         if (info->stacksize > 0)
+           {
+             m->p_size = info->stacksize;
+             m->p_size_valid = 1;
+           }
 
          *pm = m;
          pm = &m->next;
@@ -3951,24 +4160,31 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
        {
          for (m = mfirst; m != NULL; m = m->next)
            {
-             if (m->p_type == PT_LOAD)
+             if (m->p_type == PT_LOAD
+                 && m->count != 0
+                 && m->sections[0]->vma >= info->relro_start
+                 && m->sections[0]->vma < info->relro_end)
                {
-                 asection *last = m->sections[m->count - 1];
-                 bfd_vma vaddr = m->sections[0]->vma;
-                 bfd_vma filesz = last->vma - vaddr + last->size;
+                 i = m->count;
+                 while (--i != (unsigned) -1)
+                   if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS))
+                       == (SEC_LOAD | SEC_HAS_CONTENTS))
+                     break;
+
+                 if (i == (unsigned) -1)
+                   continue;
 
-                 if (vaddr < info->relro_end
-                     && vaddr >= info->relro_start
-                     && (vaddr + filesz) >= info->relro_end)
+                 if (m->sections[i]->vma + m->sections[i]->size
+                     >= info->relro_end)
                    break;
                }
-             }
+           }
 
          /* Make a PT_GNU_RELRO segment only when it isn't empty.  */
          if (m != NULL)
            {
              amt = sizeof (struct elf_segment_map);
-             m = bfd_zalloc (abfd, amt);
+             m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
              if (m == NULL)
                goto error_return;
              m->next = NULL;
@@ -4107,10 +4323,28 @@ print_segment_map (const struct elf_segment_map *m)
                  (unsigned int) m->p_type);
       pt = buf;
     }
+  fflush (stdout);
   fprintf (stderr, "%s:", pt);
   for (j = 0; j < m->count; j++)
     fprintf (stderr, " %s", m->sections [j]->name);
   putc ('\n',stderr);
+  fflush (stderr);
+}
+
+static bfd_boolean
+write_zeros (bfd *abfd, file_ptr pos, bfd_size_type len)
+{
+  void *buf;
+  bfd_boolean ret;
+
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0)
+    return FALSE;
+  buf = bfd_zmalloc (len);
+  if (buf == NULL)
+    return FALSE;
+  ret = bfd_bwrite (buf, len, abfd) == len;
+  free (buf);
+  return ret;
 }
 
 /* Assign file positions to the sections based on the mapping from
@@ -4143,8 +4377,18 @@ assign_file_positions_for_load_sections (bfd *abfd,
        header_pad = m->header_size;
     }
 
-  elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
-  elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
+  if (alloc)
+    {
+      elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
+      elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
+    }
+  else
+    {
+      /* PR binutils/12467.  */
+      elf_elfheader (abfd)->e_phoff = 0;
+      elf_elfheader (abfd)->e_phentsize = 0;
+    }
+
   elf_elfheader (abfd)->e_phnum = alloc;
 
   if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
@@ -4170,10 +4414,10 @@ assign_file_positions_for_load_sections (bfd *abfd,
      last iterations for the testcase ld-elf/header.  */
   BFD_ASSERT (elf_tdata (abfd)->program_header_size % bed->s->sizeof_phdr
              == 0);
-  phdrs = bfd_zalloc2 (abfd,
-                      (elf_tdata (abfd)->program_header_size
-                       / bed->s->sizeof_phdr),
-                      sizeof (Elf_Internal_Phdr));
+  phdrs = (Elf_Internal_Phdr *)
+     bfd_zalloc2 (abfd,
+                  (elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr),
+                  sizeof (Elf_Internal_Phdr));
   elf_tdata (abfd)->phdr = phdrs;
   if (phdrs == NULL)
     return FALSE;
@@ -4294,7 +4538,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
                break;
              }
 
-         off_adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
+         off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align);
          off += off_adjust;
          if (no_contents)
            {
@@ -4339,8 +4583,6 @@ assign_file_positions_for_load_sections (bfd *abfd,
          p->p_memsz = bed->s->sizeof_ehdr;
          if (m->count > 0)
            {
-             BFD_ASSERT (p->p_type == PT_LOAD);
-
              if (p->p_vaddr < (bfd_vma) off)
                {
                  (*_bfd_error_handler)
@@ -4367,7 +4609,6 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
              if (m->count > 0)
                {
-                 BFD_ASSERT (p->p_type == PT_LOAD);
                  p->p_vaddr -= off - p->p_offset;
                  if (!m->p_paddr_valid)
                    p->p_paddr -= off - p->p_offset;
@@ -4421,19 +4662,34 @@ assign_file_positions_for_load_sections (bfd *abfd,
                      && ((this_hdr->sh_flags & SHF_TLS) == 0
                          || p->p_type == PT_TLS))))
            {
-             bfd_signed_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
-
-             if (adjust < 0)
+             bfd_vma p_start = p->p_paddr;
+             bfd_vma p_end = p_start + p->p_memsz;
+             bfd_vma s_start = sec->lma;
+             bfd_vma adjust = s_start - p_end;
+
+             if (adjust != 0
+                 && (s_start < p_end
+                     || p_end < p_start))
                {
                  (*_bfd_error_handler)
-                   (_("%B: section %A vma 0x%lx overlaps previous sections"),
-                    abfd, sec, (unsigned long) sec->vma);
+                   (_("%B: section %A lma %#lx adjusted to %#lx"), abfd, sec,
+                    (unsigned long) s_start, (unsigned long) p_end);
                  adjust = 0;
+                 sec->lma = p_end;
                }
              p->p_memsz += adjust;
 
              if (this_hdr->sh_type != SHT_NOBITS)
                {
+                 if (p->p_filesz + adjust < p->p_memsz)
+                   {
+                     /* We have a PROGBITS section following NOBITS ones.
+                        Allocate file space for the NOBITS section(s) and
+                        zero it.  */
+                     adjust = p->p_memsz - p->p_filesz;
+                     if (!write_zeros (abfd, off, adjust))
+                       return FALSE;
+                   }
                  off += adjust;
                  p->p_filesz += adjust;
                }
@@ -4468,6 +4724,21 @@ assign_file_positions_for_load_sections (bfd *abfd,
                  if (this_hdr->sh_type != SHT_NOBITS)
                    off += this_hdr->sh_size;
                }
+             else if (this_hdr->sh_type == SHT_NOBITS
+                      && (this_hdr->sh_flags & SHF_TLS) != 0
+                      && this_hdr->sh_offset == 0)
+               {
+                 /* This is a .tbss section that didn't get a PT_LOAD.
+                    (See _bfd_elf_map_sections_to_segments "Create a
+                    final PT_LOAD".)  Set sh_offset to the value it
+                    would have if we had created a zero p_filesz and
+                    p_memsz PT_LOAD header for the section.  This
+                    also makes the PT_TLS header have the same
+                    p_offset value.  */
+                 bfd_vma adjust = vma_page_aligned_bias (this_hdr->sh_addr,
+                                                         off, align);
+                 this_hdr->sh_offset = sec->filepos = off + adjust;
+               }
 
              if (this_hdr->sh_type != SHT_NOBITS)
                {
@@ -4510,24 +4781,38 @@ assign_file_positions_for_load_sections (bfd *abfd,
       /* Check that all sections are in a PT_LOAD segment.
         Don't check funky gdb generated core files.  */
       if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core)
-       for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
-         {
-           Elf_Internal_Shdr *this_hdr;
-           asection *sec;
-
-           sec = *secpp;
-           this_hdr = &(elf_section_data(sec)->this_hdr);
-           if (this_hdr->sh_size != 0
-               && !ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, p))
+       {
+         bfd_boolean check_vma = TRUE;
+
+         for (i = 1; i < m->count; i++)
+           if (m->sections[i]->vma == m->sections[i - 1]->vma
+               && ELF_SECTION_SIZE (&(elf_section_data (m->sections[i])
+                                      ->this_hdr), p) != 0
+               && ELF_SECTION_SIZE (&(elf_section_data (m->sections[i - 1])
+                                      ->this_hdr), p) != 0)
              {
-               (*_bfd_error_handler)
-                 (_("%B: section `%A' can't be allocated in segment %d"),
-                  abfd, sec, j);
-               print_segment_map (m);
-               bfd_set_error (bfd_error_bad_value);
-               return FALSE;
+               /* Looks like we have overlays packed into the segment.  */
+               check_vma = FALSE;
+               break;
              }
-         }
+
+         for (i = 0; i < m->count; i++)
+           {
+             Elf_Internal_Shdr *this_hdr;
+             asection *sec;
+
+             sec = m->sections[i];
+             this_hdr = &(elf_section_data(sec)->this_hdr);
+             if (!ELF_SECTION_IN_SEGMENT_1 (this_hdr, p, check_vma, 0)
+                 && !ELF_TBSS_SPECIAL (this_hdr, p))
+               {
+                 (*_bfd_error_handler)
+                   (_("%B: section `%A' can't be allocated in segment %d"),
+                    abfd, sec, j);
+                 print_segment_map (m);
+               }
+           }
+       }
     }
 
   elf_tdata (abfd)->next_file_pos = off;
@@ -4546,6 +4831,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   struct elf_segment_map *m;
+  struct elf_segment_map *hdrs_segment;
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   file_ptr off;
@@ -4570,12 +4856,12 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
       else if ((hdr->sh_flags & SHF_ALLOC) != 0)
        {
          if (hdr->sh_size != 0)
-           ((*_bfd_error_handler)
-            (_("%B: warning: allocated section `%s' not in segment"),
-             abfd,
-             (hdr->bfd_section == NULL
-              ? "*unknown*"
-              : hdr->bfd_section->name)));
+           (*_bfd_error_handler)
+             (_("%B: warning: allocated section `%s' not in segment"),
+              abfd,
+              (hdr->bfd_section == NULL
+               ? "*unknown*"
+               : hdr->bfd_section->name));
          /* We don't need to page align empty sections.  */
          if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0)
            off += vma_page_aligned_bias (hdr->sh_addr, off,
@@ -4603,6 +4889,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   filehdr_paddr = 0;
   phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
   phdrs_paddr = 0;
+  hdrs_segment = NULL;
   phdrs = elf_tdata (abfd)->phdr;
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
@@ -4623,12 +4910,59 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
          phdrs_paddr = p->p_paddr;
          if (m->includes_filehdr)
            {
+             hdrs_segment = m;
              phdrs_vaddr += bed->s->sizeof_ehdr;
              phdrs_paddr += bed->s->sizeof_ehdr;
            }
        }
     }
 
+  if (hdrs_segment != NULL && link_info != NULL)
+    {
+      /* There is a segment that contains both the file headers and the
+        program headers, so provide a symbol __ehdr_start pointing there.
+        A program can use this to examine itself robustly.  */
+
+      struct elf_link_hash_entry *hash
+       = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+                               FALSE, FALSE, TRUE);
+      /* If the symbol was referenced and not defined, define it.  */
+      if (hash != NULL
+         && (hash->root.type == bfd_link_hash_new
+             || hash->root.type == bfd_link_hash_undefined
+             || hash->root.type == bfd_link_hash_undefweak
+             || hash->root.type == bfd_link_hash_common))
+       {
+         asection *s = NULL;
+         if (hdrs_segment->count != 0)
+           /* The segment contains sections, so use the first one.  */
+           s = hdrs_segment->sections[0];
+         else
+           /* Use the first (i.e. lowest-addressed) section in any segment.  */
+           for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+             if (m->count != 0)
+               {
+                 s = m->sections[0];
+                 break;
+               }
+
+         if (s != NULL)
+           {
+             hash->root.u.def.value = filehdr_vaddr - s->vma;
+             hash->root.u.def.section = s;
+           }
+         else
+           {
+             hash->root.u.def.value = filehdr_vaddr;
+             hash->root.u.def.section = bfd_abs_section_ptr;
+           }
+
+         hash->root.type = bfd_link_hash_defined;
+         hash->def_regular = 1;
+         hash->non_elf = 0;
+       }
+    }
+
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
        m = m->next, p++)
@@ -4636,21 +4970,27 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
       if (p->p_type == PT_GNU_RELRO)
        {
          const Elf_Internal_Phdr *lp;
-
-         BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+         struct elf_segment_map *lm;
 
          if (link_info != NULL)
            {
              /* During linking the range of the RELRO segment is passed
                 in link_info.  */
-             for (lp = phdrs; lp < phdrs + count; ++lp)
+             for (lm = elf_tdata (abfd)->segment_map, lp = phdrs;
+                  lm != NULL;
+                  lm = lm->next, lp++)
                {
                  if (lp->p_type == PT_LOAD
-                     && lp->p_vaddr >= link_info->relro_start
                      && lp->p_vaddr < link_info->relro_end
-                     && lp->p_vaddr + lp->p_filesz >= link_info->relro_end)
+                     && lp->p_vaddr + lp->p_filesz >= link_info->relro_end
+                     && lm->count != 0
+                     && lm->sections[0]->vma >= link_info->relro_start)
                    break;
                }
+
+             /* PR ld/14207.  If the RELRO segment doesn't fit in the
+                LOAD segment, it should be removed.  */
+             BFD_ASSERT (lm != NULL);
            }
          else
            {
@@ -4676,8 +5016,15 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
              else
                abort ();
              p->p_memsz = p->p_filesz;
-             p->p_align = 1;
-             p->p_flags = (lp->p_flags & ~PF_W);
+             /* Preserve the alignment and flags if they are valid. The
+                gold linker generates RW/4 for the PT_GNU_RELRO section.
+                It is better for objcopy/strip to honor these attributes
+                otherwise gdb will choke when using separate debug files.
+              */
+             if (!m->p_align_valid)
+               p->p_align = 1;
+             if (!m->p_flags_valid)
+               p->p_flags = (lp->p_flags & ~PF_W);
            }
          else
            {
@@ -4685,23 +5032,32 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
              p->p_type = PT_NULL;
            }
        }
+      else if (p->p_type == PT_GNU_STACK)
+       {
+         if (m->p_size_valid)
+           p->p_memsz = m->p_size;
+       }
       else if (m->count != 0)
        {
          if (p->p_type != PT_LOAD
              && (p->p_type != PT_NOTE
                  || bfd_get_format (abfd) != bfd_core))
            {
-             Elf_Internal_Shdr *hdr;
-             asection *sect;
-
              BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
 
-             sect = m->sections[m->count - 1];
-             hdr = &elf_section_data (sect)->this_hdr;
-             p->p_filesz = sect->filepos - m->sections[0]->filepos;
-             if (hdr->sh_type != SHT_NOBITS)
-               p->p_filesz += hdr->sh_size;
+             p->p_filesz = 0;
              p->p_offset = m->sections[0]->filepos;
+             for (i = m->count; i-- != 0;)
+               {
+                 asection *sect = m->sections[i];
+                 Elf_Internal_Shdr *hdr = &elf_section_data (sect)->this_hdr;
+                 if (hdr->sh_type != SHT_NOBITS)
+                   {
+                     p->p_filesz = (sect->filepos - m->sections[0]->filepos
+                                    + hdr->sh_size);
+                     break;
+                   }
+               }
            }
        }
       else if (m->includes_filehdr)
@@ -4818,8 +5174,7 @@ assign_file_positions_except_relocs (bfd *abfd,
 static bfd_boolean
 prep_headers (bfd *abfd)
 {
-  Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
-  Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
+  Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form.  */
   struct elf_strtab_hash *shstrtab;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
@@ -4887,7 +5242,6 @@ prep_headers (bfd *abfd)
   else
     {
       i_ehdrp->e_phentsize = 0;
-      i_phdrp = 0;
       i_ehdrp->e_phoff = 0;
     }
 
@@ -4935,7 +5289,6 @@ bfd_boolean
 _bfd_elf_write_object_contents (bfd *abfd)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  Elf_Internal_Ehdr *i_ehdrp;
   Elf_Internal_Shdr **i_shdrp;
   bfd_boolean failed;
   unsigned int count, num_sec;
@@ -4945,7 +5298,6 @@ _bfd_elf_write_object_contents (bfd *abfd)
     return FALSE;
 
   i_shdrp = elf_elfsections (abfd);
-  i_ehdrp = elf_elfheader (abfd);
 
   failed = FALSE;
   bfd_map_over_sections (abfd, bed->s->write_relocs, &failed);
@@ -5003,34 +5355,34 @@ unsigned int
 _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
 {
   const struct elf_backend_data *bed;
-  unsigned int index;
+  unsigned int sec_index;
 
   if (elf_section_data (asect) != NULL
       && elf_section_data (asect)->this_idx != 0)
     return elf_section_data (asect)->this_idx;
 
   if (bfd_is_abs_section (asect))
-    index = SHN_ABS;
+    sec_index = SHN_ABS;
   else if (bfd_is_com_section (asect))
-    index = SHN_COMMON;
+    sec_index = SHN_COMMON;
   else if (bfd_is_und_section (asect))
-    index = SHN_UNDEF;
+    sec_index = SHN_UNDEF;
   else
-    index = SHN_BAD;
+    sec_index = SHN_BAD;
 
   bed = get_elf_backend_data (abfd);
   if (bed->elf_backend_section_from_bfd_section)
     {
-      int retval = index;
+      int retval = sec_index;
 
       if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval))
        return retval;
     }
 
-  if (index == SHN_BAD)
+  if (sec_index == SHN_BAD)
     bfd_set_error (bfd_error_nonrepresentable_section);
 
-  return index;
+  return sec_index;
 }
 
 /* Given a BFD symbol, return the index in the ELF symbol table, or -1
@@ -5080,9 +5432,8 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
 #if DEBUG & 4
   {
     fprintf (stderr,
-            "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n",
-            (long) asym_ptr, asym_ptr->name, idx, flags,
-            elf_symbol_flags (flags));
+            "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx\n",
+            (long) asym_ptr, asym_ptr->name, idx, (long) flags);
     fflush (stderr);
   }
 #endif
@@ -5178,7 +5529,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        1. It is within the address space of the segment -- we use the LMA
          if that is set for the segment and the VMA otherwise,
        2. It is an allocated section or a NOTE section in a PT_NOTE
-         segment.         
+         segment.
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.
        5. PT_GNU_STACK segments do not include any sections.
@@ -5365,7 +5716,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
         all of the sections we have selected.  */
       amt = sizeof (struct elf_segment_map);
       amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-      map = bfd_zalloc (obfd, amt);
+      map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
       if (map == NULL)
        return FALSE;
 
@@ -5449,7 +5800,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
         pointers that we are interested in.  As these sections get assigned
         to a segment, they are removed from this array.  */
 
-      sections = bfd_malloc2 (section_count, sizeof (asection *));
+      sections = (asection **) bfd_malloc2 (section_count, sizeof (asection *));
       if (sections == NULL)
        return FALSE;
 
@@ -5695,7 +6046,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                 and carry on looping.  */
              amt = sizeof (struct elf_segment_map);
              amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-             map = bfd_alloc (obfd, amt);
+             map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
              if (map == NULL)
                {
                  free (sections);
@@ -5793,7 +6144,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       bfd_size_type amt;
       Elf_Internal_Shdr *this_hdr;
       asection *first_section = NULL;
-      asection *lowest_section = NULL;
+      asection *lowest_section;
 
       /* Compute how many sections are in this segment.  */
       for (section = ibfd->sections, section_count = 0;
@@ -5801,12 +6152,10 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
           section = section->next)
        {
          this_hdr = &(elf_section_data(section)->this_hdr);
-         if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+         if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
            {
-             if (!first_section)
-               first_section = lowest_section = section;
-             if (section->lma < lowest_section->lma)
-               lowest_section = section;
+             if (first_section == NULL)
+               first_section = section;
              section_count++;
            }
        }
@@ -5816,7 +6165,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       amt = sizeof (struct elf_segment_map);
       if (section_count != 0)
        amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-      map = bfd_zalloc (obfd, amt);
+      map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
       if (map == NULL)
        return FALSE;
 
@@ -5832,12 +6181,15 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       map->p_align_valid = 1;
       map->p_vaddr_offset = 0;
 
-      if (map->p_type == PT_GNU_RELRO)
+      if (map->p_type == PT_GNU_RELRO
+         || map->p_type == PT_GNU_STACK)
        {
          /* The PT_GNU_RELRO segment may contain the first a few
             bytes in the .got.plt section even if the whole .got.plt
             section isn't in the PT_GNU_RELRO segment.  We won't
-            change the size of the PT_GNU_RELRO segment.  */
+            change the size of the PT_GNU_RELRO segment.
+            Similarly, PT_GNU_STACK size is significant on uclinux
+            systems.    */
          map->p_size = segment->p_memsz;
          map->p_size_valid = 1;
        }
@@ -5860,17 +6212,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            phdr_included = TRUE;
        }
 
-      if (map->includes_filehdr && first_section)
-       /* We need to keep the space used by the headers fixed.  */
-       map->header_size = first_section->vma - segment->p_vaddr;
-      
-      if (!map->includes_phdrs
-         && !map->includes_filehdr
-         && map->p_paddr_valid)
-       /* There is some other padding before the first section.  */
-       map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
-                              - segment->p_paddr);
-
+      lowest_section = first_section;
       if (section_count != 0)
        {
          unsigned int isec = 0;
@@ -5880,15 +6222,44 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
               section = section->next)
            {
              this_hdr = &(elf_section_data(section)->this_hdr);
-             if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+             if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
                {
                  map->sections[isec++] = section->output_section;
+                 if (section->lma < lowest_section->lma)
+                   lowest_section = section;
+                 if ((section->flags & SEC_ALLOC) != 0)
+                   {
+                     bfd_vma seg_off;
+
+                     /* Section lmas are set up from PT_LOAD header
+                        p_paddr in _bfd_elf_make_section_from_shdr.
+                        If this header has a p_paddr that disagrees
+                        with the section lma, flag the p_paddr as
+                        invalid.  */
+                     if ((section->flags & SEC_LOAD) != 0)
+                       seg_off = this_hdr->sh_offset - segment->p_offset;
+                     else
+                       seg_off = this_hdr->sh_addr - segment->p_vaddr;
+                     if (section->lma - segment->p_paddr != seg_off)
+                       map->p_paddr_valid = FALSE;
+                   }
                  if (isec == section_count)
                    break;
                }
            }
        }
 
+      if (map->includes_filehdr && lowest_section != NULL)
+       /* We need to keep the space used by the headers fixed.  */
+       map->header_size = lowest_section->vma - segment->p_vaddr;
+
+      if (!map->includes_phdrs
+         && !map->includes_filehdr
+         && map->p_paddr_valid)
+       /* There is some other padding before the first section.  */
+       map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
+                              - segment->p_paddr);
+
       map->count = section_count;
       *pointer_to_map = map;
       pointer_to_map = &map->next;
@@ -5957,7 +6328,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
              /* Check if this section is covered by the segment.  */
              this_hdr = &(elf_section_data(section)->this_hdr);
-             if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+             if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
                {
                  /* FIXME: Check if its output section is changed or
                     removed.  What else do we need to check?  */
@@ -5988,6 +6359,26 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
     }
 
 rewrite:
+  if (ibfd->xvec == obfd->xvec)
+    {
+      /* When rewriting program header, set the output maxpagesize to
+        the maximum alignment of input PT_LOAD segments.  */
+      Elf_Internal_Phdr *segment;
+      unsigned int i;
+      unsigned int num_segments = elf_elfheader (ibfd)->e_phnum;
+      bfd_vma maxpagesize = 0;
+
+      for (i = 0, segment = elf_tdata (ibfd)->phdr;
+          i < num_segments;
+          i++, segment++)
+       if (segment->p_type == PT_LOAD
+           && maxpagesize < segment->p_align)
+         maxpagesize = segment->p_align;
+
+      if (maxpagesize != get_elf_backend_data (obfd)->maxpagesize)
+       bfd_emul_set_maxpagesize (bfd_get_target (obfd), maxpagesize);
+    }
+
   return rewrite_elf_program_header (ibfd, obfd);
 }
 
@@ -6002,18 +6393,23 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
 
 {
   Elf_Internal_Shdr *ihdr, *ohdr;
-  bfd_boolean need_group = link_info == NULL || link_info->relocatable;
+  bfd_boolean final_link = link_info != NULL && !link_info->relocatable;
 
   if (ibfd->xvec->flavour != bfd_target_elf_flavour
       || obfd->xvec->flavour != bfd_target_elf_flavour)
     return TRUE;
 
-  /* Don't copy the output ELF section type from input if the
-     output BFD section flags have been set to something different.
-     elf_fake_sections will set ELF section type based on BFD
-     section flags.  */
+  BFD_ASSERT (elf_section_data (osec) != NULL);
+
+  /* For objcopy and relocatable link, don't copy the output ELF
+     section type from input if the output BFD section flags have been
+     set to something different.  For a final link allow some flags
+     that the linker clears to differ.  */
   if (elf_section_type (osec) == SHT_NULL
-      && (osec->flags == isec->flags || !osec->flags))
+      && (osec->flags == isec->flags
+         || (final_link
+             && ((osec->flags ^ isec->flags)
+                 & ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC)) == 0)))
     elf_section_type (osec) = elf_section_type (isec);
 
   /* FIXME: Is this correct for all OS/PROC specific flags?  */
@@ -6024,7 +6420,7 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
      SHT_GROUP section will have its elf_next_in_group pointing back
      to the input group members.  Ignore linker created group section.
      See elfNN_ia64_object_p in elfxx-ia64.c.  */
-  if (need_group)
+  if (!final_link)
     {
       if (elf_sec_group (isec) == NULL
          || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0)
@@ -6083,52 +6479,92 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
                                             NULL);
 }
 
-/* Copy private header information.  */
+/* Look at all the SHT_GROUP sections in IBFD, making any adjustments
+   necessary if we are removing either the SHT_GROUP section or any of
+   the group member sections.  DISCARDED is the value that a section's
+   output_section has if the section will be discarded, NULL when this
+   function is called from objcopy, bfd_abs_section_ptr when called
+   from the linker.  */
 
 bfd_boolean
-_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+_bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded)
 {
   asection *isec;
 
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
-
-  /* Copy over private BFD data if it has not already been copied.
-     This must be done here, rather than in the copy_private_bfd_data
-     entry point, because the latter is called after the section
-     contents have been set, which means that the program headers have
-     already been worked out.  */
-  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
-    {
-      if (! copy_private_bfd_data (ibfd, obfd))
-       return FALSE;
-    }
-
-  /* _bfd_elf_copy_private_section_data copied over the SHF_GROUP flag
-     but this might be wrong if we deleted the group section.  */
   for (isec = ibfd->sections; isec != NULL; isec = isec->next)
-    if (elf_section_type (isec) == SHT_GROUP
-       && isec->output_section == NULL)
+    if (elf_section_type (isec) == SHT_GROUP)
       {
        asection *first = elf_next_in_group (isec);
        asection *s = first;
+       bfd_size_type removed = 0;
+
        while (s != NULL)
          {
-           if (s->output_section != NULL)
+           /* If this member section is being output but the
+              SHT_GROUP section is not, then clear the group info
+              set up by _bfd_elf_copy_private_section_data.  */
+           if (s->output_section != discarded
+               && isec->output_section == discarded)
              {
                elf_section_flags (s->output_section) &= ~SHF_GROUP;
                elf_group_name (s->output_section) = NULL;
              }
+           /* Conversely, if the member section is not being output
+              but the SHT_GROUP section is, then adjust its size.  */
+           else if (s->output_section == discarded
+                    && isec->output_section != discarded)
+             removed += 4;
            s = elf_next_in_group (s);
            if (s == first)
              break;
          }
+       if (removed != 0)
+         {
+           if (discarded != NULL)
+             {
+               /* If we've been called for ld -r, then we need to
+                  adjust the input section size.  This function may
+                  be called multiple times, so save the original
+                  size.  */
+               if (isec->rawsize == 0)
+                 isec->rawsize = isec->size;
+               isec->size = isec->rawsize - removed;
+             }
+           else
+             {
+               /* Adjust the output section size when called from
+                  objcopy. */
+               isec->output_section->size -= removed;
+             }
+         }
       }
 
   return TRUE;
 }
 
+/* Copy private header information.  */
+
+bfd_boolean
+_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Copy over private BFD data if it has not already been copied.
+     This must be done here, rather than in the copy_private_bfd_data
+     entry point, because the latter is called after the section
+     contents have been set, which means that the program headers have
+     already been worked out.  */
+  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
+    {
+      if (! copy_private_bfd_data (ibfd, obfd))
+       return FALSE;
+    }
+
+  return _bfd_elf_fixup_group_sections (ibfd, NULL);
+}
+
 /* Copy private symbol information.  If this symbol is in a section
    which we did not map into a BFD section, try to map the section
    index correctly.  We use special macro definitions for the mapped
@@ -6220,7 +6656,8 @@ swap_out_syms (bfd *abfd,
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
 
-  outbound_syms = bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym);
+  outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount,
+                                           bed->s->sizeof_sym);
   if (outbound_syms == NULL)
     {
       _bfd_stringtab_free (stt);
@@ -6233,8 +6670,8 @@ swap_out_syms (bfd *abfd,
   if (symtab_shndx_hdr->sh_name != 0)
     {
       amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
-      outbound_shndx = bfd_zalloc2 (abfd, 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)
        {
          _bfd_stringtab_free (stt);
@@ -6258,6 +6695,7 @@ swap_out_syms (bfd *abfd,
     sym.st_info = 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;
     if (outbound_shndx != NULL)
@@ -6355,6 +6793,7 @@ swap_out_syms (bfd *abfd,
                  shndx = elf_tdata (abfd)->symtab_shndx_section;
                  break;
                default:
+                 shndx = SHN_ABS;
                  break;
                }
            }
@@ -6457,9 +6896,16 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
        }
 
       if (type_ptr != NULL)
-       sym.st_other = type_ptr->internal_elf_sym.st_other;
+       {
+         sym.st_other = type_ptr->internal_elf_sym.st_other;
+         sym.st_target_internal
+           = type_ptr->internal_elf_sym.st_target_internal;
+       }
       else
-       sym.st_other = 0;
+       {
+         sym.st_other = 0;
+         sym.st_target_internal = 0;
+       }
 
       bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
       outbound_syms += bed->s->sizeof_sym;
@@ -6672,14 +7118,14 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver)
 
       hdr = &elf_tdata (abfd)->dynverref_hdr;
 
-      elf_tdata (abfd)->verref = bfd_zalloc2 (abfd, hdr->sh_info,
-                                             sizeof (Elf_Internal_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;
 
       elf_tdata (abfd)->cverrefs = hdr->sh_info;
 
-      contents = bfd_malloc (hdr->sh_size);
+      contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
       if (contents == NULL)
        {
 error_return_verref:
@@ -6719,8 +7165,9 @@ error_return_verref:
            iverneed->vn_auxptr = NULL;
          else
            {
-             iverneed->vn_auxptr = bfd_alloc2 (abfd, iverneed->vn_cnt,
-                                               sizeof (Elf_Internal_Vernaux));
+             iverneed->vn_auxptr = (struct elf_internal_vernaux *)
+                  bfd_alloc2 (abfd, iverneed->vn_cnt,
+                              sizeof (Elf_Internal_Vernaux));
              if (iverneed->vn_auxptr == NULL)
                goto error_return_verref;
            }
@@ -6788,7 +7235,7 @@ error_return_verref:
 
       hdr = &elf_tdata (abfd)->dynverdef_hdr;
 
-      contents = bfd_malloc (hdr->sh_size);
+      contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
       if (contents == NULL)
        goto error_return;
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
@@ -6832,8 +7279,8 @@ error_return_verref:
          else
            freeidx = ++maxidx;
        }
-      elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, maxidx,
-                                             sizeof (Elf_Internal_Verdef));
+      elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *)
+          bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef));
       if (elf_tdata (abfd)->verdef == NULL)
        goto error_return;
 
@@ -6866,8 +7313,9 @@ error_return_verdef:
            iverdef->vd_auxptr = NULL;
          else
            {
-             iverdef->vd_auxptr = bfd_alloc2 (abfd, iverdef->vd_cnt,
-                                              sizeof (Elf_Internal_Verdaux));
+             iverdef->vd_auxptr = (struct elf_internal_verdaux *)
+                  bfd_alloc2 (abfd, iverdef->vd_cnt,
+                              sizeof (Elf_Internal_Verdaux));
              if (iverdef->vd_auxptr == NULL)
                goto error_return_verdef;
            }
@@ -6924,8 +7372,8 @@ error_return_verdef:
       else
        freeidx++;
 
-      elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, freeidx,
-                                             sizeof (Elf_Internal_Verdef));
+      elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *)
+          bfd_zalloc2 (abfd, freeidx, sizeof (Elf_Internal_Verdef));
       if (elf_tdata (abfd)->verdef == NULL)
        goto error_return;
 
@@ -6938,7 +7386,7 @@ error_return_verdef:
       Elf_Internal_Verdef *iverdef;
       Elf_Internal_Verdaux *iverdaux;
 
-      iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];;
+      iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];
 
       iverdef->vd_version = VER_DEF_CURRENT;
       iverdef->vd_flags = 0;
@@ -6951,7 +7399,8 @@ error_return_verdef:
       if (iverdef->vd_nodename == NULL)
        goto error_return_verdef;
       iverdef->vd_nextdef = NULL;
-      iverdef->vd_auxptr = bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux));
+      iverdef->vd_auxptr = (struct elf_internal_verdaux *)
+          bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux));
       if (iverdef->vd_auxptr == NULL)
        goto error_return_verdef;
 
@@ -6974,7 +7423,7 @@ _bfd_elf_make_empty_symbol (bfd *abfd)
   elf_symbol_type *newsym;
   bfd_size_type amt = sizeof (elf_symbol_type);
 
-  newsym = bfd_zalloc (abfd, amt);
+  newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt);
   if (!newsym)
     return NULL;
   else
@@ -7055,71 +7504,94 @@ elf_find_function (bfd *abfd,
                   const char **filename_ptr,
                   const char **functionname_ptr)
 {
-  const char *filename;
-  asymbol *func, *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);
+  struct elf_find_function_cache
+  {
+    asection *last_section;
+    asymbol *func;
+    const char *filename;
+    bfd_size_type func_size;
+  } *cache;
 
-  filename = NULL;
-  func = NULL;
-  file = NULL;
-  low_func = 0;
-  state = nothing_seen;
+  if (symbols == NULL)
+    return FALSE;
 
-  for (p = symbols; *p != NULL; p++)
+  cache = elf_tdata (abfd)->elf_find_function_cache;
+  if (cache == NULL)
     {
-      elf_symbol_type *q;
-      unsigned int type;
+      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;
 
-      q = (elf_symbol_type *) *p;
+         if ((sym->flags & BSF_FILE) != 0)
+           {
+             file = sym;
+             if (state == symbol_seen)
+               state = file_after_symbol_seen;
+             continue;
+           }
 
-      type = ELF_ST_TYPE (q->internal_elf_sym.st_info);
-      switch (type)
-       {
-       case STT_FILE:
-         file = &q->symbol;
-         if (state == symbol_seen)
-           state = file_after_symbol_seen;
-         continue;
-       default:
-         if (!bed->is_function_type (type))
-           break;
-       case STT_NOTYPE:
-         if (bfd_get_section (&q->symbol) == section
-             && q->symbol.value >= low_func
-             && q->symbol.value <= offset)
+         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)))
            {
-             func = (asymbol *) q;
-             low_func = q->symbol.value;
-             filename = NULL;
+             cache->func = sym;
+             cache->func_size = size;
+             cache->filename = NULL;
+             low_func = code_off;
              if (file != NULL
-                 && (ELF_ST_BIND (q->internal_elf_sym.st_info) == STB_LOCAL
+                 && ((sym->flags & BSF_LOCAL) != 0
                      || state != file_after_symbol_seen))
-               filename = bfd_asymbol_name (file);
+               cache->filename = bfd_asymbol_name (file);
            }
-         break;
+         if (state == nothing_seen)
+           state = symbol_seen;
        }
-      if (state == nothing_seen)
-       state = symbol_seen;
     }
 
-  if (func == NULL)
+  if (cache->func == NULL)
     return FALSE;
 
   if (filename_ptr)
-    *filename_ptr = filename;
+    *filename_ptr = cache->filename;
   if (functionname_ptr)
-    *functionname_ptr = bfd_asymbol_name (func);
+    *functionname_ptr = bfd_asymbol_name (cache->func);
 
   return TRUE;
 }
@@ -7135,6 +7607,23 @@ _bfd_elf_find_nearest_line (bfd *abfd,
                            const char **filename_ptr,
                            const char **functionname_ptr,
                            unsigned int *line_ptr)
+{
+  return _bfd_elf_find_nearest_line_discriminator (abfd, section, symbols,
+                                                   offset, filename_ptr,
+                                                   functionname_ptr,
+                                                   line_ptr,
+                                                   NULL);
+}
+
+bfd_boolean
+_bfd_elf_find_nearest_line_discriminator (bfd *abfd,
+                                          asection *section,
+                                          asymbol **symbols,
+                                          bfd_vma offset,
+                                          const char **filename_ptr,
+                                          const char **functionname_ptr,
+                                          unsigned int *line_ptr,
+                                          unsigned int *discriminator_ptr)
 {
   bfd_boolean found;
 
@@ -7150,9 +7639,10 @@ _bfd_elf_find_nearest_line (bfd *abfd,
       return TRUE;
     }
 
-  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+  if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
+                                     section, symbols, offset,
                                     filename_ptr, functionname_ptr,
-                                    line_ptr, 0,
+                                    line_ptr, discriminator_ptr, 0,
                                     &elf_tdata (abfd)->dwarf2_find_line_info))
     {
       if (!*functionname_ptr)
@@ -7187,9 +7677,20 @@ _bfd_elf_find_nearest_line (bfd *abfd,
 bfd_boolean
 _bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
                    const char **filename_ptr, unsigned int *line_ptr)
+{
+  return _bfd_elf_find_line_discriminator (abfd, symbols, symbol,
+                                          filename_ptr, line_ptr,
+                                           NULL);
+}
+
+bfd_boolean
+_bfd_elf_find_line_discriminator (bfd *abfd, asymbol **symbols, asymbol *symbol,
+                                  const char **filename_ptr,
+                                  unsigned int *line_ptr,
+                                  unsigned int *discriminator_ptr)
 {
   return _bfd_dwarf2_find_line (abfd, symbols, symbol,
-                               filename_ptr, line_ptr, 0,
+                               filename_ptr, line_ptr, discriminator_ptr, 0,
                                &elf_tdata (abfd)->dwarf2_find_line_info);
 }
 
@@ -7371,11 +7872,12 @@ _bfd_elf_validate_reloc (bfd *abfd, arelent *areloc)
 bfd_boolean
 _bfd_elf_close_and_cleanup (bfd *abfd)
 {
-  if (bfd_get_format (abfd) == bfd_object)
+  struct elf_obj_tdata *tdata = elf_tdata (abfd);
+  if (bfd_get_format (abfd) == bfd_object && tdata != NULL)
     {
-      if (elf_tdata (abfd) != NULL && elf_shstrtab (abfd) != NULL)
+      if (elf_shstrtab (abfd) != NULL)
        _bfd_elf_strtab_free (elf_shstrtab (abfd));
-      _bfd_dwarf2_cleanup_debug_info (abfd);
+      _bfd_dwarf2_cleanup_debug_info (abfd, &tdata->dwarf2_find_line_info);
     }
 
   return _bfd_generic_close_and_cleanup (abfd);
@@ -7402,16 +7904,24 @@ _bfd_elf_rel_vtable_reloc_fn
    out details about the corefile.  */
 
 #ifdef HAVE_SYS_PROCFS_H
+/* Needed for new procfs interface on sparc-solaris.  */
+# define _STRUCTURED_PROC 1
 # include <sys/procfs.h>
 #endif
 
-/* FIXME: this is kinda wrong, but it's what gdb wants.  */
+/* Return a PID that identifies a "thread" for threaded cores, or the
+   PID of the main process for non-threaded cores.  */
 
 static int
 elfcore_make_pid (bfd *abfd)
 {
-  return ((elf_tdata (abfd)->core_lwpid << 16)
-         + (elf_tdata (abfd)->core_pid));
+  int pid;
+
+  pid = elf_tdata (abfd)->core_lwpid;
+  if (pid == 0)
+    pid = elf_tdata (abfd)->core_pid;
+
+  return pid;
 }
 
 /* If there isn't a section called NAME, make one, using
@@ -7459,7 +7969,7 @@ _bfd_elfcore_make_pseudosection (bfd *abfd,
 
   sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd));
   len = strlen (buf) + 1;
-  threaded_name = bfd_alloc (abfd, len);
+  threaded_name = (char *) bfd_alloc (abfd, len);
   if (threaded_name == NULL)
     return FALSE;
   memcpy (threaded_name, buf, len);
@@ -7501,7 +8011,8 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
         has already been set by another thread.  */
       if (elf_tdata (abfd)->core_signal == 0)
        elf_tdata (abfd)->core_signal = prstat.pr_cursig;
-      elf_tdata (abfd)->core_pid = prstat.pr_pid;
+      if (elf_tdata (abfd)->core_pid == 0)
+       elf_tdata (abfd)->core_pid = prstat.pr_pid;
 
       /* pr_who exists on:
         solaris 2.5+
@@ -7511,6 +8022,8 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
         */
 #if defined (HAVE_PRSTATUS_T_PR_WHO)
       elf_tdata (abfd)->core_lwpid = prstat.pr_who;
+#else
+      elf_tdata (abfd)->core_lwpid = prstat.pr_pid;
 #endif
     }
 #if defined (HAVE_PRSTATUS32_T)
@@ -7527,7 +8040,8 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
         has already been set by another thread.  */
       if (elf_tdata (abfd)->core_signal == 0)
        elf_tdata (abfd)->core_signal = prstat.pr_cursig;
-      elf_tdata (abfd)->core_pid = prstat.pr_pid;
+      if (elf_tdata (abfd)->core_pid == 0)
+       elf_tdata (abfd)->core_pid = prstat.pr_pid;
 
       /* pr_who exists on:
         solaris 2.5+
@@ -7537,6 +8051,8 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
         */
 #if defined (HAVE_PRSTATUS32_T_PR_WHO)
       elf_tdata (abfd)->core_lwpid = prstat.pr_who;
+#else
+      elf_tdata (abfd)->core_lwpid = prstat.pr_pid;
 #endif
     }
 #endif /* HAVE_PRSTATUS32_T */
@@ -7583,6 +8099,16 @@ elfcore_grok_prxfpreg (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
 }
 
+/* Linux dumps the Intel XSAVE extended state in a note named "LINUX"
+   with a note type of NT_X86_XSTATE.  Just include the whole note's
+   contents literally.  */
+
+static bfd_boolean
+elfcore_grok_xstatereg (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-xstate", note);
+}
+
 static bfd_boolean
 elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -7595,6 +8121,78 @@ elfcore_grok_ppc_vsx (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vsx", note);
 }
 
+static bfd_boolean
+elfcore_grok_s390_high_gprs (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-high-gprs", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_timer (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-timer", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_todcmp (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-todcmp", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_todpreg (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-todpreg", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_ctrs (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-ctrs", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_prefix (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-prefix", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_last_break (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-last-break", note);
+}
+
+static bfd_boolean
+elfcore_grok_s390_system_call (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-s390-system-call", note);
+}
+
+static bfd_boolean
+elfcore_grok_arm_vfp (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-arm-vfp", note);
+}
+
+static bfd_boolean
+elfcore_grok_aarch_tls (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-tls", note);
+}
+
+static bfd_boolean
+elfcore_grok_aarch_hw_break (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-break", note);
+}
+
+static bfd_boolean
+elfcore_grok_aarch_hw_watch (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-aarch-hw-watch", note);
+}
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)                /* Sparc64 cross Sparc32 */
@@ -7617,7 +8215,7 @@ char *
 _bfd_elfcore_strndup (bfd *abfd, char *start, size_t max)
 {
   char *dups;
-  char *end = memchr (start, '\0', max);
+  char *end = (char *) memchr (start, '\0', max);
   size_t len;
 
   if (end == NULL)
@@ -7625,7 +8223,7 @@ _bfd_elfcore_strndup (bfd *abfd, char *start, size_t max)
   else
     len = end - start;
 
-  dups = bfd_alloc (abfd, len + 1);
+  dups = (char *) bfd_alloc (abfd, len + 1);
   if (dups == NULL)
     return NULL;
 
@@ -7645,6 +8243,9 @@ elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 
       memcpy (&psinfo, note->descdata, sizeof (psinfo));
 
+#if defined (HAVE_PSINFO_T_PR_PID) || defined (HAVE_PRPSINFO_T_PR_PID)
+      elf_tdata (abfd)->core_pid = psinfo.pr_pid;
+#endif
       elf_tdata (abfd)->core_program
        = _bfd_elfcore_strndup (abfd, psinfo.pr_fname,
                                sizeof (psinfo.pr_fname));
@@ -7661,6 +8262,9 @@ elfcore_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 
       memcpy (&psinfo, note->descdata, sizeof (psinfo));
 
+#if defined (HAVE_PSINFO32_T_PR_PID) || defined (HAVE_PRPSINFO32_T_PR_PID)
+      elf_tdata (abfd)->core_pid = psinfo.pr_pid;
+#endif
       elf_tdata (abfd)->core_program
        = _bfd_elfcore_strndup (abfd, psinfo.pr_fname,
                                sizeof (psinfo.pr_fname));
@@ -7749,7 +8353,10 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
   memcpy (&lwpstat, note->descdata, sizeof (lwpstat));
 
   elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid;
-  elf_tdata (abfd)->core_signal = lwpstat.pr_cursig;
+  /* Do not overwrite the core signal if it has already been set by
+     another thread.  */
+  if (elf_tdata (abfd)->core_signal == 0)
+    elf_tdata (abfd)->core_signal = lwpstat.pr_cursig;
 
   /* Make a ".reg/999" section.  */
 
@@ -7845,7 +8452,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       sprintf (buf, ".reg/%ld", (long) bfd_get_32 (abfd, note->descdata + 8));
 
       len = strlen (buf) + 1;
-      name = bfd_alloc (abfd, len);
+      name = (char *) bfd_alloc (abfd, len);
       if (name == NULL)
        return FALSE;
 
@@ -7876,7 +8483,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       sprintf (buf, ".module/%08lx", (unsigned long) base_addr);
 
       len = strlen (buf) + 1;
-      name = bfd_alloc (abfd, len);
+      name = (char *) bfd_alloc (abfd, len);
       if (name == NULL)
        return FALSE;
 
@@ -7942,6 +8549,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
        return TRUE;
 
+    case NT_X86_XSTATE:                /* Linux XSAVE extension */
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_xstatereg (abfd, note);
+      else
+       return TRUE;
+
     case NT_PPC_VMX:
       if (note->namesz == 6
          && strcmp (note->namedata, "LINUX") == 0)
@@ -7956,6 +8570,90 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
         return TRUE;
 
+    case NT_S390_HIGH_GPRS:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_high_gprs (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_TIMER:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_timer (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_TODCMP:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_todcmp (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_TODPREG:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_todpreg (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_CTRS:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_ctrs (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_PREFIX:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_prefix (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_LAST_BREAK:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_last_break (abfd, note);
+      else
+        return TRUE;
+
+    case NT_S390_SYSTEM_CALL:
+      if (note->namesz == 6
+          && strcmp (note->namedata, "LINUX") == 0)
+        return elfcore_grok_s390_system_call (abfd, note);
+      else
+        return TRUE;
+
+    case NT_ARM_VFP:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_arm_vfp (abfd, note);
+      else
+       return TRUE;
+
+    case NT_ARM_TLS:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_tls (abfd, note);
+      else
+       return TRUE;
+
+    case NT_ARM_HW_BREAK:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_hw_break (abfd, note);
+      else
+       return TRUE;
+
+    case NT_ARM_HW_WATCH:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_aarch_hw_watch (abfd, note);
+      else
+       return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -7980,6 +8678,14 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
 
        return TRUE;
       }
+
+    case NT_FILE:
+      return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file",
+                                             note);
+
+    case NT_SIGINFO:
+      return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
+                                             note);
     }
 }
 
@@ -7987,7 +8693,7 @@ static bfd_boolean
 elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
 {
   elf_tdata (abfd)->build_id_size = note->descsz;
-  elf_tdata (abfd)->build_id = bfd_alloc (abfd, note->descsz);
+  elf_tdata (abfd)->build_id = (bfd_byte *) bfd_alloc (abfd, note->descsz);
   if (elf_tdata (abfd)->build_id == NULL)
     return FALSE;
 
@@ -8009,6 +8715,35 @@ elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note)
     }
 }
 
+static bfd_boolean
+elfobj_grok_stapsdt_note_1 (bfd *abfd, Elf_Internal_Note *note)
+{
+  struct sdt_note *cur =
+    (struct sdt_note *) bfd_alloc (abfd, sizeof (struct sdt_note)
+                                  + note->descsz);
+
+  cur->next = (struct sdt_note *) (elf_tdata (abfd))->sdt_note_head;
+  cur->size = (bfd_size_type) note->descsz;
+  memcpy (cur->data, note->descdata, note->descsz);
+
+  elf_tdata (abfd)->sdt_note_head = cur;
+
+  return TRUE;
+}
+
+static bfd_boolean
+elfobj_grok_stapsdt_note (bfd *abfd, Elf_Internal_Note *note)
+{
+  switch (note->type)
+    {
+    case NT_STAPSDT:
+      return elfobj_grok_stapsdt_note_1 (abfd, note);
+
+    default:
+      return TRUE;
+    }
+}
+
 static bfd_boolean
 elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
 {
@@ -8206,7 +8941,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid)
   /* Make a ".qnx_core_status/%d" section.  */
   sprintf (buf, ".qnx_core_status/%ld", *tid);
 
-  name = bfd_alloc (abfd, strlen (buf) + 1);
+  name = (char *) bfd_alloc (abfd, strlen (buf) + 1);
   if (name == NULL)
     return FALSE;
   strcpy (name, buf);
@@ -8235,7 +8970,7 @@ elfcore_grok_nto_regs (bfd *abfd,
   /* Make a "(base)/%d" section.  */
   sprintf (buf, "%s/%ld", base, tid);
 
-  name = bfd_alloc (abfd, strlen (buf) + 1);
+  name = (char *) bfd_alloc (abfd, strlen (buf) + 1);
   if (name == NULL)
     return FALSE;
   strcpy (name, buf);
@@ -8292,7 +9027,7 @@ elfcore_grok_spu_note (bfd *abfd, Elf_Internal_Note *note)
 
   /* Use note name as section name.  */
   len = note->namesz;
-  name = bfd_alloc (abfd, len);
+  name = (char *) bfd_alloc (abfd, len);
   if (name == NULL)
     return FALSE;
   memcpy (name, note->namedata, len);
@@ -8346,7 +9081,7 @@ elfcore_write_note (bfd *abfd,
 
   newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4);
 
-  buf = realloc (buf, *bufsiz + newspace);
+  buf = (char *) realloc (buf, *bufsiz + newspace);
   if (buf == NULL)
     return buf;
   dest = buf + *bufsiz;
@@ -8376,7 +9111,6 @@ elfcore_write_note (bfd *abfd,
   return buf;
 }
 
-#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
 char *
 elfcore_write_prpsinfo (bfd  *abfd,
                        char *buf,
@@ -8384,7 +9118,6 @@ elfcore_write_prpsinfo (bfd  *abfd,
                        const char *fname,
                        const char *psargs)
 {
-  const char *note_name = "CORE";
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (bed->elf_backend_write_core_note != NULL)
@@ -8396,6 +9129,7 @@ elfcore_write_prpsinfo (bfd  *abfd,
        return ret;
     }
 
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
 #if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T)
   if (bed->s->elfclass == ELFCLASS32)
     {
@@ -8411,7 +9145,7 @@ elfcore_write_prpsinfo (bfd  *abfd,
       strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
       strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
       return elfcore_write_note (abfd, buf, bufsiz,
-                                note_name, note_type, &data, sizeof (data));
+                                "CORE", note_type, &data, sizeof (data));
     }
   else
 #endif
@@ -8428,12 +9162,42 @@ elfcore_write_prpsinfo (bfd  *abfd,
       strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
       strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
       return elfcore_write_note (abfd, buf, bufsiz,
-                                note_name, note_type, &data, sizeof (data));
+                                "CORE", note_type, &data, sizeof (data));
     }
-}
 #endif /* PSINFO_T or PRPSINFO_T */
 
-#if defined (HAVE_PRSTATUS_T)
+  free (buf);
+  return NULL;
+}
+
+char *
+elfcore_write_linux_prpsinfo32
+  (bfd *abfd, char *buf, int *bufsiz,
+   const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+  struct elf_external_linux_prpsinfo32 data;
+
+  memset (&data, 0, sizeof (data));
+  LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
+
+  return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
+                            &data, sizeof (data));
+}
+
+char *
+elfcore_write_linux_prpsinfo64
+  (bfd *abfd, char *buf, int *bufsiz,
+   const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+  struct elf_external_linux_prpsinfo64 data;
+
+  memset (&data, 0, sizeof (data));
+  LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data);
+
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            "CORE", NT_PRPSINFO, &data, sizeof (data));
+}
+
 char *
 elfcore_write_prstatus (bfd *abfd,
                        char *buf,
@@ -8442,7 +9206,6 @@ elfcore_write_prstatus (bfd *abfd,
                        int cursig,
                        const void *gregs)
 {
-  const char *note_name = "CORE";
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if (bed->elf_backend_write_core_note != NULL)
@@ -8455,6 +9218,7 @@ elfcore_write_prstatus (bfd *abfd,
        return ret;
     }
 
+#if defined (HAVE_PRSTATUS_T)
 #if defined (HAVE_PRSTATUS32_T)
   if (bed->s->elfclass == ELFCLASS32)
     {
@@ -8464,7 +9228,7 @@ elfcore_write_prstatus (bfd *abfd,
       prstat.pr_pid = pid;
       prstat.pr_cursig = cursig;
       memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
-      return elfcore_write_note (abfd, buf, bufsiz, note_name,
+      return elfcore_write_note (abfd, buf, bufsiz, "CORE",
                                 NT_PRSTATUS, &prstat, sizeof (prstat));
     }
   else
@@ -8476,12 +9240,15 @@ elfcore_write_prstatus (bfd *abfd,
       prstat.pr_pid = pid;
       prstat.pr_cursig = cursig;
       memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
-      return elfcore_write_note (abfd, buf, bufsiz, note_name,
+      return elfcore_write_note (abfd, buf, bufsiz, "CORE",
                                 NT_PRSTATUS, &prstat, sizeof (prstat));
     }
-}
 #endif /* HAVE_PRSTATUS_T */
 
+  free (buf);
+  return NULL;
+}
+
 #if defined (HAVE_LWPSTATUS_T)
 char *
 elfcore_write_lwpstatus (bfd *abfd,
@@ -8574,6 +9341,15 @@ elfcore_write_prxfpreg (bfd *abfd,
                             note_name, NT_PRXFPREG, xfpregs, size);
 }
 
+char *
+elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz,
+                        const void *xfpregs, int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_X86_XSTATE, xfpregs, size);
+}
+
 char *
 elfcore_write_ppc_vmx (bfd *abfd,
                       char *buf,
@@ -8598,6 +9374,153 @@ elfcore_write_ppc_vsx (bfd *abfd,
                              note_name, NT_PPC_VSX, ppc_vsx, size);
 }
 
+static char *
+elfcore_write_s390_high_gprs (bfd *abfd,
+                             char *buf,
+                             int *bufsiz,
+                             const void *s390_high_gprs,
+                             int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_HIGH_GPRS,
+                            s390_high_gprs, size);
+}
+
+char *
+elfcore_write_s390_timer (bfd *abfd,
+                          char *buf,
+                          int *bufsiz,
+                          const void *s390_timer,
+                          int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_TIMER, s390_timer, size);
+}
+
+char *
+elfcore_write_s390_todcmp (bfd *abfd,
+                           char *buf,
+                           int *bufsiz,
+                           const void *s390_todcmp,
+                           int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_TODCMP, s390_todcmp, size);
+}
+
+char *
+elfcore_write_s390_todpreg (bfd *abfd,
+                            char *buf,
+                            int *bufsiz,
+                            const void *s390_todpreg,
+                            int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_TODPREG, s390_todpreg, size);
+}
+
+char *
+elfcore_write_s390_ctrs (bfd *abfd,
+                         char *buf,
+                         int *bufsiz,
+                         const void *s390_ctrs,
+                         int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_CTRS, s390_ctrs, size);
+}
+
+char *
+elfcore_write_s390_prefix (bfd *abfd,
+                           char *buf,
+                           int *bufsiz,
+                           const void *s390_prefix,
+                           int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_PREFIX, s390_prefix, size);
+}
+
+char *
+elfcore_write_s390_last_break (bfd *abfd,
+                              char *buf,
+                              int *bufsiz,
+                              const void *s390_last_break,
+                              int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_LAST_BREAK,
+                            s390_last_break, size);
+}
+
+char *
+elfcore_write_s390_system_call (bfd *abfd,
+                               char *buf,
+                               int *bufsiz,
+                               const void *s390_system_call,
+                               int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                             note_name, NT_S390_SYSTEM_CALL,
+                            s390_system_call, size);
+}
+
+char *
+elfcore_write_arm_vfp (bfd *abfd,
+                      char *buf,
+                      int *bufsiz,
+                      const void *arm_vfp,
+                      int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_VFP, arm_vfp, size);
+}
+
+char *
+elfcore_write_aarch_tls (bfd *abfd,
+                      char *buf,
+                      int *bufsiz,
+                      const void *aarch_tls,
+                      int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_TLS, aarch_tls, size);
+}
+
+char *
+elfcore_write_aarch_hw_break (bfd *abfd,
+                           char *buf,
+                           int *bufsiz,
+                           const void *aarch_hw_break,
+                           int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_HW_BREAK, aarch_hw_break, size);
+}
+
+char *
+elfcore_write_aarch_hw_watch (bfd *abfd,
+                           char *buf,
+                           int *bufsiz,
+                           const void *aarch_hw_watch,
+                           int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_ARM_HW_WATCH, aarch_hw_watch, size);
+}
+
 char *
 elfcore_write_register_note (bfd *abfd,
                             char *buf,
@@ -8610,10 +9533,36 @@ elfcore_write_register_note (bfd *abfd,
     return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-xfp") == 0)
     return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-xstate") == 0)
+    return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-ppc-vmx") == 0)
     return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size);
   if (strcmp (section, ".reg-ppc-vsx") == 0)
     return elfcore_write_ppc_vsx (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-high-gprs") == 0)
+    return elfcore_write_s390_high_gprs (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-timer") == 0)
+    return elfcore_write_s390_timer (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-todcmp") == 0)
+    return elfcore_write_s390_todcmp (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-todpreg") == 0)
+    return elfcore_write_s390_todpreg (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-ctrs") == 0)
+    return elfcore_write_s390_ctrs (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-prefix") == 0)
+    return elfcore_write_s390_prefix (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-last-break") == 0)
+    return elfcore_write_s390_last_break (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-s390-system-call") == 0)
+    return elfcore_write_s390_system_call (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)
+    return elfcore_write_aarch_tls (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-aarch-hw-break") == 0)
+    return elfcore_write_aarch_hw_break (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-aarch-hw-watch") == 0)
+    return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size);
   return NULL;
 }
 
@@ -8686,6 +9635,12 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
              if (! elfobj_grok_gnu_note (abfd, &in))
                return FALSE;
            }
+         else if (in.namesz == sizeof "stapsdt"
+                  && strcmp (in.namedata, "stapsdt") == 0)
+           {
+             if (! elfobj_grok_stapsdt_note (abfd, &in))
+               return FALSE;
+           }
          break;
        }
 
@@ -8706,7 +9661,7 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
   if (bfd_seek (abfd, offset, SEEK_SET) != 0)
     return FALSE;
 
-  buf = bfd_malloc (size);
+  buf = (char *) bfd_malloc (size);
   if (buf == NULL)
     return FALSE;
 
@@ -8788,7 +9743,7 @@ _bfd_elf_rela_local_sym (bfd *abfd,
                + sym->st_value);
   if ((sec->flags & SEC_MERGE)
       && ELF_ST_TYPE (sym->st_info) == STT_SECTION
-      && sec->sec_info_type == ELF_INFO_TYPE_MERGE)
+      && sec->sec_info_type == SEC_INFO_TYPE_MERGE)
     {
       rel->r_addend =
        _bfd_merged_section_offset (abfd, psec,
@@ -8819,7 +9774,7 @@ _bfd_elf_rel_local_sym (bfd *abfd,
 {
   asection *sec = *psec;
 
-  if (sec->sec_info_type != ELF_INFO_TYPE_MERGE)
+  if (sec->sec_info_type != SEC_INFO_TYPE_MERGE)
     return sym->st_value + addend;
 
   return _bfd_merged_section_offset (abfd, psec,
@@ -8835,12 +9790,18 @@ _bfd_elf_section_offset (bfd *abfd,
 {
   switch (sec->sec_info_type)
     {
-    case ELF_INFO_TYPE_STABS:
+    case SEC_INFO_TYPE_STABS:
       return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
                                       offset);
-    case ELF_INFO_TYPE_EH_FRAME:
+    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)
+       {
+         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;
+       }
       return offset;
     }
 }
@@ -8863,7 +9824,7 @@ bfd_elf_bfd_from_remote_memory
   (bfd *templ,
    bfd_vma ehdr_vma,
    bfd_vma *loadbasep,
-   int (*target_read_memory) (bfd_vma, bfd_byte *, int))
+   int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type))
 {
   return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
     (templ, ehdr_vma, loadbasep, target_read_memory);
@@ -8936,7 +9897,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
        }
     }
 
-  s = *ret = bfd_malloc (size);
+  s = *ret = (asymbol *) bfd_malloc (size);
   if (s == NULL)
     return -1;
 
@@ -8968,7 +9929,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
       if (p->addend != 0)
        {
          char buf[30], *a;
-         int len;
+
          memcpy (names, "+0x", sizeof ("+0x") - 1);
          names += sizeof ("+0x") - 1;
          bfd_sprintf_vma (abfd, buf, p->addend);
@@ -9002,11 +9963,11 @@ _bfd_elf_set_osabi (bfd * abfd,
   i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
 
   /* To make things simpler for the loader on Linux systems we set the
-     osabi field to ELFOSABI_LINUX if the binary contains symbols of
-     the STT_GNU_IFUNC type.  */
+     osabi field to ELFOSABI_GNU if the binary contains symbols of
+     the STT_GNU_IFUNC type or STB_GNU_UNIQUE binding.  */
   if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE
-      && elf_tdata (abfd)->has_ifunc_symbols)
-    i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+      && elf_tdata (abfd)->has_gnu_symbols)
+    i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_GNU;
 }
 
 
@@ -9020,3 +9981,27 @@ _bfd_elf_is_function_type (unsigned int type)
   return (type == STT_FUNC
          || type == STT_GNU_IFUNC);
 }
+
+/* If the ELF symbol SYM might be a function in SEC, return the
+   function size and set *CODE_OFF to the function's entry point,
+   otherwise return zero.  */
+
+bfd_size_type
+_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+                            bfd_vma *code_off)
+{
+  bfd_size_type size;
+
+  if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+      || sym->section != sec)
+    return 0;
+
+  *code_off = sym->value;
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  if (size == 0)
+    size = 1;
+  return size;
+}
This page took 0.071151 seconds and 4 git commands to generate.