bfd/
[deliverable/binutils-gdb.git] / bfd / elf.c
index d215144386a33f9870d53e5ffc835b63aadcc0ec..d65c78d963a413792fb4bbd254894e695cc736c9 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, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -226,26 +226,36 @@ bfd_elf_gnu_hash (const char *namearg)
   return h & 0xffffffff;
 }
 
+/* Create a tdata field OBJECT_SIZE bytes in length, zeroed out and with
+   the object_id field of an elf_obj_tdata field set to OBJECT_ID.  */
 bfd_boolean
-bfd_elf_mkobject (bfd *abfd)
+bfd_elf_allocate_object (bfd *abfd,
+                        size_t object_size,
+                        enum elf_object_id object_id)
 {
+  BFD_ASSERT (object_size >= sizeof (struct elf_obj_tdata));
+  abfd->tdata.any = bfd_zalloc (abfd, object_size);
   if (abfd->tdata.any == NULL)
-    {
-      abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
-      if (abfd->tdata.any == NULL)
-       return FALSE;
-    }
-
-  elf_tdata (abfd)->program_header_size = (bfd_size_type) -1;
+    return FALSE;
 
+  elf_object_id (abfd) = object_id;
+  elf_program_header_size (abfd) = (bfd_size_type) -1;
   return TRUE;
 }
 
+
+bfd_boolean
+bfd_elf_make_generic_object (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
+                                 GENERIC_ELF_TDATA);
+}
+
 bfd_boolean
 bfd_elf_mkcorefile (bfd *abfd)
 {
   /* I think this can be done just like an object file.  */
-  return bfd_elf_mkobject (abfd);
+  return bfd_elf_make_generic_object (abfd);
 }
 
 char *
@@ -271,7 +281,7 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
 
       /* Allocate and clear an extra byte at the end, to prevent crashes
         in case the string table is not terminated.  */
