]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elf.c
bfd/
[thirdparty/binutils-gdb.git] / bfd / elf.c
index 019f72a030e571445a5cf79135be315a0c5f6d60..ae3af35ee2cea7bcdcdd1e6aa18c7439fb939ab2 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,13 +1,13 @@
 /* ELF executable support for BFD.
 
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -17,7 +17,9 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
 
 /*
 SECTION
@@ -33,13 +35,14 @@ SECTION
 
 /* For sparc64-cross-sparc32.  */
 #define _SYSCALL32
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #define ARCH_SIZE 0
 #include "elf-bfd.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
 
 static int elf_sort_sections (const void *, const void *);
 static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
@@ -206,16 +209,32 @@ bfd_elf_hash (const char *namearg)
   return h & 0xffffffff;
 }
 
+/* DT_GNU_HASH hash function.  Do not change this function; you will
+   cause invalid hash tables to be generated.  */
+
+unsigned long
+bfd_elf_gnu_hash (const char *namearg)
+{
+  const unsigned char *name = (const unsigned char *) namearg;
+  unsigned long h = 5381;
+  unsigned char ch;
+
+  while ((ch = *name++) != '\0')
+    h = (h << 5) + h + ch;
+  return h & 0xffffffff;
+}
+
 bfd_boolean
 bfd_elf_mkobject (bfd *abfd)
 {
-  /* This just does initialization.  */
-  /* coff_mkobject zalloc's space for tdata.coff_obj_data ...  */
-  elf_tdata (abfd) = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
-  if (elf_tdata (abfd) == 0)
-    return FALSE;
-  /* Since everything is done at close time, do we need any
-     initialization?  */
+  if (abfd->tdata.any == NULL)
+    {
+      abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
+      if (abfd->tdata.any == NULL)
+       return FALSE;
+    }
+
+  elf_tdata (abfd)->program_header_size = (bfd_size_type) -1;
 
   return TRUE;
 }
@@ -236,7 +255,9 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
   bfd_size_type shstrtabsize;
 
   i_shdrp = elf_elfsections (abfd);
-  if (i_shdrp == 0 || i_shdrp[shindex] == 0)
+  if (i_shdrp == 0
+      || shindex >= elf_numsections (abfd)
+      || i_shdrp[shindex] == 0)
     return NULL;
 
   shstrtab = i_shdrp[shindex]->contents;
@@ -275,6 +296,9 @@ bfd_elf_string_from_elf_section (bfd *abfd,
   if (strindex == 0)
     return "";
 
+  if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd))
+    return NULL;
+
   hdr = elf_elfsections (abfd)[shindex];
 
   if (hdr->contents == NULL
@@ -384,7 +408,15 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf;
        isym < isymend;
        esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL)
-    (*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym);
+    if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym))
+      {
+       symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size;
+       (*_bfd_error_handler) (_("%B symbol number %lu references "
+                                "nonexistent SHT_SYMTAB_SHNDX section"),
+                              ibfd, (unsigned long) symoffset);
+       intsym_buf = NULL;
+       goto out;
+      }
 
  out:
   if (alloc_ext != NULL)
@@ -477,10 +509,18 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
         section with just a flag word (ie. sh_size is 4), ignore it.  */
       shnum = elf_numsections (abfd);
       num_group = 0;
+
+#define IS_VALID_GROUP_SECTION_HEADER(shdr)            \
+       (   (shdr)->sh_type == SHT_GROUP                \
+        && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE)     \
+        && (shdr)->sh_entsize == GRP_ENTRY_SIZE        \
+        && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0)
+
       for (i = 0; i < shnum; i++)
        {
          Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
-         if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
+
+         if (IS_VALID_GROUP_SECTION_HEADER (shdr))
            num_group += 1;
        }
 
@@ -505,7 +545,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
          for (i = 0; i < shnum; i++)
            {
              Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
-             if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
+
+             if (IS_VALID_GROUP_SECTION_HEADER (shdr))
                {
                  unsigned char *src;
                  Elf_Internal_Group *dest;
@@ -519,8 +560,18 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                  amt = shdr->sh_size * sizeof (*dest) / 4;
                  shdr->contents = bfd_alloc2 (abfd, shdr->sh_size,
                                               sizeof (*dest) / 4);
-                 if (shdr->contents == NULL
-                     || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
+                 /* PR binutils/4110: Handle corrupt group headers.  */
+                 if (shdr->contents == NULL)
+                   {
+                     _bfd_error_handler
+                       (_("%B: Corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size);
+                     bfd_set_error (bfd_error_bad_value);
+                     return FALSE;
+                   }
+
+                 memset (shdr->contents, 0, amt);
+
+                 if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
                      || (bfd_bread (shdr->contents, shdr->sh_size, abfd)
                          != shdr->sh_size))
                    return FALSE;
@@ -800,24 +851,24 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          int len;
        } debug_sections [] =
        {
-         { "debug",             5  },  /* 'd' */
+         { STRING_COMMA_LEN ("debug") },       /* 'd' */
          { NULL,                0  },  /* 'e' */
          { NULL,                0  },  /* 'f' */
-         { "gnu.linkonce.wi.", 17 },   /* 'g' */
+         { STRING_COMMA_LEN ("gnu.linkonce.wi.") },    /* 'g' */
          { NULL,                0  },  /* 'h' */
          { NULL,                0  },  /* 'i' */
          { NULL,                0  },  /* 'j' */
          { NULL,                0  },  /* 'k' */
-         { "line",              4  },  /* 'l' */
+         { STRING_COMMA_LEN ("line") },        /* 'l' */
          { NULL,                0  },  /* 'm' */
          { NULL,                0  },  /* 'n' */
          { NULL,                0  },  /* 'o' */
          { NULL,                0  },  /* 'p' */
          { NULL,                0  },  /* 'q' */
          { NULL,                0  },  /* 'r' */
-         { "stab",              4  }   /* 's' */
+         { STRING_COMMA_LEN ("stab") } /* 's' */
        };
-      
+
       if (name [0] == '.')
        {
          int i = name [1] - 'd';
@@ -836,7 +887,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
      The symbols will be defined as weak, so that multiple definitions
      are permitted.  The GNU linker extension is to actually discard
      all but one of the sections.  */
-  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+  if (CONST_STRNEQ (name, ".gnu.linkonce")
       && elf_next_in_group (newsect) == NULL)
     flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
@@ -854,8 +905,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
       unsigned int i;
 
       /* Look through the phdrs to see if we need to adjust the lma.
-         If all the p_paddr fields are zero, we ignore them, since
-         some ELF linkers produce such output.  */
+        If all the p_paddr fields are zero, we ignore them, since
+        some ELF linkers produce such output.  */
       phdr = elf_tdata (abfd)->phdr;
       for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
        {
@@ -876,9 +927,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
                 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.  */
+                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
@@ -993,61 +1044,6 @@ bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED,
   return bfd_reloc_continue;
 }
 \f
-/* Make sure sec_info_type is cleared if sec_info is cleared too.  */
-
-static void
-merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
-                           asection *sec)
-{
-  BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
-  sec->sec_info_type = ELF_INFO_TYPE_NONE;
-}
-
-/* Finish SHF_MERGE section merging.  */
-
-bfd_boolean
-_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
-{
-  bfd *ibfd;
-  asection *sec;
-
-  if (!is_elf_hash_table (info->hash))
-    return FALSE;
-
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
-    if ((ibfd->flags & DYNAMIC) == 0)
-      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
-       if ((sec->flags & SEC_MERGE) != 0
-           && !bfd_is_abs_section (sec->output_section))
-         {
-           struct bfd_elf_section_data *secdata;
-
-           secdata = elf_section_data (sec);
-           if (! _bfd_add_merge_section (abfd,
-                                         &elf_hash_table (info)->merge_info,
-                                         sec, &secdata->sec_info))
-             return FALSE;
-           else if (secdata->sec_info)
-             sec->sec_info_type = ELF_INFO_TYPE_MERGE;
-         }
-
-  if (elf_hash_table (info)->merge_info != NULL)
-    _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
-                        merge_sections_remove_hook);
-  return TRUE;
-}
-
-void
-_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
-{
-  sec->output_section = bfd_abs_section_ptr;
-  sec->output_offset = sec->vma;
-  if (!is_elf_hash_table (info->hash))
-    return;
-
-  sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
-}
-\f
 /* Copy the program header and other data from one object module to
    another.  */
 
@@ -1065,9 +1061,35 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   elf_gp (obfd) = elf_gp (ibfd);
   elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
   elf_flags_init (obfd) = TRUE;
+
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
   return TRUE;
 }
 
+static const char *
+get_segment_type (unsigned int p_type)
+{
+  const char *pt;
+  switch (p_type)
+    {
+    case PT_NULL: pt = "NULL"; break;
+    case PT_LOAD: pt = "LOAD"; break;
+    case PT_DYNAMIC: pt = "DYNAMIC"; break;
+    case PT_INTERP: pt = "INTERP"; break;
+    case PT_NOTE: pt = "NOTE"; break;
+    case PT_SHLIB: pt = "SHLIB"; break;
+    case PT_PHDR: pt = "PHDR"; break;
+    case PT_TLS: pt = "TLS"; break;
+    case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
+    case PT_GNU_STACK: pt = "STACK"; break;
+    case PT_GNU_RELRO: pt = "RELRO"; break;
+    default: pt = NULL; break;
+    }
+  return pt;
+}
+
 /* Print out the program headers.  */
 
 bfd_boolean
@@ -1087,23 +1109,13 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       c = elf_elfheader (abfd)->e_phnum;
       for (i = 0; i < c; i++, p++)
        {
-         const char *pt;
+         const char *pt = get_segment_type (p->p_type);
          char buf[20];
 
-         switch (p->p_type)
+         if (pt == NULL)
            {
-           case PT_NULL: pt = "NULL"; break;
-           case PT_LOAD: pt = "LOAD"; break;
-           case PT_DYNAMIC: pt = "DYNAMIC"; break;
-           case PT_INTERP: pt = "INTERP"; break;
-           case PT_NOTE: pt = "NOTE"; break;
-           case PT_SHLIB: pt = "SHLIB"; break;
-           case PT_PHDR: pt = "PHDR"; break;
-           case PT_TLS: pt = "TLS"; break;
-           case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
-           case PT_GNU_STACK: pt = "STACK"; break;
-           case PT_GNU_RELRO: pt = "RELRO"; break;
-           default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
+             sprintf (buf, "0x%lx", p->p_type);
+             pt = buf;
            }
          fprintf (f, "%8s off    0x", pt);
          bfd_fprintf_vma (abfd, f, p->p_offset);
@@ -1227,6 +1239,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break;
            case DT_USED: name = "USED"; break;
            case DT_FILTER: name = "FILTER"; stringp = TRUE; break;
+           case DT_GNU_HASH: name = "GNU_HASH"; break;
            }
 
          fprintf (f, "  %-11s ", name);
@@ -1351,7 +1364,7 @@ bfd_elf_print_symbol (bfd *abfd,
           we've already printed the size; now print the alignment.
           For other symbols, we have no specified alignment, and
           we've printed the address; now print the size.  */
-       if (bfd_is_com_section (symbol->section))
+       if (symbol->section && bfd_is_com_section (symbol->section))
          val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
        else
          val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size;
@@ -1428,331 +1441,7 @@ bfd_elf_print_symbol (bfd *abfd,
       break;
     }
 }
-\f
-/* Create an entry in an ELF linker hash table.  */
-
-struct bfd_hash_entry *
-_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
-                           struct bfd_hash_table *table,
-                           const char *string)
-{
-  /* Allocate the structure if it has not already been allocated by a
-     subclass.  */
-  if (entry == NULL)
-    {
-      entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
-      if (entry == NULL)
-       return entry;
-    }
-
-  /* Call the allocation method of the superclass.  */
-  entry = _bfd_link_hash_newfunc (entry, table, string);
-  if (entry != NULL)
-    {
-      struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
-      struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
-
-      /* Set local fields.  */
-      ret->indx = -1;
-      ret->dynindx = -1;
-      ret->got = htab->init_got_refcount;
-      ret->plt = htab->init_plt_refcount;
-      memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
-                             - offsetof (struct elf_link_hash_entry, size)));
-      /* Assume that we have been called by a non-ELF symbol reader.
-         This flag is then reset by the code which reads an ELF input
-         file.  This ensures that a symbol created by a non-ELF symbol
-         reader will have the flag set correctly.  */
-      ret->non_elf = 1;
-    }
-
-  return entry;
-}
-
-/* Copy data from an indirect symbol to its direct symbol, hiding the
-   old indirect symbol.  Also used for copying flags to a weakdef.  */
-
-void
-_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
-                                 struct elf_link_hash_entry *dir,
-                                 struct elf_link_hash_entry *ind)
-{
-  struct elf_link_hash_table *htab;
-
-  /* Copy down any references that we may have already seen to the
-     symbol which just became indirect.  */
-
-  dir->ref_dynamic |= ind->ref_dynamic;
-  dir->ref_regular |= ind->ref_regular;
-  dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
-  dir->non_got_ref |= ind->non_got_ref;
-  dir->needs_plt |= ind->needs_plt;
-  dir->pointer_equality_needed |= ind->pointer_equality_needed;
-
-  if (ind->root.type != bfd_link_hash_indirect)
-    return;
-
-  /* Copy over the global and procedure linkage table refcount entries.
-     These may have been already set up by a check_relocs routine.  */
-  htab = elf_hash_table (info);
-  if (ind->got.refcount > htab->init_got_refcount.refcount)
-    {
-      if (dir->got.refcount < 0)
-       dir->got.refcount = 0;
-      dir->got.refcount += ind->got.refcount;
-      ind->got.refcount = htab->init_got_refcount.refcount;
-    }
-
-  if (ind->plt.refcount > htab->init_plt_refcount.refcount)
-    {
-      if (dir->plt.refcount < 0)
-       dir->plt.refcount = 0;
-      dir->plt.refcount += ind->plt.refcount;
-      ind->plt.refcount = htab->init_plt_refcount.refcount;
-    }
-
-  if (ind->dynindx != -1)
-    {
-      if (dir->dynindx != -1)
-       _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index);
-      dir->dynindx = ind->dynindx;
-      dir->dynstr_index = ind->dynstr_index;
-      ind->dynindx = -1;
-      ind->dynstr_index = 0;
-    }
-}
-
-void
-_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
-                               struct elf_link_hash_entry *h,
-                               bfd_boolean force_local)
-{
-  h->plt = elf_hash_table (info)->init_plt_offset;
-  h->needs_plt = 0;
-  if (force_local)
-    {
-      h->forced_local = 1;
-      if (h->dynindx != -1)
-       {
-         h->dynindx = -1;
-         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
-                                 h->dynstr_index);
-       }
-    }
-}
-
-/* Initialize an ELF linker hash table.  */
-
-bfd_boolean
-_bfd_elf_link_hash_table_init
-  (struct elf_link_hash_table *table,
-   bfd *abfd,
-   struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
-                                     struct bfd_hash_table *,
-                                     const char *))
-{
-  bfd_boolean ret;
-  int can_refcount = get_elf_backend_data (abfd)->can_refcount;
-
-  table->dynamic_sections_created = FALSE;
-  table->dynobj = NULL;
-  table->init_got_refcount.refcount = can_refcount - 1;
-  table->init_plt_refcount.refcount = can_refcount - 1;
-  table->init_got_offset.offset = -(bfd_vma) 1;
-  table->init_plt_offset.offset = -(bfd_vma) 1;
-  /* The first dynamic symbol is a dummy.  */
-  table->dynsymcount = 1;
-  table->dynstr = NULL;
-  table->bucketcount = 0;
-  table->needed = NULL;
-  table->hgot = NULL;
-  table->merge_info = NULL;
-  memset (&table->stab_info, 0, sizeof (table->stab_info));
-  memset (&table->eh_info, 0, sizeof (table->eh_info));
-  table->dynlocal = NULL;
-  table->runpath = NULL;
-  table->tls_sec = NULL;
-  table->tls_size = 0;
-  table->loaded = NULL;
-  table->is_relocatable_executable = FALSE;
-
-  ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc);
-  table->root.type = bfd_link_elf_hash_table;
-
-  return ret;
-}
-
-/* Create an ELF linker hash table.  */
-
-struct bfd_link_hash_table *
-_bfd_elf_link_hash_table_create (bfd *abfd)
-{
-  struct elf_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct elf_link_hash_table);
-
-  ret = bfd_malloc (amt);
-  if (ret == NULL)
-    return NULL;
-
-  if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
-    {
-      free (ret);
-      return NULL;
-    }
-
-  return &ret->root;
-}
-
-/* This is a hook for the ELF emulation code in the generic linker to
-   tell the backend linker what file name to use for the DT_NEEDED
-   entry for a dynamic object.  */
-
-void
-bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
-{
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
-      && bfd_get_format (abfd) == bfd_object)
-    elf_dt_name (abfd) = name;
-}
-
-int
-bfd_elf_get_dyn_lib_class (bfd *abfd)
-{
-  int lib_class;
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
-      && bfd_get_format (abfd) == bfd_object)
-    lib_class = elf_dyn_lib_class (abfd);
-  else
-    lib_class = 0;
-  return lib_class;
-}
-
-void
-bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
-{
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
-      && bfd_get_format (abfd) == bfd_object)
-    elf_dyn_lib_class (abfd) = lib_class;
-}
-
-/* Get the list of DT_NEEDED entries for a link.  This is a hook for
-   the linker ELF emulation code.  */
-
-struct bfd_link_needed_list *
-bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
-                        struct bfd_link_info *info)
-{
-  if (! is_elf_hash_table (info->hash))
-    return NULL;
-  return elf_hash_table (info)->needed;
-}
-
-/* Get the list of DT_RPATH/DT_RUNPATH entries for a link.  This is a
-   hook for the linker ELF emulation code.  */
-
-struct bfd_link_needed_list *
-bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
-                         struct bfd_link_info *info)
-{
-  if (! is_elf_hash_table (info->hash))
-    return NULL;
-  return elf_hash_table (info)->runpath;
-}
-
-/* Get the name actually used for a dynamic object for a link.  This
-   is the SONAME entry if there is one.  Otherwise, it is the string
-   passed to bfd_elf_set_dt_needed_name, or it is the filename.  */
-
-const char *
-bfd_elf_get_dt_soname (bfd *abfd)
-{
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
-      && bfd_get_format (abfd) == bfd_object)
-    return elf_dt_name (abfd);
-  return NULL;
-}
-
-/* Get the list of DT_NEEDED entries from a BFD.  This is a hook for
-   the ELF linker emulation code.  */
-
-bfd_boolean
-bfd_elf_get_bfd_needed_list (bfd *abfd,
-                            struct bfd_link_needed_list **pneeded)
-{
-  asection *s;
-  bfd_byte *dynbuf = NULL;
-  int elfsec;
-  unsigned long shlink;
-  bfd_byte *extdyn, *extdynend;
-  size_t extdynsize;
-  void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
-
-  *pneeded = NULL;
-
-  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
-      || bfd_get_format (abfd) != bfd_object)
-    return TRUE;
 
