+2005-07-14 Bob Rossi <bob@brasko.net>
[deliverable/binutils-gdb.git] / bfd / elf.c
index 2fcfa980ed0ced9d097531ae35a40cbbd6c19702..ff46a5e2ea97ee11a30826fab7b82da610f5b376 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,7 +1,7 @@
 /* ELF executable support for BFD.
 
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -17,7 +17,7 @@
 
    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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 /*  SECTION
 
@@ -206,28 +206,6 @@ bfd_elf_hash (const char *namearg)
   return h & 0xffffffff;
 }
 
-/* Read a specified number of bytes at a specified offset in an ELF
-   file, into a newly allocated buffer, and return a pointer to the
-   buffer.  */
-
-static char *
-elf_read (bfd *abfd, file_ptr offset, bfd_size_type size)
-{
-  char *buf;
-
-  if ((buf = bfd_alloc (abfd, size)) == NULL)
-    return NULL;
-  if (bfd_seek (abfd, offset, SEEK_SET) != 0)
-    return NULL;
-  if (bfd_bread (buf, size, abfd) != size)
-    {
-      if (bfd_get_error () != bfd_error_system_call)
-       bfd_set_error (bfd_error_file_truncated);
-      return NULL;
-    }
-  return buf;
-}
-
 bfd_boolean
 bfd_elf_mkobject (bfd *abfd)
 {
@@ -253,24 +231,38 @@ char *
 bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
 {
   Elf_Internal_Shdr **i_shdrp;
-  char *shstrtab = NULL;
+  bfd_byte *shstrtab = NULL;
   file_ptr offset;
   bfd_size_type shstrtabsize;
 
   i_shdrp = elf_elfsections (abfd);
   if (i_shdrp == 0 || i_shdrp[shindex] == 0)
-    return 0;
+    return NULL;
 
-  shstrtab = (char *) i_shdrp[shindex]->contents;
+  shstrtab = i_shdrp[shindex]->contents;
   if (shstrtab == NULL)
     {
       /* No cached one, attempt to read, and cache what we read.  */
       offset = i_shdrp[shindex]->sh_offset;
       shstrtabsize = i_shdrp[shindex]->sh_size;
-      shstrtab = elf_read (abfd, offset, shstrtabsize);
+
+      /* Allocate and clear an extra byte at the end, to prevent crashes
+        in case the string table is not terminated.  */
+      if (shstrtabsize + 1 == 0
+         || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL
+         || bfd_seek (abfd, offset, SEEK_SET) != 0)
+       shstrtab = NULL;
+      else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize)
+       {
+         if (bfd_get_error () != bfd_error_system_call)
+           bfd_set_error (bfd_error_file_truncated);
+         shstrtab = NULL;
+       }
+      else
+       shstrtab[shstrtabsize] = '\0';
       i_shdrp[shindex]->contents = shstrtab;
     }
-  return shstrtab;
+  return (char *) shstrtab;
 }
 
 char *
@@ -291,13 +283,13 @@ bfd_elf_string_from_elf_section (bfd *abfd,
 
   if (strindex >= hdr->sh_size)
     {
+      unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx;
       (*_bfd_error_handler)
-       (_("%s: invalid string offset %u >= %lu for section `%s'"),
-        bfd_archive_filename (abfd), strindex, (unsigned long) hdr->sh_size,
-        ((shindex == elf_elfheader(abfd)->e_shstrndx
-          && strindex == hdr->sh_name)
+       (_("%B: invalid string offset %u >= %lu for section `%s'"),
+        abfd, strindex, (unsigned long) hdr->sh_size,
+        (shindex == shstrndx && strindex == hdr->sh_name
          ? ".shstrtab"
-         : elf_string_from_elf_strtab (abfd, hdr->sh_name)));
+         : bfd_elf_string_from_elf_section (abfd, shstrndx, hdr->sh_name)));
       return "";
     }
 
@@ -348,7 +340,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   pos = symtab_hdr->sh_offset + symoffset * extsym_size;
   if (extsym_buf == NULL)
     {
-      alloc_ext = bfd_malloc (amt);
+      alloc_ext = bfd_malloc2 (symcount, extsym_size);
       extsym_buf = alloc_ext;
     }
   if (extsym_buf == NULL
@@ -367,7 +359,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
       pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
       if (extshndx_buf == NULL)
        {
-         alloc_extshndx = bfd_malloc (amt);
+         alloc_extshndx = bfd_malloc2 (symcount,
+                                       sizeof (Elf_External_Sym_Shndx));
          extshndx_buf = alloc_extshndx;
        }
       if (extshndx_buf == NULL
@@ -381,8 +374,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
   if (intsym_buf == NULL)
     {
-      bfd_size_type amt = symcount * sizeof (Elf_Internal_Sym);
-      intsym_buf = bfd_malloc (amt);
+      intsym_buf = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
       if (intsym_buf == NULL)
        goto out;
     }
@@ -405,17 +397,31 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
 /* Look up a symbol name.  */
 const char *
-bfd_elf_local_sym_name (bfd *abfd, Elf_Internal_Sym *isym)
+bfd_elf_sym_name (bfd *abfd,
+                 Elf_Internal_Shdr *symtab_hdr,
+                 Elf_Internal_Sym *isym,
+                 asection *sym_sec)
 {
+  const char *name;
   unsigned int iname = isym->st_name;
-  unsigned int shindex = elf_tdata (abfd)->symtab_hdr.sh_link;
-  if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION)
+  unsigned int shindex = symtab_hdr->sh_link;
+
+  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))
     {
       iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name;
       shindex = elf_elfheader (abfd)->e_shstrndx;
     }
 
-  return bfd_elf_string_from_elf_section (abfd, shindex, iname);
+  name = bfd_elf_string_from_elf_section (abfd, shindex, iname);
+  if (name == NULL)
+    name = "(null)";
+  else if (sym_sec && *name == '\0')
+    name = bfd_section_name (abfd, sym_sec);
+
+  return name;
 }
 
 /* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP
@@ -438,8 +444,11 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr)
   Elf_External_Sym_Shndx eshndx;
   Elf_Internal_Sym isym;
 
-  /* First we need to ensure the symbol table is available.  */
-  if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
+  /* First we need to ensure the symbol table is available.  Make sure
+     that it is a symbol table section.  */
+  hdr = elf_elfsections (abfd) [ghdr->sh_link];
+  if (hdr->sh_type != SHT_SYMTAB
+      || ! bfd_section_from_shdr (abfd, ghdr->sh_link))
     return NULL;
 
   /* Go read the symbol.  */
@@ -448,7 +457,7 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr)
                            &isym, esym, &eshndx) == NULL)
     return NULL;
 
-  return bfd_elf_local_sym_name (abfd, &isym);
+  return bfd_elf_sym_name (abfd, hdr, &isym, NULL);
 }
 
 /* Set next_in_group list pointer, and group name for NEWSECT.  */
@@ -476,15 +485,19 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
        }
 
       if (num_group == 0)
-       num_group = (unsigned) -1;
-      elf_tdata (abfd)->num_group = num_group;
-
-      if (num_group > 0)
+       {
+         num_group = (unsigned) -1;
+         elf_tdata (abfd)->num_group = num_group;
+       }
+      else
        {
          /* We keep a list of elf section headers for group sections,
             so we can find them quickly.  */
-         bfd_size_type amt = num_group * sizeof (Elf_Internal_Shdr *);
-         elf_tdata (abfd)->group_sect_ptr = bfd_alloc (abfd, amt);
+         bfd_size_type amt;
+
+         elf_tdata (abfd)->num_group = num_group;
+         elf_tdata (abfd)->group_sect_ptr
+           = bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *));
          if (elf_tdata (abfd)->group_sect_ptr == NULL)
            return FALSE;
 
@@ -504,7 +517,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                  /* Read the raw contents.  */
                  BFD_ASSERT (sizeof (*dest) >= 4);
                  amt = shdr->sh_size * sizeof (*dest) / 4;
-                 shdr->contents = bfd_alloc (abfd, amt);
+                 shdr->contents = bfd_alloc2 (abfd, shdr->sh_size,
+                                              sizeof (*dest) / 4);
                  if (shdr->contents == NULL
                      || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
                      || (bfd_bread (shdr->contents, shdr->sh_size, abfd)
@@ -535,8 +549,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                      if (idx >= shnum)
                        {
                          ((*_bfd_error_handler)
-                          (_("%s: invalid SHT_GROUP entry"),
-                           bfd_archive_filename (abfd)));
+                          (_("%B: invalid SHT_GROUP entry"), abfd));
                          idx = 0;
                        }
                      dest->shdr = elf_elfsections (abfd)[idx];
@@ -606,27 +619,61 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
 
   if (elf_group_name (newsect) == NULL)
     {
-      (*_bfd_error_handler) (_("%s: no group info for section %s"),
-                            bfd_archive_filename (abfd), newsect->name);
+      (*_bfd_error_handler) (_("%B: no group info for section %A"),
+                            abfd, newsect);
     }
   return TRUE;
 }
 
 bfd_boolean
-bfd_elf_discard_group (bfd *abfd ATTRIBUTE_UNUSED, asection *group)
+_bfd_elf_setup_group_pointers (bfd *abfd)
 {
-  asection *first = elf_next_in_group (group);
-  asection *s = first;
-
-  while (s != NULL)
-    {
-      s->output_section = bfd_abs_section_ptr;
-      s = elf_next_in_group (s);
-      /* These lists are circular.  */
-      if (s == first)
-       break;
+  unsigned int i;
+  unsigned int num_group = elf_tdata (abfd)->num_group;
+  bfd_boolean result = TRUE;
+
+  if (num_group == (unsigned) -1)
+    return result;
+
+  for (i = 0; i < num_group; i++)
+    {
+      Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
+      Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents;
+      unsigned int n_elt = shdr->sh_size / 4;
+
+      while (--n_elt != 0)
+       if ((++idx)->shdr->bfd_section)
+         elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section;
+       else if (idx->shdr->sh_type == SHT_RELA
+                || idx->shdr->sh_type == SHT_REL)
+         /* We won't include relocation sections in section groups in
+            output object files. We adjust the group section size here
+            so that relocatable link will work correctly when
+            relocation sections are in section group in input object
+            files.  */
+         shdr->bfd_section->size -= 4;
+       else
+         {
+           /* There are some unknown sections in the group.  */
+           (*_bfd_error_handler)
+             (_("%B: unknown [%d] section `%s' in group [%s]"),
+              abfd,
+              (unsigned int) idx->shdr->sh_type,
+              bfd_elf_string_from_elf_section (abfd,
+                                               (elf_elfheader (abfd)
+                                                ->e_shstrndx),
+                                               idx->shdr->sh_name),
+              shdr->bfd_section->name);
+           result = FALSE;
+         }
     }
-  return TRUE;
+  return result;
+}
+
+bfd_boolean
+bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec)
+{
+  return elf_next_in_group (sec) != NULL;
 }
 
 /* Make a BFD section from an ELF section.  We store a pointer to the
@@ -635,7 +682,8 @@ bfd_elf_discard_group (bfd *abfd ATTRIBUTE_UNUSED, asection *group)
 bfd_boolean
 _bfd_elf_make_section_from_shdr (bfd *abfd,
                                 Elf_Internal_Shdr *hdr,
-                                const char *name)
+                                const char *name,
+                                int shindex)
 {
   asection *newsect;
   flagword flags;
@@ -652,6 +700,10 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if (newsect == NULL)
     return FALSE;
 
+  hdr->bfd_section = newsect;
+  elf_section_data (newsect)->this_hdr = *hdr;
+  elf_section_data (newsect)->this_idx = shindex;
+
   /* Always use the real type/flags.  */
   elf_section_type (newsect) = hdr->sh_type;
   elf_section_flags (newsect) = hdr->sh_flags;
@@ -694,25 +746,45 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if ((hdr->sh_flags & SHF_TLS) != 0)
     flags |= SEC_THREAD_LOCAL;
 
-  /* The debugging sections appear to be recognized only by name, not
-     any sort of flag.  */
-  {
-    static const char *debug_sec_names [] =
+  if ((flags & SEC_ALLOC) == 0)
     {
-      ".debug",
-      ".gnu.linkonce.wi.",
-      ".line",
-      ".stab"
-    };
-    int i;
-
-    for (i = ARRAY_SIZE (debug_sec_names); i--;)
-      if (strncmp (name, debug_sec_names[i], strlen (debug_sec_names[i])) == 0)
-       break;
-
-    if (i >= 0)
-      flags |= SEC_DEBUGGING;
-  }
+      /* The debugging sections appear to be recognized only by name,
+        not any sort of flag.  Their SEC_ALLOC bits are cleared.  */
+      static const struct
+       {
+         const char *name;
+         int len;
+       } debug_sections [] =
+       {
+         { "debug",             5  },  /* 'd' */
+         { NULL,                0  },  /* 'e' */
+         { NULL,                0  },  /* 'f' */
+         { "gnu.linkonce.wi.", 17 },   /* 'g' */
+         { NULL,                0  },  /* 'h' */
+         { NULL,                0  },  /* 'i' */
+         { NULL,                0  },  /* 'j' */
+         { NULL,                0  },  /* 'k' */
+         { "line",              4  },  /* 'l' */
+         { NULL,                0  },  /* 'm' */
+         { NULL,                0  },  /* 'n' */
+         { NULL,                0  },  /* 'o' */
+         { NULL,                0  },  /* 'p' */
+         { NULL,                0  },  /* 'q' */
+         { NULL,                0  },  /* 'r' */
+         { "stab",              4  }   /* 's' */
+       };
+      
+      if (name [0] == '.')
+       {
+         int i = name [1] - 'd';
+         if (i >= 0
+             && i < (int) ARRAY_SIZE (debug_sections)
+             && debug_sections [i].name != NULL
+             && strncmp (&name [1], debug_sections [i].name,
+                         debug_sections [i].len) == 0)
+           flags |= SEC_DEBUGGING;
+       }
+    }
 
   /* As a GNU extension, if the name begins with .gnu.linkonce, we
      only link a single copy of the section.  This is used to support
@@ -798,9 +870,6 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
        }
     }
 
-  hdr->bfd_section = newsect;
-  elf_section_data (newsect)->this_hdr = *hdr;
-
   return TRUE;
 }
 
@@ -895,10 +964,31 @@ merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
 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;
-  if (elf_hash_table (info)->merge_info)
-    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info,
+
+  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;
 }
@@ -968,6 +1058,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case PT_TLS: pt = "TLS"; break;
            case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
            case PT_GNU_STACK: pt = "STACK"; break;
+           case PT_GNU_RELRO: pt = "RELRO"; break;
            default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
            }
          fprintf (f, "%8s off    0x", pt);
@@ -1002,10 +1093,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
 
       fprintf (f, _("\nDynamic Section:\n"));
 
-      dynbuf = bfd_malloc (s->_raw_size);
-      if (dynbuf == NULL)
-       goto error_return;
-      if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
+      if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
        goto error_return;
 
       elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
@@ -1017,7 +1105,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
       extdyn = dynbuf;
-      extdynend = extdyn + s->_raw_size;
+      extdynend = extdyn + s->size;
       for (; extdyn < extdynend; extdyn += extdynsize)
        {
          Elf_Internal_Dyn dyn;
@@ -1120,7 +1208,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
   if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL)
       || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL))
     {
-      if (! _bfd_elf_slurp_version_tables (abfd))
+      if (! _bfd_elf_slurp_version_tables (abfd, FALSE))
        return FALSE;
     }
 
@@ -1132,8 +1220,9 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef)
        {
          fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx,
-                  t->vd_flags, t->vd_hash, t->vd_nodename);
-         if (t->vd_auxptr->vda_nextptr != NULL)
+                  t->vd_flags, t->vd_hash,
+                  t->vd_nodename ? t->vd_nodename : "<corrupt>");
+         if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL)
            {
              Elf_Internal_Verdaux *a;
 
@@ -1141,7 +1230,8 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
              for (a = t->vd_auxptr->vda_nextptr;
                   a != NULL;
                   a = a->vda_nextptr)
-               fprintf (f, "%s ", a->vda_nodename);
+               fprintf (f, "%s ",
+                        a->vda_nodename ? a->vda_nodename : "<corrupt>");
              fprintf (f, "\n");
            }
        }
@@ -1156,10 +1246,12 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
        {
          Elf_Internal_Vernaux *a;
 
-         fprintf (f, _("  required from %s:\n"), t->vn_filename);
+         fprintf (f, _("  required from %s:\n"),
+                  t->vn_filename ? t->vn_filename : "<corrupt>");
          for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
            fprintf (f, "    0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash,
-                    a->vna_flags, a->vna_other, a->vna_nodename);
+                    a->vna_flags, a->vna_other,
+                    a->vna_nodename ? a->vna_nodename : "<corrupt>");
        }
     }
 
@@ -1319,23 +1411,15 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       /* Set local fields.  */
       ret->indx = -1;
       ret->dynindx = -1;
