bfd/
[deliverable/binutils-gdb.git] / bfd / elf.c
index 1f3408e32862461f5136c71054cd0e71cad1e3ab..d65c78d963a413792fb4bbd254894e695cc736c9 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, 2006, 2007 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008 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,19 +35,22 @@ 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 *);
 static bfd_boolean prep_headers (bfd *);
 static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ;
-static bfd_boolean elfcore_read_notes (bfd *, file_ptr, bfd_size_type) ;
+static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
+static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
+                                   file_ptr offset);
 
 /* Swap version information in and out.  The version information is
    currently size independent.  If that ever changes, this code will
@@ -221,26 +226,36 @@ bfd_elf_gnu_hash (const char *namearg)
   return h & 0xffffffff;
 }
 
+/* Create a tdata field OBJECT_SIZE bytes in length, zeroed out and with
+   the object_id field of an elf_obj_tdata field set to OBJECT_ID.  */
 bfd_boolean
-bfd_elf_mkobject (bfd *abfd)
+bfd_elf_allocate_object (bfd *abfd,
+                        size_t object_size,
+                        enum elf_object_id object_id)
 {
+  BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata));
+  abfd->tdata.any = bfd_zalloc (abfd, object_size);
   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 FALSE;
 
+  elf_object_id (abfd) = object_id;
+  elf_program_header_size (abfd) = (bfd_size_type) -1;
   return TRUE;
 }
 
+
+bfd_boolean
+bfd_elf_make_generic_object (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
+                                 GENERIC_ELF_TDATA);
+}
+
 bfd_boolean
 bfd_elf_mkcorefile (bfd *abfd)
 {
   /* I think this can be done just like an object file.  */
-  return bfd_elf_mkobject (abfd);
+  return bfd_elf_make_generic_object (abfd);
 }
 
 char *
@@ -252,7 +267,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;
@@ -264,7 +281,7 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
 
       /* Allocate and clear an extra byte at the end, to prevent crashes
         in case the string table is not terminated.  */
-      if (shstrtabsize + 1 == 0
+      if (shstrtabsize + 1 <= 1
          || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL
          || bfd_seek (abfd, offset, SEEK_SET) != 0)
        shstrtab = NULL;
@@ -273,6 +290,10 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
          if (bfd_get_error () != bfd_error_system_call)
            bfd_set_error (bfd_error_file_truncated);
          shstrtab = NULL;
+         /* Once we've failed to read it, make sure we don't keep
+            trying.  Otherwise, we'll keep allocating space for
+            the string table over and over.  */
+         i_shdrp[shindex]->sh_size = 0;
        }
       else
        shstrtab[shstrtabsize] = '\0';
@@ -291,6 +312,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
@@ -316,7 +340,9 @@ bfd_elf_string_from_elf_section (bfd *abfd,
    SYMCOUNT specifies the number of symbols to read, starting from
    symbol SYMOFFSET.  If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF
    are non-NULL, they are used to store the internal symbols, external
-   symbols, and symbol section index extensions, respectively.  */
+   symbols, and symbol section index extensions, respectively.
+   Returns a pointer to the internal symbol buffer (malloced if necessary)
+   or NULL if there were no symbols or some kind of problem.  */
 
 Elf_Internal_Sym *
 bfd_elf_get_elf_syms (bfd *ibfd,
@@ -339,6 +365,9 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   bfd_size_type amt;
   file_ptr pos;
 
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+    abort ();
+
   if (symcount == 0)
     return intsym_buf;
 
@@ -432,8 +461,7 @@ bfd_elf_sym_name (bfd *abfd,
 
   if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION
       /* Check for a bogus st_shndx to avoid crashing.  */
-      && isym->st_shndx < elf_numsections (abfd)
-      && !(isym->st_shndx >= SHN_LORESERVE && isym->st_shndx <= SHN_HIRESERVE))
+      && isym->st_shndx < elf_numsections (abfd))
     {
       iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name;
       shindex = elf_elfheader (abfd)->e_shstrndx;
@@ -470,6 +498,8 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr)
 
   /* First we need to ensure the symbol table is available.  Make sure
      that it is a symbol table section.  */
+  if (ghdr->sh_link >= elf_numsections (abfd))
+    return NULL;
   hdr = elf_elfsections (abfd) [ghdr->sh_link];
   if (hdr->sh_type != SHT_SYMTAB
       || ! bfd_section_from_shdr (abfd, ghdr->sh_link))
@@ -501,13 +531,13 @@ 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];
@@ -688,8 +718,7 @@ _bfd_elf_setup_sections (bfd *abfd)
             get the situation where elfsec is 0.  */
          if (elfsec == 0)
            {
-             const struct elf_backend_data *bed
-               = get_elf_backend_data (abfd);
+             const struct elf_backend_data *bed = get_elf_backend_data (abfd);
              if (bed->link_order_error_handler)
                bed->link_order_error_handler
                  (_("%B: warning: sh_link not set for section `%A'"),
@@ -697,14 +726,17 @@ _bfd_elf_setup_sections (bfd *abfd)
            }
          else
            {
-             asection *link;
+             asection *link = NULL;
 
-             this_hdr = elf_elfsections (abfd)[elfsec];
+             if (elfsec < elf_numsections (abfd))
+               {
+                 this_hdr = elf_elfsections (abfd)[elfsec];
+                 link = this_hdr->bfd_section;
+               }
 
              /* PR 1991, 2008:
                 Some strip/objcopy may leave an incorrect value in
                 sh_link.  We don't want to proceed.  */
-             link = this_hdr->bfd_section;
              if (link == NULL)
                {
                  (*_bfd_error_handler)
@@ -800,7 +832,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr)
       || ! bfd_set_section_size (abfd, newsect, hdr->sh_size)
       || ! bfd_set_section_alignment (abfd, newsect,
-                                     bfd_log2 ((bfd_vma) hdr->sh_addralign)))
+                                     bfd_log2 (hdr->sh_addralign)))
     return FALSE;
 
   flags = SEC_NO_FLAGS;
@@ -858,9 +890,16 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          { NULL,                0  },  /* 'p' */
          { NULL,                0  },  /* 'q' */
          { NULL,                0  },  /* 'r' */
-         { STRING_COMMA_LEN ("stab") } /* 's' */
+         { STRING_COMMA_LEN ("stab") },        /* 's' */
+         { NULL,                0  },  /* 't' */
+         { NULL,                0  },  /* 'u' */
+         { NULL,                0  },  /* 'v' */
+         { NULL,                0  },  /* 'w' */
+         { NULL,                0  },  /* 'x' */
+         { NULL,                0  },  /* 'y' */
+         { STRING_COMMA_LEN ("zdebug") }       /* 'z' */
        };
-      
+
       if (name [0] == '.')
        {
          int i = name [1] - 'd';
@@ -891,68 +930,91 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if (! bfd_set_section_flags (abfd, newsect, flags))
     return FALSE;
 
+  /* We do not parse the PT_NOTE segments as we are interested even in the
+     separate debug info files which may have the segments offsets corrupted.
+     PT_NOTEs from the core files are currently not parsed using BFD.  */
+  if (hdr->sh_type == SHT_NOTE)
+    {
+      char *contents;
+
+      contents = bfd_malloc (hdr->sh_size);
+      if (!contents)
+       return FALSE;
+
+      if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
+                                    hdr->sh_size)
+         || !elf_parse_notes (abfd, contents, hdr->sh_size, -1))
+       {
+         free (contents);
+         return FALSE;
+       }
+      
+      free (contents);
+    }
+
   if ((flags & SEC_ALLOC) != 0)
     {
       Elf_Internal_Phdr *phdr;
-      unsigned int i;
+      unsigned int i, nload;
+
+      /* Some ELF linkers produce binaries with all the program header
+        p_paddr fields zero.  If we have such a binary with more than
+        one PT_LOAD header, then leave the section lma equal to vma
+        so that we don't create sections with overlapping lma.  */
+      phdr = elf_tdata (abfd)->phdr;
+      for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+       if (phdr->p_paddr != 0)
+         break;
+       else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0)
+         ++nload;
+      if (i >= elf_elfheader (abfd)->e_phnum && nload > 1)
+       return TRUE;
 