-  s = bfd_get_section_by_name (abfd, ".dynamic");
-  if (s == NULL || s->size == 0)
-    return TRUE;
-
-  if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
-    goto error_return;
-
-  elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
-  if (elfsec == -1)
-    goto error_return;
-
-  shlink = elf_elfsections (abfd)[elfsec]->sh_link;
-
-  extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
-  swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
-
-  extdyn = dynbuf;
-  extdynend = extdyn + s->size;
-  for (; extdyn < extdynend; extdyn += extdynsize)
-    {
-      Elf_Internal_Dyn dyn;
-
-      (*swap_dyn_in) (abfd, extdyn, &dyn);
-
-      if (dyn.d_tag == DT_NULL)
-       break;
-
-      if (dyn.d_tag == DT_NEEDED)
-       {
-         const char *string;
-         struct bfd_link_needed_list *l;
-         unsigned int tagv = dyn.d_un.d_val;
-         bfd_size_type amt;
-
-         string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
-         if (string == NULL)
-           goto error_return;
-
-         amt = sizeof *l;
-         l = bfd_alloc (abfd, amt);
-         if (l == NULL)
-           goto error_return;
-
-         l->by = abfd;
-         l->name = string;
-         l->next = *pneeded;
-         *pneeded = l;
-       }
-    }
-
-  free (dynbuf);
-
-  return TRUE;
-
- error_return:
-  if (dynbuf != NULL)
-    free (dynbuf);
-  return FALSE;
-}
-\f
 /* Allocate an ELF string table--force the first byte to be zero.  */
 
 struct bfd_strtab_hash *
@@ -1808,6 +1497,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
     case SHT_FINI_ARRAY:       /* .fini_array section.  */
     case SHT_PREINIT_ARRAY:    /* .preinit_array section.  */
     case SHT_GNU_LIBLIST:      /* .gnu.liblist section.  */
+    case SHT_GNU_HASH:         /* .gnu.hash section.  */
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
 
     case SHT_DYNAMIC:  /* Dynamic linking information.  */
@@ -1859,11 +1549,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       abfd->flags |= HAS_SYMS;
 
       /* Sometimes a shared object will map in the symbol table.  If
-         SHF_ALLOC is set, and this is a shared object, then we also
-         treat this section as a BFD section.  We can not base the
-         decision purely on SHF_ALLOC, because that flag is sometimes
-         set in a relocatable object file, which would confuse the
-         linker.  */
+        SHF_ALLOC is set, and this is a shared object, then we also
+        treat this section as a BFD section.  We can not base the
+        decision purely on SHF_ALLOC, because that flag is sometimes
+        set in a relocatable object file, which would confuse the
+        linker.  */
       if ((hdr->sh_flags & SHF_ALLOC) != 0
          && (abfd->flags & DYNAMIC) != 0
          && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name,
@@ -2045,15 +1735,16 @@ 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.  */
-       if (hdr->sh_link != elf_onesymtab (abfd) || hdr->sh_info == SHN_UNDEF)
+          section, an invalid section, or another reloc section.  */
+       if (hdr->sh_link != elf_onesymtab (abfd)
+           || hdr->sh_info == SHN_UNDEF
+           || (hdr->sh_info >= SHN_LORESERVE && hdr->sh_info <= SHN_HIRESERVE)
+           || hdr->sh_info >= num_sec
+           || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
+           || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
          return _bfd_elf_make_section_from_shdr (abfd, hdr, name,
                                                  shindex);
 
-       /* Prevent endless recursion on broken objects.  */
-       if (elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
-           || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
-         return FALSE;
        if (! bfd_section_from_shdr (abfd, hdr->sh_info))
          return FALSE;
        target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
@@ -2084,13 +1775,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        abfd->flags |= HAS_RELOC;
        return TRUE;
       }
-      break;
 
     case SHT_GNU_verdef:
       elf_dynverdef (abfd) = shindex;
       elf_tdata (abfd)->dynverdef_hdr = *hdr;
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
-      break;
 
     case SHT_GNU_versym:
       if (hdr->sh_entsize != sizeof (Elf_External_Versym))
@@ -2098,13 +1787,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       elf_dynversym (abfd) = shindex;
       elf_tdata (abfd)->dynversym_hdr = *hdr;
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
-      break;
 
     case SHT_GNU_verneed:
       elf_dynverref (abfd) = shindex;
       elf_tdata (abfd)->dynverref_hdr = *hdr;
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
-      break;
 
     case SHT_SHLIB:
       return TRUE;
@@ -2113,7 +1800,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       /* We need a BFD section for objcopy and relocatable linking,
         and it's handy to have the signature available as the section
         name.  */
-      if (hdr->sh_entsize != GRP_ENTRY_SIZE)
+      if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
        return FALSE;
       name = group_signature (abfd, hdr);
       if (name == NULL)
@@ -2123,7 +1810,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       if (hdr->contents != NULL)
        {
          Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents;
-         unsigned int n_elt = hdr->sh_size / 4;
+         unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE;
          asection *s;
 
          if (idx->flags & GRP_COMDAT)
@@ -2133,19 +1820,78 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          /* We try to keep the same section order as it comes in.  */
          idx += n_elt;
          while (--n_elt != 0)
-           if ((s = (--idx)->shdr->bfd_section) != NULL
-               && elf_next_in_group (s) != NULL)
-             {
-               elf_next_in_group (hdr->bfd_section) = s;
-               break;
-             }
+           {
+             --idx;
+
+             if (idx->shdr != NULL
+                 && (s = idx->shdr->bfd_section) != NULL
+                 && elf_next_in_group (s) != NULL)
+               {
+                 elf_next_in_group (hdr->bfd_section) = s;
+                 break;
+               }
+           }
        }
       break;
 
     default:
+      /* Possibly an attributes section.  */
+      if (hdr->sh_type == SHT_GNU_ATTRIBUTES
+         || hdr->sh_type == bed->obj_attrs_section_type)
+       {
+         if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+           return FALSE;
+         _bfd_elf_parse_attributes (abfd, hdr);
+         return TRUE;
+       }
+
       /* Check for any processor-specific section types.  */
-      return bed->elf_backend_section_from_shdr (abfd, hdr, name,
-                                                shindex);
+      if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex))
+       return TRUE;
+
+      if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER)
+       {
+         if ((hdr->sh_flags & SHF_ALLOC) != 0)
+           /* FIXME: How to properly handle allocated section reserved
+              for applications?  */
+           (*_bfd_error_handler)
+             (_("%B: don't know how to handle allocated, application "
+                "specific section `%s' [0x%8x]"),
+              abfd, name, hdr->sh_type);
+         else
+           /* Allow sections reserved for applications.  */
+           return _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+                                                   shindex);
+       }
+      else if (hdr->sh_type >= SHT_LOPROC
+              && hdr->sh_type <= SHT_HIPROC)
+       /* FIXME: We should handle this section.  */
+       (*_bfd_error_handler)
+         (_("%B: don't know how to handle processor specific section "
+            "`%s' [0x%8x]"),
+          abfd, name, hdr->sh_type);
+      else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS)
+       {
+         /* Unrecognised OS-specific sections.  */
+         if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0)
+           /* SHF_OS_NONCONFORMING indicates that special knowledge is
+              required to correctly process the section and the file should
+              be rejected with an error message.  */
+           (*_bfd_error_handler)
+             (_("%B: don't know how to handle OS specific section "
+                "`%s' [0x%8x]"),
+              abfd, name, hdr->sh_type);
+         else
+           /* Otherwise it should be processed.  */
+           return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+       }
+      else
+       /* FIXME: We should handle this section.  */
+       (*_bfd_error_handler)
+         (_("%B: don't know how to handle section `%s' [0x%8x]"),
+          abfd, name, hdr->sh_type);
+
+      return FALSE;
     }
 
   return TRUE;
@@ -2160,36 +1906,35 @@ bfd_section_from_r_symndx (bfd *abfd,
                           asection *sec,
                           unsigned long r_symndx)
 {
-  Elf_Internal_Shdr *symtab_hdr;
-  unsigned char esym[sizeof (Elf64_External_Sym)];
-  Elf_External_Sym_Shndx eshndx;
-  Elf_Internal_Sym isym;
   unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
+  asection *s;
 
-  if (cache->abfd == abfd && cache->indx[ent] == r_symndx)
-    return cache->sec[ent];
+  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)
-    return NULL;
+      symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+      if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
+                               &isym, esym, &eshndx) == NULL)
+       return NULL;
 
-  if (cache->abfd != abfd)
-    {
-      memset (cache->indx, -1, sizeof (cache->indx));
-      cache->abfd = abfd;
-    }
-  cache->indx[ent] = r_symndx;
-  cache->sec[ent] = sec;
-  if ((isym.st_shndx != SHN_UNDEF && isym.st_shndx < SHN_LORESERVE)
-      || isym.st_shndx > SHN_HIRESERVE)
-    {
-      asection *s;
-      s = bfd_section_from_elf_index (abfd, isym.st_shndx);
-      if (s != NULL)
-       cache->sec[ent] = s;
+      if (cache->abfd != abfd)
+       {
+         memset (cache->indx, -1, sizeof (cache->indx));
+         cache->abfd = abfd;
+       }
+      cache->indx[ent] = r_symndx;
+      cache->shndx[ent] = isym.st_shndx;
     }
-  return cache->sec[ent];
+
+  s = bfd_section_from_elf_index (abfd, cache->shndx[ent]);
+  if (s != NULL)
+    return s;
+
+  return sec;
 }
 
 /* Given an ELF section number, retrieve the corresponding BFD
@@ -2205,108 +1950,111 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int index)
 
 static const struct bfd_elf_special_section special_sections_b[] =
 {
-  { ".bss",            4, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
+  { NULL,                   0,  0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_c[] =
 {
-  { ".comment",        8,  0, SHT_PROGBITS, 0 },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 },
+  { NULL,                       0, 0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_d[] =
 {
-  { ".data",           5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { ".data1",          6,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { ".debug",          6,  0, SHT_PROGBITS, 0 },
-  { ".debug_line",    11,  0, SHT_PROGBITS, 0 },
-  { ".debug_info",    11,  0, SHT_PROGBITS, 0 },
-  { ".debug_abbrev",  13,  0, SHT_PROGBITS, 0 },
-  { ".debug_aranges", 14,  0, SHT_PROGBITS, 0 },
-  { ".dynamic",        8,  0, SHT_DYNAMIC,  SHF_ALLOC },
-  { ".dynstr",         7,  0, SHT_STRTAB,   SHF_ALLOC },
-  { ".dynsym",         7,  0, SHT_DYNSYM,   SHF_ALLOC },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".data"),         -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".data1"),         0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".debug"),         0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".debug_line"),    0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".debug_info"),    0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".debug_abbrev"),  0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".dynamic"),       0, SHT_DYNAMIC,  SHF_ALLOC },
+  { STRING_COMMA_LEN (".dynstr"),        0, SHT_STRTAB,   SHF_ALLOC },
+  { STRING_COMMA_LEN (".dynsym"),        0, SHT_DYNSYM,   SHF_ALLOC },
+  { NULL,                      0,        0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_f[] =
 {
-  { ".fini",           5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".fini_array",    11,  0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".fini"),       0, SHT_PROGBITS,   SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
+  { NULL,                          0, 0, 0,              0 }
 };
 
 static const struct bfd_elf_special_section special_sections_g[] =
 {
-  { ".gnu.linkonce.b",15, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
-  { ".got",            4,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { ".gnu.version",   12,  0, SHT_GNU_versym, 0 },
-  { ".gnu.version_d", 14,  0, SHT_GNU_verdef, 0 },
-  { ".gnu.version_r", 14,  0, SHT_GNU_verneed, 0 },
-  { ".gnu.liblist",   12,  0, SHT_GNU_LIBLIST, SHF_ALLOC },
-  { ".gnu.conflict",  13,  0, SHT_RELA,     SHF_ALLOC },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS,      SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".got"),             0, SHT_PROGBITS,    SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".gnu.version"),     0, SHT_GNU_versym,  0 },
+  { STRING_COMMA_LEN (".gnu.version_d"),   0, SHT_GNU_verdef,  0 },
+  { STRING_COMMA_LEN (".gnu.version_r"),   0, SHT_GNU_verneed, 0 },
+  { STRING_COMMA_LEN (".gnu.liblist"),     0, SHT_GNU_LIBLIST, SHF_ALLOC },
+  { STRING_COMMA_LEN (".gnu.conflict"),    0, SHT_RELA,        SHF_ALLOC },
+  { STRING_COMMA_LEN (".gnu.hash"),        0, SHT_GNU_HASH,    SHF_ALLOC },
+  { NULL,                        0,        0, 0,               0 }
 };
 
 static const struct bfd_elf_special_section special_sections_h[] =
 {
-  { ".hash",           5,  0, SHT_HASH,     SHF_ALLOC },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".hash"), 0, SHT_HASH,     SHF_ALLOC },
+  { NULL,                    0, 0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_i[] =
 {
-  { ".init",           5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".init_array",    11,  0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
-  { ".interp",         7,  0, SHT_PROGBITS, 0 },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".init"),       0, SHT_PROGBITS,   SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".interp"),     0, SHT_PROGBITS,   0 },
+  { NULL,                      0,     0, 0,              0 }
 };
 
 static const struct bfd_elf_special_section special_sections_l[] =
 {
-  { ".line",           5,  0, SHT_PROGBITS, 0 },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 },
+  { NULL,                    0, 0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_n[] =
 {
-  { ".note.GNU-stack",15,  0, SHT_PROGBITS, 0 },
-  { ".note",           5, -1, SHT_NOTE,     0 },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".note"),          -1, SHT_NOTE,     0 },
+  { NULL,                    0,           0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_p[] =
 {
-  { ".preinit_array", 14,  0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
-  { ".plt",            4,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".plt"),           0, SHT_PROGBITS,      SHF_ALLOC + SHF_EXECINSTR },
+  { NULL,                   0,           0, 0,                 0 }
 };
 
 static const struct bfd_elf_special_section special_sections_r[] =
 {
-  { ".rodata",         7, -2, SHT_PROGBITS, SHF_ALLOC },
-  { ".rodata1",        8,  0, SHT_PROGBITS, SHF_ALLOC },
-  { ".rela",           5, -1, SHT_RELA,     0 },
-  { ".rel",            4, -1, SHT_REL,      0 },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".rela"),   -1, SHT_RELA,     0 },
+  { STRING_COMMA_LEN (".rel"),    -1, SHT_REL,      0 },
+  { NULL,                   0,     0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section special_sections_s[] =
 {
-  { ".shstrtab",       9,  0, SHT_STRTAB,   0 },
-  { ".strtab",         7,  0, SHT_STRTAB,   0 },
-  { ".symtab",         7,  0, SHT_SYMTAB,   0 },
-  { ".stabstr",        5,  3, SHT_STRTAB,   0 },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 },
+  { STRING_COMMA_LEN (".strtab"),   0, SHT_STRTAB, 0 },
+  { STRING_COMMA_LEN (".symtab"),   0, SHT_SYMTAB, 0 },
+  /* See struct bfd_elf_special_section declaration for the semantics of
+     this special case where .prefix_length != strlen (.prefix).  */
+  { ".stabstr",                        5,  3, SHT_STRTAB, 0 },
+  { NULL,                       0,  0, 0,          0 }
 };
 
 static const struct bfd_elf_special_section special_sections_t[] =
 {
-  { ".text",           5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".tbss",           5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_TLS },
-  { ".tdata",          6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
-  { NULL,              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".text"),  -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".tbss"),  -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_TLS },
+  { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
+  { NULL,                     0,  0, 0,            0 }
 };
 
 static const struct bfd_elf_special_section *special_sections[] =
@@ -2437,10 +2185,13 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
   bed = get_elf_backend_data (abfd);
   sec->use_rela_p = bed->default_use_rela_p;
 
-  /* When we read a file, we don't need section type and flags unless
-     it is a linker created section.  They will be overridden in
-     _bfd_elf_make_section_from_shdr anyway.  */
-  if (abfd->direction != read_direction
+  /* When we read a file, we don't need to set ELF section type and
+     flags.  They will be overridden in _bfd_elf_make_section_from_shdr
+     anyway.  We will set ELF section type and flags for all linker
+     created sections.  If user specifies BFD section flags, we will
+     set ELF section type and flags based on BFD section flags in
+     elf_fake_sections.  */
+  if ((!sec->flags && abfd->direction != read_direction)
       || (sec->flags & SEC_LINKER_CREATED) != 0)
     {
       ssect = (*bed->get_sec_type_attr) (abfd, sec);
@@ -2451,7 +2202,7 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
        }
     }
 
-  return TRUE;
+  return _bfd_generic_new_section_hook (abfd, sec);
 }
 
 /* Create a new bfd section from an ELF program header.
@@ -2472,7 +2223,7 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
    for the single program segment.  The first has the length specified by
    the file size of the segment, and the second has the length specified
    by the difference between the two sizes.  In effect, the segment is split
-   into it's initialized and uninitialized parts.
+   into its initialized and uninitialized parts.
 
  */
 
@@ -2491,40 +2242,46 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
   split = ((hdr->p_memsz > 0)
            && (hdr->p_filesz > 0)
            && (hdr->p_memsz > hdr->p_filesz));
-  sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
-  len = strlen (namebuf) + 1;
-  name = bfd_alloc (abfd, len);
-  if (!name)
-    return FALSE;
-  memcpy (name, namebuf, len);
-  newsect = bfd_make_section (abfd, name);
-  if (newsect == NULL)
-    return FALSE;
-  newsect->vma = hdr->p_vaddr;
-  newsect->lma = hdr->p_paddr;
-  newsect->size = hdr->p_filesz;
-  newsect->filepos = hdr->p_offset;
-  newsect->flags |= SEC_HAS_CONTENTS;
-  newsect->alignment_power = bfd_log2 (hdr->p_align);
-  if (hdr->p_type == PT_LOAD)
-    {
-      newsect->flags |= SEC_ALLOC;
-      newsect->flags |= SEC_LOAD;
-      if (hdr->p_flags & PF_X)
-       {
-         /* FIXME: all we known is that it has execute PERMISSION,
-            may be data.  */
-         newsect->flags |= SEC_CODE;
-       }
-    }
-  if (!(hdr->p_flags & PF_W))
-    {
-      newsect->flags |= SEC_READONLY;
-    }
 
