* elf64-ppc.c (ppc_add_stub): Replace strcpy/strncpy with memcpy.
[deliverable/binutils-gdb.git] / bfd / elf.c
index cf51607bcbe75b6a6adc7d1d2a533f29fcdaf836..5472a16379bb57fb34ceff1672e92dfe953fcca2 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1,26 +1,25 @@
 /* ELF executable support for BFD.
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
-This file is part of BFD, the Binary File Descriptor library.
+   This file is part of BFD, the Binary File Descriptor library.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-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.  */
+   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.  */
 
-/*
-
-SECTION
+/*  SECTION
+    
        ELF backends
 
        BFD support for ELF formats is being worked on.
@@ -29,8 +28,7 @@ SECTION
 
        Documentation of the internals of the support code still needs
        to be written.  The code is changing quickly enough that we
-       haven't bothered yet.
- */
+       haven't bothered yet.  */
 
 /* For sparc64-cross-sparc32.  */
 #define _SYSCALL32
@@ -52,9 +50,10 @@ static boolean prep_headers PARAMS ((bfd *));
 static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
 static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
 static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
+static const char *group_signature PARAMS ((bfd *, Elf_Internal_Shdr *));
 static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
+static void merge_sections_remove_hook PARAMS ((bfd *, asection *));
 static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
-static void set_group_contents PARAMS ((bfd *, asection *, PTR));
 static boolean assign_section_numbers PARAMS ((bfd *));
 static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
 static boolean elf_map_symbols PARAMS ((bfd *));
@@ -71,6 +70,11 @@ static boolean elfcore_grok_prfpreg PARAMS ((bfd *, Elf_Internal_Note *));
 static boolean elfcore_grok_prxfpreg PARAMS ((bfd *, Elf_Internal_Note *));
 static boolean elfcore_grok_note PARAMS ((bfd *, Elf_Internal_Note *));
 
+static boolean elfcore_netbsd_get_lwpid PARAMS ((Elf_Internal_Note *, int *));
+static boolean elfcore_grok_netbsd_procinfo PARAMS ((bfd *,
+                                                    Elf_Internal_Note *));
+static boolean elfcore_grok_netbsd_note PARAMS ((bfd *, Elf_Internal_Note *));
+
 /* Swap version information in and out.  The version information is
    currently size independent.  If that ever changes, this code will
    need to move into elfcode.h.  */
@@ -357,6 +361,66 @@ typedef union elf_internal_group {
   unsigned int flags;
 } Elf_Internal_Group;
 
+/* Return the name of the group signature symbol.  Why isn't the
+   signature just a string?  */
+
+static const char *
+group_signature (abfd, ghdr)
+     bfd *abfd;
+     Elf_Internal_Shdr *ghdr;
+{
+  struct elf_backend_data *bed;
+  file_ptr pos;
+  bfd_size_type amt;
+  Elf_Internal_Shdr *hdr;
+  Elf_Internal_Shdr *shndx_hdr;
+  unsigned char esym[sizeof (Elf64_External_Sym)];
+  Elf_External_Sym_Shndx eshndx;
+  Elf_Internal_Sym isym;
+  unsigned int iname;
+  unsigned int shindex;
+
+  /* First we need to ensure the symbol table is available.  */
+  if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
+    return NULL;
+
+  /* Go read the symbol.  */
+  hdr = &elf_tdata (abfd)->symtab_hdr;
+  bed = get_elf_backend_data (abfd);
+  amt = bed->s->sizeof_sym;
+  pos = hdr->sh_offset + ghdr->sh_info * amt;
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread (esym, amt, abfd) != amt)
+    return NULL;
+
+  /* And possibly the symbol section index extension.  */
+  shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (elf_elfsections (abfd) != NULL
+      && elf_elfsections (abfd)[shndx_hdr->sh_link] == hdr)
+    {
+      amt = sizeof (Elf_External_Sym_Shndx);
+      pos = shndx_hdr->sh_offset + ghdr->sh_info * amt;
+      if (bfd_seek (abfd, pos, SEEK_SET) != 0
+         || bfd_bread ((PTR) &eshndx, amt, abfd) != amt)
+       return NULL;
+    }
+
+  /* Convert to internal format.  */
+  (*bed->s->swap_symbol_in) (abfd, (const PTR *) &esym, (const PTR *) &eshndx,
+                            &isym);
+
+  /* Look up the symbol name.  */
+  iname = isym.st_name;
+  shindex = hdr->sh_link;
+  if (iname == 0 && ELF_ST_TYPE (isym.st_info) == STT_SECTION)
+    {
+      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);
+}
+
 /* Set next_in_group list pointer, and group name for NEWSECT.  */
 
 static boolean
@@ -375,7 +439,7 @@ setup_group (abfd, hdr, newsect)
 
       /* First count the number of groups.  If we have a SHT_GROUP
         section with just a flag word (ie. sh_size is 4), ignore it.  */
-      shnum = elf_elfheader (abfd)->e_shnum;
+      shnum = elf_numsections (abfd);
       num_group = 0;
       for (i = 0; i < shnum; i++)
        {
@@ -436,6 +500,9 @@ setup_group (abfd, hdr, newsect)
                      if (src == shdr->contents)
                        {
                          dest->flags = idx;
+                         if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+                           shdr->bfd_section->flags
+                             |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
                          break;
                        }
                      if (idx >= shnum)
@@ -488,32 +555,22 @@ setup_group (abfd, hdr, newsect)
                  }
                else
                  {
-                   struct elf_backend_data *bed;
-                   file_ptr pos;
-                   unsigned char ename[4];
-                   unsigned long iname;
                    const char *gname;
 
-                   /* Humbug.  Get the name from the group signature
-                      symbol.  Why isn't the signature just a string?
-                      Fortunately, the name index is at the same
-                      place in the external symbol for both 32 and 64
-                      bit ELF.  */
-                   bed = get_elf_backend_data (abfd);
-                   pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
-                   pos += shdr->sh_info * bed->s->sizeof_sym;
-                   if (bfd_seek (abfd, pos, SEEK_SET) != 0
-                       || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+                   gname = group_signature (abfd, shdr);
+                   if (gname == NULL)
                      return false;
-                   iname = H_GET_32 (abfd, ename);
-                   gname = elf_string_from_elf_strtab (abfd, iname);
                    elf_group_name (newsect) = gname;
 
                    /* Start a circular list with one element.  */
                    elf_next_in_group (newsect) = newsect;
                  }
+
+               /* If the group section has been created, point to the
+                  new member.  */
                if (shdr->bfd_section != NULL)
                  elf_next_in_group (shdr->bfd_section) = newsect;
+
                i = num_group - 1;
                break;
              }
@@ -528,6 +585,25 @@ setup_group (abfd, hdr, newsect)
   return true;
 }
 
+boolean
+bfd_elf_discard_group (abfd, group)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *group;
+{
+  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;
+    }
+  return true;
+}
+
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -587,6 +663,8 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
   if (hdr->sh_flags & SHF_GROUP)
     if (!setup_group (abfd, hdr, newsect))
       return false;
+  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.  */
@@ -614,7 +692,8 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
      The symbols will be defined as weak, so that multiple definitions
      are permitted.  The GNU linker extension is to actually discard
      all but one of the sections.  */
-  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+      && elf_next_in_group (newsect) == NULL)
     flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
   bed = get_elf_backend_data (abfd);
@@ -648,27 +727,44 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name)
                 offset plus size lies within the segment's memory
                 span and, if the section is loaded, the extent of the
                 loaded data lies within the extent of the segment.  
-                If the p_paddr field is not set, we don't alter the 
-                LMA.  */
+
+                Note - we used to check the p_paddr field as well, and
+                refuse to set the LMA if it was 0.  This is wrong
+                though, as a perfectly valid initialised segment can
+                have a p_paddr of zero.  Some architectures, eg ARM,
+                place special significance on the address 0 and
+                executables need to be able to have a segment which
+                covers this address.  */
              if (phdr->p_type == PT_LOAD
-                 && phdr->p_paddr
                  && (bfd_vma) hdr->sh_offset >= phdr->p_offset
                  && (hdr->sh_offset + hdr->sh_size
                      <= phdr->p_offset + phdr->p_memsz)
                  && ((flags & SEC_LOAD) == 0
-                     || (phdr->p_offset + phdr->p_filesz
-                         >= hdr->sh_offset + hdr->sh_size)))
+                     || (hdr->sh_offset + hdr->sh_size
+                         <= phdr->p_offset + phdr->p_filesz)))
                {
-                 /* We used to do a relative adjustment here, but
-                    that doesn't work if the segment is packed with
-                    code from multiple VMAs.  Instead we calculate
-                    the LMA absoultely, based on the LMA of the
-                    segment (it is assumed that the segment will
-                    contain sections with contiguous LMAs, even if
-                    the VMAs are not).  */
-                 newsect->lma = phdr->p_paddr
-                   + hdr->sh_offset - phdr->p_offset;
-                 break;
+                 if ((flags & SEC_LOAD) == 0)
+                   newsect->lma = (phdr->p_paddr
+                                   + hdr->sh_addr - phdr->p_vaddr);
+                 else
+                   /* We used to use the same adjustment for SEC_LOAD
+                      sections, but that doesn't work if the segment
+                      is packed with code from multiple VMAs.
+                      Instead we calculate the section LMA based on
+                      the segment LMA.  It is assumed that the
+                      segment will contain sections with contiguous
+                      LMAs, even if the VMAs are not.  */
+                   newsect->lma = (phdr->p_paddr
+                                   + hdr->sh_offset - phdr->p_offset);
+
+                 /* With contiguous segments, we can't tell from file
+                    offsets whether a section with zero size should
+                    be placed at the end of one segment or the
+                    beginning of the next.  Decide based on vaddr.  */
+                 if (hdr->sh_addr >= phdr->p_vaddr
+                     && (hdr->sh_addr + hdr->sh_size
+                         <= phdr->p_vaddr + phdr->p_memsz))
+                   break;
                }
            }
        }