-      if (shstrtabsize + 1 == 0
+      if (shstrtabsize + 1 <= 1
          || (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL
          || bfd_seek (abfd, offset, SEEK_SET) != 0)
        shstrtab = NULL;
@@ -280,6 +290,10 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
          if (bfd_get_error () != bfd_error_system_call)
            bfd_set_error (bfd_error_file_truncated);
          shstrtab = NULL;
+         /* Once we've failed to read it, make sure we don't keep
+            trying.  Otherwise, we'll keep allocating space for
+            the string table over and over.  */
+         i_shdrp[shindex]->sh_size = 0;
        }
       else
        shstrtab[shstrtabsize] = '\0';
@@ -326,7 +340,9 @@ bfd_elf_string_from_elf_section (bfd *abfd,
    SYMCOUNT specifies the number of symbols to read, starting from
    symbol SYMOFFSET.  If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF
    are non-NULL, they are used to store the internal symbols, external
-   symbols, and symbol section index extensions, respectively.  */
+   symbols, and symbol section index extensions, respectively.
+   Returns a pointer to the internal symbol buffer (malloced if necessary)
+   or NULL if there were no symbols or some kind of problem.  */
 
 Elf_Internal_Sym *
 bfd_elf_get_elf_syms (bfd *ibfd,
@@ -349,6 +365,9 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   bfd_size_type amt;
   file_ptr pos;
 
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+    abort ();
+
   if (symcount == 0)
     return intsym_buf;
 
@@ -442,8 +461,7 @@ bfd_elf_sym_name (bfd *abfd,
 
   if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION
       /* Check for a bogus st_shndx to avoid crashing.  */
-      && isym->st_shndx < elf_numsections (abfd)
-      && !(isym->st_shndx >= SHN_LORESERVE && isym->st_shndx <= SHN_HIRESERVE))
+      && isym->st_shndx < elf_numsections (abfd))
     {
       iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name;
       shindex = elf_elfheader (abfd)->e_shstrndx;
@@ -480,6 +498,8 @@ group_signature (bfd *abfd, Elf_Internal_Shdr *ghdr)
 
   /* First we need to ensure the symbol table is available.  Make sure
      that it is a symbol table section.  */
+  if (ghdr->sh_link >= elf_numsections (abfd))
+    return NULL;
   hdr = elf_elfsections (abfd) [ghdr->sh_link];
   if (hdr->sh_type != SHT_SYMTAB
       || ! bfd_section_from_shdr (abfd, ghdr->sh_link))
@@ -698,8 +718,7 @@ _bfd_elf_setup_sections (bfd *abfd)
             get the situation where elfsec is 0.  */
          if (elfsec == 0)
            {
-             const struct elf_backend_data *bed
-               = get_elf_backend_data (abfd);
+             const struct elf_backend_data *bed = get_elf_backend_data (abfd);
              if (bed->link_order_error_handler)
                bed->link_order_error_handler
                  (_("%B: warning: sh_link not set for section `%A'"),
@@ -707,14 +726,17 @@ _bfd_elf_setup_sections (bfd *abfd)
            }
          else
            {
-             asection *link;
+             asection *link = NULL;
 
-             this_hdr = elf_elfsections (abfd)[elfsec];
+             if (elfsec < elf_numsections (abfd))
+               {
+                 this_hdr = elf_elfsections (abfd)[elfsec];
+                 link = this_hdr->bfd_section;
+               }
 
              /* PR 1991, 2008:
                 Some strip/objcopy may leave an incorrect value in
                 sh_link.  We don't want to proceed.  */
-             link = this_hdr->bfd_section;
              if (link == NULL)
                {
                  (*_bfd_error_handler)
@@ -810,7 +832,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr)
       || ! bfd_set_section_size (abfd, newsect, hdr->sh_size)
       || ! bfd_set_section_alignment (abfd, newsect,
-                                     bfd_log2 ((bfd_vma) hdr->sh_addralign)))
+                                     bfd_log2 (hdr->sh_addralign)))
     return FALSE;
 
   flags = SEC_NO_FLAGS;
@@ -868,7 +890,14 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
          { NULL,                0  },  /* 'p' */
          { NULL,                0  },  /* 'q' */
          { NULL,                0  },  /* 'r' */
-         { STRING_COMMA_LEN ("stab") } /* 's' */
+         { STRING_COMMA_LEN ("stab") },        /* 's' */
+         { NULL,                0  },  /* 't' */
+         { NULL,                0  },  /* 'u' */
+         { NULL,                0  },  /* 'v' */
+         { NULL,                0  },  /* 'w' */
+         { NULL,                0  },  /* 'x' */
+         { NULL,                0  },  /* 'y' */
+         { STRING_COMMA_LEN ("zdebug") }       /* 'z' */
        };
 
       if (name [0] == '.')
@@ -926,65 +955,66 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
   if ((flags & SEC_ALLOC) != 0)
     {
       Elf_Internal_Phdr *phdr;
-      unsigned int i;
+      unsigned int i, nload;
+
+      /* Some ELF linkers produce binaries with all the program header
+        p_paddr fields zero.  If we have such a binary with more than
+        one PT_LOAD header, then leave the section lma equal to vma
+        so that we don't create sections with overlapping lma.  */
+      phdr = elf_tdata (abfd)->phdr;
+      for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+       if (phdr->p_paddr != 0)
+         break;
+       else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0)
+         ++nload;
+      if (i >= elf_elfheader (abfd)->e_phnum && nload > 1)
+       return TRUE;
 
-      /* Look through the phdrs to see if we need to adjust the lma.
-        If all the p_paddr fields are zero, we ignore them, since
-        some ELF linkers produce such output.  */
       phdr = elf_tdata (abfd)->phdr;
       for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
        {
-         if (phdr->p_paddr != 0)
-           break;
-       }
-      if (i < elf_elfheader (abfd)->e_phnum)
-       {
-         phdr = elf_tdata (abfd)->phdr;
-         for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+         /* This section is part of this segment if its file
+            offset plus size lies within the segment's memory
+            span and, if the section is loaded, the extent of the
+            loaded data lies within the extent of the segment.
+
+            Note - we used to check the p_paddr field as well, and
+            refuse to set the LMA if it was 0.  This is wrong
+            though, as a perfectly valid initialised segment can
+            have a p_paddr of zero.  Some architectures, eg ARM,
+            place special significance on the address 0 and
+            executables need to be able to have a segment which
+            covers this address.  */
+         if (phdr->p_type == PT_LOAD
+             && (bfd_vma) hdr->sh_offset >= phdr->p_offset
+             && (hdr->sh_offset + hdr->sh_size
+                 <= phdr->p_offset + phdr->p_memsz)
+             && ((flags & SEC_LOAD) == 0
+                 || (hdr->sh_offset + hdr->sh_size
+                     <= phdr->p_offset + phdr->p_filesz)))
            {
-             /* This section is part of this segment if its file
-                offset plus size lies within the segment's memory
-                span and, if the section is loaded, the extent of the
-                loaded data lies within the extent of the segment.
-
-                Note - we used to check the p_paddr field as well, and
-                refuse to set the LMA if it was 0.  This is wrong
-                though, as a perfectly valid initialised segment can
-                have a p_paddr of zero.  Some architectures, eg ARM,
-                place special significance on the address 0 and
-                executables need to be able to have a segment which
-                covers this address.  */
-             if (phdr->p_type == PT_LOAD
-                 && (bfd_vma) hdr->sh_offset >= phdr->p_offset
-                 && (hdr->sh_offset + hdr->sh_size
-                     <= phdr->p_offset + phdr->p_memsz)
-                 && ((flags & SEC_LOAD) == 0
-                     || (hdr->sh_offset + hdr->sh_size
-                         <= phdr->p_offset + phdr->p_filesz)))
-               {
-                 if ((flags & SEC_LOAD) == 0)
-                   newsect->lma = (phdr->p_paddr
-                                   + hdr->sh_addr - phdr->p_vaddr);
-                 else
-                   /* We used to use the same adjustment for SEC_LOAD
-                      sections, but that doesn't work if the segment
-                      is packed with code from multiple VMAs.
-                      Instead we calculate the section LMA based on
-                      the segment LMA.  It is assumed that the
-                      segment will contain sections with contiguous
-                      LMAs, even if the VMAs are not.  */
-                   newsect->lma = (phdr->p_paddr
-                                   + hdr->sh_offset - phdr->p_offset);
-
-                 /* With contiguous segments, we can't tell from file
-                    offsets whether a section with zero size should
-                    be placed at the end of one segment or the
-                    beginning of the next.  Decide based on vaddr.  */
-                 if (hdr->sh_addr >= phdr->p_vaddr
-                     && (hdr->sh_addr + hdr->sh_size
-                         <= phdr->p_vaddr + phdr->p_memsz))
-                   break;
-               }
+             if ((flags & SEC_LOAD) == 0)
+               newsect->lma = (phdr->p_paddr
+                               + hdr->sh_addr - phdr->p_vaddr);
+             else
+               /* We used to use the same adjustment for SEC_LOAD
+                  sections, but that doesn't work if the segment
+                  is packed with code from multiple VMAs.
+                  Instead we calculate the section LMA based on
+                  the segment LMA.  It is assumed that the
+                  segment will contain sections with contiguous
+                  LMAs, even if the VMAs are not.  */
+               newsect->lma = (phdr->p_paddr
+                               + hdr->sh_offset - phdr->p_offset);
+
+             /* With contiguous segments, we can't tell from file
+                offsets whether a section with zero size should
+                be placed at the end of one segment or the
+                beginning of the next.  Decide based on vaddr.  */
+             if (hdr->sh_addr >= phdr->p_vaddr
+                 && (hdr->sh_addr + hdr->sh_size
+                     <= phdr->p_vaddr + phdr->p_memsz))
+               break;
            }
        }
     }
@@ -1165,7 +1195,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
   s = bfd_get_section_by_name (abfd, ".dynamic");
   if (s != NULL)
     {
-      int elfsec;
+      unsigned int elfsec;
       unsigned long shlink;
       bfd_byte *extdyn, *extdynend;
       size_t extdynsize;
@@ -1177,7 +1207,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
        goto error_return;
 
       elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
-      if (elfsec == -1)
+      if (elfsec == SHN_BAD)
        goto error_return;
       shlink = elf_elfsections (abfd)[elfsec]->sh_link;
 
@@ -1189,9 +1219,10 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
       for (; extdyn < extdynend; extdyn += extdynsize)
        {
          Elf_Internal_Dyn dyn;
-         const char *name;
+         const char *name = "";
          char ab[20];
          bfd_boolean stringp;
+         const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
          (*swap_dyn_in) (abfd, extdyn, &dyn);
 
@@ -1202,8 +1233,14 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
          switch (dyn.d_tag)
            {
            default:
-             sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
-             name = ab;
+             if (bed->elf_backend_get_target_dtag)
+               name = (*bed->elf_backend_get_target_dtag) (dyn.d_tag);
+
+             if (!strcmp (name, ""))
+               {
+                 sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag);
+                 name = ab;
+               }
              break;
 
            case DT_NEEDED: name = "NEEDED"; stringp = TRUE; break;
@@ -1266,9 +1303,12 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg)
            case DT_GNU_HASH: name = "GNU_HASH"; break;
            }
 