-  if (split)
+  if (hdr->p_filesz > 0)
     {
-      sprintf (namebuf, "%s%db", typename, index);
+      sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
+      len = strlen (namebuf) + 1;
+      name = bfd_alloc (abfd, len);
+      if (!name)
+       return FALSE;
+      memcpy (name, namebuf, len);
+      newsect = bfd_make_section (abfd, name);
+      if (newsect == NULL)
+       return FALSE;
+      newsect->vma = hdr->p_vaddr;
+      newsect->lma = hdr->p_paddr;
+      newsect->size = hdr->p_filesz;
+      newsect->filepos = hdr->p_offset;
+      newsect->flags |= SEC_HAS_CONTENTS;
+      newsect->alignment_power = bfd_log2 (hdr->p_align);
+      if (hdr->p_type == PT_LOAD)
+       {
+         newsect->flags |= SEC_ALLOC;
+         newsect->flags |= SEC_LOAD;
+         if (hdr->p_flags & PF_X)
+           {
+             /* FIXME: all we known is that it has execute PERMISSION,
+                may be data.  */
+             newsect->flags |= SEC_CODE;
+           }
+       }
+      if (!(hdr->p_flags & PF_W))
+       {
+         newsect->flags |= SEC_READONLY;
+       }
+    }
+
+  if (hdr->p_memsz > hdr->p_filesz)
+    {
+      bfd_vma align;
+
+      sprintf (namebuf, "%s%d%s", typename, index, split ? "b" : "");
       len = strlen (namebuf) + 1;
       name = bfd_alloc (abfd, len);
       if (!name)
@@ -2536,8 +2293,21 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
       newsect->vma = hdr->p_vaddr + hdr->p_filesz;
       newsect->lma = hdr->p_paddr + hdr->p_filesz;
       newsect->size = hdr->p_memsz - hdr->p_filesz;
+      newsect->filepos = hdr->p_offset + hdr->p_filesz;
+      align = newsect->vma & -newsect->vma;
+      if (align == 0 || align > hdr->p_align)
+       align = hdr->p_align;
+      newsect->alignment_power = bfd_log2 (align);
       if (hdr->p_type == PT_LOAD)
        {
+         /* Hack for gdb.  Segments that have not been modified do
+            not have their contents written to a core file, on the
+            assumption that a debugger can find the contents in the
+            executable.  We flag this case by setting the fake
+            section size to zero.  Note that "real" bss sections will
+            always have their contents dumped to the core file.  */
+         if (bfd_get_format (abfd) == bfd_core)
+           newsect->size = 0;
          newsect->flags |= SEC_ALLOC;
          if (hdr->p_flags & PF_X)
            newsect->flags |= SEC_CODE;
@@ -2642,11 +2412,12 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   bfd_boolean *failedptr = failedptrarg;
   Elf_Internal_Shdr *this_hdr;
+  unsigned int sh_type;
 
   if (*failedptr)
     {
       /* We already failed; just get out of the bfd_map_over_sections
-         loop.  */
+        loop.  */
       return;
     }
 
@@ -2685,8 +2456,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
       if ((asect->flags & SEC_GROUP) != 0)
        this_hdr->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))
+              && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+                  || (asect->flags & SEC_NEVER_LOAD) != 0))
        this_hdr->sh_type = SHT_NOBITS;
       else
        this_hdr->sh_type = SHT_PROGBITS;
@@ -2735,8 +2506,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
      case SHT_GNU_verdef:
       this_hdr->sh_entsize = 0;
       /* objcopy or strip will copy over sh_info, but may not set
-         cverdefs.  The linker will set cverdefs, but sh_info will be
-         zero.  */
+        cverdefs.  The linker will set cverdefs, but sh_info will be
+        zero.  */
       if (this_hdr->sh_info == 0)
        this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
       else
@@ -2747,8 +2518,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
     case SHT_GNU_verneed:
       this_hdr->sh_entsize = 0;
       /* objcopy or strip will copy over sh_info, but may not set
-         cverrefs.  The linker will set cverrefs, but sh_info will be
-         zero.  */
+        cverrefs.  The linker will set cverrefs, but sh_info will be
+        zero.  */
       if (this_hdr->sh_info == 0)
        this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
       else
@@ -2757,7 +2528,11 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
       break;
 
     case SHT_GROUP:
-      this_hdr->sh_entsize = 4;
+      this_hdr->sh_entsize = GRP_ENTRY_SIZE;
+      break;
+
+    case SHT_GNU_HASH:
+      this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4;
       break;
     }
 
@@ -2795,10 +2570,18 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
     }
 
   /* 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;
 
+  if (sh_type == SHT_NOBITS && asect->size != 0)
+    {
+      /* Don't change the header type from NOBITS if we are being
+        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
@@ -2920,14 +2703,14 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
          d = elf_section_data (sec);
 
          if (d->this_hdr.sh_type == SHT_GROUP)
-           { 
+           {
              if (sec->flags & SEC_LINKER_CREATED)
                {
                  /* Remove the linker created SHT_GROUP sections.  */
                  bfd_section_list_remove (abfd, sec);
                  abfd->section_count--;
                }
-             else 
+             else
                {
                  if (section_number == SHN_LORESERVE)
                    section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
@@ -3081,7 +2864,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
                         s, s->owner);
                      /* Point to the kept section if it has the same
                         size as the discarded one.  */
-                     kept = _bfd_elf_check_kept_section (s);
+                     kept = _bfd_elf_check_kept_section (s, link_info);
                      if (kept == NULL)
                        {
                          bfd_set_error (bfd_error_bad_value);
@@ -3114,7 +2897,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
                 The Intel C compiler generates SHT_IA_64_UNWIND with
                 SHF_LINK_ORDER.  But it doesn't set the sh_link or
                 sh_info fields.  Hence we could get the situation
-                where s is NULL.  */
+                where s is NULL.  */
              const struct elf_backend_data *bed
                = get_elf_backend_data (abfd);
              if (bed->link_order_error_handler)
@@ -3154,7 +2937,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
             string section.  We look for a section with the same name
             but without the trailing ``str'', and set its sh_link
             field to point to this section.  */
-         if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0
+         if (CONST_STRNEQ (sec->name, ".stab")
              && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0)
            {
              size_t len;
@@ -3194,9 +2977,8 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 
        case SHT_GNU_LIBLIST:
          /* sh_link is the section header index of the prelink library
-            list 
-            used for the dynamic entries, or the symbol table, or the
-            version strings.  */
+            list used for the dynamic entries, or the symbol table, or
+            the version strings.  */
          s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC)
                                             ? ".dynstr" : ".gnu.libstr");
          if (s != NULL)
@@ -3204,6 +2986,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
          break;
 
        case SHT_HASH:
+       case SHT_GNU_HASH:
        case SHT_GNU_versym:
          /* sh_link is the section header index of the symbol table
             this hash table or version table is for.  */
@@ -3229,7 +3012,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 /* Map symbol from it's internal number to the external number, moving
    all local symbols to be at the head of the list.  */
 
-static int
+static bfd_boolean
 sym_is_global (bfd *abfd, asymbol *sym)
 {
   /* If the backend has a special mapping, use it.  */
@@ -3242,6 +3025,20 @@ sym_is_global (bfd *abfd, asymbol *sym)
          || bfd_is_com_section (bfd_get_section (sym)));
 }
 
+/* Don't output section symbols for sections that are not going to be
+   output.  Also, don't output section symbols for reloc and other
+   special sections.  */
+
+static bfd_boolean
+ignore_section_sym (bfd *abfd, asymbol *sym)
+{
+  return ((sym->flags & BSF_SECTION_SYM) != 0
+         && (sym->value != 0
+             || (sym->section->owner != abfd
+                 && (sym->section->output_section->owner != abfd
+                     || sym->section->output_offset != 0))));
+}
+
 static bfd_boolean
 elf_map_symbols (bfd *abfd)
 {
@@ -3282,51 +3079,29 @@ elf_map_symbols (bfd *abfd)
       asymbol *sym = syms[idx];
 
       if ((sym->flags & BSF_SECTION_SYM) != 0
-         && sym->value == 0)
+         && !ignore_section_sym (abfd, sym))
        {
-         asection *sec;
+         asection *sec = sym->section;
 
-         sec = sym->section;
+         if (sec->owner != abfd)
+           sec = sec->output_section;
 
-         if (sec->owner != NULL)
-           {
-             if (sec->owner != abfd)
-               {
-                 if (sec->output_offset != 0)
-                   continue;
-
-                 sec = sec->output_section;
-
-                 /* Empty sections in the input files may have had a
-                    section symbol created for them.  (See the comment
-                    near the end of _bfd_generic_link_output_symbols in
-                    linker.c).  If the linker script discards such
-                    sections then we will reach this point.  Since we know
-                    that we cannot avoid this case, we detect it and skip
-                    the abort and the assignment to the sect_syms array.
-                    To reproduce this particular case try running the
-                    linker testsuite test ld-scripts/weak.exp for an ELF
-                    port that uses the generic linker.  */
-                 if (sec->owner == NULL)
-                   continue;
-
-                 BFD_ASSERT (sec->owner == abfd);
-               }
-             sect_syms[sec->index] = syms[idx];
-           }
+         sect_syms[sec->index] = syms[idx];
        }
     }
 
   /* Classify all of the symbols.  */
   for (idx = 0; idx < symcount; idx++)
     {
+      if (ignore_section_sym (abfd, syms[idx]))
+       continue;
       if (!sym_is_global (abfd, syms[idx]))
        num_locals++;
       else
        num_globals++;
     }
 
-  /* We will be adding a section symbol for each BFD section.  Most normal
+  /* We will be adding a section symbol for each normal BFD section.  Most
      sections will already have a section symbol in outsymbols, but
      eg. SHT_GROUP sections will not, and we need the section symbol mapped
      at least in that case.  */
@@ -3352,6 +3127,8 @@ elf_map_symbols (bfd *abfd)
       asymbol *sym = syms[idx];
       unsigned int i;
 
+      if (ignore_section_sym (abfd, sym))
+       continue;
       if (!sym_is_global (abfd, sym))
        i = num_locals2++;
       else
@@ -3503,7 +3280,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
       elf_tdata (abfd)->next_file_pos = off;
 
       /* Now that we know where the .strtab section goes, write it
-         out.  */
+        out.  */
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
          || ! _bfd_stringtab_emit (abfd, strtab))
        return FALSE;
@@ -3515,6 +3292,103 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   return TRUE;
 }
 
+/* Make an initial estimate of the size of the program header.  If we
+   get the number wrong here, we'll redo section placement.  */
+
+static bfd_size_type
+get_program_header_size (bfd *abfd, struct bfd_link_info *info)
+{
+  size_t segs;
+  asection *s;
+  const struct elf_backend_data *bed;
+
+  /* Assume we will need exactly two PT_LOAD segments: one for text
+     and one for data.  */
+  segs = 2;
+
+  s = bfd_get_section_by_name (abfd, ".interp");
+  if (s != NULL && (s->flags & SEC_LOAD) != 0)
+    {
+      /* If we have a loadable interpreter section, we need a
+        PT_INTERP segment.  In this case, assume we also need a
+        PT_PHDR segment, although that may not be true for all
+        targets.  */
+      segs += 2;
+    }
+
+  if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
+    {
+      /* We need a PT_DYNAMIC segment.  */
+      ++segs;
+
+      if (elf_tdata (abfd)->relro)
+       {
+         /* We need a PT_GNU_RELRO segment only when there is a
+            PT_DYNAMIC segment.  */
+         ++segs;
+       }
+    }
+
+  if (elf_tdata (abfd)->eh_frame_hdr)
+    {
+      /* We need a PT_GNU_EH_FRAME segment.  */
+      ++segs;
+    }
+
+  if (elf_tdata (abfd)->stack_flags)
+    {
+      /* We need a PT_GNU_STACK segment.  */
+      ++segs;
+    }
+
+  for (s = abfd->sections; s != NULL; s = s->next)
+    {
+      if ((s->flags & SEC_LOAD) != 0
+         && CONST_STRNEQ (s->name, ".note"))
+       {
+         /* We need a PT_NOTE segment.  */
+         ++segs;
+         /* Try to create just one PT_NOTE segment
+            for all adjacent loadable .note* sections.
+            gABI requires that within a PT_NOTE segment
+            (and also inside of each SHT_NOTE section)
+            each note is padded to a multiple of 4 size,
+            so we check whether the sections are correctly
+            aligned.  */
+         if (s->alignment_power == 2)
+           while (s->next != NULL
+                  && s->next->alignment_power == 2
+                  && (s->next->flags & SEC_LOAD) != 0
+                  && CONST_STRNEQ (s->next->name, ".note"))
+             s = s->next;
+       }
+    }
+
+  for (s = abfd->sections; s != NULL; s = s->next)
+    {
+      if (s->flags & SEC_THREAD_LOCAL)
+       {
+         /* We need a PT_TLS segment.  */
+         ++segs;
+         break;
+       }
+    }
+
+  /* Let the backend count up any program headers it might need.  */
+  bed = get_elf_backend_data (abfd);
+  if (bed->elf_backend_additional_program_headers)
+    {
+      int a;
+
+      a = (*bed->elf_backend_additional_program_headers) (abfd, info);
+      if (a == -1)
+       abort ();
+      segs += a;
+    }
+
+  return segs * bed->s->sizeof_phdr;
+}
+
 /* Create a mapping from a set of sections to a program segment.  */
 
 static struct elf_segment_map *
@@ -3565,363 +3439,446 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
   m->p_type = PT_DYNAMIC;
   m->count = 1;
   m->sections[0] = dynsec;
-  
+
   return m;
 }
 
-/* Set up a mapping from BFD sections to program segments.  */
+/* Possibly add or remove segments from the segment map.  */
 
 static bfd_boolean
-map_sections_to_segments (bfd *abfd)
+elf_modify_segment_map (bfd *abfd,
+                       struct bfd_link_info *info,
+                       bfd_boolean remove_empty_load)
 {
-  asection **sections = NULL;
-  asection *s;
-  unsigned int i;
-  unsigned int count;
-  struct elf_segment_map *mfirst;
-  struct elf_segment_map **pm;
-  struct elf_segment_map *m;
-  asection *last_hdr;
-  bfd_vma last_size;
-  unsigned int phdr_index;
-  bfd_vma maxpagesize;
-  asection **hdrpp;
-  bfd_boolean phdr_in_segment = TRUE;
-  bfd_boolean writable;
-  int tls_count = 0;
-  asection *first_tls = NULL;
-  asection *dynsec, *eh_frame_hdr;
-  bfd_size_type amt;
-
-  if (elf_tdata (abfd)->segment_map != NULL)
-    return TRUE;
+  struct elf_segment_map **m;
+  const struct elf_backend_data *bed;
 
-  if (bfd_count_sections (abfd) == 0)
-    return TRUE;
+  /* The placement algorithm assumes that non allocated sections are
+     not in PT_LOAD segments.  We ensure this here by removing such
+     sections from the segment map.  We also remove excluded
+     sections.  Finally, any PT_LOAD segment without sections is
+     removed.  */
+  m = &elf_tdata (abfd)->segment_map;
+  while (*m)
+    {
+      unsigned int i, new_count;
 
-  /* Select the allocated sections, and sort them.  */
+      for (new_count = 0, i = 0; i < (*m)->count; i++)
+       {
+         if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0
+             && (((*m)->sections[i]->flags & SEC_ALLOC) != 0
+                 || (*m)->p_type != PT_LOAD))
+           {
+             (*m)->sections[new_count] = (*m)->sections[i];
+             new_count++;
+           }
+       }
+      (*m)->count = new_count;
 
-  sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
-  if (sections == NULL)
-    goto error_return;
+      if (remove_empty_load && (*m)->p_type == PT_LOAD && (*m)->count == 0)
+       *m = (*m)->next;
+      else
+       m = &(*m)->next;
+    }
 
-  i = 0;
-  for (s = abfd->sections; s != NULL; s = s->next)
+  bed = get_elf_backend_data (abfd);
+  if (bed->elf_backend_modify_segment_map != NULL)
     {
-      if ((s->flags & SEC_ALLOC) != 0)
-       {
-         sections[i] = s;
-         ++i;
-       }
+      if (!(*bed->elf_backend_modify_segment_map) (abfd, info))
+       return FALSE;
     }
-  BFD_ASSERT (i <= bfd_count_sections (abfd));
-  count = i;
 
-  qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
+  return TRUE;
+}
 
-  /* Build the mapping.  */
+/* Set up a mapping from BFD sections to program segments.  */
 