@@ -708,11 +804,11 @@ bfd_elf_find_section (abfd, name)
   i_shdrp = elf_elfsections (abfd);
   if (i_shdrp != NULL)
     {
-      shstrtab = bfd_elf_get_str_section
-       (abfd, elf_elfheader (abfd)->e_shstrndx);
+      shstrtab = bfd_elf_get_str_section (abfd,
+                                         elf_elfheader (abfd)->e_shstrndx);
       if (shstrtab != NULL)
        {
-         max = elf_elfheader (abfd)->e_shnum;
+         max = elf_numsections (abfd);
          for (i = 1; i < max; i++)
            if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name))
              return i_shdrp[i];
@@ -765,6 +861,20 @@ bfd_elf_generic_reloc (abfd,
   return bfd_reloc_continue;
 }
 \f
+/* Make sure sec_info_type is cleared if sec_info is cleared too.  */
+
+static void
+merge_sections_remove_hook (abfd, sec)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+{
+  struct bfd_elf_section_data *sec_data;
+    
+  sec_data = elf_section_data (sec);
+  BFD_ASSERT (sec_data->sec_info_type == ELF_INFO_TYPE_MERGE);
+  sec_data->sec_info_type = ELF_INFO_TYPE_NONE;
+}
+
 /* Finish SHF_MERGE section merging.  */
 
 boolean
@@ -775,10 +885,46 @@ _bfd_elf_merge_sections (abfd, info)
   if (!is_elf_hash_table (info))
     return false;
   if (elf_hash_table (info)->merge_info)
-    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info);
+    _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info,
+                        merge_sections_remove_hook);
   return true;
 }
+
+void
+_bfd_elf_link_just_syms (sec, info)
+     asection *sec;
+     struct bfd_link_info *info;
+{
+  sec->output_section = bfd_abs_section_ptr;
+  sec->output_offset = sec->vma;
+  if (!is_elf_hash_table (info))
+    return;
+
+  elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
+}
 \f
+/* Copy the program header and other data from one object module to
+   another.  */
+
+boolean
+_bfd_elf_copy_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return true;
+
+  BFD_ASSERT (!elf_flags_init (obfd)
+             || (elf_elfheader (obfd)->e_flags
+                 == elf_elfheader (ibfd)->e_flags));
+
+  elf_gp (obfd) = elf_gp (ibfd);
+  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+  elf_flags_init (obfd) = true;
+  return true;
+}
+
 /* Print out the program headers.  */
 
 boolean
@@ -812,6 +958,8 @@ _bfd_elf_print_private_bfd_data (abfd, farg)
            case PT_NOTE: pt = "NOTE"; break;
            case PT_SHLIB: pt = "SHLIB"; break;
            case PT_PHDR: pt = "PHDR"; break;
+           case PT_TLS: pt = "TLS"; break;
+           case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
            default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break;
            }
          fprintf (f, "%8s off    0x", pt);
@@ -1242,14 +1390,23 @@ _bfd_elf_link_hash_copy_indirect (dir, ind)
 }
 
 void
-_bfd_elf_link_hash_hide_symbol (info, h)
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+_bfd_elf_link_hash_hide_symbol (info, h, force_local)
+     struct bfd_link_info *info;
      struct elf_link_hash_entry *h;
+     boolean force_local;
 {
-  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
   h->plt.offset = (bfd_vma) -1;
-  if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)
-    h->dynindx = -1;
+  h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+  if (force_local)
+    {
+      h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+      if (h->dynindx != -1)
+       {
+         h->dynindx = -1;
+         _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                 h->dynstr_index);
+       }
+    }
 }
 
 /* Initialize an ELF linker hash table.  */
@@ -1273,6 +1430,7 @@ _bfd_elf_link_hash_table_init (table, abfd, newfunc)
   table->bucketcount = 0;
   table->needed = NULL;
   table->runpath = NULL;
+  table->loaded = NULL;
   table->hgot = NULL;
   table->stab_info = NULL;
   table->merge_info = NULL;
@@ -1292,13 +1450,13 @@ _bfd_elf_link_hash_table_create (abfd)
   struct elf_link_hash_table *ret;
   bfd_size_type amt = sizeof (struct elf_link_hash_table);
 
-  ret = (struct elf_link_hash_table *) bfd_alloc (abfd, amt);
+  ret = (struct elf_link_hash_table *) bfd_malloc (amt);
   if (ret == (struct elf_link_hash_table *) NULL)
     return NULL;
 
   if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc))
     {
-      bfd_release (abfd, ret);
+      free (ret);
       return NULL;
     }
 
@@ -1492,7 +1650,7 @@ bfd_section_from_shdr (abfd, shindex)
   Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex];
   Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  char *name;
+  const char *name;
 
   name = elf_string_from_elf_strtab (abfd, hdr->sh_name);
 
@@ -1507,6 +1665,9 @@ bfd_section_from_shdr (abfd, shindex)
     case SHT_NOBITS:   /* .bss section.  */
     case SHT_HASH:     /* .hash section.  */
     case SHT_NOTE:     /* .note section.  */
+    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_SYMTAB:           /* A symbol table */
@@ -1548,6 +1709,20 @@ bfd_section_from_shdr (abfd, shindex)
         section, so that objcopy can handle it.  */
       return _bfd_elf_make_section_from_shdr (abfd, hdr, name);
 
+    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;
+
+      elf_symtab_shndx (abfd) = shindex;
+      elf_tdata (abfd)->symtab_shndx_hdr = *hdr;
+      elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr;
+      return true;
+
     case SHT_STRTAB:           /* A string table */
       if (hdr->bfd_section != NULL)
        return true;
@@ -1558,9 +1733,10 @@ bfd_section_from_shdr (abfd, shindex)
          return true;
        }
       {
-       unsigned int i;
+       unsigned int i, num_sec;
 
-       for (i = 1; i < ehdr->e_shnum; i++)
+       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)
@@ -1606,9 +1782,11 @@ bfd_section_from_shdr (abfd, shindex)
       {
        asection *target_sect;
        Elf_Internal_Shdr *hdr2;
+       unsigned int num_sec = elf_numsections (abfd);
 
        /* Check for a bogus link to avoid crashing.  */
-       if (hdr->sh_link >= ehdr->e_shnum)
+       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)"),
@@ -1626,11 +1804,11 @@ bfd_section_from_shdr (abfd, shindex)
        if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB
            && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM)
          {
-           int scan;
+           unsigned int scan;
            int found;
 
            found = 0;
-           for (scan = 1; scan < ehdr->e_shnum; scan++)
+           for (scan = 1; scan < num_sec; scan++)
              {
                if (elf_elfsections (abfd)[scan]->sh_type == SHT_SYMTAB
                    || elf_elfsections (abfd)[scan]->sh_type == SHT_DYNSYM)
@@ -1716,7 +1894,12 @@ bfd_section_from_shdr (abfd, shindex)
       return true;
 
     case SHT_GROUP:
-      /* Make a section for objcopy and relocatable links.  */
+      /* We need a BFD section for objcopy and relocatable linking,
+        and it's handy to have the signature available as the section
+        name.  */
+      name = group_signature (abfd, hdr);
+      if (name == NULL)
+       return false;
       if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
        return false;
       if (hdr->contents != NULL)
@@ -1725,6 +1908,10 @@ bfd_section_from_shdr (abfd, shindex)
          unsigned int n_elt = hdr->sh_size / 4;
          asection *s;
 
+         if (idx->flags & GRP_COMDAT)
+           hdr->bfd_section->flags
+             |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
          while (--n_elt != 0)
            if ((s = (++idx)->shdr->bfd_section) != NULL
                && elf_next_in_group (s) != NULL)
@@ -1747,6 +1934,78 @@ bfd_section_from_shdr (abfd, shindex)
   return true;
 }
 
+/* Return the section for the local symbol specified by ABFD, R_SYMNDX.
+   Return SEC for sections that have no elf section, and NULL on error.  */
+
+asection *
+bfd_section_from_r_symndx (abfd, cache, sec, r_symndx)
+     bfd *abfd;
+     struct sym_sec_cache *cache;
+     asection *sec;
+     unsigned long r_symndx;
+{
+  unsigned char esym_shndx[4];
+  unsigned int isym_shndx;
+  Elf_Internal_Shdr *symtab_hdr;
+  file_ptr pos;
+  bfd_size_type amt;
+  unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
+
+  if (cache->abfd == abfd && cache->indx[ent] == r_symndx)
+    return cache->sec[ent];
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  pos = symtab_hdr->sh_offset;
+  if (get_elf_backend_data (abfd)->s->sizeof_sym
+      == sizeof (Elf64_External_Sym))
+    {
+      pos += r_symndx * sizeof (Elf64_External_Sym);
+      pos += offsetof (Elf64_External_Sym, st_shndx);
+      amt = sizeof (((Elf64_External_Sym *) 0)->st_shndx);
+    }
+  else
+    {
+      pos += r_symndx * sizeof (Elf32_External_Sym);
+      pos += offsetof (Elf32_External_Sym, st_shndx);
+      amt = sizeof (((Elf32_External_Sym *) 0)->st_shndx);
+    }
+  if (bfd_seek (abfd, pos, SEEK_SET) != 0
+      || bfd_bread ((PTR) esym_shndx, amt, abfd) != amt)
+    return NULL;
+  isym_shndx = H_GET_16 (abfd, esym_shndx);
+
+  if (isym_shndx == SHN_XINDEX)
+    {
+      Elf_Internal_Shdr *shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+      if (shndx_hdr->sh_size != 0)
+       {
+         pos = shndx_hdr->sh_offset;
+         pos += r_symndx * sizeof (Elf_External_Sym_Shndx);
+         amt = sizeof (Elf_External_Sym_Shndx);
+         if (bfd_seek (abfd, pos, SEEK_SET) != 0
+             || bfd_bread ((PTR) esym_shndx, amt, abfd) != amt)
+           return NULL;
+         isym_shndx = H_GET_32 (abfd, esym_shndx);
+       }
+    }
+
+  if (cache->abfd != abfd)
+    {
+      memset (cache->indx, -1, sizeof (cache->indx));
+      cache->abfd = abfd;
+    }
+  cache->indx[ent] = r_symndx;
+  cache->sec[ent] = sec;
+  if (isym_shndx < SHN_LORESERVE || isym_shndx > SHN_HIRESERVE)
+    {
+      asection *s;
+      s = bfd_section_from_elf_index (abfd, isym_shndx);
+      if (s != NULL)
+       cache->sec[ent] = s;
+    }
+  return cache->sec[ent];
+}
+
 /* Given an ELF section number, retrieve the corresponding BFD
    section.  */
 
@@ -1755,8 +2014,7 @@ bfd_section_from_elf_index (abfd, index)
      bfd *abfd;
      unsigned int index;
 {
-  BFD_ASSERT (index > 0 && index < SHN_LORESERVE);
-  if (index >= elf_elfheader (abfd)->e_shnum)
+  if (index >= elf_numsections (abfd))
     return NULL;
   return elf_elfsections (abfd)[index]->bfd_section;
 }
@@ -1813,16 +2071,18 @@ _bfd_elf_make_section_from_phdr (abfd, hdr, index, typename)
   asection *newsect;
   char *name;
   char namebuf[64];
+  size_t len;
   int split;
 
   split = ((hdr->p_memsz > 0)
            && (hdr->p_filesz > 0)
            && (hdr->p_memsz > hdr->p_filesz));
   sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
-  name = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
+  len = strlen (namebuf) + 1;
+  name = bfd_alloc (abfd, (bfd_size_type) len);
   if (!name)
     return false;
-  strcpy (name, namebuf);
+  memcpy (name, namebuf, len);
   newsect = bfd_make_section (abfd, name);
   if (newsect == NULL)
     return false;
@@ -1850,10 +2110,11 @@ _bfd_elf_make_section_from_phdr (abfd, hdr, index, typename)
   if (split)
     {
       sprintf (namebuf, "%s%db", typename, index);
-      name = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
+      len = strlen (namebuf) + 1;
+      name = bfd_alloc (abfd, (bfd_size_type) len);
       if (!name)
        return false;
-      strcpy (name, namebuf);
+      memcpy (name, namebuf, len);
       newsect = bfd_make_section (abfd, name);
       if (newsect == NULL)
        return false;
@@ -1939,8 +2200,8 @@ _bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p)
     return false;
   sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
   rel_hdr->sh_name =
-    (unsigned int) _bfd_stringtab_add (elf_shstrtab (abfd), name,
-                                      true, false);
+    (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
+                                       false);
   if (rel_hdr->sh_name == (unsigned int) -1)
     return false;
   rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
@@ -1977,9 +2238,8 @@ elf_fake_sections (abfd, asect, failedptrarg)
 
   this_hdr = &elf_section_data (asect)->this_hdr;
 
-  this_hdr->sh_name = (unsigned long) _bfd_stringtab_add (elf_shstrtab (abfd),
-                                                         asect->name,
-                                                         true, false);
+  this_hdr->sh_name = (unsigned long) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+                                                          asect->name, false);
   if (this_hdr->sh_name == (unsigned long) -1)
     {
       *failedptr = true;
@@ -2034,6 +2294,12 @@ elf_fake_sections (abfd, asect, failedptrarg)
       this_hdr->sh_type = SHT_REL;
       this_hdr->sh_entsize = bed->s->sizeof_rel;
     }