-      /* 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.  */
       phdr = elf_tdata (abfd)->phdr;
       for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
        {
-         if (phdr->p_paddr != 0)
-           break;
-       }
-      if (i < elf_elfheader (abfd)->e_phnum)
-       {
-         phdr = elf_tdata (abfd)->phdr;
-         for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+         /* This section is part of this segment if its file
+            offset plus size lies within the segment's memory
+            span and, if the section is loaded, the extent of the
+            loaded data lies within the extent of the segment.
+
+            Note - we used to check the p_paddr field as well, and
+            refuse to set the LMA if it was 0.  This is wrong
+            though, as a perfectly valid initialised segment can
+            have a p_paddr of zero.  Some architectures, eg ARM,
+            place special significance on the address 0 and
+            executables need to be able to have a segment which
+            covers this address.  */
+         if (phdr->p_type == PT_LOAD
+             && (bfd_vma) hdr->sh_offset >= phdr->p_offset
+             && (hdr->sh_offset + hdr->sh_size
+                 <= phdr->p_offset + phdr->p_memsz)
+             && ((flags & SEC_LOAD) == 0
+                 || (hdr->sh_offset + hdr->sh_size
+                     <= phdr->p_offset + phdr->p_filesz)))
            {
-             /* This section is part of this segment if its file
-                offset plus size lies within the segment's memory
-                span and, if the section is loaded, the extent of the
-                loaded data lies within the extent of the segment.
-
-                Note - we used to check the p_paddr field as well, and
-                refuse to set the LMA if it was 0.  This is wrong
-                though, as a perfectly valid initialised segment can
-                have a p_paddr of zero.  Some architectures, eg ARM,
-                place special significance on the address 0 and
-                executables need to be able to have a segment which
-                covers this address.  */
-             if (phdr->p_type == PT_LOAD
-                 && (bfd_vma) hdr->sh_offset >= phdr->p_offset
-                 && (hdr->sh_offset + hdr->sh_size
-                     <= phdr->p_offset + phdr->p_memsz)
-                 && ((flags & SEC_LOAD) == 0
-                     || (hdr->sh_offset + hdr->sh_size
-                         <= phdr->p_offset + phdr->p_filesz)))
-               {
-                 if ((flags & SEC_LOAD) == 0)
-                   newsect->lma = (phdr->p_paddr
-                                   + hdr->sh_addr - phdr->p_vaddr);
-                 else
-                   /* We used to use the same adjustment for SEC_LOAD
-                      sections, but that doesn't work if the segment
-                      is packed with code from multiple VMAs.
-                      Instead we calculate the section LMA based on
-                      the segment LMA.  It is assumed that the
-                      segment will contain sections with contiguous
-                      LMAs, even if the VMAs are not.  */
-                   newsect->lma = (phdr->p_paddr
-                                   + hdr->sh_offset - phdr->p_offset);
-
-                 /* With contiguous segments, we can't tell from file
-                    offsets whether a section with zero size should
-                    be placed at the end of one segment or the
-                    beginning of the next.  Decide based on vaddr.  */
-                 if (hdr->sh_addr >= phdr->p_vaddr
-                     && (hdr->sh_addr + hdr->sh_size
-                         <= phdr->p_vaddr + phdr->p_memsz))
-                   break;
-               }
+             if ((flags & SEC_LOAD) == 0)
+               newsect->lma = (phdr->p_paddr
+                               + hdr->sh_addr - phdr->p_vaddr);
+             else
+               /* We used to use the same adjustment for SEC_LOAD
+                  sections, but that doesn't work if the segment
+                  is packed with code from multiple VMAs.
+                  Instead we calculate the section LMA based on
+                  the segment LMA.  It is assumed that the
+                  segment will contain sections with contiguous
+                  LMAs, even if the VMAs are not.  */
+               newsect->lma = (phdr->p_paddr
+                               + hdr->sh_offset - phdr->p_offset);
+
+             /* With contiguous segments, we can't tell from file
+                offsets whether a section with zero size should
+                be placed at the end of one segment or the
+                beginning of the next.  Decide based on vaddr.  */
+             if (hdr->sh_addr >= phdr->p_vaddr
+                 && (hdr->sh_addr + hdr->sh_size
+                     <= phdr->p_vaddr + phdr->p_memsz))
+               break;
            }
        }
     }
@@ -1036,61 +1098,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.  */
 
@@ -1108,6 +1115,10 @@ _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;
 }
 
@@ -1184,7 +1195,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
   s = bfd_get_section_by_name (abfd, ".dynamic");
   if (s != NULL)
     {
-      int elfsec;
+      unsigned int elfsec;
       unsigned long shlink;
       bfd_byte *extdyn, *extdynend;
       size_t extdynsize;
@@ -1196,7 +1207,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
        goto error_return;
 
       elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
-      if (elfsec == -1)
+      if (elfsec == SHN_BAD)
        goto error_return;
       shlink = elf_elfsections (abfd)[elfsec]->sh_link;
 
@@ -1208,9 +1219,10 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       for (; extdyn < extdynend; extdyn += extdynsize)
        {
          Elf_Internal_Dyn dyn;
-         const char *name;
+         const char *name = "";
          char ab[20];
          bfd_boolean stringp;
+         const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
          (*swap_dyn_in) (abfd, extdyn, &dyn);
 
@@ -1221,8 +1233,14 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
          switch (dyn.d_tag)
            {
            default:
-             sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
-             name = ab;
+             if (bed->elf_backend_get_target_dtag)
+               name = (*bed->elf_backend_get_target_dtag) (dyn.d_tag);
+
+             if (!strcmp (name, ""))
+               {
+                 sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
+                 name = ab;
+               }
              break;
 
            case DT_NEEDED: name = "NEEDED"; stringp = TRUE; break;
@@ -1285,9 +1303,12 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case DT_GNU_HASH: name = "GNU_HASH"; break;
            }
 
-         fprintf (f, "  %-11s ", name);
+         fprintf (f, "  %-20s ", name);
          if (! stringp)
-           fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val);
+           {
+             fprintf (f, "0x");
+             bfd_fprintf_vma (abfd, f, dyn.d_un.d_val);
+           }
          else
            {
              const char *string;
@@ -1407,7 +1428,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;
@@ -1484,319 +1505,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 *),
-   unsigned int entsize)
-{
-  bfd_boolean ret;
-  int can_refcount = get_elf_backend_data (abfd)->can_refcount;
-
-  memset (table, 0, sizeof * table);
-  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;
-
-  ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
-  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,
-                                      sizeof (struct elf_link_hash_entry)))
-    {
-      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, enum dynamic_lib_link_class 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 *
@@ -1827,17 +1536,22 @@ _bfd_elf_stringtab_init (void)
 bfd_boolean
 bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
 {
-  Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex];
-  Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  Elf_Internal_Shdr *hdr;
+  Elf_Internal_Ehdr *ehdr;
+  const struct elf_backend_data *bed;
   const char *name;
 
-  name = bfd_elf_string_from_elf_section (abfd,
-                                         elf_elfheader (abfd)->e_shstrndx,
+  if (shindex >= elf_numsections (abfd))
+    return FALSE;
+
+  hdr = elf_elfsections (abfd)[shindex];
+  ehdr = elf_elfheader (abfd);
+  name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx,
                                          hdr->sh_name);
   if (name == NULL)
     return FALSE;
 
+  bed = get_elf_backend_data (abfd);
   switch (hdr->sh_type)
     {
     case SHT_NULL:
@@ -1904,11 +1618,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,
@@ -2038,8 +1752,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          return FALSE;
 
        /* Check for a bogus link to avoid crashing.  */
-       if ((hdr->sh_link >= SHN_LORESERVE && hdr->sh_link <= SHN_HIRESERVE)
-           || hdr->sh_link >= num_sec)
+       if (hdr->sh_link >= num_sec)
          {
            ((*_bfd_error_handler)
             (_("%B: invalid link %lu for reloc section %s (index %u)"),
@@ -2093,7 +1806,6 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
           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)
@@ -2115,6 +1827,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
            BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
            amt = sizeof (*hdr2);
            hdr2 = bfd_alloc (abfd, amt);
+           if (hdr2 == NULL)
+             return FALSE;
            elf_section_data (target_sect)->rel_hdr2 = hdr2;
          }
        *hdr2 = *hdr;
@@ -2190,6 +1904,16 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       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.  */
       if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex))
        return TRUE;
@@ -2220,7 +1944,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          /* 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 
+              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 "
@@ -2251,36 +1975,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
@@ -2403,10 +2126,19 @@ static const struct bfd_elf_special_section special_sections_t[] =
   { NULL,                     0,  0, 0,            0 }
 };
 
+static const struct bfd_elf_special_section special_sections_z[] =
+{
+  { STRING_COMMA_LEN (".zdebug_line"),    0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".zdebug_info"),    0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".zdebug_abbrev"),  0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 },
+  { NULL,                     0,  0, 0,            0 }
+};
+
 static const struct bfd_elf_special_section *special_sections[] =
 {
   special_sections_b,          /* 'b' */
-  special_sections_c,          /* 'b' */
+  special_sections_c,          /* 'c' */
   special_sections_d,          /* 'd' */
   NULL,                                /* 'e' */
   special_sections_f,          /* 'f' */
@@ -2424,6 +2156,12 @@ static const struct bfd_elf_special_section *special_sections[] =
   special_sections_r,          /* 'r' */
   special_sections_s,          /* 's' */
   special_sections_t,          /* 't' */
+  NULL,                                /* 'u' */
+  NULL,                                /* 'v' */
+  NULL,                                /* 'w' */
+  NULL,                                /* 'x' */
+  NULL,                                /* 'y' */
+  special_sections_z           /* 'z' */
 };
 
 const struct bfd_elf_special_section *
@@ -2500,7 +2238,7 @@ _bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec)
     return NULL;
 
   i = sec->name[1] - 'b';
-  if (i < 0 || i > 't' - 'b')
+  if (i < 0 || i > 'z' - 'b')
     return NULL;
 
   spec = special_sections[i];
@@ -2569,7 +2307,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.
 
  */
 
@@ -2588,40 +2326,10 @@ _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)
@@ -2630,11 +2338,60 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
       newsect = bfd_make_section (abfd, name);
       if (newsect == NULL)
        return FALSE;
-      newsect->vma = hdr->p_vaddr + hdr->p_filesz;
+      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)
+       return FALSE;
+      memcpy (name, namebuf, len);
+      newsect = bfd_make_section (abfd, name);
+      if (newsect == NULL)
+       return FALSE;
+      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;
@@ -2668,7 +2425,7 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index)
     case PT_NOTE:
       if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note"))
        return FALSE;