-      ret->dynstr_index = 0;
-      ret->elf_hash_value = 0;
-      ret->weakdef = NULL;
-      ret->verinfo.verdef = NULL;
-      ret->vtable_entries_size = 0;
-      ret->vtable_entries_used = NULL;
-      ret->vtable_parent = NULL;
-      ret->got = htab->init_refcount;
-      ret->plt = htab->init_refcount;
-      ret->size = 0;
-      ret->type = STT_NOTYPE;
-      ret->other = 0;
+      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->elf_link_hash_flags = ELF_LINK_NON_ELF;
+      ret->non_elf = 1;
     }
 
   return entry;
@@ -1355,13 +1439,12 @@ _bfd_elf_link_hash_copy_indirect (const struct elf_backend_data *bed,
   /* Copy down any references that we may have already seen to the
      symbol which just became indirect.  */
 
-  dir->elf_link_hash_flags
-    |= ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC
-                                  | ELF_LINK_HASH_REF_REGULAR
-                                  | ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                                  | ELF_LINK_NON_GOT_REF
-                                  | ELF_LINK_HASH_NEEDS_PLT
-                                  | ELF_LINK_POINTER_EQUALITY_NEEDED);
+  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;
@@ -1402,11 +1485,11 @@ _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_offset;
-  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+  h->plt = elf_hash_table (info)->init_plt_offset;
+  h->needs_plt = 0;
   if (force_local)
     {
-      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      h->forced_local = 1;
       if (h->dynindx != -1)
        {
          h->dynindx = -1;
@@ -1427,28 +1510,29 @@ _bfd_elf_link_hash_table_init
                                      const char *))
 {
   bfd_boolean ret;
+  int can_refcount = get_elf_backend_data (abfd)->can_refcount;
 
   table->dynamic_sections_created = FALSE;
   table->dynobj = NULL;
-  /* Make sure can_refcount is extended to the width and signedness of
-     init_refcount before we subtract one from it.  */
-  table->init_refcount.refcount = get_elf_backend_data (abfd)->can_refcount;
-  table->init_refcount.refcount -= 1;
-  table->init_offset.offset = -(bfd_vma) 1;
+  table->init_got_refcount.refcount = can_refcount - 1;
+  table->init_plt_refcount.refcount = can_refcount - 1;
+  table->init_got_offset.offset = -(bfd_vma) 1;
+  table->init_plt_offset.offset = -(bfd_vma) 1;
   /* The first dynamic symbol is a dummy.  */
   table->dynsymcount = 1;
   table->dynstr = NULL;
   table->bucketcount = 0;
   table->needed = NULL;
   table->hgot = NULL;
-  table->stab_info = NULL;
   table->merge_info = NULL;
+  memset (&table->stab_info, 0, sizeof (table->stab_info));
   memset (&table->eh_info, 0, sizeof (table->eh_info));
   table->dynlocal = NULL;
   table->runpath = NULL;
   table->tls_sec = NULL;
   table->tls_size = 0;
   table->loaded = NULL;
+  table->is_relocatable_executable = FALSE;
 
   ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc);
   table->root.type = bfd_link_elf_hash_table;
@@ -1489,6 +1573,18 @@ bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
     elf_dt_name (abfd) = name;
 }
 
+int
+bfd_elf_get_dyn_lib_class (bfd *abfd)
+{
+  int lib_class;
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && bfd_get_format (abfd) == bfd_object)
+    lib_class = elf_dyn_lib_class (abfd);
+  else
+    lib_class = 0;
+  return lib_class;
+}
+
 void
 bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
 {
@@ -1556,14 +1652,10 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
     return TRUE;
 
   s = bfd_get_section_by_name (abfd, ".dynamic");
-  if (s == NULL || s->_raw_size == 0)
+  if (s == NULL || s->size == 0)
     return TRUE;
 
-  dynbuf = bfd_malloc (s->_raw_size);
-  if (dynbuf == NULL)
-    goto error_return;
-
-  if (! bfd_get_section_contents (abfd, s, dynbuf, 0, s->_raw_size))
+  if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
     goto error_return;
 
   elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
@@ -1576,7 +1668,7 @@ bfd_elf_get_bfd_needed_list (bfd *abfd,
   swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
   extdyn = dynbuf;
-  extdynend = extdyn + s->_raw_size;
+  extdynend = extdyn + s->size;
   for (; extdyn < extdynend; extdyn += extdynsize)
     {
       Elf_Internal_Dyn dyn;
@@ -1654,7 +1746,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   const char *name;
 
-  name = elf_string_from_elf_strtab (abfd, hdr->sh_name);
+  name = bfd_elf_string_from_elf_section (abfd,
+                                         elf_elfheader (abfd)->e_shstrndx,
+                                         hdr->sh_name);
+  if (name == NULL)
+    return FALSE;
 
   switch (hdr->sh_type)
     {
@@ -1669,10 +1765,14 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
     case SHT_INIT_ARRAY:       /* .init_array section.  */
     case SHT_FINI_ARRAY:       /* .fini_array section.  */
     case SHT_PREINIT_ARRAY:    /* .preinit_array section.  */
-      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+    case SHT_GNU_LIBLIST:      /* .gnu.liblist section.  */
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
 
     case SHT_DYNAMIC:  /* Dynamic linking information.  */
-      if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+      if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+       return FALSE;
+      if (hdr->sh_link > elf_numsections (abfd)
+         || elf_elfsections (abfd)[hdr->sh_link] == NULL)
        return FALSE;
       if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB)
        {
@@ -1708,7 +1808,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       if (elf_onesymtab (abfd) == shindex)
        return TRUE;
 
-      BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym);
+      if (hdr->sh_entsize != bed->s->sizeof_sym)
+       return FALSE;
       BFD_ASSERT (elf_onesymtab (abfd) == 0);
       elf_onesymtab (abfd) = shindex;
       elf_tdata (abfd)->symtab_hdr = *hdr;
@@ -1723,16 +1824,44 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          linker.  */
       if ((hdr->sh_flags & SHF_ALLOC) != 0
          && (abfd->flags & DYNAMIC) != 0
-         && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
+         && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+                                               shindex))
        return FALSE;
 
+      /* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we
+        can't read symbols without that section loaded as well.  It
+        is most likely specified by the next section header.  */
+      if (elf_elfsections (abfd)[elf_symtab_shndx (abfd)]->sh_link != shindex)
+       {
+         unsigned int i, num_sec;
+
+         num_sec = elf_numsections (abfd);
+         for (i = shindex + 1; i < num_sec; i++)
+           {
+             Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+             if (hdr2->sh_type == SHT_SYMTAB_SHNDX
+                 && hdr2->sh_link == shindex)
+               break;
+           }
+         if (i == num_sec)
+           for (i = 1; i < shindex; i++)
+             {
+               Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+               if (hdr2->sh_type == SHT_SYMTAB_SHNDX
+                   && hdr2->sh_link == shindex)
+                 break;
+             }
+         if (i != shindex)
+           return bfd_section_from_shdr (abfd, i);
+       }
       return TRUE;
 
     case SHT_DYNSYM:           /* A dynamic symbol table */
       if (elf_dynsymtab (abfd) == shindex)
        return TRUE;
 
-      BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym);
+      if (hdr->sh_entsize != bed->s->sizeof_sym)
+       return FALSE;
       BFD_ASSERT (elf_dynsymtab (abfd) == 0);
       elf_dynsymtab (abfd) = shindex;
       elf_tdata (abfd)->dynsymtab_hdr = *hdr;
@@ -1741,17 +1870,13 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
 
       /* Besides being a symbol table, we also treat this as a regular
         section, so that objcopy can handle it.  */
-      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
 
     case SHT_SYMTAB_SHNDX:     /* Symbol section indices when >64k sections */
       if (elf_symtab_shndx (abfd) == shindex)
        return TRUE;
 
-      /* Get the associated symbol table.  */
-      if (! bfd_section_from_shdr (abfd, hdr->sh_link)
-         || hdr->sh_link != elf_onesymtab (abfd))
-       return FALSE;
-
+      BFD_ASSERT (elf_symtab_shndx (abfd) == 0);
       elf_symtab_shndx (abfd) = shindex;
       elf_tdata (abfd)->symtab_shndx_hdr = *hdr;
       elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr;
@@ -1766,49 +1891,51 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr;
          return TRUE;
        }
-      {
-       unsigned int i, num_sec;
+      if (elf_elfsections (abfd)[elf_onesymtab (abfd)]->sh_link == shindex)
+       {
+       symtab_strtab:
+         elf_tdata (abfd)->strtab_hdr = *hdr;
+         elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->strtab_hdr;
+         return TRUE;
+       }
+      if (elf_elfsections (abfd)[elf_dynsymtab (abfd)]->sh_link == shindex)
+       {
+       dynsymtab_strtab:
+         elf_tdata (abfd)->dynstrtab_hdr = *hdr;
+         hdr = &elf_tdata (abfd)->dynstrtab_hdr;
+         elf_elfsections (abfd)[shindex] = hdr;
+         /* We also treat this as a regular section, so that objcopy
+            can handle it.  */
+         return _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+                                                 shindex);
+       }
 
-       num_sec = elf_numsections (abfd);
-       for (i = 1; i < num_sec; i++)
-         {
-           Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
-           if (hdr2->sh_link == shindex)
-             {
-               if (! bfd_section_from_shdr (abfd, i))
-                 return FALSE;
-               if (elf_onesymtab (abfd) == i)
-                 {
-                   elf_tdata (abfd)->strtab_hdr = *hdr;
-                   elf_elfsections (abfd)[shindex] =
-                     &elf_tdata (abfd)->strtab_hdr;
-                   return TRUE;
-                 }
-               if (elf_dynsymtab (abfd) == i)
-                 {
-                   elf_tdata (abfd)->dynstrtab_hdr = *hdr;
-                   elf_elfsections (abfd)[shindex] = hdr =
-                     &elf_tdata (abfd)->dynstrtab_hdr;
-                   /* We also treat this as a regular section, so
-                      that objcopy can handle it.  */
-                   break;
-                 }
-#if 0 /* Not handling other string tables specially right now.  */
-               hdr2 = elf_elfsections (abfd)[i];       /* in case it moved */
-               /* We have a strtab for some random other section.  */
-               newsect = (asection *) hdr2->bfd_section;
-               if (!newsect)
-                 break;
-               hdr->bfd_section = newsect;
-               hdr2 = &elf_section_data (newsect)->str_hdr;
-               *hdr2 = *hdr;
-               elf_elfsections (abfd)[shindex] = hdr2;
-#endif
-             }
-         }
-      }
+      /* If the string table isn't one of the above, then treat it as a
+        regular section.  We need to scan all the headers to be sure,
+        just in case this strtab section appeared before the above.  */
+      if (elf_onesymtab (abfd) == 0 || elf_dynsymtab (abfd) == 0)
+       {
+         unsigned int i, num_sec;
 
-      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+         num_sec = elf_numsections (abfd);
+         for (i = 1; i < num_sec; i++)
+           {
+             Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+             if (hdr2->sh_link == shindex)
+               {
+                 /* Prevent endless recursion on broken objects.  */
+                 if (i == shindex)
+                   return FALSE;
+                 if (! bfd_section_from_shdr (abfd, i))
+                   return FALSE;
+                 if (elf_onesymtab (abfd) == i)
+                   goto symtab_strtab;
+                 if (elf_dynsymtab (abfd) == i)
+                   goto dynsymtab_strtab;
+               }
+           }
+       }
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
 
     case SHT_REL:
     case SHT_RELA:
@@ -1818,14 +1945,20 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
        Elf_Internal_Shdr *hdr2;
        unsigned int num_sec = elf_numsections (abfd);
 
+       if (hdr->sh_entsize
+           != (bfd_size_type) (hdr->sh_type == SHT_REL
+                               ? bed->s->sizeof_rel : bed->s->sizeof_rela))
+         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)
          {
            ((*_bfd_error_handler)
-            (_("%s: invalid link %lu for reloc section %s (index %u)"),
-             bfd_archive_filename (abfd), hdr->sh_link, name, shindex));
-           return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+            (_("%B: invalid link %lu for reloc section %s (index %u)"),
+             abfd, hdr->sh_link, name, shindex));
+           return _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+                                                   shindex);
          }
 
        /* For some incomprehensible reason Oracle distributes
@@ -1860,7 +1993,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          }
 
        /* Get the symbol table.  */