+  else if (strcmp (asect->name, ".init_array") == 0)
+    this_hdr->sh_type = SHT_INIT_ARRAY;
+  else if (strcmp (asect->name, ".fini_array") == 0)
+    this_hdr->sh_type = SHT_FINI_ARRAY;
+  else if (strcmp (asect->name, ".preinit_array") == 0)
+    this_hdr->sh_type = SHT_PREINIT_ARRAY;
   else if (strncmp (asect->name, ".note", 5) == 0)
     this_hdr->sh_type = SHT_NOTE;
   else if (strncmp (asect->name, ".stab", 5) == 0
@@ -2076,7 +2342,8 @@ elf_fake_sections (abfd, asect, failedptrarg)
       this_hdr->sh_entsize = 4;
     }
   else if ((asect->flags & SEC_ALLOC) != 0
-          && ((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0))
+          && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+              || (asect->flags & SEC_NEVER_LOAD) != 0))
     this_hdr->sh_type = SHT_NOBITS;
   else
     this_hdr->sh_type = SHT_PROGBITS;
@@ -2094,12 +2361,15 @@ elf_fake_sections (abfd, asect, failedptrarg)
       if ((asect->flags & SEC_STRINGS) != 0)
        this_hdr->sh_flags |= SHF_STRINGS;
     }
-  if (elf_group_name (asect) != NULL)
+  if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
     this_hdr->sh_flags |= SHF_GROUP;
+  if ((asect->flags & SEC_THREAD_LOCAL) != 0)
+    this_hdr->sh_flags |= SHF_TLS;
 
   /* Check for processor-specific section types.  */
-  if (bed->elf_backend_fake_sections)
-    (*bed->elf_backend_fake_sections) (abfd, this_hdr, asect);
+  if (bed->elf_backend_fake_sections
+      && !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect))
+    *failedptr = true;
 
   /* If the section has relocs, set up a section header for the
      SHT_REL[A] section.  If two relocation sections are required for
@@ -2115,35 +2385,47 @@ elf_fake_sections (abfd, asect, failedptrarg)
 
 /* Fill in the contents of a SHT_GROUP section.  */
 
-static void
-set_group_contents (abfd, sec, failedptrarg)
+void
+bfd_elf_set_group_contents (abfd, sec, failedptrarg)
      bfd *abfd;
      asection *sec;
-     PTR failedptrarg ATTRIBUTE_UNUSED;
+     PTR failedptrarg;
 {
   boolean *failedptr = (boolean *) failedptrarg;
   unsigned long symindx;
-  asection *elt;
+  asection *elt, *first;
   unsigned char *loc;
   struct bfd_link_order *l;
+  boolean gas;
 
   if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP
       || *failedptr)
     return;
 
-  /* If called from the assembler, swap_out_syms will have set up
-     elf_section_syms;  If called for "ld -r", the symbols won't yet
-     be mapped, so emulate elf_bfd_final_link.  */
-  if (elf_section_syms (abfd) != NULL)
-    symindx = elf_section_syms (abfd)[sec->index]->udata.i;
-  else
-    symindx = elf_section_data (sec)->this_idx;
+  symindx = 0;
+  if (elf_group_id (sec) != NULL)
+    symindx = elf_group_id (sec)->udata.i;
+
+  if (symindx == 0)
+    {
+      /* If called from the assembler, swap_out_syms will have set up
+        elf_section_syms;  If called for "ld -r", use target_index.  */
+      if (elf_section_syms (abfd) != NULL)
+       symindx = elf_section_syms (abfd)[sec->index]->udata.i;
+      else
+       symindx = sec->target_index;
+    }
   elf_section_data (sec)->this_hdr.sh_info = symindx;
 
-  /* Nor will the contents be allocated for "ld -r".  */
+  /* The contents won't be allocated for "ld -r" or objcopy.  */
+  gas = true;
   if (sec->contents == NULL)
     {
+      gas = false;
       sec->contents = bfd_alloc (abfd, sec->_raw_size);
+
+      /* Arrange for the section to be written out.  */
+      elf_section_data (sec)->this_hdr.contents = sec->contents;
       if (sec->contents == NULL)
        {
          *failedptr = true;
@@ -2153,9 +2435,10 @@ set_group_contents (abfd, sec, failedptrarg)
 
   loc = sec->contents + sec->_raw_size;
 
-  /* Get the pointer to the first section in the group that we
-     squirreled away here.  */
-  elt = elf_next_in_group (sec);
+  /* Get the pointer to the first section in the group that gas
+     squirreled away here.  objcopy arranges for this to be set to the
+     start of the input section group.  */
+  first = elt = elf_next_in_group (sec);
 
   /* First element is a flag word.  Rest of section is elf section
      indices for all the sections of the group.  Write them backwards
@@ -2163,9 +2446,20 @@ set_group_contents (abfd, sec, failedptrarg)
      directives, not that it matters.  */
   while (elt != NULL)
     {
+      asection *s;
+      unsigned int idx;
+
       loc -= 4;
-      H_PUT_32 (abfd, elf_section_data (elt)->this_idx, loc);
+      s = elt;
+      if (!gas)
+       s = s->output_section;
+      idx = 0;
+      if (s != NULL)
+       idx = elf_section_data (s)->this_idx;
+      H_PUT_32 (abfd, idx, loc);
       elt = elf_next_in_group (elt);
+      if (elt == first)
+       break;
     }
 
   /* If this is a relocatable link, then the above did nothing because
@@ -2184,10 +2478,16 @@ set_group_contents (abfd, sec, failedptrarg)
        }
       while (elt != elf_next_in_group (l->u.indirect.section));
 
-  loc -= 4;
-  H_PUT_32 (abfd, 0, loc);
+  /* 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);
 
-  BFD_ASSERT (loc == sec->contents);
+  if (loc != sec->contents)
+    abort ();
+
+  H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 }
 
 /* Assign all ELF section numbers.  The dummy first section is handled here
@@ -2200,39 +2500,79 @@ assign_section_numbers (abfd)
 {
   struct elf_obj_tdata *t = elf_tdata (abfd);
   asection *sec;
-  unsigned int section_number;
+  unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
   bfd_size_type amt;
 
   section_number = 1;
 
+  _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
+
   for (sec = abfd->sections; sec; sec = sec->next)
     {
       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
-       d->rel_idx = section_number++;
+       {
+         if (section_number == SHN_LORESERVE)
+           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+         d->rel_idx = section_number++;
+         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name);
+       }
 
       if (d->rel_hdr2)
-       d->rel_idx2 = section_number++;
+       {
+         if (section_number == SHN_LORESERVE)
+           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+         d->rel_idx2 = section_number++;
+         _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name);
+       }
       else
        d->rel_idx2 = 0;
     }
 
+  if (section_number == SHN_LORESERVE)
+    section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
   t->shstrtab_section = section_number++;
+  _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
   elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
-  t->shstrtab_hdr.sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
 
   if (bfd_get_symcount (abfd) > 0)
     {
+      if (section_number == SHN_LORESERVE)
+       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
       t->symtab_section = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
+      if (section_number > SHN_LORESERVE - 2)
+       {
+         if (section_number == SHN_LORESERVE)
+           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+         t->symtab_shndx_section = section_number++;
+         t->symtab_shndx_hdr.sh_name
+           = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+                                                 ".symtab_shndx", false);
+         if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1)
+           return false;
+       }
+      if (section_number == SHN_LORESERVE)
+       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
       t->strtab_section = section_number++;
+      _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
 
+  _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
+  t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
+
+  elf_numsections (abfd) = section_number;
   elf_elfheader (abfd)->e_shnum = section_number;
+  if (section_number > SHN_LORESERVE)
+    elf_elfheader (abfd)->e_shnum -= SHN_HIRESERVE + 1 - SHN_LORESERVE;
 
   /* Set up the list of section header pointers, in agreement with the
      indices.  */
@@ -2256,6 +2596,11 @@ assign_section_numbers (abfd)
   if (bfd_get_symcount (abfd) > 0)
     {
       i_shdrp[t->symtab_section] = &t->symtab_hdr;
+      if (elf_numsections (abfd) > SHN_LORESERVE)
+       {
+         i_shdrp[t->symtab_shndx_section] = &t->symtab_shndx_hdr;
+         t->symtab_shndx_hdr.sh_link = t->symtab_section;
+       }
       i_shdrp[t->strtab_section] = &t->strtab_hdr;
       t->symtab_hdr.sh_link = t->strtab_section;
     }
@@ -2324,10 +2669,10 @@ assign_section_numbers (abfd)
              char *alc;
 
              len = strlen (sec->name);
-             alc = (char *) bfd_malloc ((bfd_size_type) len - 2);
+             alc = (char *) bfd_malloc ((bfd_size_type) (len - 2));
              if (alc == NULL)
                return false;
-             strncpy (alc, sec->name, len - 3);
+             memcpy (alc, sec->name, len - 3);
              alc[len - 3] = '\0';
              s = bfd_get_section_by_name (abfd, alc);
              free (alc);
@@ -2368,6 +2713,12 @@ assign_section_numbers (abfd)
        }
     }
 
