Fix build with -DDEBUG=7
[external/binutils.git] / bfd / elf.c
index a7cc4a5..4df0007 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 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -44,6 +45,10 @@ SECTION
 #include "libiberty.h"
 #include "safe-ctype.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 *);
 static bfd_boolean prep_headers (bfd *);
@@ -231,7 +236,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);
@@ -245,20 +250,21 @@ 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);
 }
 
-char *
+static char *
 bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
 {
   Elf_Internal_Shdr **i_shdrp;
@@ -282,7 +288,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)
@@ -330,7 +336,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;
@@ -358,6 +364,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   const bfd_byte *esym;
   Elf_External_Sym_Shndx *alloc_extshndx;
   Elf_External_Sym_Shndx *shndx;
+  Elf_Internal_Sym *alloc_intsym;
   Elf_Internal_Sym *isym;
   Elf_Internal_Sym *isymend;
   const struct elf_backend_data *bed;
@@ -379,6 +386,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   /* Read the symbols.  */
   alloc_ext = NULL;
   alloc_extshndx = NULL;
+  alloc_intsym = NULL;
   bed = get_elf_backend_data (ibfd);
   extsym_size = bed->s->sizeof_sym;
   amt = symcount * extsym_size;
@@ -404,8 +412,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
@@ -419,14 +427,17 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
   if (intsym_buf == NULL)
     {
-      intsym_buf = 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;
     }
 
   /* 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))
@@ -435,6 +446,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
        (*_bfd_error_handler) (_("%B symbol number %lu references "
                                 "nonexistent SHT_SYMTAB_SHNDX section"),
                               ibfd, (unsigned long) symoffset);
+       if (alloc_intsym != NULL)
+         free (alloc_intsym);
        intsym_buf = NULL;
        goto out;
       }
@@ -558,8 +571,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;
 
@@ -580,8 +593,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)
                    {
@@ -726,18 +739,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"),
@@ -745,7 +758,7 @@ _bfd_elf_setup_sections (bfd *abfd)
                  result = FALSE;
                }
 
-             elf_linked_to_section (s) = link;
+             elf_linked_to_section (s) = linksec;
            }
        }
     }
@@ -864,6 +877,8 @@ _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)
     {
@@ -935,20 +950,12 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
      PT_NOTEs from the core files are currently not parsed using BFD.  */
   if (hdr->sh_type == SHT_NOTE)
     {
-      char *contents;
+      bfd_byte *contents;
 
-      contents = bfd_malloc (hdr->sh_size);
-      if (!contents)
+      if (!bfd_malloc_and_get_section (abfd, newsect, &contents))
        return FALSE;
 
-      if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
-                                    hdr->sh_size)
-         || !elf_parse_notes (abfd, contents, hdr->sh_size, -1))
-       {
-         free (contents);
-         return FALSE;
-       }
-      
+      elf_parse_notes (abfd, (char *) contents, hdr->sh_size, -1);
       free (contents);
     }
 
@@ -973,25 +980,8 @@ _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)))
+             && ELF_SECTION_IN_SEGMENT (hdr, phdr))
            {
              if ((flags & SEC_LOAD) == 0)
                newsect->lma = (phdr->p_paddr
@@ -1022,45 +1012,6 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   return TRUE;
 }
 
-/*
-INTERNAL_FUNCTION
-       bfd_elf_find_section
-
-SYNOPSIS
-       struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name);
-
-DESCRIPTION
-       Helper functions for GDB to locate the string tables.
-       Since BFD hides string tables from callers, GDB needs to use an
-       internal hook to find them.  Sun's .stabstr, in particular,
-       isn't even pointed to by the .stab section, so ordinary
-       mechanisms wouldn't work to find it, even if we had some.
-*/
-
-struct elf_internal_shdr *
-bfd_elf_find_section (bfd *abfd, char *name)
-{
-  Elf_Internal_Shdr **i_shdrp;
-  char *shstrtab;
-  unsigned int max;
-  unsigned int i;
-
-  i_shdrp = elf_elfsections (abfd);
-  if (i_shdrp != NULL)
-    {
-      shstrtab = bfd_elf_get_str_section (abfd,
-                                         elf_elfheader (abfd)->e_shstrndx);
-      if (shstrtab != NULL)
-       {
-         max = elf_numsections (abfd);
-         for (i = 1; i < max; i++)
-           if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name))
-             return i_shdrp[i];
-       }
-    }
-  return 0;
-}
-
 const char *const bfd_elf_section_type_names[] = {
   "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
   "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
@@ -1118,7 +1069,6 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
   /* Copy object attributes.  */
   _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
   return TRUE;
 }
 