-      if (! elfcore_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
+      if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
        return FALSE;
       return TRUE;
 
@@ -2722,7 +2479,7 @@ _bfd_elf_init_reloc_shdr (bfd *abfd,
   rel_hdr->sh_entsize = (use_rela_p
                         ? bed->s->sizeof_rela
                         : bed->s->sizeof_rel);
-  rel_hdr->sh_addralign = 1 << bed->s->log_file_align;
+  rel_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
   rel_hdr->sh_flags = 0;
   rel_hdr->sh_addr = 0;
   rel_hdr->sh_size = 0;
@@ -2739,11 +2496,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;
     }
 
@@ -2768,7 +2526,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
   this_hdr->sh_offset = 0;
   this_hdr->sh_size = asect->size;
   this_hdr->sh_link = 0;
-  this_hdr->sh_addralign = 1 << asect->alignment_power;
+  this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power;
   /* The sh_entsize and sh_info fields may have been set already by
      copy_private_section_data.  */
 
@@ -2777,16 +2535,28 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
 
   /* If the section type is unspecified, we set it based on
      asect->flags.  */
+  if ((asect->flags & SEC_GROUP) != 0)
+    sh_type = SHT_GROUP;
+  else if ((asect->flags & SEC_ALLOC) != 0
+          && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+              || (asect->flags & SEC_NEVER_LOAD) != 0))
+    sh_type = SHT_NOBITS;
+  else
+    sh_type = SHT_PROGBITS;
+
   if (this_hdr->sh_type == SHT_NULL)
-    {
-      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))
-       this_hdr->sh_type = SHT_NOBITS;
-      else
-       this_hdr->sh_type = SHT_PROGBITS;
+    this_hdr->sh_type = sh_type;
+  else if (this_hdr->sh_type == SHT_NOBITS
+          && sh_type == SHT_PROGBITS
+          && (asect->flags & SEC_ALLOC) != 0)
+    {
+      /* Warn if we are changing a NOBITS section to PROGBITS, but
+        allow the link to proceed.  This can happen when users link
+        non-bss input sections to bss output sections, or emit data
+        to a bss output section via a linker script.  */
+      (*_bfd_error_handler)
+       (_("warning: section `%A' type changed to PROGBITS"), asect);
+      this_hdr->sh_type = sh_type;
     }
 
   switch (this_hdr->sh_type)
@@ -2832,8 +2602,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
@@ -2844,8 +2614,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
@@ -2896,10 +2666,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
@@ -3021,19 +2799,15 @@ 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 
-               {
-                 if (section_number == SHN_LORESERVE)
-                   section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-                 d->this_idx = section_number++;
-               }
+             else
+               d->this_idx = section_number++;
            }
        }
     }
@@ -3043,26 +2817,18 @@ 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 (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-         d->this_idx = section_number++;
-       }
+       d->this_idx = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
       if ((sec->flags & SEC_RELOC) == 0)
        d->rel_idx = 0;
       else
        {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
          d->rel_idx = section_number++;
          _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name);
        }
 
       if (d->rel_hdr2)
        {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
          d->rel_idx2 = section_number++;
          _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name);
        }
@@ -3070,22 +2836,16 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
        d->rel_idx2 = 0;
     }
 
-  if (section_number == SHN_LORESERVE)
-    section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
   t->shstrtab_section = section_number++;
   _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
   elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
 
   if (bfd_get_symcount (abfd) > 0)
     {
-      if (section_number == SHN_LORESERVE)
-       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
       t->symtab_section = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
-      if (section_number > SHN_LORESERVE - 2)
+      if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF))
        {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
          t->symtab_shndx_section = section_number++;
          t->symtab_shndx_hdr.sh_name
            = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
@@ -3093,8 +2853,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
          if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1)
            return FALSE;
        }
-      if (section_number == SHN_LORESERVE)
-       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
       t->strtab_section = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
@@ -3104,8 +2862,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 
   elf_numsections (abfd) = section_number;
   elf_elfheader (abfd)->e_shnum = section_number;
-  if (section_number > SHN_LORESERVE)
-    elf_elfheader (abfd)->e_shnum -= SHN_HIRESERVE + 1 - SHN_LORESERVE;
 
   /* Set up the list of section header pointers, in agreement with the
      indices.  */
@@ -3126,7 +2882,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   if (bfd_get_symcount (abfd) > 0)
     {
       i_shdrp[t->symtab_section] = &t->symtab_hdr;
-      if (elf_numsections (abfd) > SHN_LORESERVE)
+      if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
        {
          i_shdrp[t->symtab_shndx_section] = &t->symtab_shndx_hdr;
          t->symtab_shndx_hdr.sh_link = t->symtab_section;
@@ -3215,7 +2971,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)
@@ -3295,9 +3051,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)
@@ -3345,17 +3100,15 @@ sym_is_global (bfd *abfd, asymbol *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.  */
+   output.  */
 
 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))));
+         && !(sym->section->owner == abfd
+              || (sym->section->output_section->owner == abfd
+                  && sym->section->output_offset == 0)));
 }
 
 static bfd_boolean
@@ -3398,6 +3151,7 @@ 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 = sym->section;
@@ -3496,14 +3250,8 @@ _bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *i_shdrp,
                                           file_ptr offset,
                                           bfd_boolean align)
 {
-  if (align)
-    {
-      unsigned int al;
-
-      al = i_shdrp->sh_addralign;
-      if (al > 1)
-       offset = BFD_ALIGN (offset, al);
-    }
+  if (align && i_shdrp->sh_addralign > 1)
+    offset = BFD_ALIGN (offset, i_shdrp->sh_addralign);
   i_shdrp->sh_offset = offset;
   if (i_shdrp->bfd_section != NULL)
     i_shdrp->bfd_section->filepos = offset;
@@ -3599,7 +3347,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;
@@ -3639,13 +3387,12 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
     {
       /* 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 (info->relro)
+    {
+      /* We need a PT_GNU_RELRO segment.  */
+      ++segs;
     }
 
   if (elf_tdata (abfd)->eh_frame_hdr)
@@ -3667,6 +3414,19 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
        {
          /* 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;
        }
     }
 
@@ -3695,6 +3455,29 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
   return segs * bed->s->sizeof_phdr;
 }
 
+/* Find the segment that contains the output_section of section.  */
+
+Elf_Internal_Phdr *
+_bfd_elf_find_segment_containing_section (bfd * abfd, asection * section)
+{
+  struct elf_segment_map *m;
+  Elf_Internal_Phdr *p;
+
+  for (m = elf_tdata (abfd)->segment_map,
+        p = elf_tdata (abfd)->phdr;
+       m != NULL;
+       m = m->next, p++)
+    {
+      int i;
+
+      for (i = m->count - 1; i >= 0; i--)
+       if (m->sections[i] == section)
+         return p;
+    }
+
+  return NULL;
+}
+
 /* Create a mapping from a set of sections to a program segment.  */
 
 static struct elf_segment_map *
@@ -3745,14 +3528,16 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
   m->p_type = PT_DYNAMIC;
   m->count = 1;
   m->sections[0] = dynsec;
-  
+
   return m;
 }
 
 /* Possibly add or remove segments from the segment map.  */
 
 static bfd_boolean
-elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
+elf_modify_segment_map (bfd *abfd,
+                       struct bfd_link_info *info,
+                       bfd_boolean remove_empty_load)
 {
   struct elf_segment_map **m;
   const struct elf_backend_data *bed;
@@ -3779,7 +3564,7 @@ elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
        }
       (*m)->count = new_count;
 
-      if ((*m)->p_type == PT_LOAD && (*m)->count == 0)
+      if (remove_empty_load && (*m)->p_type == PT_LOAD && (*m)->count == 0)
        *m = (*m)->next;
       else
        m = &(*m)->next;
@@ -3804,9 +3589,10 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
   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 (elf_tdata (abfd)->segment_map == NULL
-      && bfd_count_sections (abfd) != 0)
+  no_user_phdrs = elf_tdata (abfd)->segment_map == NULL;
+  if (no_user_phdrs && bfd_count_sections (abfd) != 0)
     {
       asection *s;
       unsigned int i;
@@ -4041,25 +3827,47 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          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 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 = 1;
-             m->sections[0] = s;
-
+             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;
            }
@@ -4132,28 +3940,45 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
          pm = &m->next;
        }
 
-      if (dynsec != NULL && elf_tdata (abfd)->relro)
+      if (info->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;
+         for (m = mfirst; m != NULL; m = m->next)
+           {
+             if (m->p_type == PT_LOAD)
+               {
+                 asection *last = m->sections[m->count - 1];
+                 bfd_vma vaddr = m->sections[0]->vma;
+                 bfd_vma filesz = last->vma - vaddr + last->size;
 
-         *pm = m;
-         pm = &m->next;
+                 if (vaddr < info->relro_end
+                     && vaddr >= info->relro_start
+                     && (vaddr + filesz) >= info->relro_end)
+                   break;
+               }
+             }
+
+         /* Make a PT_GNU_RELRO segment only when it isn't empty.  */
+         if (m != NULL)
+           {
+             amt = sizeof (struct elf_segment_map);
+             m = bfd_zalloc (abfd, amt);
+             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;
+           }
        }
 
       free (sections);
       elf_tdata (abfd)->segment_map = mfirst;
     }
 
-  if (!elf_modify_segment_map (abfd, info))
+  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)
@@ -4246,7 +4071,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
@@ -4255,6 +4080,32 @@ 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.  */
@@ -4267,13 +4118,13 @@ assign_file_positions_for_load_sections (bfd *abfd,
   struct elf_segment_map *m;
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
-  file_ptr off, voff;
+  file_ptr off;
   bfd_size_type maxpagesize;
   unsigned int alloc;
   unsigned int i, j;
 
   if (link_info == NULL
-      && !elf_modify_segment_map (abfd, link_info))
+      && !elf_modify_segment_map (abfd, link_info, FALSE))
     return FALSE;
 
   alloc = 0;