-  mfirst = NULL;
-  pm = &mfirst;
+bfd_boolean
+_bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+{
+  unsigned int count;
+  struct elf_segment_map *m;
+  asection **sections = NULL;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  bfd_boolean no_user_phdrs;
 
-  /* If we have a .interp section, then create a PT_PHDR segment for
-     the program headers and a PT_INTERP segment for the .interp
-     section.  */
-  s = bfd_get_section_by_name (abfd, ".interp");
-  if (s != NULL && (s->flags & SEC_LOAD) != 0)
+  no_user_phdrs = elf_tdata (abfd)->segment_map == NULL;
+  if (no_user_phdrs && bfd_count_sections (abfd) != 0)
     {
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
-      if (m == NULL)
-       goto error_return;
-      m->next = NULL;
-      m->p_type = PT_PHDR;
-      /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not.  */
-      m->p_flags = PF_R | PF_X;
-      m->p_flags_valid = 1;
-      m->includes_phdrs = 1;
+      asection *s;
+      unsigned int i;
+      struct elf_segment_map *mfirst;
+      struct elf_segment_map **pm;
+      asection *last_hdr;
+      bfd_vma last_size;
+      unsigned int phdr_index;
+      bfd_vma maxpagesize;
+      asection **hdrpp;
+      bfd_boolean phdr_in_segment = TRUE;
+      bfd_boolean writable;
+      int tls_count = 0;
+      asection *first_tls = NULL;
+      asection *dynsec, *eh_frame_hdr;
+      bfd_size_type amt;
 
-      *pm = m;
-      pm = &m->next;
+      /* Select the allocated sections, and sort them.  */
 
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
-      if (m == NULL)
+      sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
+      if (sections == NULL)
        goto error_return;
-      m->next = NULL;
-      m->p_type = PT_INTERP;
-      m->count = 1;
-      m->sections[0] = s;
-
-      *pm = m;
-      pm = &m->next;
-    }
-
-  /* Look through the sections.  We put sections in the same program
-     segment when the start of the second section can be placed within
-     a few bytes of the end of the first section.  */
-  last_hdr = NULL;
-  last_size = 0;
-  phdr_index = 0;
-  maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
-  writable = FALSE;
-  dynsec = bfd_get_section_by_name (abfd, ".dynamic");
-  if (dynsec != NULL
-      && (dynsec->flags & SEC_LOAD) == 0)
-    dynsec = NULL;
-
-  /* Deal with -Ttext or something similar such that the first section
-     is not adjacent to the program headers.  This is an
-     approximation, since at this point we don't know exactly how many
-     program headers we will need.  */
-  if (count > 0)
-    {
-      bfd_size_type phdr_size;
-
-      phdr_size = elf_tdata (abfd)->program_header_size;
-      if (phdr_size == 0)
-       phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr;
-      if ((abfd->flags & D_PAGED) == 0
-         || sections[0]->lma < phdr_size
-         || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
-       phdr_in_segment = FALSE;
-    }
-
-  for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
-    {
-      asection *hdr;
-      bfd_boolean new_segment;
-
-      hdr = *hdrpp;
-
-      /* See if this section and the last one will fit in the same
-         segment.  */
-
-      if (last_hdr == NULL)
-       {
-         /* If we don't have a segment yet, then we don't need a new
-            one (we build the last one after this loop).  */
-         new_segment = FALSE;
-       }
-      else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
-       {
-         /* If this section has a different relation between the
-             virtual address and the load address, then we need a new
-             segment.  */
-         new_segment = TRUE;
-       }
-      else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
-              < BFD_ALIGN (hdr->lma, maxpagesize))
-       {
-         /* If putting this section in this segment would force us to
-             skip a page in the segment, then we need a new segment.  */
-         new_segment = TRUE;
-       }
-      else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
-              && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
-       {
-         /* We don't want to put a loadable section after a
-             nonloadable section in the same segment.
-             Consider .tbss sections as loadable for this purpose.  */
-         new_segment = TRUE;
-       }
-      else if ((abfd->flags & D_PAGED) == 0)
-       {
-         /* If the file is not demand paged, which means that we
-             don't require the sections to be correctly aligned in the
-             file, then there is no other reason for a new segment.  */
-         new_segment = FALSE;
-       }
-      else if (! writable
-              && (hdr->flags & SEC_READONLY) == 0
-              && (((last_hdr->lma + last_size - 1)
-                   & ~(maxpagesize - 1))
-                  != (hdr->lma & ~(maxpagesize - 1))))
-       {
-         /* We don't want to put a writable section in a read only
-             segment, unless they are on the same page in memory
-             anyhow.  We already know that the last section does not
-             bring us past the current section on the page, so the
-             only case in which the new section is not on the same
-             page as the previous section is when the previous section
-             ends precisely on a page boundary.  */
-         new_segment = TRUE;
-       }
-      else
-       {
-         /* Otherwise, we can use the same segment.  */
-         new_segment = FALSE;
-       }
 
-      if (! new_segment)
+      i = 0;
+      for (s = abfd->sections; s != NULL; s = s->next)
        {
-         if ((hdr->flags & SEC_READONLY) == 0)
-           writable = TRUE;
-         last_hdr = hdr;
-         /* .tbss sections effectively have zero size.  */
-         if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
-           last_size = hdr->size;
-         else
-           last_size = 0;
-         continue;
+         if ((s->flags & SEC_ALLOC) != 0)
+           {
+             sections[i] = s;
+             ++i;
+           }
        }
+      BFD_ASSERT (i <= bfd_count_sections (abfd));
+      count = i;
 
-      /* We need a new program segment.  We must create a new program
-         header holding all the sections from phdr_index until hdr.  */
-
-      m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
-      if (m == NULL)
-       goto error_return;
-
-      *pm = m;
-      pm = &m->next;
-
-      if ((hdr->flags & SEC_READONLY) == 0)
-       writable = TRUE;
-      else
-       writable = FALSE;
+      qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
 
-      last_hdr = hdr;
-      /* .tbss sections effectively have zero size.  */
-      if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
-       last_size = hdr->size;
-      else
-       last_size = 0;
-      phdr_index = i;
-      phdr_in_segment = FALSE;
-    }
+      /* Build the mapping.  */
 
-  /* Create a final PT_LOAD program segment.  */
-  if (last_hdr != NULL)
-    {
-      m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
-      if (m == NULL)
-       goto error_return;
+      mfirst = NULL;
+      pm = &mfirst;
 
-      *pm = m;
-      pm = &m->next;
-    }
+      /* If we have a .interp section, then create a PT_PHDR segment for
+        the program headers and a PT_INTERP segment for the .interp
+        section.  */
+      s = bfd_get_section_by_name (abfd, ".interp");
+      if (s != NULL && (s->flags & SEC_LOAD) != 0)
+       {
+         amt = sizeof (struct elf_segment_map);
+         m = bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           goto error_return;
+         m->next = NULL;
+         m->p_type = PT_PHDR;
+         /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not.  */
+         m->p_flags = PF_R | PF_X;
+         m->p_flags_valid = 1;
+         m->includes_phdrs = 1;
 
-  /* If there is a .dynamic section, throw in a PT_DYNAMIC segment.  */
-  if (dynsec != NULL)
-    {
-      m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
-      if (m == NULL)
-       goto error_return;
-      *pm = m;
-      pm = &m->next;
-    }
+         *pm = m;
+         pm = &m->next;
 
-  /* For each loadable .note section, add a PT_NOTE segment.  We don't
-     use bfd_get_section_by_name, because if we link together
-     nonloadable .note sections and loadable .note sections, we will
-     generate two .note sections in the output file.  FIXME: Using
-     names for section types is bogus anyhow.  */
-  for (s = abfd->sections; s != NULL; s = s->next)
-    {
-      if ((s->flags & SEC_LOAD) != 0
-         && strncmp (s->name, ".note", 5) == 0)
-       {
          amt = sizeof (struct elf_segment_map);
          m = bfd_zalloc (abfd, amt);
          if (m == NULL)
            goto error_return;
          m->next = NULL;
-         m->p_type = PT_NOTE;
+         m->p_type = PT_INTERP;
          m->count = 1;
          m->sections[0] = s;
 
          *pm = m;
          pm = &m->next;
        }
-      if (s->flags & SEC_THREAD_LOCAL)
-       {
-         if (! tls_count)
-           first_tls = s;
-         tls_count++;
-       }
-    }
 
-  /* 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);
-      if (m == NULL)
-       goto error_return;
-      m->next = NULL;
-      m->p_type = PT_TLS;
-      m->count = tls_count;
-      /* Mandated PF_R.  */
-      m->p_flags = PF_R;
-      m->p_flags_valid = 1;
-      for (i = 0; i < tls_count; ++i)
+      /* Look through the sections.  We put sections in the same program
+        segment when the start of the second section can be placed within
+        a few bytes of the end of the first section.  */
+      last_hdr = NULL;
+      last_size = 0;
+      phdr_index = 0;
+      maxpagesize = bed->maxpagesize;
+      writable = FALSE;
+      dynsec = bfd_get_section_by_name (abfd, ".dynamic");
+      if (dynsec != NULL
+         && (dynsec->flags & SEC_LOAD) == 0)
+       dynsec = NULL;
+
+      /* Deal with -Ttext or something similar such that the first section
+        is not adjacent to the program headers.  This is an
+        approximation, since at this point we don't know exactly how many
+        program headers we will need.  */
+      if (count > 0)
        {
-         BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
-         m->sections[i] = first_tls;
-         first_tls = first_tls->next;
+         bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
+
+         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)
+           phdr_in_segment = FALSE;
        }
 
-      *pm = m;
-      pm = &m->next;
-    }
+      for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
+       {
+         asection *hdr;
+         bfd_boolean new_segment;
 
-  /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
-     segment.  */
-  eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr;
-  if (eh_frame_hdr != NULL
-      && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0)
-    {
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
-      if (m == NULL)
-       goto error_return;
-      m->next = NULL;
-      m->p_type = PT_GNU_EH_FRAME;
-      m->count = 1;
-      m->sections[0] = eh_frame_hdr->output_section;
+         hdr = *hdrpp;
 
-      *pm = m;
-      pm = &m->next;
-    }
+         /* See if this section and the last one will fit in the same
+            segment.  */
 
-  if (elf_tdata (abfd)->stack_flags)
-    {
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
-      if (m == NULL)
-       goto error_return;
-      m->next = NULL;
-      m->p_type = PT_GNU_STACK;
-      m->p_flags = elf_tdata (abfd)->stack_flags;
-      m->p_flags_valid = 1;
+         if (last_hdr == NULL)
+           {
+             /* If we don't have a segment yet, then we don't need a new
+                one (we build the last one after this loop).  */
+             new_segment = FALSE;
+           }
+         else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
+           {
+             /* If this section has a different relation between the
+                virtual address and the load address, then we need a new
+                segment.  */
+             new_segment = TRUE;
+           }
+         else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
+                  < BFD_ALIGN (hdr->lma, maxpagesize))
+           {
+             /* If putting this section in this segment would force us to
+                skip a page in the segment, then we need a new segment.  */
+             new_segment = TRUE;
+           }
+         else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
+                  && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+           {
+             /* We don't want to put a loadable section after a
+                nonloadable section in the same segment.
+                Consider .tbss sections as loadable for this purpose.  */
+             new_segment = TRUE;
+           }
+         else if ((abfd->flags & D_PAGED) == 0)
+           {
+             /* If the file is not demand paged, which means that we
+                don't require the sections to be correctly aligned in the
+                file, then there is no other reason for a new segment.  */
+             new_segment = FALSE;
+           }
+         else if (! writable
+                  && (hdr->flags & SEC_READONLY) == 0
+                  && (((last_hdr->lma + last_size - 1)
+                       & ~(maxpagesize - 1))
+                      != (hdr->lma & ~(maxpagesize - 1))))
+           {
+             /* We don't want to put a writable section in a read only
+                segment, unless they are on the same page in memory
+                anyhow.  We already know that the last section does not
+                bring us past the current section on the page, so the
+                only case in which the new section is not on the same
+                page as the previous section is when the previous section
+                ends precisely on a page boundary.  */
+             new_segment = TRUE;
+           }
+         else
+           {
+             /* Otherwise, we can use the same segment.  */
+             new_segment = FALSE;
+           }
 
-      *pm = m;
-      pm = &m->next;
-    }
+         /* 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 (elf_tdata (abfd)->relro)
-    {
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
-      if (m == NULL)
-       goto error_return;
-      m->next = NULL;
-      m->p_type = PT_GNU_RELRO;
-      m->p_flags = PF_R;
-      m->p_flags_valid = 1;
+         if (! new_segment)
+           {
+             if ((hdr->flags & SEC_READONLY) == 0)
+               writable = TRUE;
+             last_hdr = hdr;
+             /* .tbss sections effectively have zero size.  */
+             if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
+                 != SEC_THREAD_LOCAL)
+               last_size = hdr->size;
+             else
+               last_size = 0;
+             continue;
+           }
+
+         /* We need a new program segment.  We must create a new program
+            header holding all the sections from phdr_index until hdr.  */
+
+         m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
+         if (m == NULL)
+           goto error_return;
+
+         *pm = m;
+         pm = &m->next;
+
+         if ((hdr->flags & SEC_READONLY) == 0)
+           writable = TRUE;
+         else
+           writable = FALSE;
+
+         last_hdr = hdr;
+         /* .tbss sections effectively have zero size.  */
+         if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
+           last_size = hdr->size;
+         else
+           last_size = 0;
+         phdr_index = i;
+         phdr_in_segment = FALSE;
+       }
+
+      /* Create a final PT_LOAD program segment.  */
+      if (last_hdr != NULL)
+       {
+         m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
+         if (m == NULL)
+           goto error_return;
+
+         *pm = m;
+         pm = &m->next;
+       }
+
+      /* If there is a .dynamic section, throw in a PT_DYNAMIC segment.  */
+      if (dynsec != NULL)
+       {
+         m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
+         if (m == NULL)
+           goto error_return;
+         *pm = m;
+         pm = &m->next;
+       }
+
+      /* For each batch of consecutive loadable .note sections,
+        add a PT_NOTE segment.  We don't use bfd_get_section_by_name,
+        because if we link together nonloadable .note sections and
+        loadable .note sections, we will generate two .note sections
+        in the output file.  FIXME: Using names for section types is
+        bogus anyhow.  */
+      for (s = abfd->sections; s != NULL; s = s->next)
+       {
+         if ((s->flags & SEC_LOAD) != 0
+             && CONST_STRNEQ (s->name, ".note"))
+           {
+             asection *s2;
+             unsigned count = 1;
+             amt = sizeof (struct elf_segment_map);
+             if (s->alignment_power == 2)
+               for (s2 = s; s2->next != NULL; s2 = s2->next)
+                 {
+                   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)
+                     count++;
+                   else
+                     break;
+                 }
+             amt += (count - 1) * sizeof (asection *);
+             m = bfd_zalloc (abfd, amt);
+             if (m == NULL)
+               goto error_return;
+             m->next = NULL;
+             m->p_type = PT_NOTE;
+             m->count = count;
+             while (count > 1)
+               {
+                 m->sections[m->count - count--] = s;
+                 BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0);
+                 s = s->next;
+               }
+             m->sections[m->count - 1] = s;
+             BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0);
+             *pm = m;
+             pm = &m->next;
+           }
+         if (s->flags & SEC_THREAD_LOCAL)
+           {
+             if (! tls_count)
+               first_tls = s;
+             tls_count++;
+           }
+       }
+
+      /* 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);
+         if (m == NULL)
+           goto error_return;
+         m->next = NULL;
+         m->p_type = PT_TLS;
+         m->count = tls_count;
+         /* Mandated PF_R.  */
+         m->p_flags = PF_R;
+         m->p_flags_valid = 1;
+         for (i = 0; i < tls_count; ++i)
+           {
+             BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
+             m->sections[i] = first_tls;
+             first_tls = first_tls->next;
+           }
+
+         *pm = m;
+         pm = &m->next;
+       }
+
+      /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+        segment.  */
+      eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr;
+      if (eh_frame_hdr != NULL
+         && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0)
+       {
+         amt = sizeof (struct elf_segment_map);
+         m = bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           goto error_return;
+         m->next = NULL;
+         m->p_type = PT_GNU_EH_FRAME;
+         m->count = 1;
+         m->sections[0] = eh_frame_hdr->output_section;
+
+         *pm = m;
+         pm = &m->next;
+       }
+
+      if (elf_tdata (abfd)->stack_flags)
+       {
+         amt = sizeof (struct elf_segment_map);
+         m = bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           goto error_return;
+         m->next = NULL;
+         m->p_type = PT_GNU_STACK;
+         m->p_flags = elf_tdata (abfd)->stack_flags;
+         m->p_flags_valid = 1;
+
+         *pm = m;
+         pm = &m->next;
+       }
+
+      if (dynsec != NULL && elf_tdata (abfd)->relro)
+       {
+         /* We make a PT_GNU_RELRO segment only when there is a
+            PT_DYNAMIC segment.  */
+         amt = sizeof (struct elf_segment_map);
+         m = bfd_zalloc (abfd, amt);
+         if (m == NULL)
+           goto error_return;
+         m->next = NULL;
+         m->p_type = PT_GNU_RELRO;
+         m->p_flags = PF_R;
+         m->p_flags_valid = 1;
+
+         *pm = m;
+         pm = &m->next;
+       }
 
-      *pm = m;
-      pm = &m->next;
+      free (sections);
+      elf_tdata (abfd)->segment_map = mfirst;
     }
 
-  free (sections);
-  sections = NULL;
+  if (!elf_modify_segment_map (abfd, info, no_user_phdrs))
+    return FALSE;
+
+  for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+    ++count;
+  elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr;
 
-  elf_tdata (abfd)->segment_map = mfirst;
   return TRUE;
 
  error_return:
@@ -4008,7 +3965,7 @@ elf_sort_sections (const void *arg1, const void *arg2)
      adjustment = vma_offset + bed->maxpagesize - off_offset;
    else
      adjustment = vma_offset - off_offset;
-     
+
    which can can be collapsed into the expression below.  */
 
 static file_ptr
@@ -4017,117 +3974,95 @@ vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize)
   return ((vma - off) % maxpagesize);
 }
 
+static void
+print_segment_map (const struct elf_segment_map *m)
+{
+  unsigned int j;
+  const char *pt = get_segment_type (m->p_type);
+  char buf[32];
+
+  if (pt == NULL)
+    {
+      if (m->p_type >= PT_LOPROC && m->p_type <= PT_HIPROC)
+       sprintf (buf, "LOPROC+%7.7x",
+                (unsigned int) (m->p_type - PT_LOPROC));
+      else if (m->p_type >= PT_LOOS && m->p_type <= PT_HIOS)
+       sprintf (buf, "LOOS+%7.7x",
+                (unsigned int) (m->p_type - PT_LOOS));
+      else
+       snprintf (buf, sizeof (buf), "%8.8x",
+                 (unsigned int) m->p_type);
+      pt = buf;
+    }
+  fprintf (stderr, "%s:", pt);
+  for (j = 0; j < m->count; j++)
+    fprintf (stderr, " %s", m->sections [j]->name);
+  putc ('\n',stderr);
+}
+
 /* 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, and writes out the program headers.  */
+   the file header.  */
 
 static bfd_boolean
-assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
+assign_file_positions_for_load_sections (bfd *abfd,
+                                        struct bfd_link_info *link_info)
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  unsigned int count;
   struct elf_segment_map *m;
-  unsigned int alloc;
   Elf_Internal_Phdr *phdrs;
-  file_ptr off, voff;
-  bfd_vma filehdr_vaddr, filehdr_paddr;
-  bfd_vma phdrs_vaddr, phdrs_paddr;
   Elf_Internal_Phdr *p;
+  file_ptr off;
+  bfd_size_type maxpagesize;
+  unsigned int alloc;
+  unsigned int i, j;
 
-  if (elf_tdata (abfd)->segment_map == NULL)
-    {
-      if (! map_sections_to_segments (abfd))
-       return FALSE;
-    }
-  else
-    {
-      /* The placement algorithm assumes that non allocated sections are
-        not in PT_LOAD segments.  We ensure this here by removing such
-        sections from the segment map.  We also remove excluded
-        sections.  */
-      for (m = elf_tdata (abfd)->segment_map;
-          m != NULL;
-          m = m->next)
-       {
-         unsigned int new_count;
-         unsigned int i;
-
-         new_count = 0;
-         for (i = 0; i < m->count; i ++)
-           {
-             if ((m->sections[i]->flags & SEC_EXCLUDE) == 0
-                 && ((m->sections[i]->flags & SEC_ALLOC) != 0
-                     || m->p_type != PT_LOAD))
-               {
-                 if (i != new_count)
-                   m->sections[new_count] = m->sections[i];
-
-                 new_count ++;
-               }
-           }
-
-         if (new_count != m->count)
-           m->count = new_count;
-       }
-    }
-
-  if (bed->elf_backend_modify_segment_map)
-    {
-      if (! (*bed->elf_backend_modify_segment_map) (abfd, link_info))
-       return FALSE;
-    }
+  if (link_info == NULL
+      && !elf_modify_segment_map (abfd, link_info, FALSE))
+    return FALSE;
 
-  count = 0;
+  alloc = 0;
   for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-    ++count;
+    ++alloc;
 
   elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
   elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
-  elf_elfheader (abfd)->e_phnum = count;
+  elf_elfheader (abfd)->e_phnum = alloc;
 
-  if (count == 0)
+  if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
+    elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
+  else
+    BFD_ASSERT (elf_tdata (abfd)->program_header_size
+               >= alloc * bed->s->sizeof_phdr);
+
+  if (alloc == 0)
     {
       elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr;
       return TRUE;
     }
 
-  /* If we already counted the number of program segments, make sure
-     that we allocated enough space.  This happens when SIZEOF_HEADERS
-     is used in a linker script.  */
-  alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr;
-  if (alloc != 0 && count > alloc)
-    {
-      ((*_bfd_error_handler)
-       (_("%B: Not enough room for program headers (allocated %u, need %u)"),
-       abfd, alloc, count));
-      bfd_set_error (bfd_error_bad_value);
-      return FALSE;
-    }
-
-  if (alloc == 0)
-    alloc = count;
-
   phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr));