@@ -1149,7 +1099,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;
@@ -1392,7 +1342,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:
@@ -1401,7 +1351,7 @@ bfd_elf_print_symbol (bfd *abfd,
     case bfd_print_symbol_more:
       fprintf (file, "elf ");
       bfd_fprintf_vma (abfd, file, symbol->value);
-      fprintf (file, " %lx", (long) symbol->flags);
+      fprintf (file, " %lx", (unsigned long) symbol->flags);
       break;
     case bfd_print_symbol_all:
       {
@@ -1572,10 +1522,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;
 
@@ -1611,6 +1576,8 @@ 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;
       BFD_ASSERT (elf_onesymtab (abfd) == 0);
       elf_onesymtab (abfd) = shindex;
       elf_tdata (abfd)->symtab_hdr = *hdr;
@@ -1743,8 +1710,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
@@ -1767,8 +1736,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
           reject them, but, unfortunately, some people need to use
           them.  We scan through the section headers; if we find only
           one suitable symbol table, we clobber the sh_link to point
-          to it.  I hope this doesn't break anything.  */
-       if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB
+          to it.  I hope this doesn't break anything.
+
+          Don't do it on executable nor shared library.  */
+       if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0
+           && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB
            && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM)
          {
            unsigned int scan;
@@ -1803,8 +1775,10 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
           represent such a section, so at least for now, we don't
           try.  We just present it as a normal section.  We also
           can't use it as a reloc section if it points to the null
-          section, an invalid section, or another reloc section.  */
+          section, an invalid section, another reloc section, or its
+          sh_link points to the null section.  */
        if (hdr->sh_link != elf_onesymtab (abfd)
+           || hdr->sh_link == SHN_UNDEF
            || hdr->sh_info == SHN_UNDEF
            || hdr->sh_info >= num_sec
            || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
@@ -1818,20 +1792,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;
@@ -1840,7 +1813,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;
       }
@@ -1866,14 +1842,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       return TRUE;
 
     case SHT_GROUP:
-      /* We need a BFD section for objcopy and relocatable linking,
-        and it's handy to have the signature available as the section
-        name.  */
       if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
        return FALSE;
-      name = group_signature (abfd, hdr);
-      if (name == NULL)
-       return FALSE;
       if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
        return FALSE;
       if (hdr->contents != NULL)
@@ -1966,28 +1936,24 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
   return TRUE;
 }
 
-/* Return the section for the local symbol specified by ABFD, R_SYMNDX.
-   Return SEC for sections that have no elf section, and NULL on error.  */
+/* Return the local symbol specified by ABFD, R_SYMNDX.  */
 
-asection *
-bfd_section_from_r_symndx (bfd *abfd,
-                          struct sym_sec_cache *cache,
-                          asection *sec,
-                          unsigned long r_symndx)
+Elf_Internal_Sym *
+bfd_sym_from_r_symndx (struct sym_cache *cache,
+                      bfd *abfd,
+                      unsigned long r_symndx)
 {
   unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
-  asection *s;
 
   if (cache->abfd != abfd || cache->indx[ent] != r_symndx)
     {
       Elf_Internal_Shdr *symtab_hdr;
       unsigned char esym[sizeof (Elf64_External_Sym)];
       Elf_External_Sym_Shndx eshndx;
-      Elf_Internal_Sym isym;
 
       symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
       if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
-                               &isym, esym, &eshndx) == NULL)
+                               &cache->sym[ent], esym, &eshndx) == NULL)
        return NULL;
 
       if (cache->abfd != abfd)
@@ -1996,25 +1962,20 @@ bfd_section_from_r_symndx (bfd *abfd,
          cache->abfd = abfd;
        }
       cache->indx[ent] = r_symndx;
-      cache->shndx[ent] = isym.st_shndx;
     }
 
-  s = bfd_section_from_elf_index (abfd, cache->shndx[ent]);
-  if (s != NULL)
-    return s;
-
-  return sec;
+  return &cache->sym[ent];
 }
 
 /* Given an ELF section number, retrieve the corresponding BFD
    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[] =
@@ -2259,7 +2220,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;
@@ -2314,8 +2276,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;
@@ -2329,9 +2291,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);
@@ -2365,9 +2327,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);
@@ -2404,69 +2366,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;
 
-  name = bfd_alloc (abfd, amt);
+  amt = sizeof (Elf_Internal_Shdr);
+  BFD_ASSERT (reldata->hdr == NULL);
+  rel_hdr = bfd_zalloc (abfd, amt);
+  reldata->hdr = rel_hdr;
+
+  amt = sizeof ".rela" + strlen (asect->name);      
+  name = (char *) bfd_alloc (abfd, amt);
   if (name == NULL)
     return FALSE;
   sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
@@ -2488,30 +2473,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;
     }
 
@@ -2537,12 +2540,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;
@@ -2664,12 +2663,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)
     {
@@ -2677,26 +2712,17 @@ 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.  */
+/* Fill in the contents of a SHT_GROUP section.  Called from
+   _bfd_elf_compute_section_file_positions for gas, objcopy, and
+   when ELF targets use the generic linker, ld.  Called for ld -r
+   from bfd_elf_final_link.  */
 
 void
 bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
 {
-  bfd_boolean *failedptr = failedptrarg;
-  unsigned long symindx;
+  bfd_boolean *failedptr = (bfd_boolean *) failedptrarg;
   asection *elt, *first;
   unsigned char *loc;
   bfd_boolean gas;
@@ -2707,27 +2733,56 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
       || *failedptr)
     return;
 