@@ -4313,9 +4164,11 @@ assign_file_positions_for_load_sections (bfd *abfd,
        m = m->next, p++, j++)
     {
       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.  */
@@ -4329,10 +4182,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
         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;
 
@@ -4346,7 +4196,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
       else if (m->count == 0)
        p->p_paddr = 0;
       else
-       p->p_paddr = m->sections[0]->lma;
+       p->p_paddr = m->sections[0]->lma - m->p_vaddr_offset;
 
       if (p->p_type == PT_LOAD
          && (abfd->flags & D_PAGED) != 0)
@@ -4364,18 +4214,19 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
          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 if (m->count == 0)
+       p->p_align = 1 << bed->s->log_file_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;
 
          if (m->p_align_valid)
@@ -4385,7 +4236,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
              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;
@@ -4395,32 +4246,45 @@ assign_file_positions_for_load_sections (bfd *abfd,
                align = 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
-                    && (m->sections[i]->flags & SEC_HAS_CONTENTS) == 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.  */
@@ -4434,6 +4298,10 @@ assign_file_positions_for_load_sections (bfd *abfd,
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
+      /* Set the note section type to SHT_NOTE.  */
+      else if (p->p_type == PT_NOTE)
+       for (i = 0; i < m->count; i++)
+         elf_section_type (m->sections[i]) = SHT_NOTE;
 
       p->p_offset = 0;
       p->p_filesz = 0;
@@ -4441,7 +4309,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
       if (m->includes_filehdr)
        {
-         if (! m->p_flags_valid)
+         if (!m->p_flags_valid)
            p->p_flags |= PF_R;
          p->p_filesz = bed->s->sizeof_ehdr;
          p->p_memsz = bed->s->sizeof_ehdr;
@@ -4459,14 +4327,14 @@ assign_file_positions_for_load_sections (bfd *abfd,
                }
 
              p->p_vaddr -= off;
-             if (! m->p_paddr_valid)
+             if (!m->p_paddr_valid)
                p->p_paddr -= off;
            }
        }
 
       if (m->includes_phdrs)
        {
-         if (! m->p_flags_valid)
+         if (!m->p_flags_valid)
            p->p_flags |= PF_R;
 
          if (!m->includes_filehdr)
@@ -4477,7 +4345,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
                {
                  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;
                }
            }
@@ -4489,14 +4357,15 @@ assign_file_positions_for_load_sections (bfd *abfd,
       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;
            }
        }
@@ -4509,37 +4378,35 @@ assign_file_positions_for_load_sections (bfd *abfd,
       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;
+         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)
+         if ((p->p_type == PT_LOAD
+              || p->p_type == PT_TLS)
+             && (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))))
            {
-             bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_filesz);
+             bfd_signed_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
 
-             if ((flags & SEC_LOAD) != 0
-                 || ((flags & SEC_ALLOC) != 0
-                     && ((flags & SEC_THREAD_LOCAL) == 0
-                         || p->p_type == PT_TLS)))
+             if (adjust < 0)
                {
-                 if (adjust < 0)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%B: section %A lma 0x%lx overlaps previous sections"),
-                        abfd, sec, (unsigned long) sec->lma);
-                     adjust = 0;
-                   }
-                 p->p_memsz += adjust;
+                 (*_bfd_error_handler)
+                   (_("%B: section %A vma 0x%lx overlaps previous sections"),
+                    abfd, sec, (unsigned long) sec->lma);
+                 adjust = 0;
+               }
+             p->p_memsz += adjust;
 
-                 if ((flags & SEC_LOAD) != 0)
-                   {
-                     off += adjust;
-                     p->p_filesz += adjust;
-                   }
+             if (this_hdr->sh_type != SHT_NOBITS)
+               {
+                 off += adjust;
+                 p->p_filesz += adjust;
                }
            }
 
@@ -4549,9 +4416,9 @@ assign_file_positions_for_load_sections (bfd *abfd,
                 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;
                }
@@ -4568,72 +4435,52 @@ assign_file_positions_for_load_sections (bfd *abfd,
            {
              if (p->p_type == PT_LOAD)
                {
-                 sec->filepos = off + voff;
-                 /* 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;
                }
-
-             /* .tbss is special.  It doesn't contribute to p_memsz of
-                normal segments.  */
-             else if ((flags & SEC_ALLOC) != 0
-                      && ((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 (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))
+             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;
            }
        }
+      off -= off_adjust;
 
-      /* Check if all sections are in the segment.  Skip PT_GNU_RELRO
-        and PT_NOTE segments since they will be processed by
-        assign_file_positions_for_non_load_sections later.  */
-      if (p->p_type != PT_GNU_RELRO
-         && p->p_type != PT_NOTE)
+      /* 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;
@@ -4647,6 +4494,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
                (*_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;
              }
@@ -4689,7 +4537,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
          && (hdr->bfd_section->filepos != 0
              || (hdr->sh_type == SHT_NOBITS
                  && hdr->contents == NULL)))
-       hdr->sh_offset = hdr->bfd_section->filepos;
+       BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos);
       else if ((hdr->sh_flags & SHF_ALLOC) != 0)
        {
          if (hdr->sh_size != 0)
@@ -4717,12 +4565,6 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        hdr->sh_offset = -1;
       else
        off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
-
-      if (i == SHN_LORESERVE - 1)
-       {
-         i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-         hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-       }
     }
 
   /* Now that we have set the section file positions, we can set up
@@ -4765,18 +4607,53 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
       if (m->count != 0)
        {
          if (p->p_type != PT_LOAD
-             && (p->p_type != PT_NOTE || bfd_get_format (abfd) != bfd_core))
+             && (p->p_type != PT_NOTE
+                 || bfd_get_format (abfd) != bfd_core))
            {
              Elf_Internal_Shdr *hdr;
+             asection *sect;
+
              BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
 
-             hdr = &elf_section_data (m->sections[m->count - 1])->this_hdr;
-             p->p_filesz = (m->sections[m->count - 1]->filepos
-                            - m->sections[0]->filepos);
+             sect = m->sections[m->count - 1];
+             hdr = &elf_section_data (sect)->this_hdr;
+             p->p_filesz = sect->filepos - m->sections[0]->filepos;
              if (hdr->sh_type != SHT_NOBITS)
                p->p_filesz += hdr->sh_size;
 
-             p->p_offset = m->sections[0]->filepos;
+             if (p->p_type == PT_GNU_RELRO)
+               {
+                 /* When we get here, we are copying executable
+                    or shared library. But we need to use the same
+                    linker logic.  */
+                 Elf_Internal_Phdr *lp;
+
+                 for (lp = phdrs; lp < phdrs + count; ++lp)
+                   {
+                     if (lp->p_type == PT_LOAD
+                         && lp->p_paddr == p->p_paddr)
+                       break;
+                   }
+         
+                 if (lp < phdrs + count)
+                   {
+                     /* We should use p_size if it is valid since it
+                        may contain the first few bytes of the next
+                        SEC_ALLOC section.  */
+                     if (m->p_size_valid)
+                       p->p_filesz = m->p_size;
+                     else
+                       abort ();
+                     p->p_vaddr = lp->p_vaddr;
+                     p->p_offset = lp->p_offset;
+                     p->p_memsz = p->p_filesz;
+                     p->p_align = 1;
+                   }
+                 else
+                   abort ();
+               }
+             else
+               p->p_offset = m->sections[0]->filepos;
            }
        }
       else
@@ -4884,12 +4761,6 @@ assign_file_positions_except_relocs (bfd *abfd,
            }
          else
            off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
-
-         if (i == SHN_LORESERVE - 1)
-           {
-             i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-             hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-           }
        }
     }
   else
@@ -4897,7 +4768,7 @@ assign_file_positions_except_relocs (bfd *abfd,
       unsigned int alloc;
 
       /* Assign file positions for the loaded sections based on the
-         assignment of sections to segments.  */
+        assignment of sections to segments.  */
       if (!assign_file_positions_for_load_sections (abfd, link_info))
        return FALSE;
 
@@ -4935,12 +4806,10 @@ prep_headers (bfd *abfd)
 {
   Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
   Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
-  Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
   struct elf_strtab_hash *shstrtab;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   i_ehdrp = elf_elfheader (abfd);
-  i_shdrp = elf_elfsections (abfd);
 
   shstrtab = _bfd_elf_strtab_init ();
   if (shstrtab == NULL)
@@ -5085,21 +4954,26 @@ _bfd_elf_write_object_contents (bfd *abfd)
              || bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt)
            return FALSE;
        }
-      if (count == SHN_LORESERVE - 1)
-       count += SHN_HIRESERVE + 1 - SHN_LORESERVE;
     }
 
   /* 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
@@ -5111,11 +4985,11 @@ _bfd_elf_write_corefile_contents (bfd *abfd)
 
 /* Given a section, search the header to find them.  */
 
-int
+unsigned int
 _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
 {
   const struct elf_backend_data *bed;
-  int index;
+  unsigned int index;
 
   if (elf_section_data (asect) != NULL
       && elf_section_data (asect)->this_idx != 0)
@@ -5128,7 +5002,7 @@ _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
   else if (bfd_is_und_section (asect))
     index = SHN_UNDEF;
   else
-    index = -1;
+    index = SHN_BAD;
 
   bed = get_elf_backend_data (abfd);
   if (bed->elf_backend_section_from_bfd_section)
@@ -5139,7 +5013,7 @@ _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
        return retval;
     }
 
-  if (index == -1)
+  if (index == SHN_BAD)
     bfd_set_error (bfd_error_nonrepresentable_section);
 
   return index;
@@ -5181,7 +5055,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));
@@ -5216,6 +5090,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   unsigned int i;
   unsigned int num_segments;
   bfd_boolean phdr_included = FALSE;
+  bfd_boolean p_paddr_valid;
   bfd_vma maxpagesize;
   struct elf_segment_map *phdr_adjust_seg = NULL;
   unsigned int phdr_adjust_num = 0;
@@ -5254,15 +5129,22 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
    && (section->lma + SECTION_SIZE (section, segment)                  \
        <= SEGMENT_END (segment, base)))
 