-       if (elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB
+       if ((elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB
+            || elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_DYNSYM)
            && ! bfd_section_from_shdr (abfd, hdr->sh_link))
          return FALSE;
 
@@ -1871,8 +2005,13 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
           can't use it as a reloc section if it points to the null
           section.  */
        if (hdr->sh_link != elf_onesymtab (abfd) || hdr->sh_info == SHN_UNDEF)
-         return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+         return _bfd_elf_make_section_from_shdr (abfd, hdr, name,
+                                                 shindex);
 
+       /* Prevent endless recursion on broken objects.  */
+       if (elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
+           || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
+         return FALSE;
        if (! bfd_section_from_shdr (abfd, hdr->sh_info))
          return FALSE;
        target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info);
@@ -1908,19 +2047,21 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
     case SHT_GNU_verdef:
       elf_dynverdef (abfd) = shindex;
       elf_tdata (abfd)->dynverdef_hdr = *hdr;
-      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
       break;
 
     case SHT_GNU_versym:
+      if (hdr->sh_entsize != sizeof (Elf_External_Versym))
+       return FALSE;
       elf_dynversym (abfd) = shindex;
       elf_tdata (abfd)->dynversym_hdr = *hdr;
-      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
       break;
 
     case SHT_GNU_verneed:
       elf_dynverref (abfd) = shindex;
       elf_tdata (abfd)->dynverref_hdr = *hdr;
-      return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
       break;
 
     case SHT_SHLIB:
@@ -1930,10 +2071,12 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
       /* We need a BFD section for objcopy and relocatable linking,
         and it's handy to have the signature available as the section
         name.  */
+      if (hdr->sh_entsize != GRP_ENTRY_SIZE)
+       return FALSE;
       name = group_signature (abfd, hdr);
       if (name == NULL)
        return FALSE;
-      if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
+      if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
        return FALSE;
       if (hdr->contents != NULL)
        {
@@ -1945,8 +2088,10 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
            hdr->bfd_section->flags
              |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
+         /* We try to keep the same section order as it comes in.  */
+         idx += n_elt;
          while (--n_elt != 0)
-           if ((s = (++idx)->shdr->bfd_section) != NULL
+           if ((s = (--idx)->shdr->bfd_section) != NULL
                && elf_next_in_group (s) != NULL)
              {
                elf_next_in_group (hdr->bfd_section) = s;
@@ -1957,11 +2102,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
 
     default:
       /* Check for any processor-specific section types.  */
-      {
-       if (bed->elf_backend_section_from_shdr)
-         (*bed->elf_backend_section_from_shdr) (abfd, hdr, name);
-      }
-      break;
+      return bed->elf_backend_section_from_shdr (abfd, hdr, name,
+                                                shindex);
     }
 
   return TRUE;
@@ -2019,24 +2161,23 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int index)
   return elf_elfsections (abfd)[index]->bfd_section;
 }
 
-static struct bfd_elf_special_section const special_sections[] =
+static const struct bfd_elf_special_section special_sections_b[] =
 {
   { ".bss",            4, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_c[] =
+{
   { ".comment",        8,  0, SHT_PROGBITS, 0 },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_d[] =
+{
   { ".data",           5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".data1",          6,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".debug",          6,  0, SHT_PROGBITS, 0 },
-  { ".fini",           5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".init",           5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".line",           5,  0, SHT_PROGBITS, 0 },
-  { ".rodata",         7, -2, SHT_PROGBITS, SHF_ALLOC },
-  { ".rodata1",        8,  0, SHT_PROGBITS, SHF_ALLOC },
-  { ".tbss",           5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_TLS },
-  { ".tdata",          6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
-  { ".text",           5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".init_array",    11,  0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
-  { ".fini_array",    11,  0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
-  { ".preinit_array", 14,  0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
   { ".debug_line",    11,  0, SHT_PROGBITS, 0 },
   { ".debug_info",    11,  0, SHT_PROGBITS, 0 },
   { ".debug_abbrev",  13,  0, SHT_PROGBITS, 0 },
@@ -2044,42 +2185,132 @@ static struct bfd_elf_special_section const special_sections[] =
   { ".dynamic",        8,  0, SHT_DYNAMIC,  SHF_ALLOC },
   { ".dynstr",         7,  0, SHT_STRTAB,   SHF_ALLOC },
   { ".dynsym",         7,  0, SHT_DYNSYM,   SHF_ALLOC },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_f[] =
+{
+  { ".fini",           5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { ".fini_array",    11,  0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_g[] =
+{
+  { ".gnu.linkonce.b",15, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
   { ".got",            4,  0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { ".hash",           5,  0, SHT_HASH,     SHF_ALLOC },
-  { ".interp",         7,  0, SHT_PROGBITS, 0 },
-  { ".plt",            4,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
-  { ".shstrtab",       9,  0, SHT_STRTAB,   0 },
-  { ".strtab",         7,  0, SHT_STRTAB,   0 },
-  { ".symtab",         7,  0, SHT_SYMTAB,   0 },
   { ".gnu.version",   12,  0, SHT_GNU_versym, 0 },
   { ".gnu.version_d", 14,  0, SHT_GNU_verdef, 0 },
   { ".gnu.version_r", 14,  0, SHT_GNU_verneed, 0 },
+  { ".gnu.liblist",   12,  0, SHT_GNU_LIBLIST, SHF_ALLOC },
+  { ".gnu.conflict",  13,  0, SHT_RELA,     SHF_ALLOC },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_h[] =
+{
+  { ".hash",           5,  0, SHT_HASH,     SHF_ALLOC },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_i[] =
+{
+  { ".init",           5,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { ".init_array",    11,  0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+  { ".interp",         7,  0, SHT_PROGBITS, 0 },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_l[] =
+{
+  { ".line",           5,  0, SHT_PROGBITS, 0 },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_n[] =
+{
+  { ".note.GNU-stack",15,  0, SHT_PROGBITS, 0 },
   { ".note",           5, -1, SHT_NOTE,     0 },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_p[] =
+{
+  { ".preinit_array", 14,  0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+  { ".plt",            4,  0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_r[] =
+{
+  { ".rodata",         7, -2, SHT_PROGBITS, SHF_ALLOC },
+  { ".rodata1",        8,  0, SHT_PROGBITS, SHF_ALLOC },
   { ".rela",           5, -1, SHT_RELA,     0 },
   { ".rel",            4, -1, SHT_REL,      0 },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section special_sections_s[] =
+{
+  { ".shstrtab",       9,  0, SHT_STRTAB,   0 },
+  { ".strtab",         7,  0, SHT_STRTAB,   0 },
+  { ".symtab",         7,  0, SHT_SYMTAB,   0 },
   { ".stabstr",        5,  3, SHT_STRTAB,   0 },
   { NULL,              0,  0, 0,            0 }
 };
 
-static const struct bfd_elf_special_section *
-get_special_section (const char *name,
-                    const struct bfd_elf_special_section *special_sections,
-                    unsigned int rela)
+static const struct bfd_elf_special_section special_sections_t[] =
+{
+  { ".text",           5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { ".tbss",           5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_TLS },
+  { ".tdata",          6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
+  { NULL,              0,  0, 0,            0 }
+};
+
+static const struct bfd_elf_special_section *special_sections[] =
+{
+  special_sections_b,          /* 'b' */
+  special_sections_c,          /* 'b' */
+  special_sections_d,          /* 'd' */
+  NULL,                                /* 'e' */
+  special_sections_f,          /* 'f' */
+  special_sections_g,          /* 'g' */
+  special_sections_h,          /* 'h' */
+  special_sections_i,          /* 'i' */
+  NULL,                                /* 'j' */
+  NULL,                                /* 'k' */
+  special_sections_l,          /* 'l' */
+  NULL,                                /* 'm' */
+  special_sections_n,          /* 'n' */
+  NULL,                                /* 'o' */
+  special_sections_p,          /* 'p' */
+  NULL,                                /* 'q' */
+  special_sections_r,          /* 'r' */
+  special_sections_s,          /* 's' */
+  special_sections_t,          /* 't' */
+};
+
+const struct bfd_elf_special_section *
+_bfd_elf_get_special_section (const char *name,
+                             const struct bfd_elf_special_section *spec,
+                             unsigned int rela)
 {
   int i;
-  int len = strlen (name);
+  int len;
+
+  len = strlen (name);
 
-  for (i = 0; special_sections[i].prefix != NULL; i++)
+  for (i = 0; spec[i].prefix != NULL; i++)
     {
       int suffix_len;
-      int prefix_len = special_sections[i].prefix_length;
+      int prefix_len = spec[i].prefix_length;
 
       if (len < prefix_len)
        continue;
-      if (memcmp (name, special_sections[i].prefix, prefix_len) != 0)
+      if (memcmp (name, spec[i].prefix, prefix_len) != 0)
        continue;
 
-      suffix_len = special_sections[i].suffix_length;
+      suffix_len = spec[i].suffix_length;
       if (suffix_len <= 0)
        {
          if (name[prefix_len] != 0)
@@ -2088,7 +2319,7 @@ get_special_section (const char *name,
                continue;
              if (name[prefix_len] != '.'
                  && (suffix_len == -2
-                     || (rela && special_sections[i].type == SHT_REL)))
+                     || (rela && spec[i].type == SHT_REL)))
                continue;
            }
        }
@@ -2097,41 +2328,58 @@ get_special_section (const char *name,
          if (len < prefix_len + suffix_len)
            continue;
          if (memcmp (name + len - suffix_len,
-                     special_sections[i].prefix + prefix_len,
+                     spec[i].prefix + prefix_len,
                      suffix_len) != 0)
            continue;
        }
-      return &special_sections[i];
+      return &spec[i];
     }
 
   return NULL;
 }
 
 const struct bfd_elf_special_section *
-_bfd_elf_get_sec_type_attr (bfd *abfd, const char *name)
+_bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec)
 {
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  const struct bfd_elf_special_section *ssect = NULL;
+  int i;
+  const struct bfd_elf_special_section *spec;
+  const struct elf_backend_data *bed;
 
   /* See if this is one of the special sections.  */
-  if (name)
+  if (sec->name == NULL)
+    return NULL;
+
+  bed = get_elf_backend_data (abfd);
+  spec = bed->special_sections;
+  if (spec)
     {
-      unsigned int rela = bed->default_use_rela_p;
+      spec = _bfd_elf_get_special_section (sec->name,
+                                          bed->special_sections,
+                                          sec->use_rela_p);
+      if (spec != NULL)
+       return spec;
+    }
+
+  if (sec->name[0] != '.')
+    return NULL;
+
+  i = sec->name[1] - 'b';
+  if (i < 0 || i > 't' - 'b')
+    return NULL;
 
-      if (bed->special_sections)
-       ssect = get_special_section (name, bed->special_sections, rela);
+  spec = special_sections[i];
 
-      if (! ssect)
-       ssect = get_special_section (name, special_sections, rela);
-    }
+  if (spec == NULL)
+    return NULL;
 
-  return ssect;
+  return _bfd_elf_get_special_section (sec->name, spec, sec->use_rela_p);
 }
 
 bfd_boolean
 _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
 {
   struct bfd_elf_section_data *sdata;
+  const struct elf_backend_data *bed;
   const struct bfd_elf_special_section *ssect;
 
   sdata = (struct bfd_elf_section_data *) sec->used_by_bfd;
@@ -2143,17 +2391,24 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec)
       sec->used_by_bfd = sdata;
     }
 
-  elf_section_type (sec) = SHT_NULL;
-  ssect = _bfd_elf_get_sec_type_attr (abfd, sec->name);
-  if (ssect != NULL)
+  /* Indicate whether or not this section should use RELA relocations.  */
+  bed = get_elf_backend_data (abfd);
+  sec->use_rela_p = bed->default_use_rela_p;
+
+  /* When we read a file, we don't need section type and flags unless
+     it is a linker created section.  They will be overridden in
+     _bfd_elf_make_section_from_shdr anyway.  */
+  if (abfd->direction != read_direction
+      || (sec->flags & SEC_LINKER_CREATED) != 0)
     {
-      elf_section_type (sec) = ssect->type;
-      elf_section_flags (sec) = ssect->attr;
+      ssect = (*bed->get_sec_type_attr) (abfd, sec);
+      if (ssect != NULL)
+       {
+         elf_section_type (sec) = ssect->type;
+         elf_section_flags (sec) = ssect->attr;
+       }
     }
 
-  /* Indicate whether or not this section should use RELA relocations.  */
-  sec->use_rela_p = get_elf_backend_data (abfd)->default_use_rela_p;
-
   return TRUE;
 }
 
@@ -2205,7 +2460,7 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
     return FALSE;
   newsect->vma = hdr->p_vaddr;
   newsect->lma = hdr->p_paddr;
-  newsect->_raw_size = hdr->p_filesz;
+  newsect->size = hdr->p_filesz;
   newsect->filepos = hdr->p_offset;
   newsect->flags |= SEC_HAS_CONTENTS;
   newsect->alignment_power = bfd_log2 (hdr->p_align);
@@ -2238,7 +2493,7 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,
        return FALSE;
       newsect->vma = hdr->p_vaddr + hdr->p_filesz;
       newsect->lma = hdr->p_paddr + hdr->p_filesz;
-      newsect->_raw_size = hdr->p_memsz - hdr->p_filesz;
+      newsect->size = hdr->p_memsz - hdr->p_filesz;
       if (hdr->p_type == PT_LOAD)
        {
          newsect->flags |= SEC_ALLOC;
@@ -2291,14 +2546,13 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int index)
     case PT_GNU_STACK:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "stack");
 
+    case PT_GNU_RELRO:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "relro");
+
     default:
-      /* Check for any processor-specific program segment types.
-         If no handler for them, default to making "segment" sections.  */
+      /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
-      if (bed->elf_backend_section_from_phdr)
-       return (*bed->elf_backend_section_from_phdr) (abfd, hdr, index);
-      else
-       return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "segment");
+      return bed->elf_backend_section_from_phdr (abfd, hdr, index, "proc");
     }
 }
 
@@ -2373,7 +2627,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
     this_hdr->sh_addr = 0;
 
   this_hdr->sh_offset = 0;
-  this_hdr->sh_size = asect->_raw_size;
+  this_hdr->sh_size = asect->size;
   this_hdr->sh_link = 0;
   this_hdr->sh_addralign = 1 << asect->alignment_power;
   /* The sh_entsize and sh_info fields may have been set already by
@@ -2386,7 +2640,31 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
      asect->flags.  */
   if (this_hdr->sh_type == SHT_NULL)
     {
-      if ((asect->flags & SEC_ALLOC) != 0
+      if ((asect->flags & SEC_GROUP) != 0)
+       {
+         /* We also need to mark SHF_GROUP here for relocatable
+            link.  */
+         struct bfd_link_order *l;
+         asection *elt;
+
+         for (l = asect->map_head.link_order; l != NULL; l = l->next)
+           if (l->type == bfd_indirect_link_order
+               && (elt = elf_next_in_group (l->u.indirect.section)) != NULL)
+             do
+               {
+                 /* The name is not important. Anything will do.  */
+                 elf_group_name (elt->output_section) = "G";
+                 elf_section_flags (elt->output_section) |= SHF_GROUP;
+
+                 elt = elf_next_in_group (elt);
+                 /* During a relocatable link, the lists are
+                    circular.  */
+               }
+             while (elt != elf_next_in_group (l->u.indirect.section));
+
+         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;
@@ -2481,12 +2759,12 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
   if ((asect->flags & SEC_THREAD_LOCAL) != 0)
     {
       this_hdr->sh_flags |= SHF_TLS;
-      if (asect->_raw_size == 0 && (asect->flags & SEC_HAS_CONTENTS) == 0)
+      if (asect->size == 0 && (asect->flags & SEC_HAS_CONTENTS) == 0)
        {
          struct bfd_link_order *o;
 
          this_hdr->sh_size = 0;
-         for (o = asect->link_order_head; o != NULL; o = o->next)
+         for (o = asect->map_head.link_order; o != NULL; o = o->next)
            if (this_hdr->sh_size < o->offset + o->size)
              this_hdr->sh_size = o->offset + o->size;
          if (this_hdr->sh_size)
@@ -2523,7 +2801,9 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   struct bfd_link_order *l;
   bfd_boolean gas;
 
-  if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP
+  /* Ignore linker created group section.  See elfNN_ia64_object_p in
+     elfxx-ia64.c.  */
+  if (((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) != SEC_GROUP)
       || *failedptr)
     return;
 
@@ -2547,7 +2827,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   if (sec->contents == NULL)
     {
       gas = FALSE;
-      sec->contents = bfd_alloc (abfd, sec->_raw_size);
+      sec->contents = bfd_alloc (abfd, sec->size);
 
       /* Arrange for the section to be written out.  */
       elf_section_data (sec)->this_hdr.contents = sec->contents;
@@ -2558,7 +2838,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
        }
     }
 
-  loc = sec->contents + sec->_raw_size;
+  loc = sec->contents + sec->size;
 
   /* Get the pointer to the first section in the group that gas
      squirreled away here.  objcopy arranges for this to be set to the
@@ -2590,7 +2870,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
   /* If this is a relocatable link, then the above did nothing because
      SEC is the output section.  Look through the input sections
      instead.  */
-  for (l = sec->link_order_head; l != NULL; l = l->next)
+  for (l = sec->map_head.link_order; l != NULL; l = l->next)
     if (l->type == bfd_indirect_link_order
        && (elt = elf_next_in_group (l->u.indirect.section)) != NULL)
       do
@@ -2603,13 +2883,7 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
        }
       while (elt != elf_next_in_group (l->u.indirect.section));
 
-  /* With ld -r, merging SHT_GROUP sections results in wasted space
-     due to allowing for the flag word on each input.  We may well
-     duplicate entries too.  */
-  while ((loc -= 4) > sec->contents)
-    H_PUT_32 (abfd, 0, loc);
-
-  if (loc != sec->contents)
+  if ((loc -= 4) != sec->contents)
     abort ();
 
   H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
@@ -2620,29 +2894,58 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
    in here too, while we're at it.  */
 
 static bfd_boolean
-assign_section_numbers (bfd *abfd)
+assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 {
   struct elf_obj_tdata *t = elf_tdata (abfd);
   asection *sec;
   unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
-  bfd_size_type amt;
+  struct bfd_elf_section_data *d;
 
   section_number = 1;
 
   _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
 
-  for (sec = abfd->sections; sec; sec = sec->next)
+  /* SHT_GROUP sections are in relocatable files only.  */
+  if (link_info == NULL || link_info->relocatable)
     {
-      struct bfd_elf_section_data *d = elf_section_data (sec);
-
-      if (section_number == SHN_LORESERVE)
-       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-      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
+      /* Put SHT_GROUP sections first.  */
+      for (sec = abfd->sections; sec != NULL; sec = sec->next)
+       {
+         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++;
+               }
+           }
+       }
+    }
+
+  for (sec = abfd->sections; sec; sec = sec->next)
+    {
+      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++;
+       }
+      _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;
@@ -2700,13 +3003,11 @@ assign_section_numbers (bfd *abfd)
 
   /* Set up the list of section header pointers, in agreement with the
      indices.  */
-  amt = section_number * sizeof (Elf_Internal_Shdr *);
-  i_shdrp = bfd_zalloc (abfd, amt);
+  i_shdrp = bfd_zalloc2 (abfd, section_number, sizeof (Elf_Internal_Shdr *));
   if (i_shdrp == NULL)
     return FALSE;
 
-  amt = sizeof (Elf_Internal_Shdr);
-  i_shdrp[0] = bfd_zalloc (abfd, amt);
+  i_shdrp[0] = bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr));
   if (i_shdrp[0] == NULL)
     {
       bfd_release (abfd, i_shdrp);
@@ -2727,6 +3028,7 @@ assign_section_numbers (bfd *abfd)
       i_shdrp[t->strtab_section] = &t->strtab_hdr;
       t->symtab_hdr.sh_link = t->strtab_section;
     }
+
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       struct bfd_elf_section_data *d = elf_section_data (sec);
@@ -2755,6 +3057,75 @@ assign_section_numbers (bfd *abfd)
          d->rel_hdr2->sh_info = d->this_idx;
        }
 
+      /* We need to set up sh_link for SHF_LINK_ORDER.  */
+      if ((d->this_hdr.sh_flags & SHF_LINK_ORDER) != 0)
+       {
+         s = elf_linked_to_section (sec);
+         if (s)
+           d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+         else
+           {
+             struct bfd_link_order *p;
+
+             /* Find out what the corresponding section in output
+                is.  */
+             for (p = sec->map_head.link_order; p != NULL; p = p->next)
+               {
+                 s = p->u.indirect.section;
+                 if (p->type == bfd_indirect_link_order
+                     && (bfd_get_flavour (s->owner)
+                         == bfd_target_elf_flavour))
+                   {
+                     Elf_Internal_Shdr ** const elf_shdrp
+                       = elf_elfsections (s->owner);
+                     int elfsec
+                       = _bfd_elf_section_from_bfd_section (s->owner, s);
+                     elfsec = elf_shdrp[elfsec]->sh_link;
+                     /* PR 290:
+                        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 elfsec is 0.  */
+                     if (elfsec == 0)
+                       {
+                         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'"),
+                              abfd, s);
+                       }
+                     else
+                       {
+                         s = elf_shdrp[elfsec]->bfd_section;
+                         if (elf_discarded_section (s))
+                           {
+                             asection *kept;
+                              (*_bfd_error_handler)
+                                 (_("%B: sh_link of section `%A' points to discarded section `%A' of `%B'"),
+                                  abfd, d->this_hdr.bfd_section,
+                                  s, s->owner);
+                              /* Point to the kept section if it has
+                                 the same size as the discarded
+                                 one.  */
+                              kept = _bfd_elf_check_kept_section (s);
+                              if (kept == NULL)
+                                {
+                                  bfd_set_error (bfd_error_bad_value);
+                                  return FALSE;
+                                }
+                              s = kept;
+                           }
+                         s = s->output_section;
+                         BFD_ASSERT (s != NULL);
+                         d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+                       }
+                     break;
+                   }
+               }
+           }
+       }
+
       switch (d->this_hdr.sh_type)
        {
        case SHT_REL:
@@ -2823,6 +3194,17 @@ assign_section_numbers (bfd *abfd)
            d->this_hdr.sh_link = elf_section_data (s)->this_idx;
          break;
 
+       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.  */
+         s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC)
+                                            ? ".dynstr" : ".gnu.libstr");
+         if (s != NULL)
+           d->this_hdr.sh_link = elf_section_data (s)->this_idx;
+         break;
+
        case SHT_HASH:
        case SHT_GNU_versym:
          /* sh_link is the section header index of the symbol table
@@ -2876,7 +3258,6 @@ elf_map_symbols (bfd *abfd)
   unsigned int idx;
   asection *asect;
   asymbol **new_syms;
-  bfd_size_type amt;
 
 #ifdef DEBUG
   fprintf (stderr, "elf_map_symbols\n");
@@ -2890,8 +3271,7 @@ elf_map_symbols (bfd *abfd)
     }
 
   max_index++;
-  amt = max_index * sizeof (asymbol *);
-  sect_syms = bfd_zalloc (abfd, amt);
+  sect_syms = bfd_zalloc2 (abfd, max_index, sizeof (asymbol *));
   if (sect_syms == NULL)
     return FALSE;
   elf_section_syms (abfd) = sect_syms;
@@ -2964,8 +3344,7 @@ elf_map_symbols (bfd *abfd)
     }
 
   /* Now sort the symbols so the local symbols are first.  */
-  amt = (num_locals + num_globals) * sizeof (asymbol *);
-  new_syms = bfd_alloc (abfd, amt);
+  new_syms = bfd_alloc2 (abfd, num_locals + num_globals, sizeof (asymbol *));
 
   if (new_syms == NULL)
     return FALSE;
@@ -3049,7 +3428,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   bfd_boolean failed;
-  struct bfd_strtab_hash *strtab;
+  struct bfd_strtab_hash *strtab = NULL;
   Elf_Internal_Shdr *shstrtab_hdr;
 
   if (abfd->output_has_begun)
@@ -3071,7 +3450,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd,
   if (failed)
     return FALSE;
 
-  if (!assign_section_numbers (abfd))
+  if (!assign_section_numbers (abfd, link_info))
     return FALSE;
 
   /* The backend linker builds symbol table information itself.  */
@@ -3173,6 +3552,25 @@ make_mapping (bfd *abfd,
   return m;
 }
 
+/* Create the PT_DYNAMIC segment, which includes DYNSEC.  Returns NULL
+   on failure.  */
+
+struct elf_segment_map *
+_bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec)
+{
+  struct elf_segment_map *m;
+
+  m = bfd_zalloc (abfd, sizeof (struct elf_segment_map));
+  if (m == NULL)
+    return NULL;
+  m->next = NULL;
+  m->p_type = PT_DYNAMIC;
+  m->count = 1;
+  m->sections[0] = dynsec;
+  
+  return m;
+}
+
 /* Set up a mapping from BFD sections to program segments.  */
 
 static bfd_boolean
@@ -3205,8 +3603,7 @@ map_sections_to_segments (bfd *abfd)
 
   /* Select the allocated sections, and sort them.  */
 
-  amt = bfd_count_sections (abfd) * sizeof (asection *);
-  sections = bfd_malloc (amt);
+  sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
   if (sections == NULL)
     goto error_return;
 
@@ -3365,7 +3762,7 @@ map_sections_to_segments (bfd *abfd)
          last_hdr = hdr;
          /* .tbss sections effectively have zero size.  */
          if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
-           last_size = hdr->_raw_size;
+           last_size = hdr->size;
          else
            last_size = 0;
          continue;
@@ -3389,7 +3786,7 @@ map_sections_to_segments (bfd *abfd)
       last_hdr = hdr;
       /* .tbss sections effectively have zero size.  */
       if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
-       last_size = hdr->_raw_size;
+       last_size = hdr->size;
       else
        last_size = 0;
       phdr_index = i;
@@ -3410,15 +3807,9 @@ map_sections_to_segments (bfd *abfd)
   /* If there is a .dynamic section, throw in a PT_DYNAMIC segment.  */
   if (dynsec != NULL)
     {
-      amt = sizeof (struct elf_segment_map);
-      m = bfd_zalloc (abfd, amt);
+      m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
       if (m == NULL)
        goto error_return;
-      m->next = NULL;
-      m->p_type = PT_DYNAMIC;
-      m->count = 1;
-      m->sections[0] = dynsec;
-
       *pm = m;
       pm = &m->next;
     }
@@ -3514,6 +3905,21 @@ map_sections_to_segments (bfd *abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_RELRO;
+      m->p_flags = PF_R;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+    }
+
   free (sections);
   sections = NULL;
 
@@ -3573,8 +3979,8 @@ elf_sort_sections (const void *arg1, const void *arg2)
   /* Sort by size, to put zero sized sections
      before others at the same address.  */
 
-  size1 = (sec1->flags & SEC_LOAD) ? sec1->_raw_size : 0;
-  size2 = (sec2->flags & SEC_LOAD) ? sec2->_raw_size : 0;
+  size1 = (sec1->flags & SEC_LOAD) ? sec1->size : 0;
+  size2 = (sec2->flags & SEC_LOAD) ? sec2->size : 0;
 
   if (size1 < size2)
     return -1;
@@ -3629,7 +4035,6 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   Elf_Internal_Phdr *p;
-  bfd_size_type amt;
 
   if (elf_tdata (abfd)->segment_map == NULL)
     {
@@ -3640,7 +4045,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
     {
       /* The placement algorithm assumes that non allocated sections are
         not in PT_LOAD segments.  We ensure this here by removing such
-        sections from the segment map.  */
+        sections from the segment map.  We also remove excluded
+        sections.  */
       for (m = elf_tdata (abfd)->segment_map;
           m != NULL;
           m = m->next)
@@ -3648,13 +4054,12 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
          unsigned int new_count;
          unsigned int i;
 
-         if (m->p_type != PT_LOAD)
-           continue;
-
          new_count = 0;
          for (i = 0; i < m->count; i ++)
            {
-             if ((m->sections[i]->flags & SEC_ALLOC) != 0)
+             if ((m->sections[i]->flags & SEC_EXCLUDE) == 0
+                 && ((m->sections[i]->flags & SEC_ALLOC) != 0
+                     || m->p_type != PT_LOAD))
                {
                  if (i != new_count)
                    m->sections[new_count] = m->sections[i];
@@ -3683,7 +4088,10 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
   elf_elfheader (abfd)->e_phnum = count;
 
   if (count == 0)
-    return TRUE;
+    {
+      elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr;
+      return TRUE;
+    }
 
   /* If we already counted the number of program segments, make sure
      that we allocated enough space.  This happens when SIZEOF_HEADERS
@@ -3692,8 +4100,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
   if (alloc != 0 && count > alloc)
     {
       ((*_bfd_error_handler)
-       (_("%s: Not enough room for program headers (allocated %u, need %u)"),
-       bfd_get_filename (abfd), alloc, count));
+       (_("%B: Not enough room for program headers (allocated %u, need %u)"),
+       abfd, alloc, count));
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
@@ -3701,8 +4109,7 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
   if (alloc == 0)
     alloc = count;
 
-  amt = alloc * sizeof (Elf_Internal_Phdr);
-  phdrs = bfd_alloc (abfd, amt);
+  phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr));
   if (phdrs == NULL)
     return FALSE;
 
@@ -3732,34 +4139,75 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
        qsort (m->sections, (size_t) m->count, sizeof (asection *),
               elf_sort_sections);
 
+      /* An ELF segment (described by Elf_Internal_Phdr) may contain a
+        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;
       p->p_type = m->p_type;
       p->p_flags = m->p_flags;
 
       if (p->p_type == PT_LOAD
-         && m->count > 0
-         && (m->sections[0]->flags & SEC_ALLOC) != 0)
+         && m->count > 0)
        {
-         if ((abfd->flags & D_PAGED) != 0)
-           off += vma_page_aligned_bias (m->sections[0]->vma, off,
-                                         bed->maxpagesize);
-         else
+         bfd_size_type align;
+         bfd_vma adjust;
+         unsigned int align_power = 0;
+
+         for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
            {
-             bfd_size_type align;
+             unsigned int secalign;
 
-             align = 0;
-             for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
-               {
-                 bfd_size_type secalign;
+             secalign = bfd_get_section_alignment (abfd, *secpp);
+             if (secalign > align_power)
+               align_power = secalign;
+           }
+         align = (bfd_size_type) 1 << align_power;
 
-                 secalign = bfd_get_section_alignment (abfd, *secpp);
-                 if (secalign > align)
-                   align = secalign;
-               }
+         if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > align)
+           align = bed->maxpagesize;
 
-             off += vma_page_aligned_bias (m->sections[0]->vma, off,
-                                           1 << align);
+         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)
+           {
+             /* If the first section isn't loadable, the same holds for
+                any other sections.  Since the segment won't need file
+                space, we can make p_offset overlap some prior segment.
+                However, .tbss is special.  If a segment starts with
+                .tbss, we need to look at the next section to decide
+                whether the segment has any loadable sections.  */
+             i = 0;
+             while ((m->sections[i]->flags & SEC_LOAD) == 0)
+               {
+                 if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
+                     || ++i >= m->count)
+                   {
+                     off -= adjust;
+                     voff = adjust - align;
+                     break;
+                   }
+               }
            }
        }
+      /* Make sure the .dynamic section is the first section in the
+        PT_DYNAMIC segment.  */
+      else if (p->p_type == PT_DYNAMIC
+              && m->count > 1
+              && strcmp (m->sections[0]->name, ".dynamic") != 0)
+       {
+         _bfd_error_handler
+           (_("%B: The first section in the PT_DYNAMIC segment is not the .dynamic section"),
+            abfd);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
 
       if (m->count == 0)
        p->p_vaddr = 0;
@@ -3799,8 +4247,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
              if (p->p_vaddr < (bfd_vma) off)
                {
                  (*_bfd_error_handler)
-                   (_("%s: Not enough room for program headers, try linking with -N"),
-                    bfd_get_filename (abfd));
+                   (_("%B: Not enough room for program headers, try linking with -N"),
+                    abfd);
                  bfd_set_error (bfd_error_bad_value);
                  return FALSE;
                }
@@ -3858,7 +4306,7 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
          || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
        {
          if (! m->includes_filehdr && ! m->includes_phdrs)
-           p->p_offset = off;
+           p->p_offset = off + voff;
          else
            {
              file_ptr adjust;
@@ -3869,8 +4317,6 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
            }
        }
 
-      voff = off;
-
       for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
        {
          asection *sec;
@@ -3881,126 +4327,112 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info)
          flags = sec->flags;
          align = 1 << bfd_get_section_alignment (abfd, sec);
 
-         /* The section may have artificial alignment forced by a
-            link script.  Notice this case by the gap between the
-            cumulative phdr lma and the section's lma.  */
-         if (p->p_paddr + p->p_memsz < sec->lma)
-           {
-             bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
-
-             p->p_memsz += adjust;
-             if (p->p_type == PT_LOAD
-                 || (p->p_type == PT_NOTE
-                     && bfd_get_format (abfd) == bfd_core))
-               {
-                 off += adjust;
-                 voff += adjust;
-               }
-             if ((flags & SEC_LOAD) != 0
-                 || (flags & SEC_THREAD_LOCAL) != 0)
-               p->p_filesz += adjust;
-           }
-
-         if (p->p_type == PT_LOAD)
+         if (p->p_type == PT_LOAD
+             || p->p_type == PT_TLS)
            {
              bfd_signed_vma adjust;
 
              if ((flags & SEC_LOAD) != 0)
                {
-                 adjust = sec->lma - (p->p_paddr + p->p_memsz);
+                 adjust = sec->lma - (p->p_paddr + p->p_filesz);
                  if (adjust < 0)
-                   adjust = 0;
+                   {
+                     (*_bfd_error_handler)
+                       (_("%B: section %A lma 0x%lx overlaps previous sections"),
+                        abfd, sec, (unsigned long) sec->lma);
+                     adjust = 0;
+                   }
+                 off += adjust;
+                 p->p_filesz += adjust;
+                 p->p_memsz += adjust;
                }
-             else if ((flags & SEC_ALLOC) != 0)
+             /* .tbss is special.  It doesn't contribute to p_memsz of
+                normal segments.  */
+             else if ((flags & SEC_THREAD_LOCAL) == 0
+                      || p->p_type == PT_TLS)
                {
                  /* The section VMA must equal the file position
-                    modulo the page size.  FIXME: I'm not sure if
-                    this adjustment is really necessary.  We used to
-                    not have the SEC_LOAD case just above, and then
-                    this was necessary, but now I'm not sure.  */
-                 if ((abfd->flags & D_PAGED) != 0)
-                   adjust = vma_page_aligned_bias (sec->vma, voff,
-                                                   bed->maxpagesize);
-                 else
-                   adjust = vma_page_aligned_bias (sec->vma, voff,
-                                                   align);
-               }
-             else
-               adjust = 0;
-
-             if (adjust != 0)
-               {
-                 if (i == 0)
-                   {
-                     (* _bfd_error_handler) (_("\
-Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x"),
-                                             bfd_section_name (abfd, sec),
-                                             sec->lma,
-                                             p->p_paddr);
-                     return FALSE;
-                   }
+                    modulo the page size.  */
+                 bfd_size_type page = align;
+                 if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > page)
+                   page = bed->maxpagesize;
+                 adjust = vma_page_aligned_bias (sec->vma,
+                                                 p->p_vaddr + p->p_memsz,
+                                                 page);
                  p->p_memsz += adjust;
-                 off += adjust;
-                 voff += adjust;
-                 if ((flags & SEC_LOAD) != 0)
-                   p->p_filesz += adjust;
                }
-
-             sec->filepos = off;
-
-             /* We check SEC_HAS_CONTENTS here because if NOLOAD is
-                 used in a linker script we may have a section with
-                 SEC_LOAD clear but which is supposed to have
-                 contents.  */
-             if ((flags & SEC_LOAD) != 0
-                 || (flags & SEC_HAS_CONTENTS) != 0)
-               off += sec->_raw_size;
-
-             if ((flags & SEC_ALLOC) != 0
-                 && ((flags & SEC_LOAD) != 0
-                     || (flags & SEC_THREAD_LOCAL) == 0))
-               voff += sec->_raw_size;
            }
 
          if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
            {
-             /* The actual "note" segment has i == 0.
-                This is the one that actually contains everything.  */
+             /* The section at i == 0 is the one that actually contains
+                everything.  */
              if (i == 0)
                {
                  sec->filepos = off;
-                 p->p_filesz = sec->_raw_size;
-                 off += sec->_raw_size;
-                 voff = off;
+                 off += sec->size;
+                 p->p_filesz = sec->size;
+                 p->p_memsz = 0;
+                 p->p_align = 1;
                }
              else
                {
-                 /* Fake sections -- don't need to be written.  */
+                 /* The rest are fake sections that shouldn't be written.  */
                  sec->filepos = 0;
-                 sec->_raw_size = 0;
-                 flags = sec->flags = 0;
+                 sec->size = 0;
+                 sec->flags = 0;
+                 continue;
                }
-             p->p_memsz = 0;
-             p->p_align = 1;
            }
          else
            {
-             if ((sec->flags & SEC_LOAD) != 0
-                 || (sec->flags & SEC_THREAD_LOCAL) == 0
-                 || p->p_type == PT_TLS)
-             p->p_memsz += sec->_raw_size;
+             if (p->p_type == PT_LOAD)
+               {
+                 sec->filepos = off;
+                 /* FIXME: The SEC_HAS_CONTENTS test here dates back to
+                    1997, and the exact reason for it isn't clear.  One
+                    plausible explanation is that it is to work around
+                    a problem we have with linker scripts using data
+                    statements in NOLOAD sections.  I don't think it
+                    makes a great deal of sense to have such a section
+                    assigned to a PT_LOAD segment, but apparently
+                    people do this.  The data statement results in a
+                    bfd_data_link_order being built, and these need
+                    section contents to write into.  Eventually, we get
+                    to _bfd_elf_write_object_contents which writes any
+                    section with contents to the output.  Make room
+                    here for the write, so that following segments are
+                    not trashed.  */
+                 if ((flags & SEC_LOAD) != 0
+                     || (flags & SEC_HAS_CONTENTS) != 0)
+                   off += sec->size;
+               }
 
              if ((flags & SEC_LOAD) != 0)
-               p->p_filesz += sec->_raw_size;
+               {
+                 p->p_filesz += sec->size;
+                 p->p_memsz += sec->size;
+               }
+             /* PR ld/594:  Sections in note segments which are not loaded
+                contribute to the file size but not the in-memory size.  */
+             else if (p->p_type == PT_NOTE
+                 && (flags & SEC_HAS_CONTENTS) != 0)
+               p->p_filesz += sec->size;
+
+             /* .tbss is special.  It doesn't contribute to p_memsz of
+                normal segments.  */
+             else if ((flags & SEC_THREAD_LOCAL) == 0
+                      || p->p_type == PT_TLS)
+               p->p_memsz += sec->size;
 
              if (p->p_type == PT_TLS
-                 && sec->_raw_size == 0
+                 && sec->size == 0
                  && (sec->flags & SEC_HAS_CONTENTS) == 0)
                {
                  struct bfd_link_order *o;
                  bfd_vma tbss_size = 0;
 
-                 for (o = sec->link_order_head; o != NULL; o = o->next)
+                 for (o = sec->map_head.link_order; o != NULL; o = o->next)
                    if (tbss_size < o->offset + o->size)
                      tbss_size = o->offset + o->size;
 
@@ -4032,6 +4464,22 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
       if (p->p_type != PT_LOAD && m->count > 0)
        {
          BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs);
+         /* If the section has not yet been assigned a file position,
+            do so now.  The ARM BPABI requires that .dynamic section
+            not be marked SEC_ALLOC because it is not part of any
+            PT_LOAD segment, so it will not be processed above.  */
+         if (p->p_type == PT_DYNAMIC && m->sections[0]->filepos == 0)
+           {
+             unsigned int i;
+             Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
+
+             i = 1;
+             while (i_shdrpp[i]->bfd_section != m->sections[0])
+               ++i;
+             off = (_bfd_elf_assign_file_position_for_section 
+                    (i_shdrpp[i], off, TRUE));
+             p->p_filesz = m->sections[0]->size;
+           }
          p->p_offset = m->sections[0]->filepos;
        }
       if (m->count == 0)
@@ -4048,6 +4496,37 @@ Error: First section in segment (%s) starts at 0x%x whereas the segment starts a
              if (! m->p_paddr_valid)
                p->p_paddr = phdrs_paddr;
            }
+         else if (p->p_type == PT_GNU_RELRO)
+           {
+             Elf_Internal_Phdr *lp;
+
+             for (lp = phdrs; lp < phdrs + count; ++lp)
+               {
+                 if (lp->p_type == PT_LOAD
+                     && lp->p_vaddr <= link_info->relro_end
+                     && lp->p_vaddr >= link_info->relro_start
+                     && lp->p_vaddr + lp->p_filesz
+                        >= link_info->relro_end)
+                   break;
+               }
+
+             if (lp < phdrs + count
+                 && link_info->relro_end > lp->p_vaddr)
+               {
+                 p->p_vaddr = lp->p_vaddr;
+                 p->p_paddr = lp->p_paddr;
+                 p->p_offset = lp->p_offset;
+                 p->p_filesz = link_info->relro_end - lp->p_vaddr;
+                 p->p_memsz = p->p_filesz;
+                 p->p_align = 1;
+                 p->p_flags = (lp->p_flags & ~PF_W);
+               }
+             else
+               {
+                 memset (p, 0, sizeof *p);
+                 p->p_type = PT_NULL;
+               }
+           }
        }
     }
 
@@ -4135,6 +4614,12 @@ get_program_header_size (bfd *abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->relro)
+    {
+      /* We need a PT_GNU_RELRO segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -4174,10 +4659,13 @@ get_program_header_size (bfd *abfd)
    _bfd_elf_compute_section_file_positions.  All the section sizes and
    VMAs must be known before this is called.
 
-   We do not consider reloc sections at this point, unless they form
-   part of the loadable image.  Reloc sections are assigned file
-   positions in assign_file_positions_for_relocs, which is called by
-   write_object_contents and final_link.
+   Reloc sections come in two flavours: Those processed specially as
+   "side-channel" data attached to a section to which they apply, and
+   those that bfd doesn't process as relocations.  The latter sort are
+   stored in a normal bfd section by bfd_section_from_shdr.   We don't
+   consider the former sort here, unless they form part of the loadable
+   image.  Reloc sections not assigned here will be handled later by
+   assign_file_positions_for_relocs.
 
    We also don't set the positions of the .symtab and .strtab here.  */
 
@@ -4209,8 +4697,8 @@ assign_file_positions_except_relocs (bfd *abfd,
          Elf_Internal_Shdr *hdr;
 
          hdr = *hdrpp;
-         if (hdr->sh_type == SHT_REL
-             || hdr->sh_type == SHT_RELA
+         if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+              && hdr->bfd_section == NULL)
              || i == tdata->symtab_section
              || i == tdata->symtab_shndx_section
              || i == tdata->strtab_section)
@@ -4251,8 +4739,8 @@ assign_file_positions_except_relocs (bfd *abfd,
          else if ((hdr->sh_flags & SHF_ALLOC) != 0)
            {
              ((*_bfd_error_handler)
-              (_("%s: warning: allocated section `%s' not in segment"),
-               bfd_get_filename (abfd),
+              (_("%B: warning: allocated section `%s' not in segment"),
+               abfd,
                (hdr->bfd_section == NULL
                 ? "*unknown*"
                 : hdr->bfd_section->name)));
@@ -4265,8 +4753,8 @@ assign_file_positions_except_relocs (bfd *abfd,
              off = _bfd_elf_assign_file_position_for_section (hdr, off,
                                                               FALSE);
            }
-         else if (hdr->sh_type == SHT_REL
-                  || hdr->sh_type == SHT_RELA
+         else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
+                   && hdr->bfd_section == NULL)
                   || hdr == i_shdrpp[tdata->symtab_section]
                   || hdr == i_shdrpp[tdata->symtab_shndx_section]
                   || hdr == i_shdrpp[tdata->strtab_section])
@@ -4361,18 +4849,8 @@ prep_headers (bfd *abfd)
 
   /* If we're building an executable, we'll need a program header table.  */
   if (abfd->flags & EXEC_P)
-    {
-      /* It all happens later.  */
-#if 0
-      i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr);
-
-      /* elf_build_phdrs() returns a (NULL-terminated) array of
-        Elf_Internal_Phdrs.  */
-      i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum);
-      i_ehdrp->e_phoff = outbase;
-      outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum;
-#endif
-    }
+    /* It all happens later.  */
+    ;
   else
     {
       i_ehdrp->e_phentsize = 0;
@@ -4462,8 +4940,9 @@ _bfd_elf_write_object_contents (bfd *abfd)
     }
 
   /* Write out the section header names.  */
-  if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
-      || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))
+  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))))
     return FALSE;
 
   if (bed->elf_backend_final_write_processing)
@@ -4499,19 +4978,7 @@ _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
   else if (bfd_is_und_section (asect))
     index = SHN_UNDEF;
   else
-    {
-      Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
-      int maxindex = elf_numsections (abfd);
-
-      for (index = 1; index < maxindex; index++)
-       {
-         Elf_Internal_Shdr *hdr = i_shdrp[index];
-
-         if (hdr != NULL && hdr->bfd_section == asect)
-           return index;
-       }
-      index = -1;
-    }
+    index = -1;
 
   bed = get_elf_backend_data (abfd);
   if (bed->elf_backend_section_from_bfd_section)
@@ -4565,8 +5032,8 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr)
       /* This case can occur when using --strip-symbol on a symbol
          which is used in a relocation entry.  */
       (*_bfd_error_handler)
-       (_("%s: symbol `%s' required but not present"),
-        bfd_archive_filename (abfd), bfd_asymbol_name (asym_ptr));
+       (_("%B: symbol `%s' required but not present"),
+        abfd, bfd_asymbol_name (asym_ptr));
       bfd_set_error (bfd_error_no_symbols);
       return -1;
     }
@@ -4627,7 +5094,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 #define SECTION_SIZE(section, segment)                                 \
   (((section->flags & (SEC_HAS_CONTENTS | SEC_THREAD_LOCAL))           \
     != SEC_THREAD_LOCAL || segment->p_type == PT_TLS)                  \
-   ? section->_raw_size : 0)
+   ? section->size : 0)
 
   /* Returns TRUE if the given section is contained within
      the given segment.  VMA addresses are compared.  */
@@ -4649,7 +5116,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && bfd_get_format (ibfd) == bfd_core                                        \
    && s->vma == 0 && s->lma == 0                                       \
    && (bfd_vma) s->filepos >= p->p_offset                              \
-   && ((bfd_vma) s->filepos + s->_raw_size                             \
+   && ((bfd_vma) s->filepos + s->size                          \
        <= p->p_offset + p->p_filesz))
 
   /* The complicated case when p_vaddr is 0 is to handle the Solaris
@@ -4661,9 +5128,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && p->p_memsz == 0                                                  \
    && p->p_filesz > 0                                                  \
    && (s->flags & SEC_HAS_CONTENTS) != 0                               \
-   && s->_raw_size > 0                                                 \
+   && s->size > 0                                                      \
    && (bfd_vma) s->filepos >= p->p_offset                              \
-   && ((bfd_vma) s->filepos + s->_raw_size                             \
+   && ((bfd_vma) s->filepos + s->size                          \
        <= p->p_offset + p->p_filesz))
 
   /* Decide if the given section should be included in the given segment.
@@ -4675,7 +5142,9 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
        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.  */
+       7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
+       8. PT_DYNAMIC should not contain empty sections at the beginning
+          (with the possible exception of .dynamic).  */
 #define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
   ((((segment->p_paddr                                                 \
       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)       \
@@ -4689,6 +5158,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
    && (segment->p_type == PT_LOAD                                      \
        || segment->p_type == PT_TLS                                    \
        || (section->flags & SEC_THREAD_LOCAL) == 0)                    \
+   && (segment->p_type != PT_DYNAMIC                                   \
+       || SECTION_SIZE (section, segment) > 0                          \
+       || (segment->p_paddr                                            \
+           ? segment->p_paddr != section->lma                          \
+           : segment->p_vaddr != section->vma)                         \
+       || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic")   \
+           == 0))                                                      \
    && ! section->segment_mark)
 
   /* Returns TRUE iff seg1 starts after the end of seg2.  */
@@ -4853,8 +5329,8 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
             a warning is produced.  */
          if (segment->p_type == PT_LOAD)
            (*_bfd_error_handler)
-             (_("%s: warning: Empty loadable segment detected, is this intentional ?\n"),
-              bfd_archive_filename (ibfd));
+             (_("%B: warning: Empty loadable segment detected, is this intentional ?\n"),
+              ibfd);
 
          map->count = 0;
          *pointer_to_map = map;
@@ -4893,8 +5369,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
       /* Gcc 2.96 miscompiles this code on mips. Don't do casting here
         to work around this long long bug.  */
-      amt = section_count * sizeof (asection *);
-      sections = bfd_malloc (amt);
+      sections = bfd_malloc2 (section_count, sizeof (asection *));
       if (sections == NULL)
        return FALSE;
 
@@ -5061,10 +5536,10 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
                      /* If the gap between the end of the previous section
                         and the start of this section is more than
                         maxpagesize then we need to start a new segment.  */
-                     if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size,
+                     if ((BFD_ALIGN (prev_sec->lma + prev_sec->size,
                                      maxpagesize)
                           < BFD_ALIGN (output_section->lma, maxpagesize))
-                         || ((prev_sec->lma + prev_sec->_raw_size)
+                         || ((prev_sec->lma + prev_sec->size)
                              > output_section->lma))
                        {
                          if (suggested_lma == 0)
@@ -5149,31 +5624,6 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
          -= (count - phdr_adjust_num) * iehdr->e_phentsize;
     }
 
-#if 0
-  /* Final Step: Sort the segments into ascending order of physical
-     address.  */
-  if (map_first != NULL)
-    {
-      struct elf_segment_map *prev;
-
-      prev = map_first;
-      for (map = map_first->next; map != NULL; prev = map, map = map->next)
-       {
-         /* Yes I know - its a bubble sort....  */
-         if (map->next != NULL && (map->next->p_paddr < map->p_paddr))
-           {
-             /* Swap map and map->next.  */
-             prev->next = map->next;
-             map->next = map->next->next;
-             prev->next->next = map;
-
-             /* Restart loop.  */
-             map = map_first;
-           }
-       }
-    }
-#endif
-
 #undef SEGMENT_END
 #undef SECTION_SIZE
 #undef IS_CONTAINED_BY_VMA
@@ -5201,24 +5651,6 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
       || obfd->xvec->flavour != bfd_target_elf_flavour)
     return TRUE;
 
-  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
-    {
-       asection *s;
-
-       /* Only set up the segments if there are no more SEC_ALLOC
-          sections.  FIXME: This won't do the right thing if objcopy is
-          used to remove the last SEC_ALLOC section, since objcopy
-          won't call this routine in that case.  */
-       for (s = isec->next; s != NULL; s = s->next)
-         if ((s->flags & SEC_ALLOC) != 0)
-           break;
-       if (s == NULL)
-         {
-           if (! copy_private_bfd_data (ibfd, obfd))
-             return FALSE;
-         }
-    }
-
   ihdr = &elf_section_data (isec)->this_hdr;
   ohdr = &elf_section_data (osec)->this_hdr;
 
@@ -5232,15 +5664,43 @@ _bfd_elf_copy_private_section_data (bfd *ibfd,
 
   /* Set things up for objcopy.  The output SHT_GROUP section will
      have its elf_next_in_group pointing back to the input group
-     members.  */
-  elf_next_in_group (osec) = elf_next_in_group (isec);
-  elf_group_name (osec) = elf_group_name (isec);
+     members.  Ignore linker created group section.  See
+     elfNN_ia64_object_p in elfxx-ia64.c.  */
+  if (elf_sec_group (isec) == NULL
+      || (elf_sec_group (isec)->flags & SEC_LINKER_CREATED) == 0)
+    {
+      elf_next_in_group (osec) = elf_next_in_group (isec);
+      elf_group_name (osec) = elf_group_name (isec);
+    }
 
   osec->use_rela_p = isec->use_rela_p;
 
   return TRUE;
 }
 
+/* Copy private header information.  */
+
+bfd_boolean
+_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Copy over private BFD data if it has not already been copied.
+     This must be done here, rather than in the copy_private_bfd_data
+     entry point, because the latter is called after the section
+     contents have been set, which means that the program headers have
+     already been worked out.  */
+  if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL)
+    {
+      if (! copy_private_bfd_data (ibfd, obfd))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* Copy private symbol information.  If this symbol is in a section
    which we did not map into a BFD section, try to map the section
    index correctly.  We use special macro definitions for the mapped
@@ -5305,8 +5765,8 @@ swap_out_syms (bfd *abfd,
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
-  char *outbound_syms;
-  char *outbound_shndx;
+  bfd_byte *outbound_syms;
+  bfd_byte *outbound_shndx;
   int idx;
   bfd_size_type amt;
   bfd_boolean name_local_sections;
@@ -5331,8 +5791,7 @@ swap_out_syms (bfd *abfd,
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
 
-  amt = (bfd_size_type) (1 + symcount) * bed->s->sizeof_sym;
-  outbound_syms = bfd_alloc (abfd, amt);
+  outbound_syms = bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym);
   if (outbound_syms == NULL)
     {
       _bfd_stringtab_free (stt);
@@ -5345,7 +5804,8 @@ swap_out_syms (bfd *abfd,
   if (symtab_shndx_hdr->sh_name != 0)
     {
       amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
-      outbound_shndx = bfd_zalloc (abfd, amt);
+      outbound_shndx = bfd_zalloc2 (abfd, 1 + symcount,
+                                   sizeof (Elf_External_Sym_Shndx));
       if (outbound_shndx == NULL)
        {
          _bfd_stringtab_free (stt);
@@ -5673,10 +6133,10 @@ _bfd_elf_canonicalize_dynamic_symtab (bfd *abfd,
   return symcount;
 }
 
-/* Return the size required for the dynamic reloc entries.  Any
-   section that was actually installed in the BFD, and has type
-   SHT_REL or SHT_RELA, and uses the dynamic symbol table, is
-   considered to be a dynamic reloc section.  */
+/* Return the size required for the dynamic reloc entries.  Any loadable
+   section that was actually installed in the BFD, and has type SHT_REL
+   or SHT_RELA, and uses the dynamic symbol table, is considered to be a
+   dynamic reloc section.  */
 
 long
 _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
@@ -5692,23 +6152,23 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
 
   ret = sizeof (arelent *);
   for (s = abfd->sections; s != NULL; s = s->next)
-    if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+    if ((s->flags & SEC_LOAD) != 0
+       && 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->_raw_size / elf_section_data (s)->this_hdr.sh_entsize)
+      ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize)
              * sizeof (arelent *));
 
   return ret;
 }
 
-/* Canonicalize the dynamic relocation entries.  Note that we return
-   the dynamic relocations as a single block, although they are
-   actually associated with particular sections; the interface, which
-   was designed for SunOS style shared libraries, expects that there
-   is only one set of dynamic relocs.  Any section that was actually
-   installed in the BFD, and has type SHT_REL or SHT_RELA, and uses
-   the dynamic symbol table, is considered to be a dynamic reloc
-   section.  */
+/* Canonicalize the dynamic relocation entries.  Note that we return the
+   dynamic relocations as a single block, although they are actually
+   associated with particular sections; the interface, which was
+   designed for SunOS style shared libraries, expects that there is only
+   one set of dynamic relocs.  Any loadable section that was actually
+   installed in the BFD, and has type SHT_REL or SHT_RELA, and uses the
+   dynamic symbol table, is considered to be a dynamic reloc section.  */
 
 long
 _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
@@ -5729,7 +6189,8 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
   ret = 0;
   for (s = abfd->sections; s != NULL; s = s->next)
     {
-      if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+      if ((s->flags & SEC_LOAD) != 0
+         && 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))
        {
@@ -5738,7 +6199,7 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
 
          if (! (*slurp_relocs) (abfd, s, syms, TRUE))
            return -1;
-         count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize;
+         count = s->size / elf_section_data (s)->this_hdr.sh_entsize;
          p = s->relocation;
          for (i = 0; i < count; i++)
            *storage++ = p++;
@@ -5754,10 +6215,123 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
 /* Read in the version information.  */
 
 bfd_boolean
-_bfd_elf_slurp_version_tables (bfd *abfd)
+_bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver)
 {
   bfd_byte *contents = NULL;
-  bfd_size_type amt;
+  unsigned int freeidx = 0;
+
+  if (elf_dynverref (abfd) != 0)
+    {
+      Elf_Internal_Shdr *hdr;
+      Elf_External_Verneed *everneed;
+      Elf_Internal_Verneed *iverneed;
+      unsigned int i;
+      bfd_byte *contents_end;
+
+      hdr = &elf_tdata (abfd)->dynverref_hdr;
+
+      elf_tdata (abfd)->verref = bfd_zalloc2 (abfd, hdr->sh_info,
+                                             sizeof (Elf_Internal_Verneed));
+      if (elf_tdata (abfd)->verref == NULL)
+       goto error_return;
+
+      elf_tdata (abfd)->cverrefs = hdr->sh_info;
+
+      contents = bfd_malloc (hdr->sh_size);
+      if (contents == NULL)
+       {
+error_return_verref:
+         elf_tdata (abfd)->verref = NULL;
+         elf_tdata (abfd)->cverrefs = 0;
+         goto error_return;
+       }
+      if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+         || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+       goto error_return_verref;
+
+      if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed))
+       goto error_return_verref;
+
+      BFD_ASSERT (sizeof (Elf_External_Verneed)
+                 == sizeof (Elf_External_Vernaux));
+      contents_end = contents + hdr->sh_size - sizeof (Elf_External_Verneed);
+      everneed = (Elf_External_Verneed *) contents;
+      iverneed = elf_tdata (abfd)->verref;
+      for (i = 0; i < hdr->sh_info; i++, iverneed++)
+       {
+         Elf_External_Vernaux *evernaux;
+         Elf_Internal_Vernaux *ivernaux;
+         unsigned int j;
+
+         _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
+
+         iverneed->vn_bfd = abfd;
+
+         iverneed->vn_filename =
+           bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                            iverneed->vn_file);
+         if (iverneed->vn_filename == NULL)
+           goto error_return_verref;
+
+         if (iverneed->vn_cnt == 0)
+           iverneed->vn_auxptr = NULL;
+         else
+           {
+             iverneed->vn_auxptr = bfd_alloc2 (abfd, iverneed->vn_cnt,
+                                               sizeof (Elf_Internal_Vernaux));
+             if (iverneed->vn_auxptr == NULL)
+               goto error_return_verref;
+           }
+
+         if (iverneed->vn_aux
+             > (size_t) (contents_end - (bfd_byte *) everneed))
+           goto error_return_verref;
+
+         evernaux = ((Elf_External_Vernaux *)
+                     ((bfd_byte *) everneed + iverneed->vn_aux));
+         ivernaux = iverneed->vn_auxptr;
+         for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
+           {
+             _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+
+             ivernaux->vna_nodename =
+               bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
+                                                ivernaux->vna_name);
+             if (ivernaux->vna_nodename == NULL)
+               goto error_return_verref;
+
+             if (j + 1 < iverneed->vn_cnt)
+               ivernaux->vna_nextptr = ivernaux + 1;
+             else
+               ivernaux->vna_nextptr = NULL;
+
+             if (ivernaux->vna_next
+                 > (size_t) (contents_end - (bfd_byte *) evernaux))
+               goto error_return_verref;
+
+             evernaux = ((Elf_External_Vernaux *)
+                         ((bfd_byte *) evernaux + ivernaux->vna_next));
+
+             if (ivernaux->vna_other > freeidx)
+               freeidx = ivernaux->vna_other;
+           }
+
+         if (i + 1 < hdr->sh_info)
+           iverneed->vn_nextref = iverneed + 1;
+         else
+           iverneed->vn_nextref = NULL;
+
+         if (iverneed->vn_next
+             > (size_t) (contents_end - (bfd_byte *) everneed))
+           goto error_return_verref;
+
+         everneed = ((Elf_External_Verneed *)
+                     ((bfd_byte *) everneed + iverneed->vn_next));
+       }
+
+      free (contents);
+      contents = NULL;
+    }
 
   if (elf_dynverdef (abfd) != 0)
     {
@@ -5768,6 +6342,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
       Elf_Internal_Verdef iverdefmem;
       unsigned int i;
       unsigned int maxidx;
+      bfd_byte *contents_end_def, *contents_end_aux;
 
       hdr = &elf_tdata (abfd)->dynverdef_hdr;
 
@@ -5778,6 +6353,16 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
          || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
        goto error_return;
 
+      if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef))
+       goto error_return;
+
+      BFD_ASSERT (sizeof (Elf_External_Verdef)
+                 >= sizeof (Elf_External_Verdaux));
+      contents_end_def = contents + hdr->sh_size
+                        - sizeof (Elf_External_Verdef);
+      contents_end_aux = contents + hdr->sh_size
+                        - sizeof (Elf_External_Verdaux);
+
       /* We know the number of entries in the section but not the maximum
         index.  Therefore we have to run through all entries and find
         the maximum.  */
@@ -5790,12 +6375,23 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
          if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx)
            maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION);
 
+         if (iverdefmem.vd_next
+             > (size_t) (contents_end_def - (bfd_byte *) everdef))
+           goto error_return;
+
          everdef = ((Elf_External_Verdef *)
                     ((bfd_byte *) everdef + iverdefmem.vd_next));
        }
 
-      amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef);
-      elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
+      if (default_imported_symver)
+       {
+         if (freeidx > maxidx)
+           maxidx = ++freeidx;
+         else
+           freeidx = ++maxidx;
+       }
+      elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, maxidx,
+                                             sizeof (Elf_Internal_Verdef));
       if (elf_tdata (abfd)->verdef == NULL)
        goto error_return;
 
@@ -5811,15 +6407,32 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
 
          _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
 
+         if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0)
+           {
+error_return_verdef:
+             elf_tdata (abfd)->verdef = NULL;
+             elf_tdata (abfd)->cverdefs = 0;
+             goto error_return;
+           }
+
          iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1];
          memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef));
 
          iverdef->vd_bfd = abfd;
 