-  symindx = 0;
-  if (elf_group_id (sec) != NULL)
-    symindx = elf_group_id (sec)->udata.i;
+  if (elf_section_data (sec)->this_hdr.sh_info == 0)
+    {
+      unsigned long symindx = 0;
 
-  if (symindx == 0)
+      /* elf_group_id will have been set up by objcopy and the
+        generic linker.  */
+      if (elf_group_id (sec) != NULL)
+       symindx = elf_group_id (sec)->udata.i;
+
+      if (symindx == 0)
+       {
+         /* If called from the assembler, swap_out_syms will have set up
+            elf_section_syms.  */
+         BFD_ASSERT (elf_section_syms (abfd) != NULL);
+         symindx = elf_section_syms (abfd)[sec->index]->udata.i;
+       }
+      elf_section_data (sec)->this_hdr.sh_info = symindx;
+    }
+  else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2)
     {
-      /* If called from the assembler, swap_out_syms will have set up
-        elf_section_syms;  If called for "ld -r", use target_index.  */
-      if (elf_section_syms (abfd) != NULL)
-       symindx = elf_section_syms (abfd)[sec->index]->udata.i;
-      else
-       symindx = sec->target_index;
+      /* The ELF backend linker sets sh_info to -2 when the group
+        signature symbol is global, and thus the index can't be
+        set until all local symbols are output.  */
+      asection *igroup = elf_sec_group (elf_next_in_group (sec));
+      struct bfd_elf_section_data *sec_data = elf_section_data (igroup);
+      unsigned long symndx = sec_data->this_hdr.sh_info;
+      unsigned long extsymoff = 0;
+      struct elf_link_hash_entry *h;
+
+      if (!elf_bad_symtab (igroup->owner))
+       {
+         Elf_Internal_Shdr *symtab_hdr;
+
+         symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr;
+         extsymoff = symtab_hdr->sh_info;
+       }
+      h = elf_sym_hashes (igroup->owner)[symndx - extsymoff];
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+      elf_section_data (sec)->this_hdr.sh_info = h->indx;
     }
-  elf_section_data (sec)->this_hdr.sh_info = symindx;
 
   /* The contents won't be allocated for "ld -r" or objcopy.  */
   gas = TRUE;
   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;
@@ -2752,16 +2807,18 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   while (elt != NULL)
     {
       asection *s;
-      unsigned int idx;
 
-      loc -= 4;
       s = elt;
       if (!gas)
        s = s->output_section;
-      idx = 0;
-      if (s != NULL)
-       idx = elf_section_data (s)->this_idx;
-      H_PUT_32 (abfd, idx, loc);
+      if (s != NULL
+         && !bfd_is_abs_section (s))
+       {
+         unsigned int idx = elf_section_data (s)->this_idx;
+
+         loc -= 4;
+         H_PUT_32 (abfd, idx, loc);
+       }
       elt = elf_next_in_group (elt);
       if (elt == first)
        break;
@@ -2785,6 +2842,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
   struct bfd_elf_section_data *d;
+  bfd_boolean need_symtab;
 
   section_number = 1;
 
@@ -2819,28 +2877,32 @@ 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++;
   _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
   elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
 
-  if (bfd_get_symcount (abfd) > 0)
+  need_symtab = (bfd_get_symcount (abfd) > 0
+               || (link_info == NULL
+                   && ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
+                       == HAS_RELOC)));
+  if (need_symtab)
     {
       t->symtab_section = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
@@ -2865,11 +2927,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);
@@ -2879,7 +2943,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   elf_elfsections (abfd) = i_shdrp;
 
   i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr;
-  if (bfd_get_symcount (abfd) > 0)
+  if (need_symtab)
     {
       i_shdrp[t->symtab_section] = &t->symtab_hdr;
       if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
@@ -2893,30 +2957,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.  */
@@ -3018,7 +3083,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);
@@ -3094,7 +3159,7 @@ 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)));
 }
@@ -3138,7 +3203,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;
@@ -3190,7 +3255,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;
@@ -3269,9 +3335,11 @@ _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;
+  bfd_boolean need_symtab;
 
   if (abfd->output_has_begun)
     return TRUE;