+  for (secn = 1; secn < section_number; ++secn)
+    if (i_shdrp[secn] == NULL)
+      i_shdrp[secn] = i_shdrp[0];
+    else
+      i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
+                                                      i_shdrp[secn]->sh_name);
   return true;
 }
 
@@ -2617,9 +2968,9 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
        return false;
     }
 
-  if (link_info == NULL || link_info->relocateable)
+  if (link_info == NULL)
     {
-      bfd_map_over_sections (abfd, set_group_contents, &failed);
+      bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed);
       if (failed)
        return false;
     }
@@ -2629,7 +2980,7 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
   shstrtab_hdr->sh_type = SHT_STRTAB;
   shstrtab_hdr->sh_flags = 0;
   shstrtab_hdr->sh_addr = 0;
-  shstrtab_hdr->sh_size = _bfd_stringtab_size (elf_shstrtab (abfd));
+  shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
   shstrtab_hdr->sh_entsize = 0;
   shstrtab_hdr->sh_link = 0;
   shstrtab_hdr->sh_info = 0;
@@ -2649,6 +3000,10 @@ _bfd_elf_compute_section_file_positions (abfd, link_info)
       hdr = &elf_tdata (abfd)->symtab_hdr;
       off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
 
+      hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+      if (hdr->sh_size != 0)
+       off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+
       hdr = &elf_tdata (abfd)->strtab_hdr;
       off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
 
@@ -2722,7 +3077,9 @@ map_sections_to_segments (abfd)
   asection **hdrpp;
   boolean phdr_in_segment = true;
   boolean writable;
-  asection *dynsec;
+  int tls_count = 0;
+  asection *first_tls = NULL;
+  asection *dynsec, *eh_frame_hdr;
   bfd_size_type amt;
 
   if (elf_tdata (abfd)->segment_map != NULL)
@@ -2960,6 +3317,59 @@ map_sections_to_segments (abfd)
          *pm = m;
          pm = &m->next;
        }
+      if (s->flags & SEC_THREAD_LOCAL)
+       {
+         if (! tls_count)
+           first_tls = s;
+         tls_count++;
+       }
+    }
+
+  /* If there are any SHF_TLS output sections, add PT_TLS segment.  */
+  if (tls_count > 0)
+    {
+      int i;
+
+      amt = sizeof (struct elf_segment_map);
+      amt += (tls_count - 1) * sizeof (asection *);
+      m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_TLS;
+      m->count = tls_count;
+      /* Mandated PF_R.  */
+      m->p_flags = PF_R;
+      m->p_flags_valid = 1;
+      for (i = 0; i < tls_count; ++i)
+       {
+         BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
+         m->sections[i] = first_tls;
+         first_tls = first_tls->next;
+       }
+
+      *pm = m;
+      pm = &m->next;
+    }
+
+  /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+     segment.  */
+  eh_frame_hdr = NULL;
+  if (elf_tdata (abfd)->eh_frame_hdr)
+    eh_frame_hdr = bfd_get_section_by_name (abfd, ".eh_frame_hdr");
+  if (eh_frame_hdr != NULL && (eh_frame_hdr->flags & SEC_LOAD))
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_GNU_EH_FRAME;
+      m->count = 1;
+      m->sections[0] = eh_frame_hdr;
+
+      *pm = m;
+      pm = &m->next;
     }
 
   free (sections);
@@ -3054,6 +3464,37 @@ assign_file_positions_for_segments (abfd)
       if (! map_sections_to_segments (abfd))
        return false;
     }
+  else
+    {
+      /* The placement algorithm assumes that non allocated sections are
+        not in PT_LOAD segments.  We ensure this here by removing such
+        sections from the segment map.  */
+      for (m = elf_tdata (abfd)->segment_map;
+          m != NULL;
+          m = m->next)
+       {
+         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 (i != new_count) 
+                   m->sections[new_count] = m->sections[i];
+
+                 new_count ++;
+               }
+           }
+
+         if (new_count != m->count)
+           m->count = new_count;
+       }
+    }
 
   if (bed->elf_backend_modify_segment_map)
     {
@@ -3109,8 +3550,13 @@ assign_file_positions_for_segments (abfd)
       asection **secpp;
 
       /* If elf_segment_map is not from map_sections_to_segments, the
-         sections may not be correctly ordered.  */
-      if (m->count > 0)
+         sections may not be correctly ordered.  NOTE: sorting should 
+        not be done to the PT_NOTE section of a corefile, which may
+        contain several pseudo-sections artificially created by bfd.
+        Sorting these pseudo-sections breaks things badly.  */
+      if (m->count > 1 
+         && !(elf_elfheader (abfd)->e_type == ET_CORE 
+              && m->p_type == PT_NOTE))
        qsort (m->sections, (size_t) m->count, sizeof (asection *),
               elf_sort_sections);
 
@@ -3178,8 +3624,9 @@ assign_file_positions_for_segments (abfd)
 
              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));
+                 (*_bfd_error_handler)
+                   (_("%s: Not enough room for program headers, try linking with -N"),
+                    bfd_get_filename (abfd));
                  bfd_set_error (bfd_error_bad_value);
                  return false;
                }
@@ -3262,10 +3709,10 @@ assign_file_positions_for_segments (abfd)
 
          /* The section may have artificial alignment forced by a
             link script.  Notice this case by the gap between the
-            cumulative phdr vma and the section's vma.  */
-         if (p->p_vaddr + p->p_memsz < sec->vma)
+            cumulative phdr lma and the section's lma.  */
+         if (p->p_paddr + p->p_memsz < sec->lma)
            {
-             bfd_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
+             bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
 
              p->p_memsz += adjust;
              off += adjust;
@@ -3303,13 +3750,11 @@ assign_file_positions_for_segments (abfd)
                {
                  if (i == 0)
                    {
-                     (* _bfd_error_handler)
-                       (_("Error: First section in segment (%s) starts at 0x%x"),
-                        bfd_section_name (abfd, sec), sec->lma);
-                     (* _bfd_error_handler)
-                       (_("       whereas segment starts at 0x%x"),
-                        p->p_paddr);
-
+                     (* _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;
                    }
                  p->p_memsz += adjust;
@@ -3361,6 +3806,20 @@ assign_file_positions_for_segments (abfd)
              if ((flags & SEC_LOAD) != 0)
                p->p_filesz += sec->_raw_size;
 
+             if (p->p_type == PT_TLS
+                 && sec->_raw_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)
+                   if (tbss_size < o->offset + o->size)
+                     tbss_size = o->offset + o->size;
+
+                 p->p_memsz += tbss_size;
+               }
+
              if (align > p->p_align
                  && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0))
                p->p_align = align;
@@ -3405,6 +3864,11 @@ assign_file_positions_for_segments (abfd)
        }
     }
 
+  /* If additional nonloadable filepos adjustments are required,
+     do them now. */
+  if (bed->set_nonloadable_filepos)
+    (*bed->set_nonloadable_filepos) (abfd, phdrs);
+
   /* Clear out any program headers we allocated but did not use.  */
   for (; count < alloc; count++, p++)
     {
@@ -3478,6 +3942,13 @@ get_program_header_size (abfd)
       ++segs;
     }
 