+  elf_tdata (abfd)->phdr = phdrs;
   if (phdrs == NULL)
     return FALSE;
 
+  maxpagesize = 1;
+  if ((abfd->flags & D_PAGED) != 0)
+    maxpagesize = bed->maxpagesize;
+
   off = bed->s->sizeof_ehdr;
   off += alloc * bed->s->sizeof_phdr;
 
-  filehdr_vaddr = 0;
-  filehdr_paddr = 0;
-  phdrs_vaddr = 0;
-  phdrs_paddr = 0;
-
-  for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+  for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0;
        m != NULL;
-       m = m->next, p++)
+       m = m->next, p++, j++)
     {
-      unsigned int i;
       asection **secpp;
+      bfd_vma off_adjust;
+      bfd_boolean no_contents;
 
       /* If elf_segment_map is not from map_sections_to_segments, the
-         sections may not be correctly ordered.  NOTE: sorting should
+        sections may not be correctly ordered.  NOTE: sorting should
         not be done to the PT_NOTE section of a corefile, which may
         contain several pseudo-sections artificially created by bfd.
         Sorting these pseudo-sections breaks things badly.  */
@@ -4141,58 +4076,109 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
         number of sections with contents contributing to both p_filesz
         and p_memsz, followed by a number of sections with no contents
         that just contribute to p_memsz.  In this loop, OFF tracks next
-        available file offset for PT_LOAD and PT_NOTE segments.  VOFF is
-        an adjustment we use for segments that have no file contents
-        but need zero filled memory allocation.  */
-      voff = 0;
+        available file offset for PT_LOAD and PT_NOTE segments.  */
       p->p_type = m->p_type;
       p->p_flags = m->p_flags;
 
+      if (m->count == 0)
+       p->p_vaddr = 0;
+      else
+       p->p_vaddr = m->sections[0]->vma - m->p_vaddr_offset;
+
+      if (m->p_paddr_valid)
+       p->p_paddr = m->p_paddr;
+      else if (m->count == 0)
+       p->p_paddr = 0;
+      else
+       p->p_paddr = m->sections[0]->lma - m->p_vaddr_offset;
+
+      if (p->p_type == PT_LOAD
+         && (abfd->flags & D_PAGED) != 0)
+       {
+         /* p_align in demand paged PT_LOAD segments effectively stores
+            the maximum page size.  When copying an executable with
+            objcopy, we set m->p_align from the input file.  Use this
+            value for maxpagesize rather than bed->maxpagesize, which
+            may be different.  Note that we use maxpagesize for PT_TLS
+            segment alignment later in this function, so we are relying
+            on at least one PT_LOAD segment appearing before a PT_TLS
+            segment.  */
+         if (m->p_align_valid)
+           maxpagesize = m->p_align;
+
+         p->p_align = maxpagesize;
+       }
+      else if (m->count == 0)
+       p->p_align = 1 << bed->s->log_file_align;
+      else if (m->p_align_valid)
+       p->p_align = m->p_align;
+      else
+       p->p_align = 0;
+
+      no_contents = FALSE;
+      off_adjust = 0;
       if (p->p_type == PT_LOAD
          && m->count > 0)
        {
          bfd_size_type align;
-         bfd_vma adjust;
          unsigned int align_power = 0;
 
-         for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+         if (m->p_align_valid)
+           align = p->p_align;
+         else
            {
-             unsigned int secalign;
+             for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+               {
+                 unsigned int secalign;
 
-             secalign = bfd_get_section_alignment (abfd, *secpp);
-             if (secalign > align_power)
-               align_power = secalign;
+                 secalign = bfd_get_section_alignment (abfd, *secpp);
+                 if (secalign > align_power)
+                   align_power = secalign;
+               }
+             align = (bfd_size_type) 1 << align_power;
+             if (align < maxpagesize)
+               align = maxpagesize;
            }
-         align = (bfd_size_type) 1 << align_power;
-
-         if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > align)
-           align = bed->maxpagesize;
 
-         adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
-         off += adjust;
-         if (adjust != 0
-             && !m->includes_filehdr
-             && !m->includes_phdrs
-             && (ufile_ptr) off >= align)
+         for (i = 0; i < m->count; i++)
+           if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+             /* If we aren't making room for this section, then
+                it must be SHT_NOBITS regardless of what we've
+                set via struct bfd_elf_special_section.  */
+             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 the first section isn't loadable, the same holds for
-                any other sections.  Since the segment won't need file
-                space, we can make p_offset overlap some prior segment.
-                However, .tbss is special.  If a segment starts with
-                .tbss, we need to look at the next section to decide
-                whether the segment has any loadable sections.  */
-             i = 0;
-             while ((m->sections[i]->flags & SEC_LOAD) == 0)
+             /* 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)
                {
-                 if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
-                     || ++i >= m->count)
-                   {
-                     off -= adjust;
-                     voff = adjust - align;
-                     break;
-                   }
+                 no_contents = TRUE;
+                 break;
                }
            }
+
+         off_adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
+         off += off_adjust;
+         if (no_contents)
+           {
+             /* We shouldn't need to align the segment on disk since
+                the segment doesn't need file space, but the gABI
+                arguably requires the alignment and glibc ld.so
+                checks it.  So to comply with the alignment
+                requirement but not waste file space, we adjust
+                p_offset for just this segment.  (OFF_ADJUST is
+                subtracted from OFF later.)  This may put p_offset
+                past the end of file, but that shouldn't matter.  */
+           }
+         else
+           off_adjust = 0;
        }
       /* Make sure the .dynamic section is the first section in the
         PT_DYNAMIC segment.  */
@@ -4207,35 +4193,14 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
          return FALSE;
        }
 
-      if (m->count == 0)
-       p->p_vaddr = 0;
-      else
-       p->p_vaddr = m->sections[0]->vma;
-
-      if (m->p_paddr_valid)
-       p->p_paddr = m->p_paddr;
-      else if (m->count == 0)
-       p->p_paddr = 0;
-      else
-       p->p_paddr = m->sections[0]->lma;
-
-      if (p->p_type == PT_LOAD
-         && (abfd->flags & D_PAGED) != 0)
-       p->p_align = bed->maxpagesize;
-      else if (m->count == 0)
-       p->p_align = 1 << bed->s->log_file_align;
-      else
-       p->p_align = 0;
-
       p->p_offset = 0;
       p->p_filesz = 0;
       p->p_memsz = 0;
 
       if (m->includes_filehdr)
        {
-         if (! m->p_flags_valid)
+         if (!m->p_flags_valid)
            p->p_flags |= PF_R;
-         p->p_offset = 0;
          p->p_filesz = bed->s->sizeof_ehdr;
          p->p_memsz = bed->s->sizeof_ehdr;
          if (m->count > 0)
@@ -4252,30 +4217,17 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
                }
 
              p->p_vaddr -= off;
-             if (! m->p_paddr_valid)
+             if (!m->p_paddr_valid)
                p->p_paddr -= off;
            }
-         if (p->p_type == PT_LOAD)
-           {
-             filehdr_vaddr = p->p_vaddr;
-             filehdr_paddr = p->p_paddr;
-           }
        }
 
       if (m->includes_phdrs)
        {
-         if (! m->p_flags_valid)
+         if (!m->p_flags_valid)
            p->p_flags |= PF_R;
 
-         if (m->includes_filehdr)
-           {
-             if (p->p_type == PT_LOAD)
-               {
-                 phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr;
-                 phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr;
-               }
-           }
-         else
+         if (!m->includes_filehdr)
            {
              p->p_offset = bed->s->sizeof_ehdr;
 
@@ -4283,17 +4235,9 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
                {
                  BFD_ASSERT (p->p_type == PT_LOAD);
                  p->p_vaddr -= off - p->p_offset;
-                 if (! m->p_paddr_valid)
+                 if (!m->p_paddr_valid)
                    p->p_paddr -= off - p->p_offset;
                }
-
-             if (p->p_type == PT_LOAD)
-               {
-                 phdrs_vaddr = p->p_vaddr;
-                 phdrs_paddr = p->p_paddr;
-               }
-             else
-               phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
            }
 
          p->p_filesz += alloc * bed->s->sizeof_phdr;
@@ -4303,36 +4247,44 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
       if (p->p_type == PT_LOAD
          || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
        {
-         if (! m->includes_filehdr && ! m->includes_phdrs)
-           p->p_offset = off + voff;
+         if (!m->includes_filehdr && !m->includes_phdrs)
+           p->p_offset = off;
          else
            {
              file_ptr adjust;
 
              adjust = off - (p->p_offset + p->p_filesz);
-             p->p_filesz += adjust;
+             if (!no_contents)
+               p->p_filesz += adjust;
              p->p_memsz += adjust;
            }
        }
 
+      /* Set up p_filesz, p_memsz, p_align and p_flags from the section
+        maps.  Set filepos for sections in PT_LOAD segments, and in
+        core files, for sections in PT_NOTE segments.
+        assign_file_positions_for_non_load_sections will set filepos
+        for other sections and update p_filesz for other segments.  */
       for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
        {
          asection *sec;
-         flagword flags;
          bfd_size_type align;
+         Elf_Internal_Shdr *this_hdr;
 
          sec = *secpp;
-         flags = sec->flags;
-         align = 1 << bfd_get_section_alignment (abfd, sec);
+         this_hdr = &elf_section_data (sec)->this_hdr;
+         align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
 
          if (p->p_type == PT_LOAD
              || p->p_type == PT_TLS)
            {
-             bfd_signed_vma adjust;
+             bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
 
-             if ((flags & SEC_LOAD) != 0)
+             if (this_hdr->sh_type != SHT_NOBITS
+                 || ((this_hdr->sh_flags & SHF_ALLOC) != 0
+                     && ((this_hdr->sh_flags & SHF_TLS) == 0
+                         || p->p_type == PT_TLS)))
                {
-                 adjust = sec->lma - (p->p_paddr + p->p_filesz);
                  if (adjust < 0)
                    {
                      (*_bfd_error_handler)
@@ -4340,24 +4292,13 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
                         abfd, sec, (unsigned long) sec->lma);
                      adjust = 0;
                    }
-                 off += adjust;
-                 p->p_filesz += adjust;
-                 p->p_memsz += adjust;
-               }
-             /* .tbss is special.  It doesn't contribute to p_memsz of
-                normal segments.  */
-             else if ((flags & SEC_THREAD_LOCAL) == 0
-                      || p->p_type == PT_TLS)
-               {
-                 /* The section VMA must equal the file position
-                    modulo the page size.  */
-                 bfd_size_type page = align;
-                 if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > page)
-                   page = bed->maxpagesize;
-                 adjust = vma_page_aligned_bias (sec->vma,
-                                                 p->p_vaddr + p->p_memsz,
-                                                 page);
                  p->p_memsz += adjust;
+
+                 if (this_hdr->sh_type != SHT_NOBITS)
+                   {
+                     off += adjust;
+                     p->p_filesz += adjust;
+                   }
                }
            }
 
@@ -4367,9 +4308,9 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
                 everything.  */
              if (i == 0)
                {
-                 sec->filepos = off;
-                 off += sec->size;
-                 p->p_filesz = sec->size;
+                 this_hdr->sh_offset = sec->filepos = off;
+                 off += this_hdr->sh_size;
+                 p->p_filesz = this_hdr->sh_size;
                  p->p_memsz = 0;
                  p->p_align = 1;
                }
@@ -4386,266 +4327,251 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
            {
              if (p->p_type == PT_LOAD)
                {
-                 sec->filepos = off;
-                 /* FIXME: The SEC_HAS_CONTENTS test here dates back to
-                    1997, and the exact reason for it isn't clear.  One
-                    plausible explanation is that it is to work around
-                    a problem we have with linker scripts using data
-                    statements in NOLOAD sections.  I don't think it
-                    makes a great deal of sense to have such a section
-                    assigned to a PT_LOAD segment, but apparently
-                    people do this.  The data statement results in a
-                    bfd_data_link_order being built, and these need
-                    section contents to write into.  Eventually, we get
-                    to _bfd_elf_write_object_contents which writes any
-                    section with contents to the output.  Make room
-                    here for the write, so that following segments are
-                    not trashed.  */
-                 if ((flags & SEC_LOAD) != 0
-                     || (flags & SEC_HAS_CONTENTS) != 0)
-                   off += sec->size;
+                 this_hdr->sh_offset = sec->filepos = off;
+                 if (this_hdr->sh_type != SHT_NOBITS)
+                   off += this_hdr->sh_size;
                }
 
-             if ((flags & SEC_LOAD) != 0)
+             if (this_hdr->sh_type != SHT_NOBITS)
                {
-                 p->p_filesz += sec->size;
-                 p->p_memsz += sec->size;
+                 p->p_filesz += this_hdr->sh_size;
+                 /* A load section without SHF_ALLOC is something like
+                    a note section in a PT_NOTE segment.  These take
+                    file space but are not loaded into memory.  */
+                 if ((this_hdr->sh_flags & SHF_ALLOC) != 0)
+                   p->p_memsz += this_hdr->sh_size;
                }
-             /* PR ld/594:  Sections in note segments which are not loaded
-                contribute to the file size but not the in-memory size.  */
-             else if (p->p_type == PT_NOTE
-                 && (flags & SEC_HAS_CONTENTS) != 0)
-               p->p_filesz += sec->size;
-
-             /* .tbss is special.  It doesn't contribute to p_memsz of
-                normal segments.  */
-             else if ((flags & SEC_THREAD_LOCAL) == 0
-                      || p->p_type == PT_TLS)
-               p->p_memsz += sec->size;
-
-             if (p->p_type == PT_TLS
-                 && sec->size == 0
-                 && (sec->flags & SEC_HAS_CONTENTS) == 0)
+             else if ((this_hdr->sh_flags & SHF_ALLOC) != 0)
                {
-                 struct bfd_link_order *o = sec->map_tail.link_order;
-                 if (o != NULL)
-                   p->p_memsz += o->offset + o->size;
+                 if (p->p_type == PT_TLS)
+                   p->p_memsz += this_hdr->sh_size;
+
+                 /* .tbss is special.  It doesn't contribute to p_memsz of
+                    normal segments.  */
+                 else if ((this_hdr->sh_flags & SHF_TLS) == 0)
+                   p->p_memsz += this_hdr->sh_size;
                }
 
-             if (align > p->p_align
-                 && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0))
+             if (p->p_type == PT_GNU_RELRO)
+               p->p_align = 1;
+             else if (align > p->p_align
+                      && !m->p_align_valid
+                      && (p->p_type != PT_LOAD
+                          || (abfd->flags & D_PAGED) == 0))
                p->p_align = align;
            }
 
-         if (! m->p_flags_valid)
+         if (!m->p_flags_valid)
            {
              p->p_flags |= PF_R;
-             if ((flags & SEC_CODE) != 0)
+             if ((this_hdr->sh_flags & SHF_EXECINSTR) != 0)
                p->p_flags |= PF_X;
-             if ((flags & SEC_READONLY) == 0)
+             if ((this_hdr->sh_flags & SHF_WRITE) != 0)
                p->p_flags |= PF_W;
            }
        }
-    }
-
-  /* Now that we have set the section file positions, we can set up
-     the file positions for the non PT_LOAD segments.  */
-  for (m = elf_tdata (abfd)->segment_map, p = phdrs;
-       m != NULL;
-       m = m->next, p++)
-    {
-      if (p->p_type != PT_LOAD && m->count > 0)
-       {
-         BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs);
-         /* If the section has not yet been assigned a file position,
-            do so now.  The ARM BPABI requires that .dynamic section
-            not be marked SEC_ALLOC because it is not part of any
-            PT_LOAD segment, so it will not be processed above.  */
-         if (p->p_type == PT_DYNAMIC && m->sections[0]->filepos == 0)
-           {
-             unsigned int i;
-             Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
-
-             i = 1;
-             while (i_shdrpp[i]->bfd_section != m->sections[0])
-               ++i;
-             off = (_bfd_elf_assign_file_position_for_section 
-                    (i_shdrpp[i], off, TRUE));
-             p->p_filesz = m->sections[0]->size;
-           }
-         p->p_offset = m->sections[0]->filepos;
-       }
-      if (m->count == 0)
-       {
-         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;
-               }
+      off -= off_adjust;
 
-             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;
-               }
-           }
-       }
-    }
+      /* 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;
 
-  /* Clear out any program headers we allocated but did not use.  */
-  for (; count < alloc; count++, p++)
-    {
-      memset (p, 0, sizeof *p);
-      p->p_type = PT_NULL;
+           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_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;
+             }
+         }
     }
 
-  elf_tdata (abfd)->phdr = phdrs;
-
   elf_tdata (abfd)->next_file_pos = off;
-
-  /* Write out the program headers.  */
-  if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
-      || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0)
-    return FALSE;
-
   return TRUE;
 }
 
-/* Get the size of the program header.
+/* Assign file positions for the other sections.  */
 
-   If this is called by the linker before any of the section VMA's are set, it
-   can't calculate the correct value for a strange memory layout.  This only
-   happens when SIZEOF_HEADERS is used in a linker script.  In this case,
-   SORTED_HDRS is NULL and we assume the normal scenario of one text and one
-   data segment (exclusive of .interp and .dynamic).
-
-   ??? User written scripts must either not use SIZEOF_HEADERS, or assume there
-   will be two segments.  */
-
-static bfd_size_type
-get_program_header_size (bfd *abfd)
+static bfd_boolean
+assign_file_positions_for_non_load_sections (bfd *abfd,
+                                            struct bfd_link_info *link_info)
 {
-  size_t segs;
-  asection *s;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  Elf_Internal_Shdr **i_shdrpp;
+  Elf_Internal_Shdr **hdrpp;
+  Elf_Internal_Phdr *phdrs;
+  Elf_Internal_Phdr *p;
+  struct elf_segment_map *m;
+  bfd_vma filehdr_vaddr, filehdr_paddr;
+  bfd_vma phdrs_vaddr, phdrs_paddr;
+  file_ptr off;
+  unsigned int num_sec;
+  unsigned int i;
+  unsigned int count;
 
-  /* We can't return a different result each time we're called.  */
-  if (elf_tdata (abfd)->program_header_size != 0)
-    return elf_tdata (abfd)->program_header_size;
-
-  if (elf_tdata (abfd)->segment_map != NULL)
-    {
-      struct elf_segment_map *m;
-
-      segs = 0;
-      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
-       ++segs;
-      elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
-      return elf_tdata (abfd)->program_header_size;
-    }
-
-  /* Assume we will need exactly two PT_LOAD segments: one for text
-     and one for data.  */
-  segs = 2;
-
-  s = bfd_get_section_by_name (abfd, ".interp");
-  if (s != NULL && (s->flags & SEC_LOAD) != 0)
-    {
-      /* If we have a loadable interpreter section, we need a
-        PT_INTERP segment.  In this case, assume we also need a
-        PT_PHDR segment, although that may not be true for all
-        targets.  */
-      segs += 2;
-    }
-
-  if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
+  i_shdrpp = elf_elfsections (abfd);
+  num_sec = elf_numsections (abfd);
+  off = elf_tdata (abfd)->next_file_pos;
+  for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++)
     {
-      /* We need a PT_DYNAMIC segment.  */
-      ++segs;
-    }
+      struct elf_obj_tdata *tdata = elf_tdata (abfd);
+      Elf_Internal_Shdr *hdr;
 