-         fprintf (f, "  %-11s ", name);
+         fprintf (f, "  %-20s ", name);
          if (! stringp)
-           fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val);
+           {
+             fprintf (f, "0x");
+             bfd_fprintf_vma (abfd, f, dyn.d_un.d_val);
+           }
          else
            {
              const char *string;
@@ -1496,17 +1536,22 @@ _bfd_elf_stringtab_init (void)
 bfd_boolean
 bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
 {
-  Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex];
-  Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd);
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  Elf_Internal_Shdr *hdr;
+  Elf_Internal_Ehdr *ehdr;
+  const struct elf_backend_data *bed;
   const char *name;
 
-  name = bfd_elf_string_from_elf_section (abfd,
-                                         elf_elfheader (abfd)->e_shstrndx,
+  if (shindex >= elf_numsections (abfd))
+    return FALSE;
+
+  hdr = elf_elfsections (abfd)[shindex];
+  ehdr = elf_elfheader (abfd);
+  name = bfd_elf_string_from_elf_section (abfd, ehdr->e_shstrndx,
                                          hdr->sh_name);
   if (name == NULL)
     return FALSE;
 
+  bed = get_elf_backend_data (abfd);
   switch (hdr->sh_type)
     {
     case SHT_NULL:
@@ -1707,8 +1752,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
          return FALSE;
 
        /* Check for a bogus link to avoid crashing.  */
-       if ((hdr->sh_link >= SHN_LORESERVE && hdr->sh_link <= SHN_HIRESERVE)
-           || hdr->sh_link >= num_sec)
+       if (hdr->sh_link >= num_sec)
          {
            ((*_bfd_error_handler)
             (_("%B: invalid link %lu for reloc section %s (index %u)"),
@@ -1762,7 +1806,6 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex)
           section, an invalid section, or another reloc section.  */
        if (hdr->sh_link != elf_onesymtab (abfd)
            || hdr->sh_info == SHN_UNDEF
-           || (hdr->sh_info >= SHN_LORESERVE && hdr->sh_info <= SHN_HIRESERVE)
            || hdr->sh_info >= num_sec
            || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL
            || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_RELA)
@@ -2083,6 +2126,15 @@ static const struct bfd_elf_special_section special_sections_t[] =
   { NULL,                     0,  0, 0,            0 }
 };
 
+static const struct bfd_elf_special_section special_sections_z[] =
+{
+  { STRING_COMMA_LEN (".zdebug_line"),    0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".zdebug_info"),    0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".zdebug_abbrev"),  0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 },
+  { NULL,                     0,  0, 0,            0 }
+};
+
 static const struct bfd_elf_special_section *special_sections[] =
 {
   special_sections_b,          /* 'b' */
@@ -2104,6 +2156,12 @@ static const struct bfd_elf_special_section *special_sections[] =
   special_sections_r,          /* 'r' */
   special_sections_s,          /* 's' */
   special_sections_t,          /* 't' */
+  NULL,                                /* 'u' */
+  NULL,                                /* 'v' */
+  NULL,                                /* 'w' */
+  NULL,                                /* 'x' */
+  NULL,                                /* 'y' */
+  special_sections_z           /* 'z' */
 };
 
 const struct bfd_elf_special_section *
@@ -2180,7 +2238,7 @@ _bfd_elf_get_sec_type_attr (bfd *abfd, asection *sec)
     return NULL;
 
   i = sec->name[1] - 'b';
-  if (i < 0 || i > 't' - 'b')
+  if (i < 0 || i > 'z' - 'b')
     return NULL;
 
   spec = special_sections[i];
@@ -2421,7 +2479,7 @@ _bfd_elf_init_reloc_shdr (bfd *abfd,
   rel_hdr->sh_entsize = (use_rela_p
                         ? bed->s->sizeof_rela
                         : bed->s->sizeof_rel);
-  rel_hdr->sh_addralign = 1 << bed->s->log_file_align;
+  rel_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
   rel_hdr->sh_flags = 0;
   rel_hdr->sh_addr = 0;
   rel_hdr->sh_size = 0;
@@ -2468,7 +2526,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
   this_hdr->sh_offset = 0;
   this_hdr->sh_size = asect->size;
   this_hdr->sh_link = 0;
-  this_hdr->sh_addralign = 1 << asect->alignment_power;
+  this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power;
   /* The sh_entsize and sh_info fields may have been set already by
      copy_private_section_data.  */
 
@@ -2497,7 +2555,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg)
         non-bss input sections to bss output sections, or emit data
         to a bss output section via a linker script.  */
       (*_bfd_error_handler)
-       (_("section `%A' type changed to PROGBITS"), asect);
+       (_("warning: section `%A' type changed to PROGBITS"), asect);
       this_hdr->sh_type = sh_type;
     }
 
@@ -2749,11 +2807,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
                  abfd->section_count--;
                }
              else
-               {
-                 if (section_number == SHN_LORESERVE)
-                   section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-                 d->this_idx = section_number++;
-               }
+               d->this_idx = section_number++;
            }
        }
     }
@@ -2763,26 +2817,18 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
       d = elf_section_data (sec);
 
       if (d->this_hdr.sh_type != SHT_GROUP)
-       {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-         d->this_idx = section_number++;
-       }
+       d->this_idx = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
       if ((sec->flags & SEC_RELOC) == 0)
        d->rel_idx = 0;
       else
        {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
          d->rel_idx = section_number++;
          _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name);
        }
 
       if (d->rel_hdr2)
        {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
          d->rel_idx2 = section_number++;
          _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name);
        }
@@ -2790,22 +2836,16 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
        d->rel_idx2 = 0;
     }
 
-  if (section_number == SHN_LORESERVE)
-    section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
   t->shstrtab_section = section_number++;
   _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
   elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section;
 
   if (bfd_get_symcount (abfd) > 0)
     {
-      if (section_number == SHN_LORESERVE)
-       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
       t->symtab_section = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
-      if (section_number > SHN_LORESERVE - 2)
+      if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF))
        {
-         if (section_number == SHN_LORESERVE)
-           section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
          t->symtab_shndx_section = section_number++;
          t->symtab_shndx_hdr.sh_name
            = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
@@ -2813,8 +2853,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
          if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1)
            return FALSE;
        }