+  if (elf_tdata (abfd)->eh_frame_hdr
+      && bfd_get_section_by_name (abfd, ".eh_frame_hdr") != NULL)
+    {
+      /* We need a PT_GNU_EH_FRAME segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -3488,6 +3959,16 @@ get_program_header_size (abfd)
        }
     }
 
+  for (s = abfd->sections; s != NULL; s = s->next)
+    {
+      if (s->flags & SEC_THREAD_LOCAL)
+       {
+         /* We need a PT_TLS segment.  */
+         ++segs;
+         break;
+       }
+    }
+
   /* Let the backend count up any program headers it might need.  */
   if (bed->elf_backend_additional_program_headers)
     {
@@ -3521,6 +4002,7 @@ assign_file_positions_except_relocs (abfd)
   struct elf_obj_tdata * const tdata = elf_tdata (abfd);
   Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd);
   Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd);
+  unsigned int num_sec = elf_numsections (abfd);
   file_ptr off;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
@@ -3536,24 +4018,27 @@ assign_file_positions_except_relocs (abfd)
       /* We are not creating an executable, which means that we are
         not creating a program header, and that the actual order of
         the sections in the file is unimportant.  */
-      for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++)
+      for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++)
        {
          Elf_Internal_Shdr *hdr;
 
          hdr = *hdrpp;
-         if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
-           {
-             hdr->sh_offset = -1;
-             continue;
-           }
-         if (i == tdata->symtab_section
+         if (hdr->sh_type == SHT_REL
+             || hdr->sh_type == SHT_RELA
+             || i == tdata->symtab_section
+             || i == tdata->symtab_shndx_section
              || i == tdata->strtab_section)
            {
              hdr->sh_offset = -1;
-             continue;
            }
+         else
+           off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
 
-         off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+         if (i == SHN_LORESERVE - 1)
+           {
+             i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+             hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+           }
        }
     }
   else
@@ -3569,7 +4054,7 @@ assign_file_positions_except_relocs (abfd)
       /* Assign file positions for the other sections.  */
 
       off = elf_tdata (abfd)->next_file_pos;
-      for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++)
+      for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++)
        {
          Elf_Internal_Shdr *hdr;
 
@@ -3595,10 +4080,17 @@ assign_file_positions_except_relocs (abfd)
          else if (hdr->sh_type == SHT_REL
                   || hdr->sh_type == SHT_RELA
                   || hdr == i_shdrpp[tdata->symtab_section]
+                  || hdr == i_shdrpp[tdata->symtab_shndx_section]
                   || hdr == i_shdrpp[tdata->strtab_section])
            hdr->sh_offset = -1;
          else
            off = _bfd_elf_assign_file_position_for_section (hdr, off, true);
+
+         if (i == SHN_LORESERVE - 1)
+           {
+             i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+             hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
+           }
        }
     }
 
@@ -3619,14 +4111,13 @@ prep_headers (abfd)
   Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
   Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
   Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
-  int count;
-  struct bfd_strtab_hash *shstrtab;
+  struct elf_strtab_hash *shstrtab;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   i_ehdrp = elf_elfheader (abfd);
   i_shdrp = elf_elfsections (abfd);
 
-  shstrtab = _bfd_elf_stringtab_init ();
+  shstrtab = _bfd_elf_strtab_init ();
   if (shstrtab == NULL)
     return false;
 
@@ -3642,12 +4133,6 @@ prep_headers (abfd)
     bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB;
   i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current;
 
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_NONE;
-  i_ehdrp->e_ident[EI_ABIVERSION] = 0;
-
-  for (count = EI_PAD; count < EI_NIDENT; count++)
-    i_ehdrp->e_ident[count] = 0;
-
   if ((abfd->flags & DYNAMIC) != 0)
     i_ehdrp->e_type = ET_DYN;
   else if ((abfd->flags & EXEC_P) != 0)
@@ -3712,11 +4197,11 @@ prep_headers (abfd)
     }
 
   elf_tdata (abfd)->symtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".symtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", false);
   elf_tdata (abfd)->strtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".strtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".strtab", false);
   elf_tdata (abfd)->shstrtab_hdr.sh_name =
-    (unsigned int) _bfd_stringtab_add (shstrtab, ".shstrtab", true, false);
+    (unsigned int) _bfd_elf_strtab_add (shstrtab, ".shstrtab", false);
   if (elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
       || elf_tdata (abfd)->symtab_hdr.sh_name == (unsigned int) -1
       || elf_tdata (abfd)->shstrtab_hdr.sh_name == (unsigned int) -1)
@@ -3733,14 +4218,13 @@ _bfd_elf_assign_file_positions_for_relocs (abfd)
      bfd *abfd;
 {
   file_ptr off;
-  unsigned int i;
+  unsigned int i, num_sec;
   Elf_Internal_Shdr **shdrpp;
 
   off = elf_tdata (abfd)->next_file_pos;
 
-  for (i = 1, shdrpp = elf_elfsections (abfd) + 1;
-       i < elf_elfheader (abfd)->e_shnum;
-       i++, shdrpp++)
+  num_sec = elf_numsections (abfd);
+  for (i = 1, shdrpp = elf_elfsections (abfd) + 1; i < num_sec; i++, shdrpp++)
     {
       Elf_Internal_Shdr *shdrp;
 
@@ -3761,7 +4245,7 @@ _bfd_elf_write_object_contents (abfd)
   Elf_Internal_Ehdr *i_ehdrp;
   Elf_Internal_Shdr **i_shdrp;
   boolean failed;
-  unsigned int count;
+  unsigned int count, num_sec;
 
   if (! abfd->output_has_begun
       && ! _bfd_elf_compute_section_file_positions
@@ -3779,7 +4263,8 @@ _bfd_elf_write_object_contents (abfd)
   _bfd_elf_assign_file_positions_for_relocs (abfd);
 
   /* After writing the headers, we need to write the sections too...  */
-  for (count = 1; count < i_ehdrp->e_shnum; count++)
+  num_sec = elf_numsections (abfd);
+  for (count = 1; count < num_sec; count++)
     {
       if (bed->elf_backend_section_processing)
        (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]);
@@ -3791,11 +4276,13 @@ _bfd_elf_write_object_contents (abfd)
              || bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt)
            return false;
        }
+      if (count == SHN_LORESERVE - 1)
+       count += SHN_HIRESERVE + 1 - SHN_LORESERVE;
     }
 
   /* Write out the section header names.  */
   if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
-      || ! _bfd_stringtab_emit (abfd, elf_shstrtab (abfd)))
+      || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))
     return false;
 
   if (bed->elf_backend_final_write_processing)
@@ -3820,43 +4307,47 @@ _bfd_elf_section_from_bfd_section (abfd, asect)
      bfd *abfd;
      struct sec *asect;
 {
-  struct elf_backend_data *bed = get_elf_backend_data (abfd);
-  Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+  struct elf_backend_data *bed;
   int index;
-  Elf_Internal_Shdr *hdr;
-  int maxindex = elf_elfheader (abfd)->e_shnum;
 
-  for (index = 0; index < maxindex; index++)
-    {
-      hdr = i_shdrp[index];
-      if (hdr->bfd_section == asect)
-       return index;
-    }
+  if (elf_section_data (asect) != NULL
+      && elf_section_data (asect)->this_idx != 0)
+    return elf_section_data (asect)->this_idx;
 
-  if (bed->elf_backend_section_from_bfd_section)
+  if (bfd_is_abs_section (asect))
+    index = SHN_ABS;
+  else if (bfd_is_com_section (asect))
+    index = SHN_COMMON;
+  else if (bfd_is_und_section (asect))
+    index = SHN_UNDEF;
+  else
     {
-      for (index = 0; index < maxindex; index++)
+      Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd);
+      int maxindex = elf_numsections (abfd);
+
+      for (index = 1; index < maxindex; index++)
        {
-         int retval;
+         Elf_Internal_Shdr *hdr = i_shdrp[index];
 
-         hdr = i_shdrp[index];
-         retval = index;
-         if ((*bed->elf_backend_section_from_bfd_section)
-             (abfd, hdr, asect, &retval))
-           return retval;
+         if (hdr != NULL && hdr->bfd_section == asect)
+           return index;
        }
+      index = -1;
     }
 
-  if (bfd_is_abs_section (asect))
-    return SHN_ABS;
-  if (bfd_is_com_section (asect))
-    return SHN_COMMON;
-  if (bfd_is_und_section (asect))
-    return SHN_UNDEF;
+  bed = get_elf_backend_data (abfd);
+  if (bed->elf_backend_section_from_bfd_section)
+    {
+      int retval = index;
+
+      if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval))
+       return retval;
+    }
 
-  bfd_set_error (bfd_error_nonrepresentable_section);
+  if (index == -1)
+    bfd_set_error (bfd_error_nonrepresentable_section);
 