-  /* Special case: corefile "NOTE" section containing regs, prpsinfo etc.  */
-#define IS_COREFILE_NOTE(p, s)                                         \
+  /* Handle PT_NOTE segment.  */
+#define IS_NOTE(p, s)                                                  \
   (p->p_type == PT_NOTE                                                        \
-   && bfd_get_format (ibfd) == bfd_core                                        \
-   && s->vma == 0 && s->lma == 0                                       \
+   && elf_section_type (s) == SHT_NOTE                                 \
    && (bfd_vma) s->filepos >= p->p_offset                              \
    && ((bfd_vma) s->filepos + s->size                                  \
        <= p->p_offset + p->p_filesz))
 
+  /* Special case: corefile "NOTE" section containing regs, prpsinfo
+     etc.  */
+#define IS_COREFILE_NOTE(p, s)                                         \
+  (IS_NOTE (p, s)                                                      \
+   && bfd_get_format (ibfd) == bfd_core                                        \
+   && s->vma == 0                                                      \
+   && s->lma == 0)
+
   /* The complicated case when p_vaddr is 0 is to handle the Solaris
      linker, which generates a PT_INTERP section with p_vaddr and
      p_memsz set to 0.  */
@@ -5280,21 +5162,22 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   /* 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,
-       2. It is an allocated segment,
+         if that is set for the segment and the VMA otherwise,
+       2. It is an allocated section or a NOTE section in a PT_NOTE
+         segment.         
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.
        5. PT_GNU_STACK segments do not include any sections.
        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).  */
+         (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))                            \
+    || IS_NOTE (segment, section))                                     \
    && segment->p_type != PT_GNU_STACK                                  \
    && (segment->p_type != PT_TLS                                       \
        || (section->flags & SEC_THREAD_LOCAL))                         \
@@ -5304,11 +5187,11 @@ rewrite_elf_program_header (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))                                                      \
-   && ! section->segment_mark)
+          == 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.   */
@@ -5328,14 +5211,28 @@ rewrite_elf_program_header (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)
     section->segment_mark = FALSE;
 
+  /* 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
+     don't set the p_paddr_valid fields.  */
+  p_paddr_valid = FALSE;
+  for (i = 0, segment = elf_tdata (ibfd)->phdr;
+       i < num_segments;
+       i++, segment++)
+    if (segment->p_paddr != 0)
+      {
+       p_paddr_valid = TRUE;
+       break;
+      }
+
   /* Scan through the segments specified in the program header
      of the input BFD.  For this first scan we look for overlaps
      in the loadable segments.  These can be created by weird
@@ -5358,29 +5255,33 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
            }
 
       if (segment->p_type != PT_LOAD)
-       continue;
+       {
+         /* Remove PT_GNU_RELRO segment.  */
+         if (segment->p_type == PT_GNU_RELRO)
+           segment->p_type = PT_NULL;
+         continue;
+       }
 
       /* Determine if this segment overlaps any previous segments.  */
-      for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2 ++)
+      for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2++)
        {
          bfd_signed_vma extra_length;
 
          if (segment2->p_type != PT_LOAD
-             || ! SEGMENT_OVERLAPS (segment, segment2))
+             || !SEGMENT_OVERLAPS (segment, segment2))
            continue;
 
          /* Merge the two segments together.  */
          if (segment2->p_vaddr < segment->p_vaddr)
            {
              /* Extend SEGMENT2 to include SEGMENT and then delete
-                 SEGMENT.  */
-             extra_length =
-               SEGMENT_END (segment, segment->p_vaddr)
-               - SEGMENT_END (segment2, segment2->p_vaddr);
+                SEGMENT.  */
+             extra_length = (SEGMENT_END (segment, segment->p_vaddr)
+                             - SEGMENT_END (segment2, segment2->p_vaddr));
 
              if (extra_length > 0)
                {
-                 segment2->p_memsz  += extra_length;
+                 segment2->p_memsz += extra_length;
                  segment2->p_filesz += extra_length;
                }
 
@@ -5394,14 +5295,13 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
          else
            {
              /* Extend SEGMENT to include SEGMENT2 and then delete
-                 SEGMENT2.  */
-             extra_length =
-               SEGMENT_END (segment2, segment2->p_vaddr)
-               - SEGMENT_END (segment, segment->p_vaddr);
+                SEGMENT2.  */
+             extra_length = (SEGMENT_END (segment2, segment2->p_vaddr)
+                             - SEGMENT_END (segment, segment->p_vaddr));
 
              if (extra_length > 0)
                {
-                 segment->p_memsz  += extra_length;
+                 segment->p_memsz += extra_length;
                  segment->p_filesz += extra_length;
                }
 
@@ -5413,17 +5313,19 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   /* The second scan attempts to assign sections to segments.  */
   for (i = 0, segment = elf_tdata (ibfd)->phdr;
        i < num_segments;
-       i ++, segment ++)
-    {
-      unsigned int  section_count;
-      asection **   sections;
-      asection *    output_section;
-      unsigned int  isec;
-      bfd_vma       matching_lma;
-      bfd_vma       suggested_lma;
-      unsigned int  j;
+       i++, segment++)
+    {
+      unsigned int section_count;
+      asection **sections;
+      asection *output_section;
+      unsigned int isec;
+      bfd_vma matching_lma;
+      bfd_vma suggested_lma;
+      unsigned int j;
       bfd_size_type amt;
-      asection *    first_section;
+      asection *first_section;
+      bfd_boolean first_matching_lma;
+      bfd_boolean first_suggested_lma;
 
       if (segment->p_type == PT_NULL)
        continue;
@@ -5455,9 +5357,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 
       /* Initialise the fields of the segment map.  Default to
         using the physical address of the segment in the input BFD.  */
-      map->next          = NULL;
-      map->p_type        = segment->p_type;
-      map->p_flags       = segment->p_flags;
+      map->next = NULL;
+      map->p_type = segment->p_type;
+      map->p_flags = segment->p_flags;
       map->p_flags_valid = 1;
 
       /* If the first section in the input segment is removed, there is
@@ -5466,17 +5368,16 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       if (!first_section || first_section->output_section != NULL)
        {
          map->p_paddr = segment->p_paddr;
-         map->p_paddr_valid = 1;
+         map->p_paddr_valid = p_paddr_valid;
        }
 
       /* 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)
+      if (!phdr_included || segment->p_type != PT_LOAD)
        {
          map->includes_phdrs =
            (segment->p_offset <= (bfd_vma) iehdr->e_phoff
@@ -5495,9 +5396,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
             something.  They are allowed by the ELF spec however, so only
             a warning is produced.  */
          if (segment->p_type == PT_LOAD)
-           (*_bfd_error_handler)
-             (_("%B: warning: Empty loadable segment detected, is this intentional ?\n"),
-              ibfd);
+           (*_bfd_error_handler) (_("%B: warning: Empty loadable segment"
+                                    " detected, is this intentional ?\n"),
+                                  ibfd);
 
          map->count = 0;
          *pointer_to_map = map;
@@ -5534,8 +5435,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
         pointers that we are interested in.  As these sections get assigned
         to a segment, they are removed from this array.  */
 
-      /* Gcc 2.96 miscompiles this code on mips. Don't do casting here
-        to work around this long long bug.  */
       sections = bfd_malloc2 (section_count, sizeof (asection *));
       if (sections == NULL)
        return FALSE;
@@ -5549,54 +5448,68 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       isec = 0;
       matching_lma = 0;
       suggested_lma = 0;
+      first_matching_lma = TRUE;
+      first_suggested_lma = TRUE;
 
-      for (j = 0, section = ibfd->sections;
+      for (section = ibfd->sections;
           section != NULL;
           section = section->next)
+       if (section == first_section)
+         break;
+
+      for (j = 0; section != NULL; section = section->next)
        {
          if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
            {
              output_section = section->output_section;
 
-             sections[j ++] = section;
+             sections[j++] = section;
 
              /* The Solaris native linker always sets p_paddr to 0.
                 We try to catch that case here, and set it to the
                 correct value.  Note - some backends require that
                 p_paddr be left as zero.  */
-             if (segment->p_paddr == 0
+             if (!p_paddr_valid
                  && segment->p_vaddr != 0
-                 && (! bed->want_p_paddr_set_to_zero)
+                 && !bed->want_p_paddr_set_to_zero
                  && isec == 0
                  && output_section->lma != 0
-                 && (output_section->vma == (segment->p_vaddr
-                                             + (map->includes_filehdr
-                                                ? iehdr->e_ehsize
-                                                : 0)
-                                             + (map->includes_phdrs
-                                                ? (iehdr->e_phnum
-                                                   * iehdr->e_phentsize)
-                                                : 0))))
+                 && output_section->vma == (segment->p_vaddr
+                                            + (map->includes_filehdr
+                                               ? iehdr->e_ehsize
+                                               : 0)
+                                            + (map->includes_phdrs
+                                               ? (iehdr->e_phnum
+                                                  * iehdr->e_phentsize)
+                                               : 0)))
                map->p_paddr = segment->p_vaddr;
 
              /* Match up the physical address of the segment with the
                 LMA address of the output section.  */
              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))
-                )
+                 || (bed->want_p_paddr_set_to_zero
+                     && IS_CONTAINED_BY_VMA (output_section, segment)))
                {
-                 if (matching_lma == 0)
-                   matching_lma = output_section->lma;
+                 if (first_matching_lma || output_section->lma < matching_lma)
+                   {
+                     matching_lma = output_section->lma;
+                     first_matching_lma = FALSE;
+                   }
 
                  /* We assume that if the section fits within the segment
                     then it does not overlap any other section within that
                     segment.  */
-                 map->sections[isec ++] = output_section;
+                 map->sections[isec++] = output_section;
+               }
+             else if (first_suggested_lma)
+               {
+                 suggested_lma = output_section->lma;
+                 first_suggested_lma = FALSE;
                }
-             else if (suggested_lma == 0)
-               suggested_lma = output_section->lma;
+
+             if (j == section_count)
+               break;
            }
        }
 