-      if (section_number == SHN_LORESERVE)
-       section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
       t->strtab_section = section_number++;
       _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
     }
@@ -2824,8 +2862,6 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
 
   elf_numsections (abfd) = section_number;
   elf_elfheader (abfd)->e_shnum = section_number;
-  if (section_number > SHN_LORESERVE)
-    elf_elfheader (abfd)->e_shnum -= SHN_HIRESERVE + 1 - SHN_LORESERVE;
 
   /* Set up the list of section header pointers, in agreement with the
      indices.  */
@@ -2846,7 +2882,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info)
   if (bfd_get_symcount (abfd) > 0)
     {
       i_shdrp[t->symtab_section] = &t->symtab_hdr;
-      if (elf_numsections (abfd) > SHN_LORESERVE)
+      if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
        {
          i_shdrp[t->symtab_shndx_section] = &t->symtab_shndx_hdr;
          t->symtab_shndx_hdr.sh_link = t->symtab_section;
@@ -3064,17 +3100,15 @@ sym_is_global (bfd *abfd, asymbol *sym)
 }
 
 /* Don't output section symbols for sections that are not going to be
-   output.  Also, don't output section symbols for reloc and other
-   special sections.  */
+   output.  */
 
 static bfd_boolean
 ignore_section_sym (bfd *abfd, asymbol *sym)
 {
   return ((sym->flags & BSF_SECTION_SYM) != 0
-         && (sym->value != 0
-             || (sym->section->owner != abfd
-                 && (sym->section->output_section->owner != abfd
-                     || sym->section->output_offset != 0))));
+         && !(sym->section->owner == abfd
+              || (sym->section->output_section->owner == abfd
+                  && sym->section->output_offset == 0)));
 }
 
 static bfd_boolean
@@ -3117,6 +3151,7 @@ elf_map_symbols (bfd *abfd)
       asymbol *sym = syms[idx];
 
       if ((sym->flags & BSF_SECTION_SYM) != 0
+         && sym->value == 0
          && !ignore_section_sym (abfd, sym))
        {
          asection *sec = sym->section;
@@ -3215,14 +3250,8 @@ _bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *i_shdrp,
                                           file_ptr offset,
                                           bfd_boolean align)
 {
-  if (align)
-    {
-      unsigned int al;
-
-      al = i_shdrp->sh_addralign;
-      if (al > 1)
-       offset = BFD_ALIGN (offset, al);
-    }
+  if (align && i_shdrp->sh_addralign > 1)
+    offset = BFD_ALIGN (offset, i_shdrp->sh_addralign);
   i_shdrp->sh_offset = offset;
   if (i_shdrp->bfd_section != NULL)
     i_shdrp->bfd_section->filepos = offset;
@@ -3426,6 +3455,29 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
   return segs * bed->s->sizeof_phdr;
 }
 
+/* Find the segment that contains the output_section of section.  */
+
+Elf_Internal_Phdr *
+_bfd_elf_find_segment_containing_section (bfd * abfd, asection * section)
+{
+  struct elf_segment_map *m;
+  Elf_Internal_Phdr *p;
+
+  for (m = elf_tdata (abfd)->segment_map,
+        p = elf_tdata (abfd)->phdr;
+       m != NULL;
+       m = m->next, p++)
+    {
+      int i;
+
+      for (i = m->count - 1; i >= 0; i--)
+       if (m->sections[i] == section)
+         return p;
+    }
+
+  return NULL;
+}
+
 /* Create a mapping from a set of sections to a program segment.  */
 
 static struct elf_segment_map *
@@ -4246,6 +4298,10 @@ assign_file_positions_for_load_sections (bfd *abfd,
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
+      /* Set the note section type to SHT_NOTE.  */
+      else if (p->p_type == PT_NOTE)
+       for (i = 0; i < m->count; i++)
+         elf_section_type (m->sections[i]) = SHT_NOTE;
 
       p->p_offset = 0;
       p->p_filesz = 0;
@@ -4329,30 +4385,28 @@ assign_file_positions_for_load_sections (bfd *abfd,
          this_hdr = &elf_section_data (sec)->this_hdr;
          align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
 
-         if (p->p_type == PT_LOAD
-             || p->p_type == PT_TLS)
-           {
-             bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
-
-             if (this_hdr->sh_type != SHT_NOBITS
+         if ((p->p_type == PT_LOAD
+              || p->p_type == PT_TLS)
+             && (this_hdr->sh_type != SHT_NOBITS
                  || ((this_hdr->sh_flags & SHF_ALLOC) != 0
                      && ((this_hdr->sh_flags & SHF_TLS) == 0
-                         || p->p_type == PT_TLS)))
+                         || p->p_type == PT_TLS))))
+           {
+             bfd_signed_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
+
+             if (adjust < 0)
                {
-                 if (adjust < 0)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%B: section %A lma 0x%lx overlaps previous sections"),
-                        abfd, sec, (unsigned long) sec->lma);
-                     adjust = 0;
-                   }
-                 p->p_memsz += adjust;
+                 (*_bfd_error_handler)
+                   (_("%B: section %A vma 0x%lx overlaps previous sections"),
+                    abfd, sec, (unsigned long) sec->lma);
+                 adjust = 0;
+               }
+             p->p_memsz += adjust;
 
-                 if (this_hdr->sh_type != SHT_NOBITS)
-                   {
-                     off += adjust;
-                     p->p_filesz += adjust;
-                   }
+             if (this_hdr->sh_type != SHT_NOBITS)
+               {
+                 off += adjust;
+                 p->p_filesz += adjust;
                }
            }
 
@@ -4511,12 +4565,6 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
        hdr->sh_offset = -1;
       else
        off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
-
-      if (i == SHN_LORESERVE - 1)
-       {
-         i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-         hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-       }
     }
 
   /* Now that we have set the section file positions, we can set up
@@ -4713,12 +4761,6 @@ assign_file_positions_except_relocs (bfd *abfd,
            }
          else
            off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
-
-         if (i == SHN_LORESERVE - 1)
-           {
-             i += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-             hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE;
-           }
        }
     }
   else
@@ -4764,12 +4806,10 @@ prep_headers (bfd *abfd)
 {
   Elf_Internal_Ehdr *i_ehdrp;  /* Elf file header, internal form */
   Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */
-  Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */
   struct elf_strtab_hash *shstrtab;
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
   i_ehdrp = elf_elfheader (abfd);
-  i_shdrp = elf_elfsections (abfd);
 
   shstrtab = _bfd_elf_strtab_init ();
   if (shstrtab == NULL)
@@ -4914,8 +4954,6 @@ _bfd_elf_write_object_contents (bfd *abfd)
              || bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt)
            return FALSE;
        }
-      if (count == SHN_LORESERVE - 1)
-       count += SHN_HIRESERVE + 1 - SHN_LORESERVE;
     }
 
   /* Write out the section header names.  */
@@ -4947,11 +4985,11 @@ _bfd_elf_write_corefile_contents (bfd *abfd)
 
 /* Given a section, search the header to find them.  */
 
-int
+unsigned int
 _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
 {
   const struct elf_backend_data *bed;
-  int index;
+  unsigned int index;
 
   if (elf_section_data (asect) != NULL
       && elf_section_data (asect)->this_idx != 0)
@@ -4964,7 +5002,7 @@ _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
   else if (bfd_is_und_section (asect))
     index = SHN_UNDEF;
   else
-    index = -1;
+    index = SHN_BAD;
 
   bed = get_elf_backend_data (abfd);
   if (bed->elf_backend_section_from_bfd_section)
@@ -4975,7 +5013,7 @@ _bfd_elf_section_from_bfd_section (bfd *abfd, struct bfd_section *asect)
        return retval;
     }
 
-  if (index == -1)
+  if (index == SHN_BAD)
     bfd_set_error (bfd_error_nonrepresentable_section);
 
   return index;
@@ -5052,6 +5090,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   unsigned int i;
   unsigned int num_segments;
   bfd_boolean phdr_included = FALSE;
+  bfd_boolean p_paddr_valid;
   bfd_vma maxpagesize;
   struct elf_segment_map *phdr_adjust_seg = NULL;
   unsigned int phdr_adjust_num = 0;
@@ -5090,15 +5129,22 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
    && (section->lma + SECTION_SIZE (section, segment)                  \
        <= SEGMENT_END (segment, base)))
 
-  /* Special case: corefile "NOTE" section containing regs, prpsinfo etc.  */
-#define IS_COREFILE_NOTE(p, s)                                         \
+  /* Handle PT_NOTE segment.  */
+#define IS_NOTE(p, s)                                                  \
   (p->p_type == PT_NOTE                                                        \
-   && bfd_get_format (ibfd) == bfd_core                                        \
-   && s->vma == 0 && s->lma == 0                                       \
+   && elf_section_type (s) == SHT_NOTE                                 \
    && (bfd_vma) s->filepos >= p->p_offset                              \
    && ((bfd_vma) s->filepos + s->size                                  \
        <= p->p_offset + p->p_filesz))
 
+  /* Special case: corefile "NOTE" section containing regs, prpsinfo
+     etc.  */
+#define IS_COREFILE_NOTE(p, s)                                         \
+  (IS_NOTE (p, s)                                                      \
+   && bfd_get_format (ibfd) == bfd_core                                        \
+   && s->vma == 0                                                      \
+   && s->lma == 0)
+
   /* The complicated case when p_vaddr is 0 is to handle the Solaris
      linker, which generates a PT_INTERP section with p_vaddr and
      p_memsz set to 0.  */
@@ -5117,7 +5163,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
      A section will be included if:
        1. It is within the address space of the segment -- we use the LMA
          if that is set for the segment and the VMA otherwise,
-       2. It is an allocated segment,
+       2. It is an allocated section or a NOTE section in a PT_NOTE
+         segment.         
        3. There is an output section associated with it,
        4. The section has not already been allocated to a previous segment.
        5. PT_GNU_STACK segments do not include any sections.
@@ -5130,7 +5177,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)       \
       : IS_CONTAINED_BY_VMA (section, segment))                                \
      && (section->flags & SEC_ALLOC) != 0)                             \
-    || IS_COREFILE_NOTE (segment, section))                            \
+    || IS_NOTE (segment, section))                                     \
    && segment->p_type != PT_GNU_STACK                                  \
    && (segment->p_type != PT_TLS                                       \
        || (section->flags & SEC_THREAD_LOCAL))                         \
@@ -5144,7 +5191,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
           : segment->p_vaddr != section->vma)                          \
        || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic")   \
           == 0))                                                       \
-   && ! section->segment_mark)
+   && !section->segment_mark)
 
 /* If the output section of a section in the input segment is NULL,
    it is removed from the corresponding output segment.   */
@@ -5172,6 +5219,20 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   for (section = ibfd->sections; section != NULL; section = section->next)
     section->segment_mark = FALSE;
 
+  /* The Solaris linker creates program headers in which all the
+     p_paddr fields are zero.  When we try to objcopy or strip such a
+     file, we get confused.  Check for this case, and if we find it
+     don't set the p_paddr_valid fields.  */
+  p_paddr_valid = FALSE;
+  for (i = 0, segment = elf_tdata (ibfd)->phdr;
+       i < num_segments;
+       i++, segment++)
+    if (segment->p_paddr != 0)
+      {
+       p_paddr_valid = TRUE;
+       break;
+      }
+
   /* Scan through the segments specified in the program header
      of the input BFD.  For this first scan we look for overlaps
      in the loadable segments.  These can be created by weird
@@ -5202,12 +5263,12 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        }
 
       /* Determine if this segment overlaps any previous segments.  */
-      for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2 ++)
+      for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2++)
        {
          bfd_signed_vma extra_length;
 
          if (segment2->p_type != PT_LOAD
-             || ! SEGMENT_OVERLAPS (segment, segment2))
+             || !SEGMENT_OVERLAPS (segment, segment2))
            continue;
 
          /* Merge the two segments together.  */