-  return -1;
+  return index;
 }
 
 /* Given a BFD symbol, return the index in the ELF symbol table, or -1
@@ -3907,7 +4398,7 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr)
 #if DEBUG & 4
   {
     fprintf (stderr,
-            _("elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n"),
+            "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n",
             (long) asym_ptr, asym_ptr->name, idx, flags,
             elf_symbol_flags (flags));
     fflush (stderr);
@@ -3936,6 +4427,7 @@ copy_private_bfd_data (ibfd, obfd)
   bfd_vma                   maxpagesize;
   struct elf_segment_map *  phdr_adjust_seg = NULL;
   unsigned int              phdr_adjust_num = 0;
+  struct elf_backend_data * bed;
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
@@ -3944,6 +4436,7 @@ copy_private_bfd_data (ibfd, obfd)
   if (elf_tdata (ibfd)->phdr == NULL)
     return true;
 
+  bed = get_elf_backend_data (ibfd);
   iehdr = elf_elfheader (ibfd);
 
   map_first = NULL;
@@ -3971,6 +4464,13 @@ copy_private_bfd_data (ibfd, obfd)
      && (section->lma + section->_raw_size)            \
      <= SEGMENT_END (segment, base))
 
+  /* Returns true if the given section is contained within the
+     given segment.  Filepos addresses are compared in an elf
+     backend function. */
+#define IS_CONTAINED_BY_FILEPOS(sec, seg, bed)         \
+  (bed->is_contained_by_filepos                                \
+   && (*bed->is_contained_by_filepos) (sec, seg))
+
   /* Special case: corefile "NOTE" section containing regs, prpsinfo etc.  */
 #define IS_COREFILE_NOTE(p, s)                          \
            (p->p_type == PT_NOTE                       \
@@ -3994,17 +4494,22 @@ copy_private_bfd_data (ibfd, obfd)
 
   /* Decide if the given section should be included in the given segment.
      A section will be included if:
-       1. It is within the address space of the segment,
+       1. It is within the address space of the segment -- we use the LMA
+          if that is set for the segment and the VMA otherwise,
        2. It is an allocated segment,
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.  */
-#define INCLUDE_SECTION_IN_SEGMENT(section, segment)   \
-  ((((IS_CONTAINED_BY_VMA (section, segment)           \
-      || IS_SOLARIS_PT_INTERP (segment, section))      \
-     && (section->flags & SEC_ALLOC) != 0)             \
-    || IS_COREFILE_NOTE (segment, section))            \
-   && section->output_section != NULL                  \
-   && section->segment_mark == false)
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)              \
+  (((((segment->p_paddr                                                        \
+       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)      \
+       : IS_CONTAINED_BY_VMA (section, segment))                       \
+      || IS_SOLARIS_PT_INTERP (segment, section))                      \
+     && (section->flags & SEC_ALLOC) != 0)                             \
+    || IS_COREFILE_NOTE (segment, section)                             \
+    || (IS_CONTAINED_BY_FILEPOS (section, segment, bed)                        \
+        && (section->flags & SEC_ALLOC) == 0))                         \
+   && section->output_section != NULL                                  \
+   && ! section->segment_mark)
 
   /* Returns true iff seg1 starts after the end of seg2.  */
 #define SEGMENT_AFTER_SEGMENT(seg1, seg2)              \
@@ -4020,7 +4525,7 @@ copy_private_bfd_data (ibfd, obfd)
 
   /* Scan through the segments specified in the program header
      of the input BFD.  For this first scan we look for overlaps
-     in the loadable segments.  These can be created by wierd
+     in the loadable segments.  These can be created by weird
      parameters to objcopy.  */
   for (i = 0, segment = elf_tdata (ibfd)->phdr;
        i < num_segments;
@@ -4102,7 +4607,7 @@ copy_private_bfd_data (ibfd, obfd)
       /* Compute how many sections might be placed into this segment.  */
       section_count = 0;
       for (section = ibfd->sections; section != NULL; section = section->next)
-       if (INCLUDE_SECTION_IN_SEGMENT (section, segment))
+       if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
          ++section_count;
 
       /* Allocate a segment map big enough to contain all of the
@@ -4145,11 +4650,12 @@ copy_private_bfd_data (ibfd, obfd)
        {
          /* Special segments, such as the PT_PHDR segment, may contain
             no sections, but ordinary, loadable segments should contain
-            something.  */
+            something.  They are allowed by the ELF spec however, so only
+            a warning is produced.  */
          if (segment->p_type == PT_LOAD)
-             _bfd_error_handler
-               (_("%s: warning: Empty loadable segment detected\n"),
-                bfd_archive_filename (ibfd));
+           (*_bfd_error_handler)
+             (_("%s: warning: Empty loadable segment detected, is this intentional ?\n"),
+              bfd_archive_filename (ibfd));
 
          map->count = 0;
          *pointer_to_map = map;
@@ -4186,7 +4692,9 @@ copy_private_bfd_data (ibfd, obfd)
         pointers that we are interested in.  As these sections get assigned
         to a segment, they are removed from this array.  */
 
-      amt = (bfd_size_type) section_count * sizeof (asection *);
+      /* 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 = (asection **) bfd_malloc (amt);
       if (sections == NULL)
        return false;
@@ -4205,7 +4713,7 @@ copy_private_bfd_data (ibfd, obfd)
           section != NULL;
           section = section->next)
        {
-         if (INCLUDE_SECTION_IN_SEGMENT (section, segment))
+         if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
            {
              output_section = section->output_section;
 
@@ -4231,6 +4739,7 @@ copy_private_bfd_data (ibfd, obfd)
              /* Match up the physical address of the segment with the
                 LMA address of the output section.  */
              if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
+                 || IS_CONTAINED_BY_FILEPOS (section, segment, bed)
                  || IS_COREFILE_NOTE (segment, section))
                {
                  if (matching_lma == 0)
@@ -4300,7 +4809,7 @@ copy_private_bfd_data (ibfd, obfd)
        }
 
       /* Step Three: Loop over the sections again, this time assigning
-        those that fit to the current segment and remvoing them from the
+        those that fit to the current segment and removing them from the
         sections array; but making sure not to leave large gaps.  Once all
         possible sections have been assigned to the current segment it is
         added to the list of built segments and if sections still remain
@@ -4351,7 +4860,7 @@ copy_private_bfd_data (ibfd, obfd)
                         maxpagesize then we need to start a new segment.  */
                      if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size,
                                      maxpagesize)
-                         < BFD_ALIGN (output_section->lma, maxpagesize))
+                          < BFD_ALIGN (output_section->lma, maxpagesize))
                          || ((prev_sec->lma + prev_sec->_raw_size)
                              > output_section->lma))
                        {
@@ -4422,7 +4931,7 @@ copy_private_bfd_data (ibfd, obfd)
   elf_tdata (obfd)->segment_map = map_first;
 
   /* If we had to estimate the number of program headers that were
-     going to be needed, then check our estimate know and adjust
+     going to be needed, then check our estimate now and adjust
      the offset if necessary.  */
   if (phdr_adjust_seg != NULL)
     {
@@ -4464,6 +4973,7 @@ copy_private_bfd_data (ibfd, obfd)
 #undef SEGMENT_END
 #undef IS_CONTAINED_BY_VMA
 #undef IS_CONTAINED_BY_LMA
+#undef IS_CONTAINED_BY_FILEPOS
 #undef IS_COREFILE_NOTE
 #undef IS_SOLARIS_PT_INTERP
 #undef INCLUDE_SECTION_IN_SEGMENT
@@ -4483,6 +4993,7 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
      asection *osec;
 {
   Elf_Internal_Shdr *ihdr, *ohdr;
+  const struct elf_backend_data *bed = get_elf_backend_data (ibfd);
 
   if (ibfd->xvec->flavour != bfd_target_elf_flavour
       || obfd->xvec->flavour != bfd_target_elf_flavour)
@@ -4492,24 +5003,31 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
      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)
-    {
-      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;
-       }
+     already been worked out.  The backend function provides a way to 
+     override the test conditions and code path for the call to 
+     copy_private_bfd_data.  */
+  if (bed->copy_private_bfd_data_p)
+    {
+      if ((*bed->copy_private_bfd_data_p) (ibfd, isec, obfd, osec))
+        if (! copy_private_bfd_data (ibfd, obfd))
+          return false;
+    } 
+  else 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;
@@ -4523,6 +5041,12 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
       || ihdr->sh_type == SHT_GNU_verdef)
     ohdr->sh_info = ihdr->sh_info;
 
+  /* 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);
+
   elf_section_data (osec)->use_rela_p
     = elf_section_data (isec)->use_rela_p;
 
@@ -4535,10 +5059,11 @@ _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)
    section indices; these definitions are interpreted by the
    swap_out_syms function.  */
 
-#define MAP_ONESYMTAB (SHN_LORESERVE - 1)
-#define MAP_DYNSYMTAB (SHN_LORESERVE - 2)
-#define MAP_STRTAB (SHN_LORESERVE - 3)
-#define MAP_SHSTRTAB (SHN_LORESERVE - 4)
+#define MAP_ONESYMTAB (SHN_HIOS + 1)
+#define MAP_DYNSYMTAB (SHN_HIOS + 2)
+#define MAP_STRTAB    (SHN_HIOS + 3)
+#define MAP_SHSTRTAB  (SHN_HIOS + 4)
+#define MAP_SYM_SHNDX (SHN_HIOS + 5)
 
 boolean
 _bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg)
@@ -4571,6 +5096,8 @@ _bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg)
        shndx = MAP_STRTAB;
       else if (shndx == elf_tdata (ibfd)->shstrtab_section)
        shndx = MAP_SHSTRTAB;
+      else if (shndx == elf_tdata (ibfd)->symtab_shndx_section)
+       shndx = MAP_SYM_SHNDX;
       osym->internal_elf_sym.st_shndx = shndx;
     }
 
@@ -4590,8 +5117,10 @@ swap_out_syms (abfd, sttp, relocatable_p)
   asymbol **syms;
   struct bfd_strtab_hash *stt;
   Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Shdr *symtab_shndx_hdr;
   Elf_Internal_Shdr *symstrtab_hdr;
   char *outbound_syms;
+  char *outbound_shndx;
   int idx;
   bfd_size_type amt;
 
@@ -4621,6 +5150,21 @@ swap_out_syms (abfd, sttp, relocatable_p)
     return false;
   symtab_hdr->contents = (PTR) outbound_syms;
 
+  outbound_shndx = NULL;
+  symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+  if (symtab_shndx_hdr->sh_name != 0)
+    {
+      amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
+      outbound_shndx = bfd_zalloc (abfd, amt);
+      if (outbound_shndx == NULL)
+       return false;
+      symtab_shndx_hdr->contents = outbound_shndx;
+      symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+      symtab_shndx_hdr->sh_size = amt;
+      symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+      symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+    }
+
   /* now generate the data (for "contents") */
   {
     /* Fill in zeroth symbol and swap it out.  */
@@ -4631,8 +5175,10 @@ swap_out_syms (abfd, sttp, relocatable_p)
     sym.st_info = 0;
     sym.st_other = 0;
     sym.st_shndx = SHN_UNDEF;
-    bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms);
+    bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
     outbound_syms += bed->s->sizeof_sym;