@@ -3287,16 +3355,21 @@ _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))
     return FALSE;
 
   /* The backend linker builds symbol table information itself.  */
-  if (link_info == NULL && bfd_get_symcount (abfd) > 0)
+  need_symtab = (link_info == NULL
+                && (bfd_get_symcount (abfd) > 0
+                    || ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
+                        == HAS_RELOC)));
+  if (need_symtab)
     {
       /* Non-zero if doing a relocatable link.  */
       int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC));
@@ -3305,6 +3378,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);
@@ -3327,7 +3401,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   if (!assign_file_positions_except_relocs (abfd, link_info))
     return FALSE;
 
-  if (link_info == NULL && bfd_get_symcount (abfd) > 0)
+  if (need_symtab)
     {
       file_ptr off;
       Elf_Internal_Shdr *hdr;
@@ -3389,7 +3463,7 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
       ++segs;
     }
 
-  if (info->relro)
+  if (info != NULL && info->relro)
     {
       /* We need a PT_GNU_RELRO segment.  */
       ++segs;
@@ -3494,7 +3568,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;
@@ -3521,7 +3595,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;
@@ -3609,13 +3684,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)
        {
@@ -3623,6 +3706,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));
@@ -3642,7 +3728,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;
@@ -3656,7 +3742,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;
@@ -3692,8 +3778,10 @@ _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);
          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;
        }
 
@@ -3720,6 +3808,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
@@ -3728,7 +3823,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          else if ((BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize
                    > last_hdr->lma)
                   && (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize
-                      < hdr->lma))
+                      <= hdr->lma))
            {
              /* If putting this section in this segment would force us to
                 skip a page in the segment, then we need a new segment.  */
@@ -3751,9 +3846,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
@@ -3771,8 +3865,13 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
            }
 
          /* Allow interested parties a chance to override our decision.  */
-         if (last_hdr && info->callbacks->override_segment_assignment)
-           new_segment = info->callbacks->override_segment_assignment (info, abfd, hdr, last_hdr, new_segment);
+         if (last_hdr != NULL
+             && info != NULL
+             && info->callbacks->override_segment_assignment != NULL)
+           new_segment
+             = info->callbacks->override_segment_assignment (info, abfd, hdr,
+                                                             last_hdr,
+                                                             new_segment);
 
          if (! new_segment)
            {
@@ -3846,7 +3945,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 +3954,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 +3989,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 +4000,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 +4018,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,7 +4033,7 @@ _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;
@@ -3947,7 +4045,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          pm = &m->next;
        }
 