@@ -5613,20 +5526,23 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
          map->count = section_count;
          *pointer_to_map = map;
          pointer_to_map = &map->next;
-         
-         if (matching_lma != map->p_paddr
-             && !map->includes_filehdr && !map->includes_phdrs)
+
+         if (p_paddr_valid
+             && !bed->want_p_paddr_set_to_zero
+             && 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;
        }
       else
        {
-         if (matching_lma != 0)
+         if (!first_matching_lma)
            {
              /* At least one section fits inside the current segment.
                 Keep it, but modify its physical address to match the
@@ -5672,6 +5588,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        {
          map->count = 0;
          suggested_lma = 0;
+         first_suggested_lma = TRUE;
 
          /* Fill the current segment with sections that fit.  */
          for (j = 0; j < section_count; j++)
@@ -5693,17 +5610,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                      /* If the first section in a segment does not start at
                         the beginning of the segment, then something is
                         wrong.  */
-                     if (output_section->lma !=
-                         (map->p_paddr
-                          + (map->includes_filehdr ? iehdr->e_ehsize : 0)
-                          + (map->includes_phdrs
-                             ? iehdr->e_phnum * iehdr->e_phentsize
-                             : 0)))
+                     if (output_section->lma
+                         != (map->p_paddr
+                             + (map->includes_filehdr ? iehdr->e_ehsize : 0)
+                             + (map->includes_phdrs
+                                ? iehdr->e_phnum * iehdr->e_phentsize
+                                : 0)))
                        abort ();
                    }
                  else
                    {
-                     asection * prev_sec;
+                     asection *prev_sec;
 
                      prev_sec = map->sections[map->count - 1];
 
@@ -5713,11 +5630,14 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                      if ((BFD_ALIGN (prev_sec->lma + prev_sec->size,
                                      maxpagesize)
                           < BFD_ALIGN (output_section->lma, maxpagesize))
-                         || ((prev_sec->lma + prev_sec->size)
+                         || (prev_sec->lma + prev_sec->size
                              > output_section->lma))
                        {
-                         if (suggested_lma == 0)
-                           suggested_lma = output_section->lma;
+                         if (first_suggested_lma)
+                           {
+                             suggested_lma = output_section->lma;
+                             first_suggested_lma = FALSE;
+                           }
 
                          continue;
                        }
@@ -5728,8 +5648,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                  sections[j] = NULL;
                  section->segment_mark = TRUE;
                }
-             else if (suggested_lma == 0)
-               suggested_lma = output_section->lma;
+             else if (first_suggested_lma)
+               {
+                 suggested_lma = output_section->lma;
+                 first_suggested_lma = FALSE;
+               }
            }
 
          BFD_ASSERT (map->count > 0);
@@ -5755,14 +5678,14 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
              /* 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->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 = p_paddr_valid;
              map->includes_filehdr = 0;
-             map->includes_phdrs   = 0;
+             map->includes_phdrs = 0;
            }
        }
       while (isec < section_count);
@@ -5770,17 +5693,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       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
@@ -5802,6 +5714,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 #undef SECTION_SIZE
 #undef IS_CONTAINED_BY_VMA
 #undef IS_CONTAINED_BY_LMA
+#undef IS_NOTE
 #undef IS_COREFILE_NOTE
 #undef IS_SOLARIS_PT_INTERP
 #undef IS_SECTION_IN_INPUT_SEGMENT
@@ -5824,13 +5737,26 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
   unsigned int i;
   unsigned int num_segments;
   bfd_boolean phdr_included = FALSE;
+  bfd_boolean p_paddr_valid;
 
   iehdr = elf_elfheader (ibfd);
 
   map_first = NULL;
   pointer_to_map = &map_first;
 
+  /* If all the segment p_paddr fields are zero, don't set
+     map->p_paddr_valid.  */
+  p_paddr_valid = FALSE;
   num_segments = elf_elfheader (ibfd)->e_phnum;
+  for (i = 0, segment = elf_tdata (ibfd)->phdr;
+       i < num_segments;
+       i++, segment++)
+    if (segment->p_paddr != 0)
+      {
+       p_paddr_valid = TRUE;
+       break;
+      }
+
   for (i = 0, segment = elf_tdata (ibfd)->phdr;
        i < num_segments;
        i++, segment++)
@@ -5840,10 +5766,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       bfd_size_type amt;
       Elf_Internal_Shdr *this_hdr;
       asection *first_section = NULL;
-
-      /* FIXME: Do we need to copy PT_NULL segment?  */
-      if (segment->p_type == PT_NULL)
-       continue;
+      asection *lowest_section = NULL;
 
       /* Compute how many sections are in this segment.  */
       for (section = ibfd->sections, section_count = 0;
@@ -5854,7 +5777,9 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
          if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
            {
              if (!first_section)
-               first_section = section;
+               first_section = lowest_section = section;
+             if (section->lma < lowest_section->lma)
+               lowest_section = section;
              section_count++;
            }
        }
@@ -5875,11 +5800,22 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       map->p_flags = segment->p_flags;
       map->p_flags_valid = 1;
       map->p_paddr = segment->p_paddr;
-      map->p_paddr_valid = 1;
+      map->p_paddr_valid = p_paddr_valid;
       map->p_align = segment->p_align;
       map->p_align_valid = 1;
       map->p_vaddr_offset = 0;
 
+      if (map->p_type == PT_GNU_RELRO
+         && segment->p_filesz == segment->p_memsz)
+       {
+         /* The PT_GNU_RELRO segment may contain the first a few
+            bytes in the .got.plt section even if the whole .got.plt
+            section isn't in the PT_GNU_RELRO segment.  We won't
+            change the size of the PT_GNU_RELRO segment.  */
+         map->p_size = segment->p_filesz;
+         map->p_size_valid = 1;
+       }
+
       /* Determine if this segment contains the ELF file header
         and if it contains the program headers themselves.  */
       map->includes_filehdr = (segment->p_offset == 0
@@ -5898,11 +5834,13 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            phdr_included = TRUE;
        }
 
-      if (!map->includes_phdrs && !map->includes_filehdr)
+      if (!map->includes_phdrs
+         && !map->includes_filehdr
+         && map->p_paddr_valid)
        /* There is some other padding before the first section.  */
-       map->p_vaddr_offset = ((first_section ? first_section->lma : 0)
+       map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
                               - segment->p_paddr);
-      
+
       if (section_count != 0)
        {
          unsigned int isec = 0;
@@ -5951,6 +5889,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
       asection *section, *osec;
       unsigned int i, num_segments;
       Elf_Internal_Shdr *this_hdr;
+      const struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (ibfd);
+
+      /* Regenerate the segment map if p_paddr is set to 0.  */
+      if (bed->want_p_paddr_set_to_zero)
+       goto rewrite;
 
       /* Initialize the segment mark field.  */
       for (section = obfd->sections; section != NULL;
@@ -6037,13 +5982,9 @@ _bfd_elf_init_private_section_data (bfd *ibfd,
      output BFD section flags have been set to something different.
      elf_fake_sections will set ELF section type based on BFD
      section flags.  */
-  if (osec->flags == isec->flags || !osec->flags)
-    {
-      BFD_ASSERT (osec->flags == isec->flags 
-                 || (!osec->flags
-                     && elf_section_type (osec) == SHT_NULL));
-      elf_section_type (osec) = elf_section_type (isec);
-    }
+  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)
@@ -6186,6 +6127,7 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd,
   osym = elf_symbol_from (obfd, osymarg);
 
   if (isym != NULL
+      && isym->internal_elf_sym.st_shndx != 0
       && osym != NULL
       && bfd_is_abs_section (isym->symbol.section))
     {
@@ -6243,7 +6185,7 @@ swap_out_syms (bfd *abfd,
   symtab_hdr->sh_entsize = bed->s->sizeof_sym;
   symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1);
   symtab_hdr->sh_info = elf_num_locals (abfd) + 1;
-  symtab_hdr->sh_addralign = 1 << bed->s->log_file_align;
+  symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
 
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
@@ -6343,7 +6285,7 @@ swap_out_syms (bfd *abfd,
       else
        {
          asection *sec = syms[idx]->section;
-         int shndx;
+         unsigned int shndx;
 
          if (sec->output_section)
            {
@@ -6390,7 +6332,7 @@ swap_out_syms (bfd *abfd,
            {
              shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 
-             if (shndx == -1)
+             if (shndx == SHN_BAD)
                {
                  asection *sec2;
 
@@ -6414,7 +6356,7 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
                    }
 
                  shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
-                 BFD_ASSERT (shndx != -1);
+                 BFD_ASSERT (shndx != SHN_BAD);
                }
            }
 
@@ -6451,7 +6393,15 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
            sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
        }
       else if (bfd_is_com_section (syms[idx]->section))
-       sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+       {
+#ifdef USE_STT_COMMON
+         if (type == STT_OBJECT)
+           sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON);
+         else
+#else
+           sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+#endif
+       }
       else if (bfd_is_und_section (syms[idx]->section))
        sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
                                    ? STB_WEAK
@@ -6613,8 +6563,7 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
 
   ret = sizeof (arelent *);
   for (s = abfd->sections; s != NULL; s = s->next)
-    if ((s->flags & SEC_LOAD) != 0
-       && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+    if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
        && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
            || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
       ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize)
@@ -6650,8 +6599,7 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
   ret = 0;
   for (s = abfd->sections; s != NULL; s = s->next)
     {
-      if ((s->flags & SEC_LOAD) != 0
-         && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+      if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
          && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
              || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
        {
@@ -7590,7 +7538,7 @@ elfcore_grok_prfpreg (bfd *abfd, Elf_Internal_Note *note)
 }
 
 /* Linux dumps the Intel SSE regs in a note named "LINUX" with a note
-   type of 5 (NT_PRXFPREG).  Just include the whole note's contents
+   type of NT_PRXFPREG.  Just include the whole note's contents
    literally.  */
 
 static bfd_boolean
@@ -7599,6 +7547,13 @@ elfcore_grok_prxfpreg (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
 }
 
+static bfd_boolean
+elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note);
+}
+
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)                /* Sparc64 cross Sparc32 */
@@ -7814,7 +7769,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
 }
 #endif /* defined (HAVE_LWPSTATUS_T) */
 
-#if defined (HAVE_WIN32_PSTATUS_T)
 static bfd_boolean
 elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
 {
@@ -7822,24 +7776,32 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
   char *name;
   size_t len;
   asection *sect;
-  win32_pstatus_t pstatus;
+  int type;
+  int is_active_thread;
+  bfd_vma base_addr;
+
+  if (note->descsz < 728)
+    return TRUE;
 
-  if (note->descsz < sizeof (pstatus))
+  if (! CONST_STRNEQ (note->namedata, "win32"))
     return TRUE;
 
-  memcpy (&pstatus, note->descdata, sizeof (pstatus));
+  type = bfd_get_32 (abfd, note->descdata);
 
-  switch (pstatus.data_type)
+  switch (type)
     {
-    case NOTE_INFO_PROCESS:
+    case 1 /* NOTE_INFO_PROCESS */:
       /* FIXME: need to add ->core_command.  */
-      elf_tdata (abfd)->core_signal = pstatus.data.process_info.signal;
-      elf_tdata (abfd)->core_pid = pstatus.data.process_info.pid;
+      /* process_info.pid */
+      elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 8);
+      /* process_info.signal */
+      elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 12);
       break;
 
-    case NOTE_INFO_THREAD:
+    case 2 /* NOTE_INFO_THREAD */:
       /* Make a ".reg/999" section.  */
-      sprintf (buf, ".reg/%ld", (long) pstatus.data.thread_info.tid);
+      /* thread_info.tid */
+      sprintf (buf, ".reg/%ld", (long) bfd_get_32 (abfd, note->descdata + 8));
 
       len = strlen (buf) + 1;
       name = bfd_alloc (abfd, len);
@@ -7852,21 +7814,25 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       if (sect == NULL)
        return FALSE;
 
-      sect->size = sizeof (pstatus.data.thread_info.thread_context);
-      sect->filepos = (note->descpos
-                      + offsetof (struct win32_pstatus,
-                                  data.thread_info.thread_context));
+      /* sizeof (thread_info.thread_context) */
+      sect->size = 716;
+      /* offsetof (thread_info.thread_context) */
+      sect->filepos = note->descpos + 12;
       sect->alignment_power = 2;
 
-      if (pstatus.data.thread_info.is_active_thread)
+      /* thread_info.is_active_thread */
+      is_active_thread = bfd_get_32 (abfd, note->descdata + 8);
+
+      if (is_active_thread)
        if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
          return FALSE;
       break;
 
-    case NOTE_INFO_MODULE:
+    case 3 /* NOTE_INFO_MODULE */:
       /* Make a ".module/xxxxxxxx" section.  */
-      sprintf (buf, ".module/%08lx",
-              (long) pstatus.data.module_info.base_address);
+      /* module_info.base_address */
+      base_addr = bfd_get_32 (abfd, note->descdata + 4);
+      sprintf (buf, ".module/%08lx", (long) base_addr);
 
       len = strlen (buf) + 1;
       name = bfd_alloc (abfd, len);
@@ -7891,7 +7857,6 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
 
   return TRUE;
 }
-#endif /* HAVE_WIN32_PSTATUS_T */
 
 static bfd_boolean
 elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
@@ -7926,10 +7891,8 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
     case NT_FPREGSET:          /* FIXME: rename to NT_PRFPREG */
       return elfcore_grok_prfpreg (abfd, note);
 
-#if defined (HAVE_WIN32_PSTATUS_T)
     case NT_WIN32PSTATUS:
       return elfcore_grok_win32pstatus (abfd, note);
-#endif
 
     case NT_PRXFPREG:          /* Linux SSE extension */
       if (note->namesz == 6
@@ -7938,6 +7901,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
        return TRUE;
 
+    case NT_PPC_VMX:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_ppc_vmx (abfd, note);
+      else
+       return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -7965,6 +7935,32 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
     }
 }
 
+static bfd_boolean
+elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
+{
+  elf_tdata (abfd)->build_id_size = note->descsz;
+  elf_tdata (abfd)->build_id = bfd_alloc (abfd, note->descsz);
+  if (elf_tdata (abfd)->build_id == NULL)
+    return FALSE;
+
+  memcpy (elf_tdata (abfd)->build_id, note->descdata, note->descsz);
+
+  return TRUE;
+}
+
+static bfd_boolean
+elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note)
+{
+  switch (note->type)
+    {
+    default:
+      return TRUE;
+
+    case NT_GNU_BUILD_ID:
+      return elfobj_grok_gnu_build_id (abfd, note);
+    }
+}
+
 static bfd_boolean
 elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
 {
@@ -7982,7 +7978,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);
@@ -8010,9 +8005,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);
     }