@@ -5215,13 +5276,12 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
            {
              /* Extend SEGMENT2 to include SEGMENT and then delete
                 SEGMENT.  */
-             extra_length =
-               SEGMENT_END (segment, segment->p_vaddr)
-               - SEGMENT_END (segment2, segment2->p_vaddr);
+             extra_length = (SEGMENT_END (segment, segment->p_vaddr)
+                             - SEGMENT_END (segment2, segment2->p_vaddr));
 
              if (extra_length > 0)
                {
-                 segment2->p_memsz  += extra_length;
+                 segment2->p_memsz += extra_length;
                  segment2->p_filesz += extra_length;
                }
 
@@ -5236,13 +5296,12 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
            {
              /* Extend SEGMENT to include SEGMENT2 and then delete
                 SEGMENT2.  */
-             extra_length =
-               SEGMENT_END (segment2, segment2->p_vaddr)
-               - SEGMENT_END (segment, segment->p_vaddr);
+             extra_length = (SEGMENT_END (segment2, segment2->p_vaddr)
+                             - SEGMENT_END (segment, segment->p_vaddr));
 
              if (extra_length > 0)
                {
-                 segment->p_memsz  += extra_length;
+                 segment->p_memsz += extra_length;
                  segment->p_filesz += extra_length;
                }
 
@@ -5254,17 +5313,19 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   /* The second scan attempts to assign sections to segments.  */
   for (i = 0, segment = elf_tdata (ibfd)->phdr;
        i < num_segments;
-       i ++, segment ++)
-    {
-      unsigned int  section_count;
-      asection **   sections;
-      asection *    output_section;
-      unsigned int  isec;
-      bfd_vma       matching_lma;
-      bfd_vma       suggested_lma;
-      unsigned int  j;
+       i++, segment++)
+    {
+      unsigned int section_count;
+      asection **sections;
+      asection *output_section;
+      unsigned int isec;
+      bfd_vma matching_lma;
+      bfd_vma suggested_lma;
+      unsigned int j;
       bfd_size_type amt;
-      asection *    first_section;
+      asection *first_section;
+      bfd_boolean first_matching_lma;
+      bfd_boolean first_suggested_lma;
 
       if (segment->p_type == PT_NULL)
        continue;
@@ -5296,9 +5357,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 
       /* Initialise the fields of the segment map.  Default to
         using the physical address of the segment in the input BFD.  */
-      map->next          = NULL;
-      map->p_type        = segment->p_type;
-      map->p_flags       = segment->p_flags;
+      map->next = NULL;
+      map->p_type = segment->p_type;
+      map->p_flags = segment->p_flags;
       map->p_flags_valid = 1;
 
       /* If the first section in the input segment is removed, there is
@@ -5307,17 +5368,16 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       if (!first_section || first_section->output_section != NULL)
        {
          map->p_paddr = segment->p_paddr;
-         map->p_paddr_valid = 1;
+         map->p_paddr_valid = p_paddr_valid;
        }
 
       /* Determine if this segment contains the ELF file header
         and if it contains the program headers themselves.  */
       map->includes_filehdr = (segment->p_offset == 0
                               && segment->p_filesz >= iehdr->e_ehsize);
-
       map->includes_phdrs = 0;
 
-      if (! phdr_included || segment->p_type != PT_LOAD)
+      if (!phdr_included || segment->p_type != PT_LOAD)
        {
          map->includes_phdrs =
            (segment->p_offset <= (bfd_vma) iehdr->e_phoff
@@ -5336,9 +5396,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
             something.  They are allowed by the ELF spec however, so only
             a warning is produced.  */
          if (segment->p_type == PT_LOAD)
-           (*_bfd_error_handler)
-             (_("%B: warning: Empty loadable segment detected, is this intentional ?\n"),
-              ibfd);
+           (*_bfd_error_handler) (_("%B: warning: Empty loadable segment"
+                                    " detected, is this intentional ?\n"),
+                                  ibfd);
 
          map->count = 0;
          *pointer_to_map = map;
@@ -5375,8 +5435,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
         pointers that we are interested in.  As these sections get assigned
         to a segment, they are removed from this array.  */
 
-      /* Gcc 2.96 miscompiles this code on mips. Don't do casting here
-        to work around this long long bug.  */
       sections = bfd_malloc2 (section_count, sizeof (asection *));
       if (sections == NULL)
        return FALSE;
@@ -5390,53 +5448,68 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       isec = 0;
       matching_lma = 0;
       suggested_lma = 0;
+      first_matching_lma = TRUE;
+      first_suggested_lma = TRUE;
 
-      for (j = 0, section = ibfd->sections;
+      for (section = ibfd->sections;
           section != NULL;
           section = section->next)
+       if (section == first_section)
+         break;
+
+      for (j = 0; section != NULL; section = section->next)
        {
          if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
            {
              output_section = section->output_section;
 
-             sections[j ++] = section;
+             sections[j++] = section;
 
              /* The Solaris native linker always sets p_paddr to 0.
                 We try to catch that case here, and set it to the
                 correct value.  Note - some backends require that
                 p_paddr be left as zero.  */
-             if (segment->p_paddr == 0
+             if (!p_paddr_valid
                  && segment->p_vaddr != 0
-                 && (! bed->want_p_paddr_set_to_zero)
+                 && !bed->want_p_paddr_set_to_zero
                  && isec == 0
                  && output_section->lma != 0
-                 && (output_section->vma == (segment->p_vaddr
-                                             + (map->includes_filehdr
-                                                ? iehdr->e_ehsize
-                                                : 0)
-                                             + (map->includes_phdrs
-                                                ? (iehdr->e_phnum
-                                                   * iehdr->e_phentsize)
-                                                : 0))))
+                 && output_section->vma == (segment->p_vaddr
+                                            + (map->includes_filehdr
+                                               ? iehdr->e_ehsize
+                                               : 0)
+                                            + (map->includes_phdrs
+                                               ? (iehdr->e_phnum
+                                                  * iehdr->e_phentsize)
+                                               : 0)))
                map->p_paddr = segment->p_vaddr;
 
              /* Match up the physical address of the segment with the
                 LMA address of the output section.  */
              if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
                  || IS_COREFILE_NOTE (segment, section)
-                 || (bed->want_p_paddr_set_to_zero &&
-                     IS_CONTAINED_BY_VMA (output_section, segment)))
+                 || (bed->want_p_paddr_set_to_zero
+                     && IS_CONTAINED_BY_VMA (output_section, segment)))
                {
-                 if (matching_lma == 0 || output_section->lma < matching_lma)
-                   matching_lma = output_section->lma;
+                 if (first_matching_lma || output_section->lma < matching_lma)
+                   {
+                     matching_lma = output_section->lma;
+                     first_matching_lma = FALSE;
+                   }
 
                  /* We assume that if the section fits within the segment
                     then it does not overlap any other section within that
                     segment.  */
-                 map->sections[isec ++] = output_section;
+                 map->sections[isec++] = output_section;
                }
-             else if (suggested_lma == 0)
-               suggested_lma = output_section->lma;
+             else if (first_suggested_lma)
+               {
+                 suggested_lma = output_section->lma;
+                 first_suggested_lma = FALSE;
+               }
+
+             if (j == section_count)
+               break;
            }
        }
 
@@ -5454,8 +5527,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
          *pointer_to_map = map;
          pointer_to_map = &map->next;
 
-         if (matching_lma != map->p_paddr
-             && !map->includes_filehdr && !map->includes_phdrs)
+         if (p_paddr_valid
+             && !bed->want_p_paddr_set_to_zero
+             && matching_lma != map->p_paddr
+             && !map->includes_filehdr
+             && !map->includes_phdrs)
            /* There is some padding before the first section in the
               segment.  So, we must account for that in the output
               segment's vma.  */
@@ -5466,7 +5542,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        }
       else
        {
-         if (matching_lma != 0)
+         if (!first_matching_lma)
            {
              /* At least one section fits inside the current segment.
                 Keep it, but modify its physical address to match the
@@ -5512,6 +5588,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        {
          map->count = 0;
          suggested_lma = 0;
+         first_suggested_lma = TRUE;
 
          /* Fill the current segment with sections that fit.  */
          for (j = 0; j < section_count; j++)
@@ -5533,17 +5610,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                      /* If the first section in a segment does not start at
                         the beginning of the segment, then something is
                         wrong.  */
-                     if (output_section->lma !=
-                         (map->p_paddr
-                          + (map->includes_filehdr ? iehdr->e_ehsize : 0)
-                          + (map->includes_phdrs
-                             ? iehdr->e_phnum * iehdr->e_phentsize
-                             : 0)))
+                     if (output_section->lma
+                         != (map->p_paddr
+                             + (map->includes_filehdr ? iehdr->e_ehsize : 0)
+                             + (map->includes_phdrs
+                                ? iehdr->e_phnum * iehdr->e_phentsize
+                                : 0)))
                        abort ();
                    }
                  else
                    {
-                     asection * prev_sec;
+                     asection *prev_sec;
 
                      prev_sec = map->sections[map->count - 1];
 
@@ -5553,11 +5630,14 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                      if ((BFD_ALIGN (prev_sec->lma + prev_sec->size,
                                      maxpagesize)
                           < BFD_ALIGN (output_section->lma, maxpagesize))
-                         || ((prev_sec->lma + prev_sec->size)
+                         || (prev_sec->lma + prev_sec->size
                              > output_section->lma))
                        {
-                         if (suggested_lma == 0)
-                           suggested_lma = output_section->lma;
+                         if (first_suggested_lma)
+                           {
+                             suggested_lma = output_section->lma;
+                             first_suggested_lma = FALSE;
+                           }
 
                          continue;
                        }
@@ -5568,8 +5648,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                  sections[j] = NULL;
                  section->segment_mark = TRUE;
                }
-             else if (suggested_lma == 0)
-               suggested_lma = output_section->lma;
+             else if (first_suggested_lma)
+               {
+                 suggested_lma = output_section->lma;
+                 first_suggested_lma = FALSE;
+               }
            }
 
          BFD_ASSERT (map->count > 0);
@@ -5595,14 +5678,14 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
              /* Initialise the fields of the segment map.  Set the physical
                 physical address to the LMA of the first section that has
                 not yet been assigned.  */
-             map->next             = NULL;
-             map->p_type           = segment->p_type;
-             map->p_flags          = segment->p_flags;
-             map->p_flags_valid    = 1;
-             map->p_paddr          = suggested_lma;
-             map->p_paddr_valid    = 1;
+             map->next = NULL;
+             map->p_type = segment->p_type;
+             map->p_flags = segment->p_flags;
+             map->p_flags_valid = 1;
+             map->p_paddr = suggested_lma;
+             map->p_paddr_valid = p_paddr_valid;
              map->includes_filehdr = 0;
-             map->includes_phdrs   = 0;
+             map->includes_phdrs = 0;
            }
        }
       while (isec < section_count);
@@ -5610,17 +5693,6 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       free (sections);
     }
 
-  /* The Solaris linker creates program headers in which all the
-     p_paddr fields are zero.  When we try to objcopy or strip such a
-     file, we get confused.  Check for this case, and if we find it
-     reset the p_paddr_valid fields.  */
-  for (map = map_first; map != NULL; map = map->next)
-    if (map->p_paddr != 0)
-      break;
-  if (map == NULL)
-    for (map = map_first; map != NULL; map = map->next)
-      map->p_paddr_valid = 0;
-
   elf_tdata (obfd)->segment_map = map_first;
 
   /* If we had to estimate the number of program headers that were
@@ -5642,6 +5714,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 #undef SECTION_SIZE
 #undef IS_CONTAINED_BY_VMA
 #undef IS_CONTAINED_BY_LMA
+#undef IS_NOTE
 #undef IS_COREFILE_NOTE
 #undef IS_SOLARIS_PT_INTERP
 #undef IS_SECTION_IN_INPUT_SEGMENT
@@ -5664,13 +5737,26 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
   unsigned int i;
   unsigned int num_segments;
   bfd_boolean phdr_included = FALSE;
+  bfd_boolean p_paddr_valid;
 
   iehdr = elf_elfheader (ibfd);
 
   map_first = NULL;
   pointer_to_map = &map_first;
 
+  /* If all the segment p_paddr fields are zero, don't set
+     map->p_paddr_valid.  */
+  p_paddr_valid = FALSE;
   num_segments = elf_elfheader (ibfd)->e_phnum;
+  for (i = 0, segment = elf_tdata (ibfd)->phdr;
+       i < num_segments;
+       i++, segment++)
+    if (segment->p_paddr != 0)
+      {
+       p_paddr_valid = TRUE;
+       break;
+      }
+
   for (i = 0, segment = elf_tdata (ibfd)->phdr;
        i < num_segments;
        i++, segment++)
@@ -5714,7 +5800,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       map->p_flags = segment->p_flags;
       map->p_flags_valid = 1;
       map->p_paddr = segment->p_paddr;
-      map->p_paddr_valid = 1;
+      map->p_paddr_valid = p_paddr_valid;
       map->p_align = segment->p_align;
       map->p_align_valid = 1;
       map->p_vaddr_offset = 0;
@@ -5748,7 +5834,9 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            phdr_included = TRUE;
        }
 