-  if (elf_tdata (abfd)->eh_frame_hdr)
-    {
-      /* We need a PT_GNU_EH_FRAME segment.  */
-      ++segs;
-    }
+      hdr = *hdrpp;
+      if (hdr->bfd_section != NULL
+         && (hdr->bfd_section->filepos != 0
+             || (hdr->sh_type == SHT_NOBITS
+                 && hdr->contents == NULL)))
+       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)));
+         /* 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,
+                                         bed->maxpagesize);
+         else
+           off += vma_page_aligned_bias (hdr->sh_addr, off,
+                                         hdr->sh_addralign);
+         off = _bfd_elf_assign_file_position_for_section (hdr, off,
+                                                          FALSE);
+       }
+      else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+               && hdr->bfd_section == NULL)
+              || hdr == i_shdrpp[tdata->symtab_section]
+              || hdr == i_shdrpp[tdata->symtab_shndx_section]
+              || hdr == i_shdrpp[tdata->strtab_section])
+       hdr->sh_offset = -1;
+      else
+       off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
 
-  if (elf_tdata (abfd)->stack_flags)
-    {
-      /* We need a PT_GNU_STACK segment.  */
-      ++segs;
+      if (i == SHN_LORESERVE - 1)
+       {
+         i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+         hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+       }
     }
 
-  if (elf_tdata (abfd)->relro)
+  /* Now that we have set the section file positions, we can set up
+     the file positions for the non PT_LOAD segments.  */
+  count = 0;
+  filehdr_vaddr = 0;
+  filehdr_paddr = 0;
+  phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
+  phdrs_paddr = 0;
+  phdrs = elf_tdata (abfd)->phdr;
+  for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+       m != NULL;
+       m = m->next, p++)
     {
-      /* We need a PT_GNU_RELRO segment.  */
-      ++segs;
-    }
+      ++count;
+      if (p->p_type != PT_LOAD)
+       continue;
 
-  for (s = abfd->sections; s != NULL; s = s->next)
-    {
-      if ((s->flags & SEC_LOAD) != 0
-         && strncmp (s->name, ".note", 5) == 0)
+      if (m->includes_filehdr)
+       {
+         filehdr_vaddr = p->p_vaddr;
+         filehdr_paddr = p->p_paddr;
+       }
+      if (m->includes_phdrs)
        {
-         /* We need a PT_NOTE segment.  */
-         ++segs;
+         phdrs_vaddr = p->p_vaddr;
+         phdrs_paddr = p->p_paddr;
+         if (m->includes_filehdr)
+           {
+             phdrs_vaddr += bed->s->sizeof_ehdr;
+             phdrs_paddr += bed->s->sizeof_ehdr;
+           }
        }
     }
 
-  for (s = abfd->sections; s != NULL; s = s->next)
+  for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+       m != NULL;
+       m = m->next, p++)
     {
-      if (s->flags & SEC_THREAD_LOCAL)
+      if (m->count != 0)
        {
-         /* We need a PT_TLS segment.  */
-         ++segs;
-         break;
+         if (p->p_type != PT_LOAD
+             && (p->p_type != PT_NOTE || bfd_get_format (abfd) != bfd_core))
+           {
+             Elf_Internal_Shdr *hdr;
+             BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+
+             hdr = &elf_section_data (m->sections[m->count - 1])->this_hdr;
+             p->p_filesz = (m->sections[m->count - 1]->filepos
+                            - m->sections[0]->filepos);
+             if (hdr->sh_type != SHT_NOBITS)
+               p->p_filesz += hdr->sh_size;
+
+             p->p_offset = m->sections[0]->filepos;
+           }
        }
-    }
+      else
+       {
+         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;
 
-  /* Let the backend count up any program headers it might need.  */
-  if (bed->elf_backend_additional_program_headers)
-    {
-      int a;
+             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;
+               }
 
-      a = (*bed->elf_backend_additional_program_headers) (abfd);
-      if (a == -1)
-       abort ();
-      segs += a;
+             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;
+               }
+           }
+       }
     }
 
-  elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
-  return elf_tdata (abfd)->program_header_size;
+  elf_tdata (abfd)->next_file_pos = off;
+
+  return TRUE;
 }
 
 /* Work out the file positions of all the sections.  This is called by
@@ -4666,16 +4592,16 @@ static bfd_boolean
 assign_file_positions_except_relocs (bfd *abfd,
                                     struct bfd_link_info *link_info)
 {
-  struct elf_obj_tdata * const tdata = elf_tdata (abfd);
-  Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd);
-  Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
-  unsigned int num_sec = elf_numsections (abfd);
+  struct elf_obj_tdata *tdata = elf_tdata (abfd);
+  Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
   file_ptr off;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
       && bfd_get_format (abfd) != bfd_core)
     {
+      Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
+      unsigned int num_sec = elf_numsections (abfd);
       Elf_Internal_Shdr **hdrpp;
       unsigned int i;
 
@@ -4710,57 +4636,30 @@ assign_file_positions_except_relocs (bfd *abfd,
     }
   else
     {
-      unsigned int i;
-      Elf_Internal_Shdr **hdrpp;
+      unsigned int alloc;
 
       /* Assign file positions for the loaded sections based on the
-         assignment of sections to segments.  */
-      if (! assign_file_positions_for_segments (abfd, link_info))
+        assignment of sections to segments.  */
+      if (!assign_file_positions_for_load_sections (abfd, link_info))
        return FALSE;
 
-      /* Assign file positions for the other sections.  */
+      /* And for non-load sections.  */
+      if (!assign_file_positions_for_non_load_sections (abfd, link_info))
+       return FALSE;
 
-      off = elf_tdata (abfd)->next_file_pos;
-      for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++)
+      if (bed->elf_backend_modify_program_headers != NULL)
        {
-         Elf_Internal_Shdr *hdr;
+         if (!(*bed->elf_backend_modify_program_headers) (abfd, link_info))
+           return FALSE;
+       }
 
-         hdr = *hdrpp;
-         if (hdr->bfd_section != NULL
-             && hdr->bfd_section->filepos != 0)
-           hdr->sh_offset = hdr->bfd_section->filepos;
-         else if ((hdr->sh_flags & SHF_ALLOC) != 0)
-           {
-             ((*_bfd_error_handler)
-              (_("%B: warning: allocated section `%s' not in segment"),
-               abfd,
-               (hdr->bfd_section == NULL
-                ? "*unknown*"
-                : hdr->bfd_section->name)));
-             if ((abfd->flags & D_PAGED) != 0)
-               off += vma_page_aligned_bias (hdr->sh_addr, off,
-                                             bed->maxpagesize);
-             else
-               off += vma_page_aligned_bias (hdr->sh_addr, off,
-                                             hdr->sh_addralign);
-             off = _bfd_elf_assign_file_position_for_section (hdr, off,
-                                                              FALSE);
-           }
-         else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
-                   && hdr->bfd_section == NULL)
-                  || hdr == i_shdrpp[tdata->symtab_section]
-                  || hdr == i_shdrpp[tdata->symtab_shndx_section]
-                  || hdr == i_shdrpp[tdata->strtab_section])
-           hdr->sh_offset = -1;
-         else
-           off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
+      /* Write out the program headers.  */
+      alloc = tdata->program_header_size / bed->s->sizeof_phdr;
+      if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
+         || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
+       return FALSE;
 
-         if (i == SHN_LORESERVE - 1)
-           {
-             i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-             hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-           }
-       }
+      off = tdata->next_file_pos;
     }
 
   /* Place the section headers.  */
@@ -4768,7 +4667,7 @@ assign_file_positions_except_relocs (bfd *abfd,
   i_ehdrp->e_shoff = off;
   off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize;
 
-  elf_tdata (abfd)->next_file_pos = off;
+  tdata->next_file_pos = off;
 
   return TRUE;
 }
@@ -4935,14 +4834,21 @@ _bfd_elf_write_object_contents (bfd *abfd)
   /* Write out the section header names.  */
   if (elf_shstrtab (abfd) != NULL
       && (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
-          || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))))
+         || !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))))
     return FALSE;
 
   if (bed->elf_backend_final_write_processing)
     (*bed->elf_backend_final_write_processing) (abfd,
                                                elf_tdata (abfd)->linker);
 
-  return bed->s->write_shdrs_and_ehdr (abfd);
+  if (!bed->s->write_shdrs_and_ehdr (abfd))
+    return FALSE;
+
+  /* This is last since write_shdrs_and_ehdr can touch i_shdrp[0].  */
+  if (elf_tdata (abfd)->after_write_object_contents)
+    return (*elf_tdata (abfd)->after_write_object_contents) (abfd);
+
+  return TRUE;
 }
 
 bfd_boolean
@@ -5007,13 +4913,14 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
       && (flags & BSF_SECTION_SYM)
       && asym_ptr->section)
     {
+      asection *sec;
       int indx;
 
-      if (asym_ptr->section->output_section != NULL)
-       indx = asym_ptr->section->output_section->index;
-      else
-       indx = asym_ptr->section->index;
-      if (indx < elf_num_section_syms (abfd)
+      sec = asym_ptr->section;
+      if (sec->owner != abfd && sec->output_section != NULL)
+       sec = sec->output_section;
+      if (sec->owner == abfd
+         && (indx = sec->index) < elf_num_section_syms (abfd)
          && elf_section_syms (abfd)[indx] != NULL)
        asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i;
     }
@@ -5023,7 +4930,7 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
   if (idx == 0)
     {
       /* This case can occur when using --strip-symbol on a symbol
-         which is used in a relocation entry.  */
+        which is used in a relocation entry.  */
       (*_bfd_error_handler)
        (_("%B: symbol `%s' required but not present"),
         abfd, bfd_asymbol_name (asym_ptr));
@@ -5044,10 +4951,10 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
   return idx;
 }
 
-/* Copy private BFD data.  This copies any program header information.  */
+/* Rewrite program header information.  */
 
 static bfd_boolean
-copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 {
   Elf_Internal_Ehdr *iehdr;
   struct elf_segment_map *map;
@@ -5063,13 +4970,6 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
   unsigned int phdr_adjust_num = 0;
   const struct elf_backend_data *bed;
 
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
-
-  if (elf_tdata (ibfd)->phdr == NULL)
-    return TRUE;
-
   bed = get_elf_backend_data (ibfd);
   iehdr = elf_elfheader (ibfd);
 
@@ -5109,7 +5009,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && bfd_get_format (ibfd) == bfd_core                                        \
    && s->vma == 0 && s->lma == 0                                       \
    && (bfd_vma) s->filepos >= p->p_offset                              \
-   && ((bfd_vma) s->filepos + s->size                          \
+   && ((bfd_vma) s->filepos + s->size                                  \
        <= p->p_offset + p->p_filesz))
 
   /* The complicated case when p_vaddr is 0 is to handle the Solaris
@@ -5123,13 +5023,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && (s->flags & SEC_HAS_CONTENTS) != 0                               \
    && s->size > 0                                                      \
    && (bfd_vma) s->filepos >= p->p_offset                              \
-   && ((bfd_vma) s->filepos + s->size                          \
+   && ((bfd_vma) s->filepos + s->size                                  \
        <= p->p_offset + p->p_filesz))
 
   /* Decide if the given section should be included in the given segment.
      A section will be included if:
        1. It is within the address space of the segment -- we use the LMA
-          if that is set for the segment and the VMA otherwise,
+         if that is set for the segment and the VMA otherwise,
        2. It is an allocated segment,
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.
@@ -5137,14 +5037,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
        6. PT_TLS segment includes only SHF_TLS sections.
        7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
        8. PT_DYNAMIC should not contain empty sections at the beginning
-          (with the possible exception of .dynamic).  */
-#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
+         (with the possible exception of .dynamic).  */
+#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed)             \
   ((((segment->p_paddr                                                 \
       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)       \
       : IS_CONTAINED_BY_VMA (section, segment))                                \
      && (section->flags & SEC_ALLOC) != 0)                             \
     || IS_COREFILE_NOTE (segment, section))                            \
-   && section->output_section != NULL                                  \
    && segment->p_type != PT_GNU_STACK                                  \
    && (segment->p_type != PT_TLS                                       \
        || (section->flags & SEC_THREAD_LOCAL))                         \
@@ -5154,12 +5053,18 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && (segment->p_type != PT_DYNAMIC                                   \
        || SECTION_SIZE (section, segment) > 0                          \
        || (segment->p_paddr                                            \
-           ? segment->p_paddr != section->lma                          \
-           : segment->p_vaddr != section->vma)                         \
+          ? segment->p_paddr != section->lma                           \
+          : segment->p_vaddr != section->vma)                          \
        || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic")   \
-           == 0))                                                      \
+          == 0))                                                       \
    && ! section->segment_mark)
 
+/* If the output section of a section in the input segment is NULL,
+   it is removed from the corresponding output segment.   */
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
+  (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)         \
+   && section->output_section != NULL)
+
   /* Returns TRUE iff seg1 starts after the end of seg2.  */
 #define SEGMENT_AFTER_SEGMENT(seg1, seg2, field)                       \
   (seg1->field >= SEGMENT_END (seg2, seg2->field))
@@ -5172,9 +5077,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
      LMA.  */
 #define SEGMENT_OVERLAPS(seg1, seg2)                                   \
   (   !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_vaddr)                    \
-        || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr))                \
+       || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr))                 \
    && !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_paddr)                    \
-        || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr)))
+       || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr)))
 
   /* Initialise the segment mark field.  */
   for (section = ibfd->sections; section != NULL; section = section->next)
@@ -5217,7 +5122,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
          if (segment2->p_vaddr < segment->p_vaddr)
            {
              /* Extend SEGMENT2 to include SEGMENT and then delete
-                 SEGMENT.  */
+                SEGMENT.  */
              extra_length =
                SEGMENT_END (segment, segment->p_vaddr)
                - SEGMENT_END (segment2, segment2->p_vaddr);
@@ -5238,7 +5143,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
          else
            {
              /* Extend SEGMENT to include SEGMENT2 and then delete
-                 SEGMENT2.  */
+                SEGMENT2.  */
              extra_length =
                SEGMENT_END (segment2, segment2->p_vaddr)
                - SEGMENT_END (segment, segment->p_vaddr);
@@ -5267,22 +5172,33 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
       bfd_vma       suggested_lma;
       unsigned int  j;
       bfd_size_type amt;
+      asection *    first_section;
 
       if (segment->p_type == PT_NULL)
        continue;
 
+      first_section = NULL;
       /* Compute how many sections might be placed into this segment.  */
       for (section = ibfd->sections, section_count = 0;
           section != NULL;
           section = section->next)
-       if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
-         ++section_count;
+       {
+         /* Find the first section in the input segment, which may be
+            removed from the corresponding output segment.   */
+         if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed))
+           {
+             if (first_section == NULL)
+               first_section = section;
+             if (section->output_section != NULL)
+               ++section_count;
+           }
+       }
 
       /* Allocate a segment map big enough to contain
         all of the sections we have selected.  */
       amt = sizeof (struct elf_segment_map);
       amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-      map = bfd_alloc (obfd, amt);
+      map = bfd_zalloc (obfd, amt);
       if (map == NULL)
        return FALSE;
 
@@ -5292,8 +5208,15 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
       map->p_type        = segment->p_type;
       map->p_flags       = segment->p_flags;
       map->p_flags_valid = 1;
-      map->p_paddr       = segment->p_paddr;
-      map->p_paddr_valid = 1;
+
+      /* If the first section in the input segment is removed, there is
+        no need to preserve segment physical address in the corresponding
+        output segment.  */
+      if (!first_section || first_section->output_section != NULL)
+       {
+         map->p_paddr = segment->p_paddr;
+         map->p_paddr_valid = 1;
+       }
 
       /* Determine if this segment contains the ELF file header
         and if it contains the program headers themselves.  */
@@ -5410,10 +5333,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
              if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
                  || IS_COREFILE_NOTE (segment, section)
                  || (bed->want_p_paddr_set_to_zero &&
-                     IS_CONTAINED_BY_VMA (output_section, segment))
-                )
+                     IS_CONTAINED_BY_VMA (output_section, segment)))
                {
-                 if (matching_lma == 0)
+                 if (matching_lma == 0 || output_section->lma < matching_lma)
                    matching_lma = output_section->lma;
 
                  /* We assume that if the section fits within the segment
@@ -5440,6 +5362,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
          *pointer_to_map = map;
          pointer_to_map = &map->next;
 
+         if (matching_lma != map->p_paddr
+             && !map->includes_filehdr && !map->includes_phdrs)
+           /* There is some padding before the first section in the
+              segment.  So, we must account for that in the output
+              segment's vma.  */
+           map->p_vaddr_offset = matching_lma - map->p_paddr;
+
          free (sections);
          continue;
        }
@@ -5542,91 +5471,300 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
                        }
                    }
 