@@ -8028,38 +8023,38 @@ 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 */
 }
@@ -8176,6 +8171,32 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note)
     }
 }
 
+static bfd_boolean
+elfcore_grok_spu_note (bfd *abfd, Elf_Internal_Note *note)
+{
+  char *name;
+  asection *sect;
+  size_t len;
+
+  /* Use note name as section name.  */
+  len = note->namesz;
+  name = bfd_alloc (abfd, len);
+  if (name == NULL)
+    return FALSE;
+  memcpy (name, note->namedata, len);
+  name[len - 1] = '\0';
+
+  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->alignment_power = 1;
+
+  return TRUE;
+}
+
 /* Function: elfcore_write_note
 
    Inputs:
@@ -8214,6 +8235,8 @@ elfcore_write_note (bfd *abfd,
   newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4);
 
   buf = realloc (buf, *bufsiz + newspace);
+  if (buf == NULL)
+    return buf;
   dest = buf + *bufsiz;
   *bufsiz += newspace;
   xnp = (Elf_External_Note *) dest;
@@ -8439,28 +8462,39 @@ elfcore_write_prxfpreg (bfd *abfd,
                             note_name, NT_PRXFPREG, xfpregs, size);
 }
 
-static bfd_boolean
-elfcore_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
+char *
+elfcore_write_ppc_vmx (bfd *abfd,
+                      char *buf,
+                      int *bufsiz,
+                      const void *ppc_vmx,
+                      int size)
 {
-  char *buf;
-  char *p;
-
-  if (size <= 0)
-    return TRUE;
-
-  if (bfd_seek (abfd, offset, SEEK_SET) != 0)
-    return FALSE;
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_PPC_VMX, ppc_vmx, size);
+}
 
-  buf = bfd_malloc (size);
-  if (buf == NULL)
-    return FALSE;
+char *
+elfcore_write_register_note (bfd *abfd,
+                            char *buf,
+                            int *bufsiz,
+                            const char *section,
+                            const void *data,
+                            int size)
+{
+  if (strcmp (section, ".reg2") == 0)
+    return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-xfp") == 0)
+    return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-ppc-vmx") == 0)
+    return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size);
+  return NULL;
+}
 
-  if (bfd_bread (buf, size, abfd) != size)
-    {
-    error:
-      free (buf);
-      return FALSE;
-    }
+static bfd_boolean
+elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
+{
+  char *p;
 
   p = buf;
   while (p < buf + size)
@@ -8478,25 +8512,71 @@ 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 (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
+      switch (bfd_get_format (abfd))
         {
-          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;
+       default:
+         return TRUE;
+
+       case bfd_core:
+         if (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
+           {
+             if (! elfcore_grok_netbsd_note (abfd, &in))
+               return FALSE;
+           }
+         else if (CONST_STRNEQ (in.namedata, "QNX"))
+           {
+             if (! elfcore_grok_nto_note (abfd, &in))
+               return FALSE;
+           }
+         else if (CONST_STRNEQ (in.namedata, "SPU/"))
+           {
+             if (! elfcore_grok_spu_note (abfd, &in))
+               return FALSE;
+           }
+         else
+           {
+             if (! elfcore_grok_note (abfd, &in))
+               return FALSE;
+           }
+         break;
+
+       case bfd_object:
+         if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
+           {
+             if (! elfobj_grok_gnu_note (abfd, &in))
+               return FALSE;
+           }
+         break;
        }
-      else
-        {
-          if (! elfcore_grok_note (abfd, &in))
-            goto error;
-        }
 
       p = in.descdata + BFD_ALIGN (in.descsz, 4);
     }
 
+  return TRUE;
+}
+
+static bfd_boolean
+elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
+{
+  char *buf;
+
+  if (size <= 0)
+    return TRUE;
+
+  if (bfd_seek (abfd, offset, SEEK_SET) != 0)
+    return FALSE;
+
+  buf = bfd_malloc (size);
+  if (buf == NULL)
+    return FALSE;
+
+  if (bfd_bread (buf, size, abfd) != size
+      || !elf_parse_notes (abfd, buf, size, offset))
+    {
+      free (buf);
+      return FALSE;
+    }
+
   free (buf);
   return TRUE;
 }
@@ -8545,63 +8625,6 @@ bfd_get_elf_phdrs (bfd *abfd, void *phdrs)
   return num_phdrs;
 }
 
-void
-_bfd_elf_sprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, char *buf, bfd_vma value)
-{
-#ifdef BFD64
-  Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
-
-  i_ehdrp = elf_elfheader (abfd);
-  if (i_ehdrp == NULL)
-    sprintf_vma (buf, value);
-  else
-    {
-      if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64)
-       {
-#if BFD_HOST_64BIT_LONG
-         sprintf (buf, "%016lx", value);
-#else
-         sprintf (buf, "%08lx%08lx", _bfd_int64_high (value),
-                  _bfd_int64_low (value));
-#endif
-       }
-      else
-       sprintf (buf, "%08lx", (unsigned long) (value & 0xffffffff));
-    }
-#else
-  sprintf_vma (buf, value);
-#endif
-}
-
-void
-_bfd_elf_fprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, void *stream, bfd_vma value)
-{
-#ifdef BFD64
-  Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
-
-  i_ehdrp = elf_elfheader (abfd);
-  if (i_ehdrp == NULL)
-    fprintf_vma ((FILE *) stream, value);
-  else
-    {
-      if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64)
-       {
-#if BFD_HOST_64BIT_LONG
-         fprintf ((FILE *) stream, "%016lx", value);
-#else
-         fprintf ((FILE *) stream, "%08lx%08lx",
-                  _bfd_int64_high (value), _bfd_int64_low (value));
-#endif
-       }
-      else
-       fprintf ((FILE *) stream, "%08lx",
-                (unsigned long) (value & 0xffffffff));
-    }
-#else
-  fprintf_vma ((FILE *) stream, value);
-#endif
-}
-
 enum elf_reloc_type_class
 _bfd_elf_reloc_type_class (const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED)
 {
@@ -8760,7 +8783,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 += bed->s->int_rels_per_ext_rel)
     size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
 
   s = *ret = bfd_malloc (size);
@@ -8770,7 +8793,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
   names = (char *) (s + count);
   p = relplt->relocation;
   n = 0;
-  for (i = 0; i < count; i++, s++, p++)
+  for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
     {
       size_t len;
       bfd_vma addr;
@@ -8784,379 +8807,27 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
         we are defining a symbol, ensure one of them is set.  */
       if ((s->flags & BSF_LOCAL) == 0)
        s->flags |= BSF_GLOBAL;