-         amt = (bfd_size_type) iverdef->vd_cnt * sizeof (Elf_Internal_Verdaux);
-         iverdef->vd_auxptr = bfd_alloc (abfd, amt);
-         if (iverdef->vd_auxptr == NULL)
-           goto error_return;
+         if (iverdef->vd_cnt == 0)
+           iverdef->vd_auxptr = NULL;
+         else
+           {
+             iverdef->vd_auxptr = bfd_alloc2 (abfd, iverdef->vd_cnt,
+                                              sizeof (Elf_Internal_Verdaux));
+             if (iverdef->vd_auxptr == NULL)
+               goto error_return_verdef;
+           }
+
+         if (iverdef->vd_aux
+             > (size_t) (contents_end_aux - (bfd_byte *) everdef))
+           goto error_return_verdef;
 
          everdaux = ((Elf_External_Verdaux *)
                      ((bfd_byte *) everdef + iverdef->vd_aux));
@@ -5832,20 +6445,25 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
                bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
                                                 iverdaux->vda_name);
              if (iverdaux->vda_nodename == NULL)
-               goto error_return;
+               goto error_return_verdef;
 
              if (j + 1 < iverdef->vd_cnt)
                iverdaux->vda_nextptr = iverdaux + 1;
              else
                iverdaux->vda_nextptr = NULL;
 