-      if (info->relro)
+      if (info != NULL && info->relro)
        {
          for (m = mfirst; m != NULL; m = m->next)
            {
@@ -3968,7 +4066,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          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;
@@ -4113,6 +4211,22 @@ print_segment_map (const struct elf_segment_map *m)
   putc ('\n',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
    sections to segments.  This function also sets up some fields in
    the file header.  */
@@ -4129,14 +4243,19 @@ assign_file_positions_for_load_sections (bfd *abfd,
   bfd_size_type maxpagesize;
   unsigned int alloc;
   unsigned int i, j;
+  bfd_vma header_pad = 0;
 
   if (link_info == NULL
-      && !elf_modify_segment_map (abfd, link_info, FALSE))
+      && !_bfd_elf_map_sections_to_segments (abfd, link_info))
     return FALSE;
 
   alloc = 0;
   for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-    ++alloc;
+    {
+      ++alloc;
+      if (m->header_size)
+       header_pad = m->header_size;
+    }
 
   elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
   elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
@@ -4154,7 +4273,21 @@ assign_file_positions_for_load_sections (bfd *abfd,
       return TRUE;
     }
 
-  phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr));
+  /* We're writing the size in elf_tdata (abfd)->program_header_size,
+     see assign_file_positions_except_relocs, so make sure we have
+     that amount allocated, with trailing space cleared.
+     The variable alloc contains the computed need, while elf_tdata
+     (abfd)->program_header_size contains the size used for the
+     layout.
+     See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments
+     where the layout is forced to according to a larger size in the
+     last iterations for the testcase ld-elf/header.  */
+  BFD_ASSERT (elf_tdata (abfd)->program_header_size % bed->s->sizeof_phdr
+             == 0);
+  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;
@@ -4165,6 +4298,11 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
   off = bed->s->sizeof_ehdr;
   off += alloc * bed->s->sizeof_phdr;
+  if (header_pad < (bfd_vma) off)
+    header_pad = 0;
+  else
+    header_pad -= off;
+  off += header_pad;
 
   for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0;
        m != NULL;
@@ -4261,23 +4399,16 @@ assign_file_positions_for_load_sections (bfd *abfd,
              elf_section_type (m->sections[i]) = SHT_NOBITS;
 
          /* Find out whether this segment contains any loadable
-            sections.  If the first section isn't loadable, the same
-            holds for any other sections.  */
-         i = 0;
-         while (elf_section_type (m->sections[i]) == SHT_NOBITS)
-           {
-             /* If a segment starts with .tbss, we need to look
-                at the next section to decide whether the segment
-                has any loadable sections.  */
-             if ((elf_section_flags (m->sections[i]) & SHF_TLS) == 0
-                 || ++i >= m->count)
-               {
-                 no_contents = TRUE;
-                 break;
-               }
-           }
+            sections.  */
+         no_contents = TRUE;
+         for (i = 0; i < m->count; i++)
+           if (elf_section_type (m->sections[i]) != SHT_NOBITS)
+             {
+               no_contents = FALSE;
+               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)
            {
@@ -4359,6 +4490,11 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
          p->p_filesz += alloc * bed->s->sizeof_phdr;
          p->p_memsz += alloc * bed->s->sizeof_phdr;
+         if (m->count)
+           {
+             p->p_filesz += header_pad;
+             p->p_memsz += header_pad;
+           }
        }
 
       if (p->p_type == PT_LOAD
@@ -4399,19 +4535,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;
                }
@@ -4488,24 +4639,37 @@ 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))
+               {
+                 (*_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;
@@ -4547,13 +4711,12 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos);
       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,
@@ -4611,7 +4774,59 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        m != NULL;
        m = m->next, p++)
     {
-      if (m->count != 0)
+      if (p->p_type == PT_GNU_RELRO)
+       {
+         const Elf_Internal_Phdr *lp;
+
+         BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+
+         if (link_info != NULL)
+           {
+             /* During linking the range of the RELRO segment is passed
+                in link_info.  */
+             for (lp = phdrs; lp < phdrs + count; ++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)
+                   break;
+               }
+           }
+         else
+           {
+             /* Otherwise we are copying an executable or shared
+                library, but we need to use the same linker logic.  */
+             for (lp = phdrs; lp < phdrs + count; ++lp)
+               {
+                 if (lp->p_type == PT_LOAD
+                     && lp->p_paddr == p->p_paddr)
+                   break;
+               }
+           }
+
+         if (lp < phdrs + count)
+           {
+             p->p_vaddr = lp->p_vaddr;
+             p->p_paddr = lp->p_paddr;
+             p->p_offset = lp->p_offset;
+             if (link_info != NULL)
+               p->p_filesz = link_info->relro_end - lp->p_vaddr;
+             else if (m->p_size_valid)
+               p->p_filesz = m->p_size;
+             else
+               abort ();
+             p->p_memsz = p->p_filesz;
+             p->p_align = 1;
+             p->p_flags = (lp->p_flags & ~PF_W);
+           }
+         else
+           {
+             memset (p, 0, sizeof *p);
+             p->p_type = PT_NULL;
+           }
+       }
+      else if (m->count != 0)
        {
          if (p->p_type != PT_LOAD
              && (p->p_type != PT_NOTE
@@ -4627,87 +4842,20 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
              p->p_filesz = sect->filepos - m->sections[0]->filepos;
              if (hdr->sh_type != SHT_NOBITS)
                p->p_filesz += hdr->sh_size;
-
-             if (p->p_type == PT_GNU_RELRO)
-               {
-                 /* When we get here, we are copying executable
-                    or shared library. But we need to use the same
-                    linker logic.  */
-                 Elf_Internal_Phdr *lp;
-
-                 for (lp = phdrs; lp < phdrs + count; ++lp)
-                   {
-                     if (lp->p_type == PT_LOAD
-                         && lp->p_paddr == p->p_paddr)
-                       break;
-                   }
-         
-                 if (lp < phdrs + count)
-                   {
-                     /* We should use p_size if it is valid since it
-                        may contain the first few bytes of the next
-                        SEC_ALLOC section.  */
-                     if (m->p_size_valid)
-                       p->p_filesz = m->p_size;
-                     else
-                       abort ();
-                     p->p_vaddr = lp->p_vaddr;
-                     p->p_offset = lp->p_offset;
-                     p->p_memsz = p->p_filesz;
-                     p->p_align = 1;
-                   }
-                 else
-                   abort ();
-               }
-             else
-               p->p_offset = m->sections[0]->filepos;
+             p->p_offset = m->sections[0]->filepos;
            }
        }
-      else
+      else if (m->includes_filehdr)
        {
-         if (m->includes_filehdr)
-           {
-             p->p_vaddr = filehdr_vaddr;
-             if (! m->p_paddr_valid)
-               p->p_paddr = filehdr_paddr;
-           }
-         else if (m->includes_phdrs)
-           {
-             p->p_vaddr = phdrs_vaddr;
-             if (! m->p_paddr_valid)
-               p->p_paddr = phdrs_paddr;
-           }
-         else if (p->p_type == PT_GNU_RELRO)
-           {
-             Elf_Internal_Phdr *lp;
-
-             for (lp = phdrs; lp < phdrs + count; ++lp)
-               {
-                 if (lp->p_type == PT_LOAD
-                     && lp->p_vaddr <= link_info->relro_end
-                     && lp->p_vaddr >= link_info->relro_start
-                     && (lp->p_vaddr + lp->p_filesz
-                         >= link_info->relro_end))
-                   break;
-               }
-
-             if (lp < phdrs + count
-                 && link_info->relro_end > lp->p_vaddr)
-               {
-                 p->p_vaddr = lp->p_vaddr;
-                 p->p_paddr = lp->p_paddr;
-                 p->p_offset = lp->p_offset;
-                 p->p_filesz = link_info->relro_end - lp->p_vaddr;
-                 p->p_memsz = p->p_filesz;
-                 p->p_align = 1;
-                 p->p_flags = (lp->p_flags & ~PF_W);
-               }
-             else
-               {
-                 memset (p, 0, sizeof *p);
-                 p->p_type = PT_NULL;
-               }
-           }
+         p->p_vaddr = filehdr_vaddr;
+         if (! m->p_paddr_valid)
+           p->p_paddr = filehdr_paddr;
+       }
+      else if (m->includes_phdrs)
+       {
+         p->p_vaddr = phdrs_vaddr;
+         if (! m->p_paddr_valid)
+           p->p_paddr = phdrs_paddr;
        }
     }
 