+    if (outbound_shndx != NULL)
+      outbound_shndx += sizeof (Elf_External_Sym_Shndx);
   }
 
   syms = bfd_get_outsymbols (abfd);
@@ -4713,6 +5259,9 @@ swap_out_syms (abfd, sttp, relocatable_p)
                case MAP_SHSTRTAB:
                  shndx = elf_tdata (abfd)->shstrtab_section;
                  break;
+               case MAP_SYM_SHNDX:
+                 shndx = elf_tdata (abfd)->symtab_shndx_section;
+                 break;
                default:
                  break;
                }
@@ -4742,13 +5291,18 @@ swap_out_syms (abfd, sttp, relocatable_p)
          sym.st_shndx = shndx;
        }
 
-      if ((flags & BSF_FUNCTION) != 0)
+      if ((flags & BSF_THREAD_LOCAL) != 0)
+       type = STT_TLS;
+      else if ((flags & BSF_FUNCTION) != 0)
        type = STT_FUNC;
       else if ((flags & BSF_OBJECT) != 0)
        type = STT_OBJECT;
       else
        type = STT_NOTYPE;
 
+      if (syms[idx]->section->flags & SEC_THREAD_LOCAL)
+       type = STT_TLS;
+
       /* Processor-specific types */
       if (type_ptr != NULL
          && bed->elf_backend_get_symbol_type)
@@ -4790,8 +5344,10 @@ swap_out_syms (abfd, sttp, relocatable_p)
       else
        sym.st_other = 0;
 
-      bed->s->swap_symbol_out (abfd, &sym, (PTR) outbound_syms);
+      bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
       outbound_syms += bed->s->sizeof_sym;
+      if (outbound_shndx != NULL)
+       outbound_shndx += sizeof (Elf_External_Sym_Shndx);
     }
 
   *sttp = stt;
@@ -4823,7 +5379,9 @@ _bfd_elf_get_symtab_upper_bound (abfd)
   Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr;
 
   symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
-  symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *));
+  symtab_size = (symcount + 1) * (sizeof (asymbol *));
+  if (symcount > 0)
+    symtab_size -= sizeof (asymbol *);
 
   return symtab_size;
 }
@@ -4843,7 +5401,9 @@ _bfd_elf_get_dynamic_symtab_upper_bound (abfd)
     }
 
   symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym;
-  symtab_size = (symcount - 1 + 1) * (sizeof (asymbol *));
+  symtab_size = (symcount + 1) * (sizeof (asymbol *));
+  if (symcount > 0)
+    symtab_size -= sizeof (asymbol *);
 
   return symtab_size;
 }
@@ -5408,8 +5968,8 @@ _bfd_elf_set_section_contents (abfd, section, location, offset, count)
   bfd_signed_vma pos;
 
   if (! abfd->output_has_begun
-      && ! _bfd_elf_compute_section_file_positions
-      (abfd, (struct bfd_link_info *) NULL))
+      && ! (_bfd_elf_compute_section_file_positions
+           (abfd, (struct bfd_link_info *) NULL)))
     return false;
 
   hdr = &elf_section_data (section)->this_hdr;
@@ -5546,7 +6106,7 @@ _bfd_elf_close_and_cleanup (abfd)
   if (bfd_get_format (abfd) == bfd_object)
     {
       if (elf_shstrtab (abfd) != NULL)
-       _bfd_stringtab_free (elf_shstrtab (abfd));
+       _bfd_elf_strtab_free (elf_shstrtab (abfd));
     }
 
   return _bfd_generic_close_and_cleanup (abfd);
@@ -5632,15 +6192,17 @@ _bfd_elfcore_make_pseudosection (abfd, name, size, filepos)
 {
   char buf[100];
   char *threaded_name;
+  size_t len;
   asection *sect;
 
   /* Build the section name.  */
 
   sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd));
-  threaded_name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+  len = strlen (buf) + 1;
+  threaded_name = bfd_alloc (abfd, (bfd_size_type) len);
   if (threaded_name == NULL)
     return false;
-  strcpy (threaded_name, buf);
+  memcpy (threaded_name, buf, len);
 
   sect = bfd_make_section (abfd, threaded_name);
   if (sect == NULL)
@@ -5678,7 +6240,10 @@ elfcore_grok_prstatus (abfd, note)
       offset   = offsetof (prstatus_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
-      elf_tdata (abfd)->core_signal = prstat.pr_cursig;
+      /* Do not overwrite the core signal if it
+        has already been set by another thread.  */
+      if (elf_tdata (abfd)->core_signal == 0)
+       elf_tdata (abfd)->core_signal = prstat.pr_cursig;
       elf_tdata (abfd)->core_pid = prstat.pr_pid;
 
       /* pr_who exists on:
@@ -5701,7 +6266,10 @@ elfcore_grok_prstatus (abfd, note)
       offset   = offsetof (prstatus32_t, pr_reg);
       memcpy (&prstat, note->descdata, sizeof (prstat));
 
-      elf_tdata (abfd)->core_signal = prstat.pr_cursig;
+      /* Do not overwrite the core signal if it
+        has already been set by another thread.  */
+      if (elf_tdata (abfd)->core_signal == 0)
+       elf_tdata (abfd)->core_signal = prstat.pr_cursig;
       elf_tdata (abfd)->core_pid = prstat.pr_pid;
 
       /* pr_who exists on:
@@ -5870,6 +6438,8 @@ elfcore_grok_psinfo (abfd, note)
 #endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */
 
 #if defined (HAVE_PSTATUS_T)
+static boolean elfcore_grok_pstatus PARAMS ((bfd *, Elf_Internal_Note *));
+
 static boolean
 elfcore_grok_pstatus (abfd, note)
      bfd *abfd;
@@ -5907,6 +6477,8 @@ elfcore_grok_pstatus (abfd, note)
 #endif /* defined (HAVE_PSTATUS_T) */
 
 #if defined (HAVE_LWPSTATUS_T)
+static boolean elfcore_grok_lwpstatus PARAMS ((bfd *, Elf_Internal_Note *));
+
 static boolean
 elfcore_grok_lwpstatus (abfd, note)
      bfd *abfd;
@@ -5915,6 +6487,7 @@ elfcore_grok_lwpstatus (abfd, note)
   lwpstatus_t lwpstat;
   char buf[100];
   char *name;
+  size_t len;
   asection *sect;
 
   if (note->descsz != sizeof (lwpstat)
@@ -5932,10 +6505,11 @@ elfcore_grok_lwpstatus (abfd, note)
   /* Make a ".reg/999" section.  */
 
   sprintf (buf, ".reg/%d", elfcore_make_pid (abfd));
-  name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+  len = strlen (buf) + 1;
+  name = bfd_alloc (abfd, (bfd_size_type) len);
   if (name == NULL)
     return false;
-  strcpy (name, buf);
+  memcpy (name, buf, len);
 
   sect = bfd_make_section (abfd, name);
   if (sect == NULL)
@@ -5961,10 +6535,11 @@ elfcore_grok_lwpstatus (abfd, note)
   /* Make a ".reg2/999" section */
 
   sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd));
-  name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+  len = strlen (buf) + 1;
+  name = bfd_alloc (abfd, (bfd_size_type) len);
   if (name == NULL)
     return false;
-  strcpy (name, buf);
+  memcpy (name, buf, len);
 
   sect = bfd_make_section (abfd, name);
   if (sect == NULL)
@@ -5996,13 +6571,14 @@ elfcore_grok_win32pstatus (abfd, note)
 {
   char buf[30];
   char *name;
+  size_t len;
   asection *sect;
   win32_pstatus_t pstatus;
 
   if (note->descsz < sizeof (pstatus))
     return true;
 
-  memcpy (&pstatus, note->descdata, note->descsz);
+  memcpy (&pstatus, note->descdata, sizeof (pstatus));
 
   switch (pstatus.data_type)
     {
@@ -6016,11 +6592,12 @@ elfcore_grok_win32pstatus (abfd, note)
       /* Make a ".reg/999" section.  */
       sprintf (buf, ".reg/%d", pstatus.data.thread_info.tid);
 
-      name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+      len = strlen (buf) + 1;
+      name = bfd_alloc (abfd, (bfd_size_type) len);
       if (name == NULL)
        return false;
 
-      strcpy (name, buf);
+      memcpy (name, buf, len);
 
       sect = bfd_make_section (abfd, name);
       if (sect == NULL)
@@ -6042,11 +6619,12 @@ elfcore_grok_win32pstatus (abfd, note)
       /* Make a ".module/xxxxxxxx" section.  */
       sprintf (buf, ".module/%08x", pstatus.data.module_info.base_address);
 
-      name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1);
+      len = strlen (buf) + 1;
+      name = bfd_alloc (abfd, (bfd_size_type) len);
       if (name == NULL)
        return false;
 
-      strcpy (name, buf);
+      memcpy (name, buf, len);
 
       sect = bfd_make_section (abfd, name);
 
@@ -6127,6 +6705,302 @@ elfcore_grok_note (abfd, note)
     }
 }
 