+             if (iverdaux->vda_next
+                 > (size_t) (contents_end_aux - (bfd_byte *) everdaux))
+               goto error_return_verdef;
+
              everdaux = ((Elf_External_Verdaux *)
                          ((bfd_byte *) everdaux + iverdaux->vda_next));
            }
 
-         iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
+         if (iverdef->vd_cnt)
+           iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
 
-         if (i + 1 < hdr->sh_info)
+         if ((size_t) (iverdef - iverdefarr) + 1 < maxidx)
            iverdef->vd_nextdef = iverdef + 1;
          else
            iverdef->vd_nextdef = NULL;
@@ -5857,85 +6475,47 @@ _bfd_elf_slurp_version_tables (bfd *abfd)
       free (contents);
       contents = NULL;
     }
-
-  if (elf_dynverref (abfd) != 0)
+  else if (default_imported_symver)
     {
-      Elf_Internal_Shdr *hdr;
-      Elf_External_Verneed *everneed;
-      Elf_Internal_Verneed *iverneed;
-      unsigned int i;
-
-      hdr = &elf_tdata (abfd)->dynverref_hdr;
-
-      amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed);
-      elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt);
-      if (elf_tdata (abfd)->verref == NULL)
-       goto error_return;
-
-      elf_tdata (abfd)->cverrefs = hdr->sh_info;
+      if (freeidx < 3)
+       freeidx = 3;
+      else
+       freeidx++;
 