@@ -4811,8 +4959,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);
 
@@ -4880,7 +5027,6 @@ prep_headers (bfd *abfd)
   else
     {
       i_ehdrp->e_phentsize = 0;
-      i_phdrp = 0;
       i_ehdrp->e_phoff = 0;
     }
 
@@ -4928,7 +5074,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;
@@ -4938,7 +5083,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);
@@ -4996,34 +5140,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
@@ -5073,9 +5217,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
@@ -5358,7 +5501,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;
 
@@ -5442,7 +5585,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;
 
@@ -5567,19 +5710,32 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
          /* Offset the segment physical address from the lma
             to allow for space taken up by elf headers.  */
          if (map->includes_filehdr)
-           map->p_paddr -= iehdr->e_ehsize;
+           {
+             if (map->p_paddr >= iehdr->e_ehsize)
+               map->p_paddr -= iehdr->e_ehsize;
+             else
+               {
+                 map->includes_filehdr = FALSE;
+                 map->includes_phdrs = FALSE;
+               }
+           }
 
          if (map->includes_phdrs)
            {
-             map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
-
-             /* iehdr->e_phnum is just an estimate of the number
-                of program headers that we will need.  Make a note
-                here of the number we used and the segment we chose
-                to hold these headers, so that we can adjust the
-                offset when we know the correct value.  */
-             phdr_adjust_num = iehdr->e_phnum;
-             phdr_adjust_seg = map;
+             if (map->p_paddr >= iehdr->e_phnum * iehdr->e_phentsize)
+               {
+                 map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
+
+                 /* iehdr->e_phnum is just an estimate of the number
+                    of program headers that we will need.  Make a note
+                    here of the number we used and the segment we chose
+                    to hold these headers, so that we can adjust the
+                    offset when we know the correct value.  */
+                 phdr_adjust_num = iehdr->e_phnum;
+                 phdr_adjust_seg = map;
+               }
+             else
+               map->includes_phdrs = FALSE;
            }
        }
 
@@ -5675,7 +5831,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_alloc (obfd, amt);
              if (map == NULL)
                {
                  free (sections);
@@ -5773,7 +5929,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;
@@ -5781,12 +5937,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++;
            }
        }
@@ -5796,7 +5950,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;
 
@@ -5812,14 +5966,13 @@ 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
-         && segment->p_filesz == segment->p_memsz)
+      if (map->p_type == PT_GNU_RELRO)
        {
          /* 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.  */
-         map->p_size = segment->p_filesz;
+         map->p_size = segment->p_memsz;
          map->p_size_valid = 1;
        }
 
@@ -5841,13 +5994,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            phdr_included = TRUE;
        }
 
-      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;
@@ -5857,15 +6004,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;
@@ -5934,7 +6110,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?  */
@@ -5979,18 +6155,21 @@ _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.  */
+  /* 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?  */
@@ -6001,7 +6180,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)
@@ -6009,7 +6188,7 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
          if (elf_section_flags (isec) & SHF_GROUP)
            elf_section_flags (osec) |= SHF_GROUP;
          elf_next_in_group (osec) = elf_next_in_group (isec);