-                 map->sections[map->count++] = output_section;
-                 ++isec;
-                 sections[j] = NULL;
-                 section->segment_mark = TRUE;
-               }
-             else if (suggested_lma == 0)
-               suggested_lma = output_section->lma;
-           }
+                 map->sections[map->count++] = output_section;
+                 ++isec;
+                 sections[j] = NULL;
+                 section->segment_mark = TRUE;
+               }
+             else if (suggested_lma == 0)
+               suggested_lma = output_section->lma;
+           }
+
+         BFD_ASSERT (map->count > 0);
+
+         /* Add the current segment to the list of built segments.  */
+         *pointer_to_map = map;
+         pointer_to_map = &map->next;
+
+         if (isec < section_count)
+           {
+             /* We still have not allocated all of the sections to
+                segments.  Create a new segment here, initialise it
+                and carry on looping.  */
+             amt = sizeof (struct elf_segment_map);
+             amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
+             map = bfd_alloc (obfd, amt);
+             if (map == NULL)
+               {
+                 free (sections);
+                 return FALSE;
+               }
+
+             /* Initialise the fields of the segment map.  Set the physical
+                physical address to the LMA of the first section that has
+                not yet been assigned.  */
+             map->next             = NULL;
+             map->p_type           = segment->p_type;
+             map->p_flags          = segment->p_flags;
+             map->p_flags_valid    = 1;
+             map->p_paddr          = suggested_lma;
+             map->p_paddr_valid    = 1;
+             map->includes_filehdr = 0;
+             map->includes_phdrs   = 0;
+           }
+       }
+      while (isec < section_count);
+
+      free (sections);
+    }
+
+  /* The Solaris linker creates program headers in which all the
+     p_paddr fields are zero.  When we try to objcopy or strip such a
+     file, we get confused.  Check for this case, and if we find it
+     reset the p_paddr_valid fields.  */
+  for (map = map_first; map != NULL; map = map->next)
+    if (map->p_paddr != 0)
+      break;
+  if (map == NULL)
+    for (map = map_first; map != NULL; map = map->next)
+      map->p_paddr_valid = 0;
+
+  elf_tdata (obfd)->segment_map = map_first;
+
+  /* If we had to estimate the number of program headers that were
+     going to be needed, then check our estimate now and adjust
+     the offset if necessary.  */
+  if (phdr_adjust_seg != NULL)
+    {
+      unsigned int count;
+
+      for (count = 0, map = map_first; map != NULL; map = map->next)
+       count++;
+
+      if (count > phdr_adjust_num)
+       phdr_adjust_seg->p_paddr
+         -= (count - phdr_adjust_num) * iehdr->e_phentsize;
+    }
+
+#undef SEGMENT_END
+#undef SECTION_SIZE
+#undef IS_CONTAINED_BY_VMA
+#undef IS_CONTAINED_BY_LMA
+#undef IS_COREFILE_NOTE
+#undef IS_SOLARIS_PT_INTERP
+#undef IS_SECTION_IN_INPUT_SEGMENT
+#undef INCLUDE_SECTION_IN_SEGMENT
+#undef SEGMENT_AFTER_SEGMENT
+#undef SEGMENT_OVERLAPS
+  return TRUE;
+}
+
+/* Copy ELF program header information.  */
+
+static bfd_boolean
+copy_elf_program_header (bfd *ibfd, bfd *obfd)
+{
+  Elf_Internal_Ehdr *iehdr;
+  struct elf_segment_map *map;
+  struct elf_segment_map *map_first;
+  struct elf_segment_map **pointer_to_map;
+  Elf_Internal_Phdr *segment;
+  unsigned int i;
+  unsigned int num_segments;
+  bfd_boolean phdr_included = FALSE;
+
+  iehdr = elf_elfheader (ibfd);
+
+  map_first = NULL;
+  pointer_to_map = &map_first;
+
+  num_segments = elf_elfheader (ibfd)->e_phnum;
+  for (i = 0, segment = elf_tdata (ibfd)->phdr;
+       i < num_segments;
+       i++, segment++)
+    {
+      asection *section;
+      unsigned int section_count;
+      bfd_size_type amt;
+      Elf_Internal_Shdr *this_hdr;
+      asection *first_section = NULL;
+      asection *lowest_section = NULL;
+
+      /* FIXME: Do we need to copy PT_NULL segment?  */
+      if (segment->p_type == PT_NULL)
+       continue;
+
+      /* Compute how many sections are in this segment.  */
+      for (section = ibfd->sections, section_count = 0;
+          section != NULL;
+          section = section->next)
+       {
+         this_hdr = &(elf_section_data(section)->this_hdr);
+         if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
+           {
+             if (!first_section)
+               first_section = lowest_section = section;
+             if (section->lma < lowest_section->lma)
+               lowest_section = section;
+             section_count++;
+           }
+       }
+
+      /* Allocate a segment map big enough to contain
+        all of the sections we have selected.  */
+      amt = sizeof (struct elf_segment_map);
+      if (section_count != 0)
+       amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
+      map = bfd_zalloc (obfd, amt);
+      if (map == NULL)
+       return FALSE;
+
+      /* Initialize the fields of the output segment map with the
+        input segment.  */
+      map->next = NULL;
+      map->p_type = segment->p_type;
+      map->p_flags = segment->p_flags;
+      map->p_flags_valid = 1;
+      map->p_paddr = segment->p_paddr;
+      map->p_paddr_valid = 1;
+      map->p_align = segment->p_align;
+      map->p_align_valid = 1;
+      map->p_vaddr_offset = 0;
+
+      /* Determine if this segment contains the ELF file header
+        and if it contains the program headers themselves.  */
+      map->includes_filehdr = (segment->p_offset == 0
+                              && segment->p_filesz >= iehdr->e_ehsize);
+
+      map->includes_phdrs = 0;
+      if (! phdr_included || segment->p_type != PT_LOAD)
+       {
+         map->includes_phdrs =
+           (segment->p_offset <= (bfd_vma) iehdr->e_phoff
+            && (segment->p_offset + segment->p_filesz
+                >= ((bfd_vma) iehdr->e_phoff
+                    + iehdr->e_phnum * iehdr->e_phentsize)));
+
+         if (segment->p_type == PT_LOAD && map->includes_phdrs)
+           phdr_included = TRUE;
+       }
 
-         BFD_ASSERT (map->count > 0);
+      if (!map->includes_phdrs && !map->includes_filehdr)
+       /* There is some other padding before the first section.  */
+       map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
+                              - segment->p_paddr);
 
-         /* Add the current segment to the list of built segments.  */
-         *pointer_to_map = map;
-         pointer_to_map = &map->next;
+      if (section_count != 0)
+       {
+         unsigned int isec = 0;
 
-         if (isec < section_count)
+         for (section = first_section;
+              section != NULL;
+              section = section->next)
            {
-             /* We still have not allocated all of the sections to
-                segments.  Create a new segment here, initialise it
-                and carry on looping.  */
-             amt = sizeof (struct elf_segment_map);
-             amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
-             map = bfd_alloc (obfd, amt);
-             if (map == NULL)
+             this_hdr = &(elf_section_data(section)->this_hdr);
+             if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
                {
-                 free (sections);
-                 return FALSE;
+                 map->sections[isec++] = section->output_section;
+                 if (isec == section_count)
+                   break;
                }
-
-             /* Initialise the fields of the segment map.  Set the physical
-                physical address to the LMA of the first section that has
-                not yet been assigned.  */
-             map->next             = NULL;
-             map->p_type           = segment->p_type;
-             map->p_flags          = segment->p_flags;
-             map->p_flags_valid    = 1;
-             map->p_paddr          = suggested_lma;
-             map->p_paddr_valid    = 1;
-             map->includes_filehdr = 0;
-             map->includes_phdrs   = 0;
            }
        }
-      while (isec < section_count);
 
-      free (sections);
+      map->count = section_count;
+      *pointer_to_map = map;
+      pointer_to_map = &map->next;
     }
 
-  /* The Solaris linker creates program headers in which all the
-     p_paddr fields are zero.  When we try to objcopy or strip such a
-     file, we get confused.  Check for this case, and if we find it
-     reset the p_paddr_valid fields.  */
-  for (map = map_first; map != NULL; map = map->next)
-    if (map->p_paddr != 0)
-      break;
-  if (map == NULL)
-    for (map = map_first; map != NULL; map = map->next)
-      map->p_paddr_valid = 0;
-
   elf_tdata (obfd)->segment_map = map_first;
+  return TRUE;
+}
 
-  /* If we had to estimate the number of program headers that were
-     going to be needed, then check our estimate now and adjust
-     the offset if necessary.  */
-  if (phdr_adjust_seg != NULL)
+/* Copy private BFD data.  This copies or rewrites ELF program header
+   information.  */
+
+static bfd_boolean
+copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  if (elf_tdata (ibfd)->phdr == NULL)
+    return TRUE;
+
+  if (ibfd->xvec == obfd->xvec)
     {
-      unsigned int count;
+      /* Check to see if any sections in the input BFD
+        covered by ELF program header have changed.  */
+      Elf_Internal_Phdr *segment;
+      asection *section, *osec;
+      unsigned int i, num_segments;
+      Elf_Internal_Shdr *this_hdr;
 
-      for (count = 0, map = map_first; map != NULL; map = map->next)
-       count++;
+      /* Initialize the segment mark field.  */
+      for (section = obfd->sections; section != NULL;
+          section = section->next)
+       section->segment_mark = FALSE;
 
-      if (count > phdr_adjust_num)
-       phdr_adjust_seg->p_paddr
-         -= (count - phdr_adjust_num) * iehdr->e_phentsize;
+      num_segments = elf_elfheader (ibfd)->e_phnum;
+      for (i = 0, segment = elf_tdata (ibfd)->phdr;
+          i < num_segments;
+          i++, segment++)
+       {
+         /* PR binutils/3535.  The Solaris linker always sets the p_paddr
+            and p_memsz fields of special segments (DYNAMIC, INTERP) to 0
+            which severly confuses things, so always regenerate the segment
+            map in this case.  */
+         if (segment->p_paddr == 0
+             && segment->p_memsz == 0
+             && (segment->p_type == PT_INTERP || segment->p_type == PT_DYNAMIC))
+           goto rewrite;
+
+         for (section = ibfd->sections;
+              section != NULL; section = section->next)
+           {
+             /* We mark the output section so that we know it comes
+                from the input BFD.  */
+             osec = section->output_section;
+             if (osec)
+               osec->segment_mark = TRUE;
+
+             /* 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))
+               {
+                 /* FIXME: Check if its output section is changed or
+                    removed.  What else do we need to check?  */
+                 if (osec == NULL
+                     || section->flags != osec->flags
+                     || section->lma != osec->lma
+                     || section->vma != osec->vma
+                     || section->size != osec->size
+                     || section->rawsize != osec->rawsize
+                     || section->alignment_power != osec->alignment_power)
+                   goto rewrite;
+               }
+           }
+       }
+
+      /* Check to see if any output section do not come from the
+        input BFD.  */
+      for (section = obfd->sections; section != NULL;
+          section = section->next)
+       {
+         if (section->segment_mark == FALSE)
+           goto rewrite;
+         else
+           section->segment_mark = FALSE;
+       }
+
+      return copy_elf_program_header (ibfd, obfd);
     }
 
-#undef SEGMENT_END
-#undef SECTION_SIZE
-#undef IS_CONTAINED_BY_VMA
-#undef IS_CONTAINED_BY_LMA
-#undef IS_COREFILE_NOTE
-#undef IS_SOLARIS_PT_INTERP
-#undef INCLUDE_SECTION_IN_SEGMENT
-#undef SEGMENT_AFTER_SEGMENT
-#undef SEGMENT_OVERLAPS
-  return TRUE;
+rewrite:
+  return rewrite_elf_program_header (ibfd, obfd);
 }
 
 /* Initialize private output section information from input section.  */
@@ -5646,16 +5784,22 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
       || obfd->xvec->flavour != bfd_target_elf_flavour)
     return TRUE;
 
-  /* FIXME: What if the output ELF section type has been set to
-     something different?  */
-  if (elf_section_type (osec) == SHT_NULL)
+  /* 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.  */
+  if (elf_section_type (osec) == SHT_NULL
+      && (osec->flags == isec->flags || !osec->flags))
     elf_section_type (osec) = elf_section_type (isec);
 
+  /* FIXME: Is this correct for all OS/PROC specific flags?  */
+  elf_section_flags (osec) |= (elf_section_flags (isec)
+                              & (SHF_MASKOS | SHF_MASKPROC));
+
   /* Set things up for objcopy and relocatable link.  The output
      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 (elf_sec_group (isec) == NULL
@@ -5720,6 +5864,8 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
 bfd_boolean
 _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
 {
+  asection *isec;
+
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return TRUE;
@@ -5735,6 +5881,27 @@ _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *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)
+      {
+       asection *first = elf_next_in_group (isec);
+       asection *s = first;
+       while (s != NULL)
+         {
+           if (s->output_section != NULL)
+             {
+               elf_section_flags (s->output_section) &= ~SHF_GROUP;
+               elf_group_name (s->output_section) = NULL;
+             }
+           s = elf_next_in_group (s);
+           if (s == first)
+             break;
+         }
+      }
+
   return TRUE;
 }
 
@@ -6007,6 +6174,10 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
        type = STT_FUNC;
       else if ((flags & BSF_OBJECT) != 0)
        type = STT_OBJECT;
+      else if ((flags & BSF_RELC) != 0)
+       type = STT_RELC;
+      else if ((flags & BSF_SRELC) != 0)
+       type = STT_SRELC;
       else
        type = STT_NOTYPE;
 
@@ -6685,8 +6856,6 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
          if (state == symbol_seen)
            state = file_after_symbol_seen;
          continue;
-       case STT_SECTION:
-         continue;
        case STT_NOTYPE:
        case STT_FUNC:
          if (bfd_get_section (&q->symbol) == section
@@ -6695,12 +6864,10 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
            {
              func = (asymbol *) q;
              low_func = q->symbol.value;
-             if (file == NULL)
-               filename = NULL;
-             else if (ELF_ST_BIND (q->internal_elf_sym.st_info) != STB_LOCAL
-                      && state == file_after_symbol_seen)
-               filename = NULL;
-             else
+             filename = NULL;
+             if (file != NULL
+                 && (ELF_ST_BIND (q->internal_elf_sym.st_info) == STB_LOCAL
+                     || state != file_after_symbol_seen))
                filename = bfd_asymbol_name (file);
            }
          break;
@@ -6809,13 +6976,31 @@ _bfd_elf_find_inliner_info (bfd *abfd,
 }
 
 int
-_bfd_elf_sizeof_headers (bfd *abfd, bfd_boolean reloc)
+_bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info)
 {
-  int ret;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  int ret = bed->s->sizeof_ehdr;
+
+  if (!info->relocatable)
+    {
+      bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
+
+      if (phdr_size == (bfd_size_type) -1)
+       {
+         struct elf_segment_map *m;
+
+         phdr_size = 0;
+         for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+           phdr_size += bed->s->sizeof_phdr;
+
+         if (phdr_size == 0)
+           phdr_size = get_program_header_size (abfd, info);
+       }
+
+      elf_tdata (abfd)->program_header_size = phdr_size;
+      ret += phdr_size;
+    }
 
-  ret = get_elf_backend_data (abfd)->s->sizeof_ehdr;
-  if (! reloc)
-    ret += get_program_header_size (abfd);
   return ret;
 }
 
@@ -6951,7 +7136,7 @@ _bfd_elf_close_and_cleanup (bfd *abfd)
 {
   if (bfd_get_format (abfd) == bfd_object)
     {
-      if (elf_shstrtab (abfd) != NULL)
+      if (elf_tdata (abfd) != NULL && elf_shstrtab (abfd) != NULL)
        _bfd_elf_strtab_free (elf_shstrtab (abfd));
       _bfd_dwarf2_cleanup_debug_info (abfd);
     }
@@ -7005,13 +7190,12 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect)
   if (bfd_get_section_by_name (abfd, name) != NULL)
     return TRUE;
 
-  sect2 = bfd_make_section (abfd, name);
+  sect2 = bfd_make_section_with_flags (abfd, name, sect->flags);
   if (sect2 == NULL)
     return FALSE;
 
   sect2->size = sect->size;
   sect2->filepos = sect->filepos;
-  sect2->flags = sect->flags;
   sect2->alignment_power = sect->alignment_power;
   return TRUE;
 }
@@ -7043,12 +7227,12 @@ _bfd_elfcore_make_pseudosection (bfd *abfd,
     return FALSE;
   memcpy (threaded_name, buf, len);
 
-  sect = bfd_make_section_anyway (abfd, threaded_name);
+  sect = bfd_make_section_anyway_with_flags (abfd, threaded_name,
+                                            SEC_HAS_CONTENTS);
   if (sect == NULL)
     return FALSE;
   sect->size = size;
   sect->filepos = filepos;
-  sect->flags = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
 
   return elfcore_maybe_make_sect (abfd, name, sect);
@@ -7327,7 +7511,7 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
   memcpy (name, buf, len);
 
-  sect = bfd_make_section_anyway (abfd, name);
+  sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
   if (sect == NULL)
     return FALSE;
 
@@ -7342,7 +7526,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
   sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
 #endif
 
-  sect->flags = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
 
   if (!elfcore_maybe_make_sect (abfd, ".reg", sect))
@@ -7357,7 +7540,7 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
   memcpy (name, buf, len);
 
-  sect = bfd_make_section_anyway (abfd, name);
+  sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
   if (sect == NULL)
     return FALSE;
 
@@ -7372,7 +7555,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
   sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
 #endif
 
-  sect->flags = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
 
   return elfcore_maybe_make_sect (abfd, ".reg2", sect);
@@ -7413,7 +7595,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
 
       memcpy (name, buf, len);
 
-      sect = bfd_make_section_anyway (abfd, name);
+      sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
       if (sect == NULL)
        return FALSE;
 
@@ -7421,7 +7603,6 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       sect->filepos = (note->descpos
                       + offsetof (struct win32_pstatus,
                                   data.thread_info.thread_context));
-      sect->flags = SEC_HAS_CONTENTS;
       sect->alignment_power = 2;
 
       if (pstatus.data.thread_info.is_active_thread)
@@ -7441,14 +7622,13 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
 
       memcpy (name, buf, len);
 
-      sect = bfd_make_section_anyway (abfd, name);
+      sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
 
       if (sect == NULL)
        return FALSE;
 
       sect->size = note->descsz;
       sect->filepos = note->descpos;
-      sect->flags = SEC_HAS_CONTENTS;
       sect->alignment_power = 2;
       break;
 
@@ -7518,13 +7698,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
 
     case NT_AUXV:
       {
-       asection *sect = bfd_make_section_anyway (abfd, ".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->flags = SEC_HAS_CONTENTS;
        sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
 
        return TRUE;
@@ -7549,7 +7729,6 @@ elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
 static bfd_boolean
 elfcore_grok_netbsd_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);
@@ -7577,9 +7756,9 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note)
   if (note->type == NT_NETBSDCORE_PROCINFO)
     {
       /* NetBSD-specific core "procinfo".  Note that we expect to
-         find this note before any of the others, which is fine,
-         since the kernel writes this note out first when it
-         creates a core file.  */
+        find this note before any of the others, which is fine,
+        since the kernel writes this note out first when it
+        creates a core file.  */
 
       return elfcore_grok_netbsd_procinfo (abfd, note);
     }
@@ -7595,44 +7774,44 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note)
 
   switch (bfd_get_arch (abfd))
     {
-    /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
-       PT_GETFPREGS == mach+2.  */
+      /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
+        PT_GETFPREGS == mach+2.  */
 
     case bfd_arch_alpha:
     case bfd_arch_sparc:
       switch (note->type)
-        {
-        case NT_NETBSDCORE_FIRSTMACH+0:
-          return elfcore_make_note_pseudosection (abfd, ".reg", note);
+       {
+       case NT_NETBSDCORE_FIRSTMACH+0:
+         return elfcore_make_note_pseudosection (abfd, ".reg", note);
 
-        case NT_NETBSDCORE_FIRSTMACH+2:
-          return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+       case NT_NETBSDCORE_FIRSTMACH+2:
+         return elfcore_make_note_pseudosection (abfd, ".reg2", note);
 
-        default:
-          return TRUE;
-        }
+       default:
+         return TRUE;
+       }
 
-    /* On all other arch's, PT_GETREGS == mach+1 and
-       PT_GETFPREGS == mach+3.  */
+      /* On all other arch's, PT_GETREGS == mach+1 and
+        PT_GETFPREGS == mach+3.  */
 
     default:
       switch (note->type)
-        {
-        case NT_NETBSDCORE_FIRSTMACH+1:
-          return elfcore_make_note_pseudosection (abfd, ".reg", note);
+       {
+       case NT_NETBSDCORE_FIRSTMACH+1:
+         return elfcore_make_note_pseudosection (abfd, ".reg", note);
 
-        case NT_NETBSDCORE_FIRSTMACH+3:
-          return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+       case NT_NETBSDCORE_FIRSTMACH+3:
+         return elfcore_make_note_pseudosection (abfd, ".reg2", note);
 
-        default:
-          return TRUE;
-        }
+       default:
+         return TRUE;
+       }
     }
     /* NOTREACHED */
 }
 
 static bfd_boolean
-elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
+elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid)
 {
   void *ddata = note->descdata;
   char buf[100];
@@ -7664,20 +7843,19 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
     elf_tdata (abfd)->core_lwpid = *tid;
 
   /* Make a ".qnx_core_status/%d" section.  */
-  sprintf (buf, ".qnx_core_status/%ld", (long) *tid);
+  sprintf (buf, ".qnx_core_status/%ld", *tid);
 
   name = bfd_alloc (abfd, strlen (buf) + 1);
   if (name == NULL)
     return FALSE;
   strcpy (name, buf);
 
-  sect = bfd_make_section_anyway (abfd, name);
+  sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
   if (sect == NULL)
     return FALSE;
 
   sect->size            = note->descsz;
   sect->filepos         = note->descpos;
-  sect->flags           = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
 
   return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect));
@@ -7686,7 +7864,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
 static bfd_boolean
 elfcore_grok_nto_regs (bfd *abfd,
                       Elf_Internal_Note *note,
-                      pid_t tid,
+                      long tid,
                       char *base)
 {
   char buf[100];
@@ -7694,20 +7872,19 @@ elfcore_grok_nto_regs (bfd *abfd,
   asection *sect;
 
   /* Make a "(base)/%d" section.  */
-  sprintf (buf, "%s/%ld", base, (long) tid);
+  sprintf (buf, "%s/%ld", base, tid);
 
   name = bfd_alloc (abfd, strlen (buf) + 1);
   if (name == NULL)
     return FALSE;
   strcpy (name, buf);
 
-  sect = bfd_make_section_anyway (abfd, name);
+  sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
   if (sect == NULL)
     return FALSE;
 
   sect->size            = note->descsz;
   sect->filepos         = note->descpos;
-  sect->flags           = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
 
   /* This is the current thread.  */
@@ -7728,7 +7905,7 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note)
   /* Every GREG section has a STATUS section before it.  Store the
      tid from the previous call to pass down to the next gregs
      function.  */
-  static pid_t tid = 1;
+  static long tid = 1;
 
   switch (note->type)
     {
@@ -7748,45 +7925,42 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note)
 /* Function: elfcore_write_note
 
    Inputs:
-     buffer to hold note
+     buffer to hold note, and current size of buffer
      name of note
      type of note
      data for note
      size of data for note
 
+   Writes note to end of buffer.  ELF64 notes are written exactly as
+   for ELF32, despite the current (as of 2006) ELF gabi specifying
+   that they ought to have 8-byte namesz and descsz field, and have
+   8-byte alignment.  Other writers, eg. Linux kernel, do the same.
+
    Return:
-   End of buffer containing note.  */
+   Pointer to realloc'd buffer, *BUFSIZ updated.  */
 
 char *
-elfcore_write_note (bfd  *abfd,
+elfcore_write_note (bfd *abfd,
                    char *buf,
-                   int  *bufsiz,
+                   int *bufsiz,
                    const char *name,
-                   int  type,
+                   int type,
                    const void *input,
-                   int  size)
+                   int size)
 {
   Elf_External_Note *xnp;
   size_t namesz;
-  size_t pad;
   size_t newspace;
-  char *p, *dest;
+  char *dest;
 
   namesz = 0;
-  pad = 0;
   if (name != NULL)
-    {
-      const struct elf_backend_data *bed;
+    namesz = strlen (name) + 1;
 
-      namesz = strlen (name) + 1;
-      bed = get_elf_backend_data (abfd);
-      pad = -namesz & ((1 << bed->s->log_file_align) - 1);
-    }
+  newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4);
 
-  newspace = 12 + namesz + pad + size;
-
-  p = realloc (buf, *bufsiz + newspace);
-  dest = p + *bufsiz;
+  buf = realloc (buf, *bufsiz + newspace);
+  dest = buf + *bufsiz;
   *bufsiz += newspace;
   xnp = (Elf_External_Note *) dest;
   H_PUT_32 (abfd, namesz, xnp->namesz);
@@ -7797,14 +7971,20 @@ elfcore_write_note (bfd  *abfd,
     {
       memcpy (dest, name, namesz);
       dest += namesz;
-      while (pad != 0)
+      while (namesz & 3)
        {
          *dest++ = '\0';
-         --pad;
+         ++namesz;
        }
     }
   memcpy (dest, input, size);
-  return p;
+  dest += size;
+  while (size & 3)
+    {
+      *dest++ = '\0';
+      ++size;
+    }
+  return buf;
 }
 
 #if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
@@ -7815,22 +7995,52 @@ elfcore_write_prpsinfo (bfd  *abfd,
                        const char *fname,
                        const char *psargs)
 {
-  int note_type;
-  char *note_name = "CORE";
+  const char *note_name = "CORE";
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  if (bed->elf_backend_write_core_note != NULL)
+    {
+      char *ret;
+      ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz,
+                                                NT_PRPSINFO, fname, psargs);
+      if (ret != NULL)
+       return ret;
+    }
+
+#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T)
+  if (bed->s->elfclass == ELFCLASS32)
+    {
+#if defined (HAVE_PSINFO32_T)
+      psinfo32_t data;
+      int note_type = NT_PSINFO;
+#else
+      prpsinfo32_t data;
+      int note_type = NT_PRPSINFO;
+#endif
 
+      memset (&data, 0, sizeof (data));
+      strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+      strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+      return elfcore_write_note (abfd, buf, bufsiz,
+                                note_name, note_type, &data, sizeof (data));
+    }
+  else
+#endif
+    {
 #if defined (HAVE_PSINFO_T)
-  psinfo_t  data;
-  note_type = NT_PSINFO;
+      psinfo_t data;
+      int note_type = NT_PSINFO;
 #else
-  prpsinfo_t data;
-  note_type = NT_PRPSINFO;
+      prpsinfo_t data;
+      int note_type = NT_PRPSINFO;
 #endif
 
-  memset (&data, 0, sizeof (data));
-  strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
-  strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
-  return elfcore_write_note (abfd, buf, bufsiz,
-                            note_name, note_type, &data, sizeof (data));
+      memset (&data, 0, sizeof (data));
+      strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+      strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+      return elfcore_write_note (abfd, buf, bufsiz,
+                                note_name, note_type, &data, sizeof (data));
+    }
 }
 #endif /* PSINFO_T or PRPSINFO_T */
 
@@ -7843,15 +8053,43 @@ elfcore_write_prstatus (bfd *abfd,
                        int cursig,
                        const void *gregs)
 {
-  prstatus_t prstat;
-  char *note_name = "CORE";
+  const char *note_name = "CORE";
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
-  memset (&prstat, 0, sizeof (prstat));
-  prstat.pr_pid = pid;
-  prstat.pr_cursig = cursig;
-  memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
-  return elfcore_write_note (abfd, buf, bufsiz,
-                            note_name, NT_PRSTATUS, &prstat, sizeof (prstat));
+  if (bed->elf_backend_write_core_note != NULL)
+    {
+      char *ret;
+      ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz,
+                                                NT_PRSTATUS,
+                                                pid, cursig, gregs);
+      if (ret != NULL)
+       return ret;
+    }
+
+#if defined (HAVE_PRSTATUS32_T)
+  if (bed->s->elfclass == ELFCLASS32)
+    {
+      prstatus32_t prstat;
+
+      memset (&prstat, 0, sizeof (prstat));
+      prstat.pr_pid = pid;
+      prstat.pr_cursig = cursig;
+      memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+      return elfcore_write_note (abfd, buf, bufsiz, note_name,
+                                NT_PRSTATUS, &prstat, sizeof (prstat));
+    }
+  else
+#endif
+    {
+      prstatus_t prstat;
+
+      memset (&prstat, 0, sizeof (prstat));
+      prstat.pr_pid = pid;
+      prstat.pr_cursig = cursig;
+      memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+      return elfcore_write_note (abfd, buf, bufsiz, note_name,
+                                NT_PRSTATUS, &prstat, sizeof (prstat));
+    }
 }
 #endif /* HAVE_PRSTATUS_T */
 
@@ -7865,7 +8103,7 @@ elfcore_write_lwpstatus (bfd *abfd,
                         const void *gregs)
 {
   lwpstatus_t lwpstat;
-  char *note_name = "CORE";
+  const char *note_name = "CORE";
 
   memset (&lwpstat, 0, sizeof (lwpstat));
   lwpstat.pr_lwpid  = pid >> 16;
@@ -7892,17 +8130,34 @@ elfcore_write_pstatus (bfd *abfd,
                       char *buf,
                       int *bufsiz,
                       long pid,
-                      int cursig,
-                      const void *gregs)
+                      int cursig ATTRIBUTE_UNUSED,
+                      const void *gregs ATTRIBUTE_UNUSED)
 {
-  pstatus_t pstat;
-  char *note_name = "CORE";
+  const char *note_name = "CORE";
+#if defined (HAVE_PSTATUS32_T)
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
-  memset (&pstat, 0, sizeof (pstat));
-  pstat.pr_pid = pid & 0xffff;
-  buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
-                           NT_PSTATUS, &pstat, sizeof (pstat));
-  return buf;
+  if (bed->s->elfclass == ELFCLASS32)
+    {
+      pstatus32_t pstat;
+
+      memset (&pstat, 0, sizeof (pstat));
+      pstat.pr_pid = pid & 0xffff;
+      buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
+                               NT_PSTATUS, &pstat, sizeof (pstat));
+      return buf;
+    }
+  else
+#endif
+    {
+      pstatus_t pstat;
+
+      memset (&pstat, 0, sizeof (pstat));
+      pstat.pr_pid = pid & 0xffff;
+      buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
+                               NT_PSTATUS, &pstat, sizeof (pstat));
+      return buf;
+    }
 }
 #endif /* HAVE_PSTATUS_T */
 
@@ -7913,7 +8168,7 @@ elfcore_write_prfpreg (bfd *abfd,
                       const void *fpregs,
                       int size)
 {
-  char *note_name = "CORE";
+  const char *note_name = "CORE";
   return elfcore_write_note (abfd, buf, bufsiz,
                             note_name, NT_FPREGSET, fpregs, size);
 }
@@ -7969,21 +8224,21 @@ elfcore_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
       in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
       in.descpos = offset + (in.descdata - buf);
 
-      if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0)
-        {
-          if (! elfcore_grok_netbsd_note (abfd, &in))
-            goto error;
-        }
-      else if (strncmp (in.namedata, "QNX", 3) == 0)
+      if (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
+       {
+         if (! elfcore_grok_netbsd_note (abfd, &in))
+           goto error;
+       }
+      else if (CONST_STRNEQ (in.namedata, "QNX"))
        {
          if (! elfcore_grok_nto_note (abfd, &in))
            goto error;
        }
       else
-        {
-          if (! elfcore_grok_note (abfd, &in))
-            goto error;
-        }
+       {
+         if (! elfcore_grok_note (abfd, &in))
+           goto error;
+       }
 
       p = in.descdata + BFD_ALIGN (in.descsz, 4);
     }
@@ -8251,7 +8506,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
   count = relplt->size / hdr->sh_entsize;
   size = count * sizeof (asymbol);
   p = relplt->relocation;
-  for (i = 0; i < count; i++, s++, p++)
+  for (i = 0; i < count; i++, p++)
     size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
 
   s = *ret = bfd_malloc (size);
@@ -8289,232 +8544,29 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
   return n;
 }
 
-/* Sort symbol by binding and section. We want to put definitions
-   sorted by section at the beginning.  */
-
-static int
-elf_sort_elf_symbol (const void *arg1, const void *arg2)
-{
-  const Elf_Internal_Sym *s1;
-  const Elf_Internal_Sym *s2;
-  int shndx;
-
-  /* Make sure that undefined symbols are at the end.  */
-  s1 = (const Elf_Internal_Sym *) arg1;
-  if (s1->st_shndx == SHN_UNDEF)
-    return 1;
-  s2 = (const Elf_Internal_Sym *) arg2;
-  if (s2->st_shndx == SHN_UNDEF)
-    return -1;
-
-  /* Sorted by section index.  */
-  shndx = s1->st_shndx - s2->st_shndx;
-  if (shndx != 0)
-    return shndx;
-
-  /* Sorted by binding.  */
-  return ELF_ST_BIND (s1->st_info)  - ELF_ST_BIND (s2->st_info);
-}
-
-struct elf_symbol
-{
-  Elf_Internal_Sym *sym;
-  const char *name;
-};
+/* It is only used by x86-64 so far.  */
+asection _bfd_elf_large_com_section
+  = BFD_FAKE_SECTION (_bfd_elf_large_com_section,
+                     SEC_IS_COMMON, NULL, "LARGE_COMMON", 0);
 
-static int
-elf_sym_name_compare (const void *arg1, const void *arg2)
+void
+_bfd_elf_set_osabi (bfd * abfd,
+                   struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
 {
-  const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
-  const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
-  return strcmp (s1->name, s2->name);
-}
-
-/* Check if 2 sections define the same set of local and global
-   symbols.  */
-
-bfd_boolean
-bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
-{
-  bfd *bfd1, *bfd2;
-  const struct elf_backend_data *bed1, *bed2;
-  Elf_Internal_Shdr *hdr1, *hdr2;
-  bfd_size_type symcount1, symcount2;
-  Elf_Internal_Sym *isymbuf1, *isymbuf2;
-  Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym;
-  Elf_Internal_Sym *isymend;
-  struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL;
-  bfd_size_type count1, count2, i;
-  int shndx1, shndx2;
-  bfd_boolean result;
-
-  bfd1 = sec1->owner;
-  bfd2 = sec2->owner;
-
-  /* If both are .gnu.linkonce sections, they have to have the same
-     section name.  */
-  if (strncmp (sec1->name, ".gnu.linkonce",
-              sizeof ".gnu.linkonce" - 1) == 0
-      && strncmp (sec2->name, ".gnu.linkonce",
-                 sizeof ".gnu.linkonce" - 1) == 0)
-    return strcmp (sec1->name + sizeof ".gnu.linkonce",
-                  sec2->name + sizeof ".gnu.linkonce") == 0;
-
-  /* Both sections have to be in ELF.  */
-  if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
-      || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
-    return FALSE;
-
-  if (elf_section_type (sec1) != elf_section_type (sec2))
-    return FALSE;
-
-  if ((elf_section_flags (sec1) & SHF_GROUP) != 0
-      && (elf_section_flags (sec2) & SHF_GROUP) != 0)
-    {
-      /* If both are members of section groups, they have to have the
-        same group name.  */
-      if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
-       return FALSE;
-    }
-
-  shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
-  shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
-  if (shndx1 == -1 || shndx2 == -1)
-    return FALSE;
-
-  bed1 = get_elf_backend_data (bfd1);
-  bed2 = get_elf_backend_data (bfd2);
-  hdr1 = &elf_tdata (bfd1)->symtab_hdr;
-  symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
-  hdr2 = &elf_tdata (bfd2)->symtab_hdr;
-  symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
-
-  if (symcount1 == 0 || symcount2 == 0)
-    return FALSE;
-
-  isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
-                                  NULL, NULL, NULL);
-  isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
-                                  NULL, NULL, NULL);
-
-  result = FALSE;
-  if (isymbuf1 == NULL || isymbuf2 == NULL)
-    goto done;
-
-  /* Sort symbols by binding and section. Global definitions are at
-     the beginning.  */
-  qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
-        elf_sort_elf_symbol);
-  qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
-        elf_sort_elf_symbol);
-
-  /* Count definitions in the section.  */
-  count1 = 0;
-  for (isym = isymbuf1, isymend = isym + symcount1;
-       isym < isymend; isym++)
-    {
-      if (isym->st_shndx == (unsigned int) shndx1)
-       {
-         if (count1 == 0)
-           isymstart1 = isym;
-         count1++;
-       }
-
-      if (count1 && isym->st_shndx != (unsigned int) shndx1)
-       break;
-    }
-
-  count2 = 0;
-  for (isym = isymbuf2, isymend = isym + symcount2;
-       isym < isymend; isym++)
-    {
-      if (isym->st_shndx == (unsigned int) shndx2)
-       {
-         if (count2 == 0)
-           isymstart2 = isym;
-         count2++;
-       }
-
-      if (count2 && isym->st_shndx != (unsigned int) shndx2)
-       break;
-    }
+  Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form.  */
 
-  if (count1 == 0 || count2 == 0 || count1 != count2)
-    goto done;
-
-  symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
-  symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
-
-  if (symtable1 == NULL || symtable2 == NULL)
-    goto done;
-
-  symp = symtable1;
-  for (isym = isymstart1, isymend = isym + count1;
-       isym < isymend; isym++)
-    {
-      symp->sym = isym;
-      symp->name = bfd_elf_string_from_elf_section (bfd1,
-                                                   hdr1->sh_link,
-                                                   isym->st_name);
-      symp++;
-    }
-  symp = symtable2;
-  for (isym = isymstart2, isymend = isym + count1;
-       isym < isymend; isym++)
-    {
-      symp->sym = isym;
-      symp->name = bfd_elf_string_from_elf_section (bfd2,
-                                                   hdr2->sh_link,
-                                                   isym->st_name);
-      symp++;
-    }
-  
-  /* Sort symbol by name.  */
-  qsort (symtable1, count1, sizeof (struct elf_symbol),
-        elf_sym_name_compare);
-  qsort (symtable2, count1, sizeof (struct elf_symbol),
-        elf_sym_name_compare);
-
-  for (i = 0; i < count1; i++)
-    /* Two symbols must have the same binding, type and name.  */
-    if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info
-       || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other
-       || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
-      goto done;
-
-  result = TRUE;
-
-done:
-  if (symtable1)
-    free (symtable1);
-  if (symtable2)
-    free (symtable2);
-  if (isymbuf1)
-    free (isymbuf1);
-  if (isymbuf2)
-    free (isymbuf2);
+  i_ehdrp = elf_elfheader (abfd);
 
-  return result;
+  i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
 }
 
-/* It is only used by x86-64 so far.  */
-asection _bfd_elf_large_com_section
-  = BFD_FAKE_SECTION (_bfd_elf_large_com_section,
-                     SEC_IS_COMMON, NULL, NULL, "LARGE_COMMON",
-                     0);
 
-/* Return TRUE if 2 section types are compatible.  */
+/* 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.  */
 
 bfd_boolean
-_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec,
-                                bfd *bbfd, const asection *bsec)
+_bfd_elf_is_function_type (unsigned int type)
 {
-  if (asec == NULL
-      || bsec == NULL
-      || abfd->xvec->flavour != bfd_target_elf_flavour
-      || bbfd->xvec->flavour != bfd_target_elf_flavour)
-    return TRUE;
-
-  return elf_section_type (asec) == elf_section_type (bsec);
+  return (type == STT_FUNC);
 }