-      contents = bfd_malloc (hdr->sh_size);
-      if (contents == NULL)
-       goto error_return;
-      if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+      elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, freeidx,
+                                             sizeof (Elf_Internal_Verdef));
+      if (elf_tdata (abfd)->verdef == NULL)
        goto error_return;
 
-      everneed = (Elf_External_Verneed *) contents;
-      iverneed = elf_tdata (abfd)->verref;
-      for (i = 0; i < hdr->sh_info; i++, iverneed++)
-       {
-         Elf_External_Vernaux *evernaux;
-         Elf_Internal_Vernaux *ivernaux;
-         unsigned int j;
-
-         _bfd_elf_swap_verneed_in (abfd, everneed, iverneed);
-
-         iverneed->vn_bfd = abfd;
-
-         iverneed->vn_filename =
-           bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                            iverneed->vn_file);
-         if (iverneed->vn_filename == NULL)
-           goto error_return;
-
-         amt = iverneed->vn_cnt;
-         amt *= sizeof (Elf_Internal_Vernaux);
-         iverneed->vn_auxptr = bfd_alloc (abfd, amt);
-
-         evernaux = ((Elf_External_Vernaux *)
-                     ((bfd_byte *) everneed + iverneed->vn_aux));
-         ivernaux = iverneed->vn_auxptr;
-         for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++)
-           {
-             _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux);
+      elf_tdata (abfd)->cverdefs = freeidx;
+    }
 