-         elf_group_name (osec) = elf_group_name (isec);
+         elf_section_data (osec)->group = elf_section_data (isec)->group;
        }
     }
 
@@ -6060,52 +6239,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
@@ -6197,7 +6416,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);
@@ -6210,8 +6430,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);
@@ -6372,6 +6592,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
 
       if ((flags & BSF_THREAD_LOCAL) != 0)
        type = STT_TLS;
+      else if ((flags & BSF_GNU_INDIRECT_FUNCTION) != 0)
+       type = STT_GNU_IFUNC;
       else if ((flags & BSF_FUNCTION) != 0)
        type = STT_FUNC;
       else if ((flags & BSF_OBJECT) != 0)
@@ -6405,9 +6627,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
          if (type == STT_OBJECT)
            sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON);
          else
-#else
-           sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
 #endif
+           sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
        }
       else if (bfd_is_und_section (syms[idx]->section))
        sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
@@ -6422,6 +6643,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
 
          if (flags & BSF_LOCAL)
            bind = STB_LOCAL;
+         else if (flags & BSF_GNU_UNIQUE)
+           bind = STB_GNU_UNIQUE;
          else if (flags & BSF_WEAK)
            bind = STB_WEAK;
          else if (flags & BSF_GLOBAL)
@@ -6646,14 +6869,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:
@@ -6693,8 +6916,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;
            }
@@ -6762,7 +6986,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
@@ -6806,8 +7030,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;
 
@@ -6840,8 +7064,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;
            }
@@ -6898,8 +7123,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;
 
@@ -6925,7 +7150,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;
 
@@ -6948,7 +7174,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
@@ -7022,7 +7248,7 @@ _bfd_elf_set_arch_mach (bfd *abfd,
    for error reporting.  */
 
 static bfd_boolean
-elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
+elf_find_function (bfd *abfd,
                   asection *section,
                   asymbol **symbols,
                   bfd_vma offset,
@@ -7042,6 +7268,7 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
      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);
 
   filename = NULL;
   func = NULL;
@@ -7052,20 +7279,22 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
   for (p = symbols; *p != NULL; p++)
     {
       elf_symbol_type *q;
+      unsigned int type;
 
       q = (elf_symbol_type *) *p;
 
-      switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
+      type = ELF_ST_TYPE (q->internal_elf_sym.st_info);
+      switch (type)
        {
-       default:
-         break;
        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:
-       case STT_FUNC:
          if (bfd_get_section (&q->symbol) == section
              && q->symbol.value >= low_func
              && q->symbol.value <= offset)
@@ -7373,16 +7602,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
@@ -7430,7 +7667,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);
@@ -7472,7 +7709,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+
@@ -7482,6 +7720,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)
@@ -7498,7 +7738,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+
@@ -7508,6 +7749,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 */
@@ -7554,6 +7797,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)
 {
@@ -7566,6 +7819,42 @@ 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);
+}
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)                /* Sparc64 cross Sparc32 */
@@ -7588,7 +7877,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)
@@ -7596,7 +7885,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;
 
@@ -7720,7 +8009,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.  */
 
@@ -7816,7 +8108,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;
 
@@ -7844,10 +8136,10 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       /* Make a ".module/xxxxxxxx" section.  */
       /* module_info.base_address */
       base_addr = bfd_get_32 (abfd, note->descdata + 4);
-      sprintf (buf, ".module/%08lx", (long) base_addr);
+      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;
 
@@ -7913,6 +8205,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)
@@ -7927,6 +8226,48 @@ 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_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -7958,7 +8299,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;
 
@@ -8079,6 +8420,70 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note)
 }
 
 static bfd_boolean
+elfcore_grok_openbsd_procinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+  /* Signal number at offset 0x08. */
+  elf_tdata (abfd)->core_signal
+    = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08);
+
+  /* Process ID at offset 0x20. */
+  elf_tdata (abfd)->core_pid
+    = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x20);
+
+  /* Command name at 0x48 (max 32 bytes, including nul). */
+  elf_tdata (abfd)->core_command
+    = _bfd_elfcore_strndup (abfd, note->descdata + 0x48, 31);
+
+  return TRUE;
+}
+
+static bfd_boolean
+elfcore_grok_openbsd_note (bfd *abfd, Elf_Internal_Note *note)
+{
+  if (note->type == NT_OPENBSD_PROCINFO)
+    return elfcore_grok_openbsd_procinfo (abfd, note);
+
+  if (note->type == NT_OPENBSD_REGS)
+    return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+  if (note->type == NT_OPENBSD_FPREGS)
+    return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+  if (note->type == NT_OPENBSD_XFPREGS)
+    return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
+
+  if (note->type == NT_OPENBSD_AUXV)
+    {
+      asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv",
+                                                          SEC_HAS_CONTENTS);
+
+      if (sect == NULL)
+       return FALSE;
+      sect->size = note->descsz;
+      sect->filepos = note->descpos;
+      sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+      return TRUE;
+    }
+
+  if (note->type == NT_OPENBSD_WCOOKIE)
+    {
+      asection *sect = bfd_make_section_anyway_with_flags (abfd, ".wcookie",
+                                                          SEC_HAS_CONTENTS);
+
+      if (sect == NULL)
+       return FALSE;
+      sect->size = note->descsz;
+      sect->filepos = note->descpos;
+      sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+      return TRUE;
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
 elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid)
 {
   void *ddata = note->descdata;
@@ -8113,7 +8518,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);
@@ -8142,7 +8547,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);
@@ -8199,7 +8604,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);
@@ -8253,7 +8658,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;
@@ -8482,6 +8887,15 @@ elfcore_write_prxfpreg (bfd *abfd,
 }
 
 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,
                       int *bufsiz,