+static boolean
+elfcore_netbsd_get_lwpid (note, lwpidp)
+     Elf_Internal_Note *note;
+     int *lwpidp;
+{
+  char *cp;
+
+  cp = strchr (note->namedata, '@');
+  if (cp != NULL)
+    {
+      *lwpidp = atoi(cp + 1);
+      return true;
+    }
+  return false;
+}
+
+static boolean
+elfcore_grok_netbsd_procinfo (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+
+  /* Signal number at offset 0x08. */
+  elf_tdata (abfd)->core_signal
+    = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08);
+
+  /* Process ID at offset 0x50. */
+  elf_tdata (abfd)->core_pid
+    = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x50);
+
+  /* Command name at 0x7c (max 32 bytes, including nul). */
+  elf_tdata (abfd)->core_command
+    = _bfd_elfcore_strndup (abfd, note->descdata + 0x7c, 31);
+
+  return true;
+}
+
+static boolean
+elfcore_grok_netbsd_note (abfd, note)
+     bfd *abfd;
+     Elf_Internal_Note *note;
+{
+  int lwp;
+
+  if (elfcore_netbsd_get_lwpid (note, &lwp))
+    elf_tdata (abfd)->core_lwpid = lwp;
+
+  if (note->type == NT_NETBSDCORE_PROCINFO)
+    {
+      /* NetBSD-specific core "procinfo".  Note that we expect to
+         find this note before any of the others, which is fine,
+         since the kernel writes this note out first when it
+         creates a core file.  */
+      
+      return elfcore_grok_netbsd_procinfo (abfd, note);
+    }
+
+  /* As of Jan 2002 there are no other machine-independent notes
+     defined for NetBSD core files.  If the note type is less
+     than the start of the machine-dependent note types, we don't
+     understand it.  */
+  
+  if (note->type < NT_NETBSDCORE_FIRSTMACH)
+    return true;
+
+
+  switch (bfd_get_arch (abfd))
+    {
+    /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
+       PT_GETFPREGS == mach+2.  */
+
+    case bfd_arch_alpha:
+    case bfd_arch_sparc:
+      switch (note->type)
+        {
+        case NT_NETBSDCORE_FIRSTMACH+0:
+          return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+        case NT_NETBSDCORE_FIRSTMACH+2:
+          return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+        default:
+          return true;
+        }
+
+    /* On all other arch's, PT_GETREGS == mach+1 and
+       PT_GETFPREGS == mach+3.  */
+
+    default:
+      switch (note->type)
+        {
+        case NT_NETBSDCORE_FIRSTMACH+1:
+          return elfcore_make_note_pseudosection (abfd, ".reg", note);
+
+        case NT_NETBSDCORE_FIRSTMACH+3:
+          return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+
+        default:
+          return true;
+        }
+    }
+    /* NOTREACHED */
+}
+
+/* Function: elfcore_write_note
+
+   Inputs: 
+     buffer to hold note
+     name of note
+     type of note
+     data for note
+     size of data for note
+
+   Return:
+   End of buffer containing note.  */
+
+char *
+elfcore_write_note (abfd, buf, bufsiz, name, type, input, size)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     const char *name;
+     int  type;
+     const PTR input;
+     int  size;
+{
+  Elf_External_Note *xnp;
+  size_t namesz;
+  size_t pad;
+  size_t newspace;
+  char *p, *dest;
+
+  namesz = 0;
+  pad = 0;
+  if (name != NULL)
+    {
+      struct elf_backend_data *bed;
+
+      namesz = strlen (name) + 1;
+      bed = get_elf_backend_data (abfd);
+      pad = -namesz & (bed->s->file_align - 1);
+    }
+
+  newspace = sizeof (Elf_External_Note) - 1 + namesz + pad + size;
+
+  p = realloc (buf, *bufsiz + newspace);
+  dest = p + *bufsiz;
+  *bufsiz += newspace;
+  xnp = (Elf_External_Note *) dest;
+  H_PUT_32 (abfd, namesz, xnp->namesz);
+  H_PUT_32 (abfd, size, xnp->descsz);
+  H_PUT_32 (abfd, type, xnp->type);
+  dest = xnp->name;
+  if (name != NULL)
+    {
+      memcpy (dest, name, namesz);
+      dest += namesz;
+      while (pad != 0)
+       {
+         *dest++ = '\0';
+         --pad;
+       }
+    }
+  memcpy (dest, input, size);
+  return p;
+}
+
+#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
+char *
+elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     const char *fname; 
+     const char *psargs;
+{
+  int note_type;
+  char *note_name = "CORE";
+
+#if defined (HAVE_PSINFO_T)
+  psinfo_t  data;
+  note_type = NT_PSINFO;
+#else
+  prpsinfo_t data;
+  note_type = NT_PRPSINFO;
+#endif
+
+  memset (&data, 0, sizeof (data));
+  strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+  strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, note_type, &data, sizeof (data));
+}
+#endif /* PSINFO_T or PRPSINFO_T */
+
+#if defined (HAVE_PRSTATUS_T)
+char *
+elfcore_write_prstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+     bfd *abfd;
+     char *buf;
+     int *bufsiz;
+     long pid;
+     int cursig;
+     const PTR gregs;
+{
+  prstatus_t prstat;
+  char *note_name = "CORE";
+
+  memset (&prstat, 0, sizeof (prstat));
+  prstat.pr_pid = pid;
+  prstat.pr_cursig = cursig;
+  memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, NT_PRSTATUS, &prstat, sizeof (prstat));
+}
+#endif /* HAVE_PRSTATUS_T */
+
+#if defined (HAVE_LWPSTATUS_T)
+char *
+elfcore_write_lwpstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+     bfd *abfd;
+     char *buf;
+     int *bufsiz;
+     long pid;
+     int cursig;
+     const PTR gregs;
+{
+  lwpstatus_t lwpstat;
+  char *note_name = "CORE";
+
+  memset (&lwpstat, 0, sizeof (lwpstat));
+  lwpstat.pr_lwpid  = pid >> 16;
+  lwpstat.pr_cursig = cursig;
+#if defined (HAVE_LWPSTATUS_T_PR_REG)
+  memcpy (lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg));
+#elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT)
+#if !defined(gregs)
+  memcpy (lwpstat.pr_context.uc_mcontext.gregs,
+         gregs, sizeof (lwpstat.pr_context.uc_mcontext.gregs));
+#else
+  memcpy (lwpstat.pr_context.uc_mcontext.__gregs,
+         gregs, sizeof (lwpstat.pr_context.uc_mcontext.__gregs));
+#endif
+#endif
+  return elfcore_write_note (abfd, buf, bufsiz, note_name, 
+                            NT_LWPSTATUS, &lwpstat, sizeof (lwpstat));
+}
+#endif /* HAVE_LWPSTATUS_T */
+
+#if defined (HAVE_PSTATUS_T)
+char *
+elfcore_write_pstatus (abfd, buf, bufsiz, pid, cursig, gregs)
+     bfd *abfd;
+     char *buf;
+     int *bufsiz;
+     long pid;
+     int cursig;
+     const PTR gregs;
+{
+  pstatus_t pstat;
+  char *note_name = "CORE";
+
+  memset (&pstat, 0, sizeof (pstat));
+  pstat.pr_pid = pid & 0xffff;
+  buf = elfcore_write_note (abfd, buf, bufsiz, note_name, 
+                           NT_PSTATUS, &pstat, sizeof (pstat));
+  return buf;
+}
+#endif /* HAVE_PSTATUS_T */
+
+char *
+elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     const PTR fpregs;
+     int size;
+{
+  char *note_name = "CORE";
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, NT_FPREGSET, fpregs, size);
+}
+
+char *
+elfcore_write_prxfpreg (abfd, buf, bufsiz, xfpregs, size)
+     bfd  *abfd;
+     char *buf;
+     int  *bufsiz;
+     const PTR xfpregs;
+     int size;
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz, 
+                            note_name, NT_PRXFPREG, xfpregs, size);
+}
+
 static boolean
 elfcore_read_notes (abfd, offset, size)
      bfd *abfd;
@@ -6169,8 +7043,16 @@ elfcore_read_notes (abfd, offset, size)
       in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
       in.descpos = offset + (in.descdata - buf);
 
-      if (! elfcore_grok_note (abfd, &in))
-       goto error;
+      if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0)
+        {
+          if (! elfcore_grok_netbsd_note (abfd, &in))
+            goto error;
+        }
+      else
+        {
+          if (! elfcore_grok_note (abfd, &in))
+            goto error;
+        }
 
       p = in.descdata + BFD_ALIGN (in.descsz, 4);
     }
@@ -6295,3 +7177,76 @@ _bfd_elf_reloc_type_class (rela)
 {
   return reloc_class_normal;
 }
+
+/* For RELA architectures, return what the relocation value for
+   relocation against a local symbol.  */
+
+bfd_vma
+_bfd_elf_rela_local_sym (abfd, sym, sec, rel)
+     bfd *abfd;
+     Elf_Internal_Sym *sym;
+     asection *sec;
+     Elf_Internal_Rela *rel;
+{
+  bfd_vma relocation;
+
+  relocation = (sec->output_section->vma
+               + sec->output_offset
+               + sym->st_value);
+  if ((sec->flags & SEC_MERGE)
+      && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+      && elf_section_data (sec)->sec_info_type == ELF_INFO_TYPE_MERGE)
+    {
+      asection *msec;
+
+      msec = sec;
+      rel->r_addend =
+       _bfd_merged_section_offset (abfd, &msec,
+                                   elf_section_data (sec)->sec_info,
+                                   sym->st_value + rel->r_addend,
+                                   (bfd_vma) 0)
+       - relocation;
+      rel->r_addend += msec->output_section->vma + msec->output_offset;
+    }
+  return relocation;
+}
+
+bfd_vma
+_bfd_elf_rel_local_sym (abfd, sym, psec, addend)
+     bfd *abfd;
+     Elf_Internal_Sym *sym;
+     asection **psec;
+     bfd_vma addend;
+{     
+  asection *sec = *psec;
+
+  if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_MERGE)
+    return sym->st_value + addend;
+
+  return _bfd_merged_section_offset (abfd, psec,
+                                    elf_section_data (sec)->sec_info,
+                                    sym->st_value + addend, (bfd_vma) 0);
+}
+
+bfd_vma
+_bfd_elf_section_offset (abfd, info, sec, offset)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     bfd_vma offset;
+{
+  struct bfd_elf_section_data *sec_data;
+
+  sec_data = elf_section_data (sec);
+  switch (sec_data->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);
+    case ELF_INFO_TYPE_EH_FRAME:
+      return _bfd_elf_eh_frame_section_offset (abfd, sec, offset);
+    default:
+      return offset;
+    }
+}
This page took 0.054389 seconds and 4 git commands to generate.