-             ivernaux->vna_nodename =
-               bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
-                                                ivernaux->vna_name);
-             if (ivernaux->vna_nodename == NULL)
-               goto error_return;
+  /* Create a default version based on the soname.  */
+  if (default_imported_symver)
+    {
+      Elf_Internal_Verdef *iverdef;
+      Elf_Internal_Verdaux *iverdaux;
 
-             if (j + 1 < iverneed->vn_cnt)
-               ivernaux->vna_nextptr = ivernaux + 1;
-             else
-               ivernaux->vna_nextptr = NULL;
+      iverdef = &elf_tdata (abfd)->verdef[freeidx - 1];;
 
-             evernaux = ((Elf_External_Vernaux *)
-                         ((bfd_byte *) evernaux + ivernaux->vna_next));
-           }
+      iverdef->vd_version = VER_DEF_CURRENT;
+      iverdef->vd_flags = 0;
+      iverdef->vd_ndx = freeidx;
+      iverdef->vd_cnt = 1;
 
-         if (i + 1 < hdr->sh_info)
-           iverneed->vn_nextref = iverneed + 1;
-         else
-           iverneed->vn_nextref = NULL;
+      iverdef->vd_bfd = abfd;
 
-         everneed = ((Elf_External_Verneed *)
-                     ((bfd_byte *) everneed + iverneed->vn_next));
-       }
+      iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd);
+      if (iverdef->vd_nodename == NULL)
+       goto error_return_verdef;
+      iverdef->vd_nextdef = NULL;
+      iverdef->vd_auxptr = bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux));
+      if (iverdef->vd_auxptr == NULL)
+       goto error_return_verdef;
 
-      free (contents);
-      contents = NULL;
+      iverdaux = iverdef->vd_auxptr;
+      iverdaux->vda_nodename = iverdef->vd_nodename;
+      iverdaux->vda_nextptr = NULL;
     }
 
   return TRUE;
@@ -6034,13 +6614,24 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
                   const char **functionname_ptr)
 {
   const char *filename;
-  asymbol *func;
+  asymbol *func, *file;
   bfd_vma low_func;
   asymbol **p;
+  /* ??? Given multiple file symbols, it is impossible to reliably
+     choose the right file name for global symbols.  File symbols are
+     local symbols, and thus all file symbols must sort before any
+     global symbols.  The ELF spec may be interpreted to say that a
+     file symbol must sort before other local symbols, but currently
+     ld -r doesn't do this.  So, for ld -r output, it is possible to
+     make a better choice of file name for local symbols by ignoring
+     file symbols appearing after a given local symbol.  */
+  enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
 
   filename = NULL;
   func = NULL;
+  file = NULL;
   low_func = 0;
+  state = nothing_seen;
 
   for (p = symbols; *p != NULL; p++)
     {
@@ -6048,27 +6639,37 @@ elf_find_function (bfd *abfd ATTRIBUTE_UNUSED,
 
       q = (elf_symbol_type *) *p;
 
-      if (bfd_get_section (&q->symbol) != section)
-       continue;
-
       switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
        {
        default:
          break;
        case STT_FILE:
-         filename = bfd_asymbol_name (&q->symbol);
-         break;
+         file = &q->symbol;
+         if (state == symbol_seen)
+           state = file_after_symbol_seen;
+         continue;
+       case STT_SECTION:
+         continue;
        case STT_NOTYPE:
        case STT_FUNC:
-         if (q->symbol.section == section
+         if (bfd_get_section (&q->symbol) == section
              && q->symbol.value >= low_func
              && q->symbol.value <= offset)
            {
              func = (asymbol *) q;
              low_func = q->symbol.value;
+             if (file == NULL)
+               filename = NULL;
+             else if (ELF_ST_BIND (q->internal_elf_sym.st_info) != STB_LOCAL
+                      && state == file_after_symbol_seen)
+               filename = NULL;
+             else
+               filename = bfd_asymbol_name (file);
            }
          break;
        }
+      if (state == nothing_seen)
+       state = symbol_seen;
     }
 
   if (func == NULL)
@@ -6140,6 +6741,36 @@ _bfd_elf_find_nearest_line (bfd *abfd,
   return TRUE;
 }
 
+/* Find the line for a symbol.  */
+
+bfd_boolean
+_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
+                   const char **filename_ptr, unsigned int *line_ptr)
+{
+  return _bfd_dwarf2_find_line (abfd, symbols, symbol,
+                               filename_ptr, line_ptr, 0,
+                               &elf_tdata (abfd)->dwarf2_find_line_info);
+}
+
+/* After a call to bfd_find_nearest_line, successive calls to
+   bfd_find_inliner_info can be used to get source information about
+   each level of function inlining that terminated at the address
+   passed to bfd_find_nearest_line.  Currently this is only supported
+   for DWARF2 with appropriate DWARF3 extensions. */
+
+bfd_boolean
+_bfd_elf_find_inliner_info (bfd *abfd,
+                           const char **filename_ptr,
+                           const char **functionname_ptr,
+                           unsigned int *line_ptr)
+{
+  bfd_boolean found;
+  found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr,
+                                        functionname_ptr, line_ptr,
+                                        & elf_tdata (abfd)->dwarf2_find_line_info);
+  return found;
+}
+
 int
 _bfd_elf_sizeof_headers (bfd *abfd, bfd_boolean reloc)
 {
@@ -6272,8 +6903,8 @@ _bfd_elf_validate_reloc (bfd *abfd, arelent *areloc)
 
  fail:
   (*_bfd_error_handler)
-    (_("%s: unsupported relocation type %s"),
-     bfd_archive_filename (abfd), areloc->howto->name);
+    (_("%B: unsupported relocation type %s"),
+     abfd, areloc->howto->name);
   bfd_set_error (bfd_error_bad_value);
   return FALSE;
 }
@@ -6285,6 +6916,7 @@ _bfd_elf_close_and_cleanup (bfd *abfd)
     {
       if (elf_shstrtab (abfd) != NULL)
        _bfd_elf_strtab_free (elf_shstrtab (abfd));
+      _bfd_dwarf2_cleanup_debug_info (abfd);
     }
 
   return _bfd_generic_close_and_cleanup (abfd);
@@ -6340,7 +6972,7 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect)
   if (sect2 == NULL)
     return FALSE;
 
-  sect2->_raw_size = sect->_raw_size;
+  sect2->size = sect->size;
   sect2->filepos = sect->filepos;
   sect2->flags = sect->flags;
   sect2->alignment_power = sect->alignment_power;
@@ -6377,7 +7009,7 @@ _bfd_elfcore_make_pseudosection (bfd *abfd,
   sect = bfd_make_section_anyway (abfd, threaded_name);
   if (sect == NULL)
     return FALSE;
-  sect->_raw_size = size;
+  sect->size = size;
   sect->filepos = filepos;
   sect->flags = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
@@ -6396,14 +7028,14 @@ _bfd_elfcore_make_pseudosection (bfd *abfd,
 static bfd_boolean
 elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
-  size_t raw_size;
+  size_t size;
   int offset;
 
   if (note->descsz == sizeof (prstatus_t))
     {
       prstatus_t prstat;
 
-      raw_size = sizeof (prstat.pr_reg);
+      size = sizeof (prstat.pr_reg);
       offset   = offsetof (prstatus_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
@@ -6429,7 +7061,7 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
       /* 64-bit host, 32-bit corefile */
       prstatus32_t prstat;
 
-      raw_size = sizeof (prstat.pr_reg);
+      size = sizeof (prstat.pr_reg);
       offset   = offsetof (prstatus32_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
@@ -6459,7 +7091,7 @@ elfcore_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 
   /* Make a ".reg/999" section and a ".reg" section.  */
   return _bfd_elfcore_make_pseudosection (abfd, ".reg",
-                                         raw_size, note->descpos + offset);
+                                         size, note->descpos + offset);
 }
 #endif /* defined (HAVE_PRSTATUS_T) */
 
@@ -6663,13 +7295,13 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
 
 #if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
-  sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
+  sect->size = sizeof (lwpstat.pr_context.uc_mcontext.gregs);
   sect->filepos = note->descpos
     + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs);
 #endif
 
 #if defined (HAVE_LWPSTATUS_T_PR_REG)
-  sect->_raw_size = sizeof (lwpstat.pr_reg);
+  sect->size = sizeof (lwpstat.pr_reg);
   sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
 #endif
 
@@ -6693,13 +7325,13 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
 
 #if defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
-  sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
+  sect->size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs);
   sect->filepos = note->descpos
     + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs);
 #endif
 
 #if defined (HAVE_LWPSTATUS_T_PR_FPREG)
-  sect->_raw_size = sizeof (lwpstat.pr_fpreg);
+  sect->size = sizeof (lwpstat.pr_fpreg);
   sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
 #endif
 
@@ -6735,7 +7367,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
 
     case NOTE_INFO_THREAD:
       /* Make a ".reg/999" section.  */
-      sprintf (buf, ".reg/%d", pstatus.data.thread_info.tid);
+      sprintf (buf, ".reg/%ld", (long) pstatus.data.thread_info.tid);
 
       len = strlen (buf) + 1;
       name = bfd_alloc (abfd, len);