@@ -8505,6 +8919,79 @@ 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_register_note (bfd *abfd,
                             char *buf,
@@ -8517,10 +9004,24 @@ 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);
   return NULL;
 }
 
@@ -8536,14 +9037,23 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
       Elf_External_Note *xnp = (Elf_External_Note *) p;
       Elf_Internal_Note in;
 
+      if (offsetof (Elf_External_Note, name) > buf - p + size)
+       return FALSE;
+
       in.type = H_GET_32 (abfd, xnp->type);
 
       in.namesz = H_GET_32 (abfd, xnp->namesz);
       in.namedata = xnp->name;
+      if (in.namesz > buf - in.namedata + size)
+       return FALSE;
 
       in.descsz = H_GET_32 (abfd, xnp->descsz);
       in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
       in.descpos = offset + (in.descdata - buf);
+      if (in.descsz != 0
+         && (in.descdata >= buf + size
+             || in.descsz > buf - in.descdata + size))
+       return FALSE;
 
       switch (bfd_get_format (abfd))
         {
@@ -8556,6 +9066,11 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
              if (! elfcore_grok_netbsd_note (abfd, &in))
                return FALSE;
            }
+         else if (CONST_STRNEQ (in.namedata, "OpenBSD"))
+           {
+             if (! elfcore_grok_openbsd_note (abfd, &in))
+               return FALSE;
+           }
          else if (CONST_STRNEQ (in.namedata, "QNX"))
            {
              if (! elfcore_grok_nto_note (abfd, &in))
@@ -8599,7 +9114,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;
 
@@ -8795,7 +9310,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
 
   relplt_name = bed->relplt_name;
   if (relplt_name == NULL)
-    relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt";
+    relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
   relplt = bfd_get_section_by_name (abfd, relplt_name);
   if (relplt == NULL)
     return 0;
@@ -8817,9 +9332,19 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
   size = count * sizeof (asymbol);
   p = relplt->relocation;
   for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
-    size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+    {
+      size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+      if (p->addend != 0)
+       {
+#ifdef BFD64
+         size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64);
+#else
+         size += sizeof ("+0x") - 1 + 8;
+#endif
+       }
+    }
 
-  s = *ret = bfd_malloc (size);
+  s = *ret = (asymbol *) bfd_malloc (size);
   if (s == NULL)
     return -1;
 
@@ -8848,6 +9373,19 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
       len = strlen ((*p->sym_ptr_ptr)->name);
       memcpy (names, (*p->sym_ptr_ptr)->name, len);
       names += len;
+      if (p->addend != 0)
+       {
+         char buf[30], *a;
+         
+         memcpy (names, "+0x", sizeof ("+0x") - 1);
+         names += sizeof ("+0x") - 1;
+         bfd_sprintf_vma (abfd, buf, p->addend);
+         for (a = buf; *a == '0'; ++a)
+           ;
+         len = strlen (a);
+         memcpy (names, a, len);
+         names += len;
+       }
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s, ++n;
@@ -8870,15 +9408,23 @@ _bfd_elf_set_osabi (bfd * abfd,
   i_ehdrp = elf_elfheader (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.  */
+  if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE
+      && elf_tdata (abfd)->has_ifunc_symbols)
+    i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX;
 }
 
 
 /* Return TRUE for ELF symbol types that represent functions.
    This is the default version of this function, which is sufficient for
-   most targets.  It returns true if TYPE is STT_FUNC.  */
+   most targets.  It returns true if TYPE is STT_FUNC or STT_GNU_IFUNC.  */
 
 bfd_boolean
 _bfd_elf_is_function_type (unsigned int type)
 {
-  return (type == STT_FUNC);
+  return (type == STT_FUNC
+         || type == STT_GNU_IFUNC);
 }