+      s->flags |= BSF_SYNTHETIC;
       s->section = plt;
       s->value = addr - plt->vma;
       s->name = names;
+      s->udata.p = NULL;
       len = strlen ((*p->sym_ptr_ptr)->name);
       memcpy (names, (*p->sym_ptr_ptr)->name, len);
       names += len;
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
-      ++n;
+      ++s, ++n;
     }
 
   return n;
 }
 
-struct elf_symbuf_symbol
-{
-  unsigned long st_name;       /* Symbol name, index in string tbl */
-  unsigned char st_info;       /* Type and binding attributes */
-  unsigned char st_other;      /* Visibilty, and target specific */
-};
-
-struct elf_symbuf_head
-{
-  struct elf_symbuf_symbol *ssym;
-  bfd_size_type count;
-  unsigned int st_shndx;
-};
-
-struct elf_symbol
-{
-  union
-    {
-      Elf_Internal_Sym *isym;
-      struct elf_symbuf_symbol *ssym;
-    } u;
-  const char *name;
-};
-
-/* Sort references to symbols by ascending section number.  */
-
-static int
-elf_sort_elf_symbol (const void *arg1, const void *arg2)
-{
-  const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
-  const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
-
-  return s1->st_shndx - s2->st_shndx;
-}
-
-static int
-elf_sym_name_compare (const void *arg1, const void *arg2)
-{
-  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);
-}
-
-static struct elf_symbuf_head *
-elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
-{
-  Elf_Internal_Sym **ind, **indbufend, **indbuf
-    = bfd_malloc2 (symcount, sizeof (*indbuf));
-  struct elf_symbuf_symbol *ssym;
-  struct elf_symbuf_head *ssymbuf, *ssymhead;
-  bfd_size_type i, shndx_count;
-
-  if (indbuf == NULL)
-    return NULL;
-
-  for (ind = indbuf, i = 0; i < symcount; i++)
-    if (isymbuf[i].st_shndx != SHN_UNDEF)
-      *ind++ = &isymbuf[i];
-  indbufend = ind;
-
-  qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *),
-        elf_sort_elf_symbol);
-
-  shndx_count = 0;
-  if (indbufend > indbuf)
-    for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++)
-      if (ind[0]->st_shndx != ind[1]->st_shndx)
-       shndx_count++;
-
-  ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
-                       + (indbufend - indbuf) * sizeof (*ssymbuf));
-  if (ssymbuf == NULL)
-    {
-      free (indbuf);
-      return NULL;
-    }
-
-  ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
-  ssymbuf->ssym = NULL;
-  ssymbuf->count = shndx_count;
-  ssymbuf->st_shndx = 0;
-  for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++)
-    {
-      if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx)
-       {
-         ssymhead++;
-         ssymhead->ssym = ssym;
-         ssymhead->count = 0;
-         ssymhead->st_shndx = (*ind)->st_shndx;
-       }
-      ssym->st_name = (*ind)->st_name;
-      ssym->st_info = (*ind)->st_info;
-      ssym->st_other = (*ind)->st_other;
-      ssymhead->count++;
-    }
-  BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
-
-  free (indbuf);
-  return ssymbuf;
-}
-
-/* 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,
-                                  struct bfd_link_info *info)
-{
-  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;
-  struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
-  Elf_Internal_Sym *isym, *isymend;
-  struct elf_symbol *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 (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
-      && CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
-    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;
-
-  result = FALSE;
-  isymbuf1 = NULL;
-  isymbuf2 = NULL;
-  ssymbuf1 = elf_tdata (bfd1)->symbuf;
-  ssymbuf2 = elf_tdata (bfd2)->symbuf;
-
-  if (ssymbuf1 == NULL)
-    {
-      isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
-                                      NULL, NULL, NULL);
-      if (isymbuf1 == NULL)
-       goto done;
-
-      if (!info->reduce_memory_overheads)
-       elf_tdata (bfd1)->symbuf = ssymbuf1
-         = elf_create_symbuf (symcount1, isymbuf1);
-    }
-
-  if (ssymbuf1 == NULL || ssymbuf2 == NULL)
-    {
-      isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
-                                      NULL, NULL, NULL);
-      if (isymbuf2 == NULL)
-       goto done;
-
-      if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
-       elf_tdata (bfd2)->symbuf = ssymbuf2
-         = elf_create_symbuf (symcount2, isymbuf2);
-    }
-
-  if (ssymbuf1 != NULL && ssymbuf2 != NULL)
-    {
-      /* Optimized faster version.  */
-      bfd_size_type lo, hi, mid;
-      struct elf_symbol *symp;
-      struct elf_symbuf_symbol *ssym, *ssymend;
-
-      lo = 0;
-      hi = ssymbuf1->count;
-      ssymbuf1++;
-      count1 = 0;
-      while (lo < hi)
-       {
-         mid = (lo + hi) / 2;
-         if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
-           hi = mid;
-         else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
-           lo = mid + 1;
-         else
-           {
-             count1 = ssymbuf1[mid].count;
-             ssymbuf1 += mid;
-             break;
-           }
-       }
-
-      lo = 0;
-      hi = ssymbuf2->count;
-      ssymbuf2++;
-      count2 = 0;
-      while (lo < hi)
-       {
-         mid = (lo + hi) / 2;
-         if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
-           hi = mid;
-         else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
-           lo = mid + 1;
-         else
-           {
-             count2 = ssymbuf2[mid].count;
-             ssymbuf2 += mid;
-             break;
-           }
-       }
-
-      if (count1 == 0 || count2 == 0 || count1 != count2)
-       goto done;
-
-      symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
-      symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
-      if (symtable1 == NULL || symtable2 == NULL)
-       goto done;
-
-      symp = symtable1;
-      for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
-          ssym < ssymend; ssym++, symp++)
-       {
-         symp->u.ssym = ssym;
-         symp->name = bfd_elf_string_from_elf_section (bfd1,
-                                                       hdr1->sh_link,
-                                                       ssym->st_name);
-       }
-
-      symp = symtable2;
-      for (ssym = ssymbuf2->ssym, ssymend = ssym + count2;
-          ssym < ssymend; ssym++, symp++)
-       {
-         symp->u.ssym = ssym;
-         symp->name = bfd_elf_string_from_elf_section (bfd2,
-                                                       hdr2->sh_link,
-                                                       ssym->st_name);
-       }
-
-      /* 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].u.ssym->st_info != symtable2 [i].u.ssym->st_info
-           || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other
-           || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
-         goto done;
-
-      result = TRUE;
-      goto done;
-    }
-
-  symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
-  symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
-  if (symtable1 == NULL || symtable2 == NULL)
-    goto done;
-
-  /* Count definitions in the section.  */
-  count1 = 0;
-  for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
-    if (isym->st_shndx == (unsigned int) shndx1)
-      symtable1[count1++].u.isym = isym;
-
-  count2 = 0;
-  for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
-    if (isym->st_shndx == (unsigned int) shndx2)
-      symtable2[count2++].u.isym = isym;
-
-  if (count1 == 0 || count2 == 0 || count1 != count2)
-    goto done;
-
-  for (i = 0; i < count1; i++)
-    symtable1[i].name
-      = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link,
-                                        symtable1[i].u.isym->st_name);
-
-  for (i = 0; i < count2; i++)
-    symtable2[i].name
-      = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link,
-                                        symtable2[i].u.isym->st_name);
-
-  /* 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].u.isym->st_info != symtable2 [i].u.isym->st_info
-       || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->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);
-
-  return result;
-}
-
 /* 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);
 
-/* Return TRUE if 2 section types are compatible.  */
-
-bfd_boolean
-_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec,
-                                bfd *bbfd, const asection *bsec)
-{
-  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);
-}
-
 void
 _bfd_elf_set_osabi (bfd * abfd,
                    struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
This page took 0.073961 seconds and 4 git commands to generate.