@@ -6748,7 +7380,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       if (sect == NULL)
        return FALSE;
 
-      sect->_raw_size = sizeof (pstatus.data.thread_info.thread_context);
+      sect->size = sizeof (pstatus.data.thread_info.thread_context);
       sect->filepos = (note->descpos
                       + offsetof (struct win32_pstatus,
                                   data.thread_info.thread_context));
@@ -6762,7 +7394,8 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
 
     case NOTE_INFO_MODULE:
       /* Make a ".module/xxxxxxxx" section.  */
-      sprintf (buf, ".module/%08x", pstatus.data.module_info.base_address);
+      sprintf (buf, ".module/%08lx",
+              (long) pstatus.data.module_info.base_address);
 
       len = strlen (buf) + 1;
       name = bfd_alloc (abfd, len);
@@ -6776,7 +7409,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
       if (sect == NULL)
        return FALSE;
 
-      sect->_raw_size = note->descsz;
+      sect->size = note->descsz;
       sect->filepos = note->descpos;
       sect->flags = SEC_HAS_CONTENTS;
       sect->alignment_power = 2;
@@ -6852,7 +7485,7 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
 
        if (sect == NULL)
          return FALSE;
-       sect->_raw_size = note->descsz;
+       sect->size = note->descsz;
        sect->filepos = note->descpos;
        sect->flags = SEC_HAS_CONTENTS;
        sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
@@ -6994,7 +7627,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
     elf_tdata (abfd)->core_lwpid = *tid;
 
   /* Make a ".qnx_core_status/%d" section.  */
-  sprintf (buf, ".qnx_core_status/%d", *tid);
+  sprintf (buf, ".qnx_core_status/%ld", (long) *tid);
 
   name = bfd_alloc (abfd, strlen (buf) + 1);
   if (name == NULL)
@@ -7005,7 +7638,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
   if (sect == NULL)
     return FALSE;
 
-  sect->_raw_size       = note->descsz;
+  sect->size            = note->descsz;
   sect->filepos         = note->descpos;
   sect->flags           = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
@@ -7014,14 +7647,17 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
 }
 
 static bfd_boolean
-elfcore_grok_nto_gregs (bfd *abfd, Elf_Internal_Note *note, pid_t tid)
+elfcore_grok_nto_regs (bfd *abfd,
+                      Elf_Internal_Note *note,
+                      pid_t tid,
+                      char *base)
 {
   char buf[100];
   char *name;
   asection *sect;
 
-  /* Make a ".reg/%d" section.  */
-  sprintf (buf, ".reg/%d", tid);
+  /* Make a "(base)/%d" section.  */
+  sprintf (buf, "%s/%ld", base, (long) tid);
 
   name = bfd_alloc (abfd, strlen (buf) + 1);
   if (name == NULL)
@@ -7032,14 +7668,14 @@ elfcore_grok_nto_gregs (bfd *abfd, Elf_Internal_Note *note, pid_t tid)
   if (sect == NULL)
     return FALSE;
 
-  sect->_raw_size       = note->descsz;
+  sect->size            = note->descsz;
   sect->filepos         = note->descpos;
   sect->flags           = SEC_HAS_CONTENTS;
   sect->alignment_power = 2;
 
   /* This is the current thread.  */
   if (elf_tdata (abfd)->core_lwpid == tid)
-    return elfcore_maybe_make_sect (abfd, ".reg", sect);
+    return elfcore_maybe_make_sect (abfd, base, sect);
 
   return TRUE;
 }
@@ -7059,11 +7695,16 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note)
 
   switch (note->type)
     {
-    case BFD_QNT_CORE_INFO:   return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note);
-    case BFD_QNT_CORE_STATUS: return elfcore_grok_nto_status (abfd, note, &tid);
-    case BFD_QNT_CORE_GREG:   return elfcore_grok_nto_gregs (abfd, note, tid);
-    case BFD_QNT_CORE_FPREG:  return elfcore_grok_prfpreg (abfd, note);
-    default:                  return TRUE;
+    case BFD_QNT_CORE_INFO:
+      return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note);
+    case BFD_QNT_CORE_STATUS:
+      return elfcore_grok_nto_status (abfd, note, &tid);
+    case BFD_QNT_CORE_GREG:
+      return elfcore_grok_nto_regs (abfd, note, tid, ".reg");
+    case BFD_QNT_CORE_FPREG:
+      return elfcore_grok_nto_regs (abfd, note, tid, ".reg2");
+    default:
+      return TRUE;
     }
 }
 
@@ -7443,9 +8084,18 @@ _bfd_elf_rela_local_sym (bfd *abfd,
       rel->r_addend =
        _bfd_merged_section_offset (abfd, psec,
                                    elf_section_data (sec)->sec_info,
-                                   sym->st_value + rel->r_addend,
-                                   0);
-      sec = *psec;
+                                   sym->st_value + rel->r_addend);
+      if (sec != *psec)
+       {
+         /* If we have changed the section, and our original section is
+            marked with SEC_EXCLUDE, it means that the original
+            SEC_MERGE section has been completely subsumed in some
+            other SEC_MERGE section.  In this case, we need to leave
+            some info around for --emit-relocs.  */
+         if ((sec->flags & SEC_EXCLUDE) != 0)
+           sec->kept_section = *psec;
+         sec = *psec;
+       }
       rel->r_addend -= relocation;
       rel->r_addend += sec->output_section->vma + sec->output_offset;
     }
@@ -7465,7 +8115,7 @@ _bfd_elf_rel_local_sym (bfd *abfd,
 
   return _bfd_merged_section_offset (abfd, psec,
                                     elf_section_data (sec)->sec_info,
-                                    sym->st_value + addend, 0);
+                                    sym->st_value + addend);
 }
 
 bfd_vma
@@ -7474,17 +8124,13 @@ _bfd_elf_section_offset (bfd *abfd,
                         asection *sec,
                         bfd_vma offset)
 {
-  struct bfd_elf_section_data *sec_data;
-
-  sec_data = elf_section_data (sec);
   switch (sec->sec_info_type)
     {
     case ELF_INFO_TYPE_STABS:
-      return _bfd_stab_section_offset (abfd,
-                                      &elf_hash_table (info)->merge_info,
-                                      sec, &sec_data->sec_info, offset);
+      return _bfd_stab_section_offset (sec, elf_section_data (sec)->sec_info,
+                                      offset);
     case ELF_INFO_TYPE_EH_FRAME:
-      return _bfd_elf_eh_frame_section_offset (abfd, sec, offset);
+      return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
     default:
       return offset;
     }
@@ -7508,8 +8154,305 @@ bfd_elf_bfd_from_remote_memory
   (bfd *templ,
    bfd_vma ehdr_vma,
    bfd_vma *loadbasep,
-   int (*target_read_memory) (bfd_vma, char *, int))
+   int (*target_read_memory) (bfd_vma, bfd_byte *, int))
 {
   return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
     (templ, ehdr_vma, loadbasep, target_read_memory);
 }
+\f
+long
+_bfd_elf_get_synthetic_symtab (bfd *abfd,
+                              long symcount ATTRIBUTE_UNUSED,
+                              asymbol **syms ATTRIBUTE_UNUSED,
+                              long dynsymcount,
+                              asymbol **dynsyms,
+                              asymbol **ret)
+{
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  asection *relplt;
+  asymbol *s;
+  const char *relplt_name;
+  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  arelent *p;
+  long count, i, n;
+  size_t size;
+  Elf_Internal_Shdr *hdr;
+  char *names;
+  asection *plt;
+
+  *ret = NULL;
+
+  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+    return 0;
+
+  if (dynsymcount <= 0)
+    return 0;
+
+  if (!bed->plt_sym_val)
+    return 0;
+
+  relplt_name = bed->relplt_name;
+  if (relplt_name == NULL)
+    relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt";
+  relplt = bfd_get_section_by_name (abfd, relplt_name);
+  if (relplt == NULL)
+    return 0;
+
+  hdr = &elf_section_data (relplt)->this_hdr;
+  if (hdr->sh_link != elf_dynsymtab (abfd)
+      || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
+    return 0;
+
+  plt = bfd_get_section_by_name (abfd, ".plt");
+  if (plt == NULL)
+    return 0;
+
+  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+    return -1;
+
+  count = relplt->size / hdr->sh_entsize;
+  size = count * sizeof (asymbol);
+  p = relplt->relocation;
+  for (i = 0; i < count; i++, s++, p++)
+    size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+
+  s = *ret = bfd_malloc (size);
+  if (s == NULL)
+    return -1;
+
+  names = (char *) (s + count);
+  p = relplt->relocation;
+  n = 0;
+  for (i = 0; i < count; i++, s++, p++)
+    {
+      size_t len;
+      bfd_vma addr;
+
+      addr = bed->plt_sym_val (i, plt, p);
+      if (addr == (bfd_vma) -1)
+       continue;
+
+      *s = **p->sym_ptr_ptr;
+      s->section = plt;
+      s->value = addr - plt->vma;
+      s->name = names;
+      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;
+    }
+
+  return n;
+}
+
+/* Sort symbol by binding and section. We want to put definitions
+   sorted by section at the beginning.  */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+  const Elf_Internal_Sym *s1;
+  const Elf_Internal_Sym *s2;
+  int shndx;
+
+  /* Make sure that undefined symbols are at the end.  */
+  s1 = (const Elf_Internal_Sym *) arg1;
+  if (s1->st_shndx == SHN_UNDEF)
+    return 1;
+  s2 = (const Elf_Internal_Sym *) arg2;
+  if (s2->st_shndx == SHN_UNDEF)
+    return -1;
+
+  /* Sorted by section index.  */
+  shndx = s1->st_shndx - s2->st_shndx;
+  if (shndx != 0)
+    return shndx;
+
+  /* Sorted by binding.  */
+  return ELF_ST_BIND (s1->st_info)  - ELF_ST_BIND (s2->st_info);
+}
+
+struct elf_symbol
+{
+  Elf_Internal_Sym *sym;
+  const char *name;
+};
+
+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);
+}
+
+/* Check if 2 sections define the same set of local and global
+   symbols.  */
+
+bfd_boolean
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
+{
+  bfd *bfd1, *bfd2;
+  const struct elf_backend_data *bed1, *bed2;
+  Elf_Internal_Shdr *hdr1, *hdr2;
+  bfd_size_type symcount1, symcount2;
+  Elf_Internal_Sym *isymbuf1, *isymbuf2;
+  Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym;
+  Elf_Internal_Sym *isymend;
+  struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL;
+  bfd_size_type count1, count2, i;
+  int shndx1, shndx2;
+  bfd_boolean result;
+
+  bfd1 = sec1->owner;
+  bfd2 = sec2->owner;
+
+  /* If both are .gnu.linkonce sections, they have to have the same
+     section name.  */
+  if (strncmp (sec1->name, ".gnu.linkonce",
+              sizeof ".gnu.linkonce" - 1) == 0
+      && strncmp (sec2->name, ".gnu.linkonce",
+                 sizeof ".gnu.linkonce" - 1) == 0)
+    return strcmp (sec1->name + sizeof ".gnu.linkonce",
+                  sec2->name + sizeof ".gnu.linkonce") == 0;
+
+  /* Both sections have to be in ELF.  */
+  if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
+      || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
+    return FALSE;
+
+  if (elf_section_type (sec1) != elf_section_type (sec2))
+    return FALSE;
+
+  if ((elf_section_flags (sec1) & SHF_GROUP) != 0
+      && (elf_section_flags (sec2) & SHF_GROUP) != 0)
+    {
+      /* If both are members of section groups, they have to have the
+        same group name.  */
+      if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
+       return FALSE;
+    }
+
+  shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
+  shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
+  if (shndx1 == -1 || shndx2 == -1)
+    return FALSE;
+
+  bed1 = get_elf_backend_data (bfd1);
+  bed2 = get_elf_backend_data (bfd2);
+  hdr1 = &elf_tdata (bfd1)->symtab_hdr;
+  symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
+  hdr2 = &elf_tdata (bfd2)->symtab_hdr;
+  symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
+
+  if (symcount1 == 0 || symcount2 == 0)
+    return FALSE;
+
+  isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+                                  NULL, NULL, NULL);
+  isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+                                  NULL, NULL, NULL);
+
+  result = FALSE;
+  if (isymbuf1 == NULL || isymbuf2 == NULL)
+    goto done;
+
+  /* Sort symbols by binding and section. Global definitions are at
+     the beginning.  */
+  qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
+        elf_sort_elf_symbol);
+  qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
+        elf_sort_elf_symbol);
+
+  /* Count definitions in the section.  */
+  count1 = 0;
+  for (isym = isymbuf1, isymend = isym + symcount1;
+       isym < isymend; isym++)
+    {
+      if (isym->st_shndx == (unsigned int) shndx1)
+       {
+         if (count1 == 0)
+           isymstart1 = isym;
+         count1++;
+       }
+
+      if (count1 && isym->st_shndx != (unsigned int) shndx1)
+       break;
+    }
+
+  count2 = 0;
+  for (isym = isymbuf2, isymend = isym + symcount2;
+       isym < isymend; isym++)
+    {
+      if (isym->st_shndx == (unsigned int) shndx2)
+       {
+         if (count2 == 0)
+           isymstart2 = isym;
+         count2++;
+       }
+
+      if (count2 && isym->st_shndx != (unsigned int) shndx2)
+       break;
+    }
+
+  if (count1 == 0 || count2 == 0 || count1 != count2)
+    goto done;
+
+  symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+  symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+
+  if (symtable1 == NULL || symtable2 == NULL)
+    goto done;
+
+  symp = symtable1;
+  for (isym = isymstart1, isymend = isym + count1;
+       isym < isymend; isym++)
+    {
+      symp->sym = isym;
+      symp->name = bfd_elf_string_from_elf_section (bfd1,
+                                                   hdr1->sh_link,
+                                                   isym->st_name);
+      symp++;
+    }
+  symp = symtable2;
+  for (isym = isymstart2, isymend = isym + count1;
+       isym < isymend; isym++)
+    {
+      symp->sym = isym;
+      symp->name = bfd_elf_string_from_elf_section (bfd2,
+                                                   hdr2->sh_link,
+                                                   isym->st_name);
+      symp++;
+    }
+  
+  /* Sort symbol by name.  */
+  qsort (symtable1, count1, sizeof (struct elf_symbol),
+        elf_sym_name_compare);
+  qsort (symtable2, count1, sizeof (struct elf_symbol),
+        elf_sym_name_compare);
+
+  for (i = 0; i < count1; i++)
+    /* Two symbols must have the same binding, type and name.  */
+    if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info
+       || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other
+       || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+      goto done;
+
+  result = TRUE;
+
+done:
+  if (symtable1)
+    free (symtable1);
+  if (symtable2)
+    free (symtable2);
+  if (isymbuf1)
+    free (isymbuf1);
+  if (isymbuf2)
+    free (isymbuf2);
+
+  return result;
+}
This page took 0.067528 seconds and 4 git commands to generate.