-      if (!map->includes_phdrs && !map->includes_filehdr)
+      if (!map->includes_phdrs
+         && !map->includes_filehdr
+         && map->p_paddr_valid)
        /* There is some other padding before the first section.  */
        map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
                               - segment->p_paddr);
@@ -5801,6 +5889,13 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
       asection *section, *osec;
       unsigned int i, num_segments;
       Elf_Internal_Shdr *this_hdr;
+      const struct elf_backend_data *bed;
+
+      bed = get_elf_backend_data (ibfd);
+
+      /* Regenerate the segment map if p_paddr is set to 0.  */
+      if (bed->want_p_paddr_set_to_zero)
+       goto rewrite;
 
       /* Initialize the segment mark field.  */
       for (section = obfd->sections; section != NULL;
@@ -6032,6 +6127,7 @@ _bfd_elf_copy_private_symbol_data (bfd *ibfd,
   osym = elf_symbol_from (obfd, osymarg);
 
   if (isym != NULL
+      && isym->internal_elf_sym.st_shndx != 0
       && osym != NULL
       && bfd_is_abs_section (isym->symbol.section))
     {
@@ -6089,7 +6185,7 @@ swap_out_syms (bfd *abfd,
   symtab_hdr->sh_entsize = bed->s->sizeof_sym;
   symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1);
   symtab_hdr->sh_info = elf_num_locals (abfd) + 1;
-  symtab_hdr->sh_addralign = 1 << bed->s->log_file_align;
+  symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
 
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
@@ -6189,7 +6285,7 @@ swap_out_syms (bfd *abfd,
       else
        {
          asection *sec = syms[idx]->section;
-         int shndx;
+         unsigned int shndx;
 
          if (sec->output_section)
            {
@@ -6236,7 +6332,7 @@ swap_out_syms (bfd *abfd,
            {
              shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 
-             if (shndx == -1)
+             if (shndx == SHN_BAD)
                {
                  asection *sec2;
 
@@ -6260,7 +6356,7 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
                    }
 
                  shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
-                 BFD_ASSERT (shndx != -1);
+                 BFD_ASSERT (shndx != SHN_BAD);
                }
            }
 
@@ -6297,7 +6393,15 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
            sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
        }
       else if (bfd_is_com_section (syms[idx]->section))
-       sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+       {
+#ifdef USE_STT_COMMON
+         if (type == STT_OBJECT)
+           sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON);
+         else
+#else
+           sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+#endif
+       }
       else if (bfd_is_und_section (syms[idx]->section))
        sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
                                    ? STB_WEAK
@@ -6459,8 +6563,7 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
 
   ret = sizeof (arelent *);
   for (s = abfd->sections; s != NULL; s = s->next)
-    if ((s->flags & SEC_LOAD) != 0
-       && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+    if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
        && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
            || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
       ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize)
@@ -6496,8 +6599,7 @@ _bfd_elf_canonicalize_dynamic_reloc (bfd *abfd,
   ret = 0;
   for (s = abfd->sections; s != NULL; s = s->next)
     {
-      if ((s->flags & SEC_LOAD) != 0
-         && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+      if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
          && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
              || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
        {
@@ -7436,7 +7538,7 @@ elfcore_grok_prfpreg (bfd *abfd, Elf_Internal_Note *note)
 }
 
 /* Linux dumps the Intel SSE regs in a note named "LINUX" with a note
-   type of 5 (NT_PRXFPREG).  Just include the whole note's contents
+   type of NT_PRXFPREG.  Just include the whole note's contents
    literally.  */
 
 static bfd_boolean
@@ -7445,6 +7547,13 @@ elfcore_grok_prxfpreg (bfd *abfd, Elf_Internal_Note *note)
   return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
 }
 
+static bfd_boolean
+elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note)
+{
+  return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note);
+}
+
+
 #if defined (HAVE_PRPSINFO_T)
 typedef prpsinfo_t   elfcore_psinfo_t;
 #if defined (HAVE_PRPSINFO32_T)                /* Sparc64 cross Sparc32 */
@@ -7792,6 +7901,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       else
        return TRUE;
 
+    case NT_PPC_VMX:
+      if (note->namesz == 6
+         && strcmp (note->namedata, "LINUX") == 0)
+       return elfcore_grok_ppc_vmx (abfd, note);
+      else
+       return TRUE;
+
     case NT_PRPSINFO:
     case NT_PSINFO:
       if (bed->elf_backend_grok_psinfo)
@@ -8346,6 +8462,35 @@ elfcore_write_prxfpreg (bfd *abfd,
                             note_name, NT_PRXFPREG, xfpregs, size);
 }
 
+char *
+elfcore_write_ppc_vmx (bfd *abfd,
+                      char *buf,
+                      int *bufsiz,
+                      const void *ppc_vmx,
+                      int size)
+{
+  char *note_name = "LINUX";
+  return elfcore_write_note (abfd, buf, bufsiz,
+                            note_name, NT_PPC_VMX, ppc_vmx, size);
+}
+
+char *
+elfcore_write_register_note (bfd *abfd,
+                            char *buf,
+                            int *bufsiz,
+                            const char *section,
+                            const void *data,
+                            int size)
+{
+  if (strcmp (section, ".reg2") == 0)
+    return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-xfp") == 0)
+    return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size);
+  if (strcmp (section, ".reg-ppc-vmx") == 0)
+    return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size);
+  return NULL;
+}
+
 static bfd_boolean
 elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
 {
@@ -8638,7 +8783,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
   count = relplt->size / hdr->sh_entsize;
   size = count * sizeof (asymbol);
   p = relplt->relocation;
-  for (i = 0; i < count; i++, p++)
+  for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
     size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
 
   s = *ret = bfd_malloc (size);
@@ -8648,7 +8793,7 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
   names = (char *) (s + count);
   p = relplt->relocation;
   n = 0;
-  for (i = 0; i < count; i++, s++, p++)
+  for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
     {
       size_t len;
       bfd_vma addr;
@@ -8662,15 +8807,17 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd,
         we are defining a symbol, ensure one of them is set.  */
       if ((s->flags & BSF_LOCAL) == 0)
        s->flags |= BSF_GLOBAL;
+      s->flags |= BSF_SYNTHETIC;
       s->section = plt;
       s->value = addr - plt->vma;
       s->name = names;
+      s->udata.p = NULL;
       len = strlen ((*p->sym_ptr_ptr)->name);
       memcpy (names, (*p->sym_ptr_ptr)->name, len);
       names += len;
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
-      ++n;
+      ++s, ++n;
     }
 
   return n;
This page took 0.042863 seconds and 4 git commands to generate.