PR4499, assign file positions assumes segment offsets increasing
authorAlan Modra <amodra@gmail.com>
Wed, 23 Oct 2019 07:10:51 +0000 (17:40 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 25 Oct 2019 03:00:05 +0000 (13:30 +1030)
This rewrites much of assign_file_positions_for_non_load_sections to
allow objcopy and strip to handle cases like that in PR4499 where
program headers were not in their usual position immediately after the
ELF file header, and PT_LOAD headers were not sorted by paddr.

PR 4499
include/
* elf/internal.h (struct elf_segment_map): Delete header_size.
Add no_sort_lma and idx.
bfd/
* elf-nacl.c (nacl_modify_segment_map): Set no_sort_lma for all
PT_LOAD segments.
* elf32-spu.c (spu_elf_modify_segment_map): Likewise on overlay
PT_LOAD segments.
* elf.c (elf_sort_segments): New function.
(assign_file_positions_except_relocs): Use shortcuts to elfheader
and elf_tdata.  Seek to e_phoff not sizeof_ehdr to write program
headers.  Move PT_PHDR check..
(assign_file_positions_for_non_load_sections): ..and code setting
PT_PHDR p_vaddr and p_paddr, and code setting __ehdr_start value..
(assign_file_positions_for_load_sections): ..to here.  Sort
PT_LOAD headers.  Delete header_pad code.  Use actual number of
headers rather than allocated in calculating size for program
headers.  Don't assume program headers follow ELF file header.
Simplify pt_load_count code.  Only set "off" for PT_LOAD or
PT_NOTE in cores.
(rewrite_elf_program_header): Set p_vaddr_offset for segments
that include file and program headers.
(copy_elf_program_header): Likewise, replacing header_size code.

bfd/ChangeLog
bfd/elf-nacl.c
bfd/elf.c
bfd/elf32-spu.c
include/ChangeLog
include/elf/internal.h

index f71c9aa846d887ddc66ac87a712a9838804a4136..2b41fb36c4c68a8258b6fb612ea2935cee69e42c 100644 (file)
@@ -1,3 +1,26 @@
+2019-10-25  Alan Modra  <amodra@gmail.com>
+
+       PR 4499
+       * elf-nacl.c (nacl_modify_segment_map): Set no_sort_lma for all
+       PT_LOAD segments.
+       * elf32-spu.c (spu_elf_modify_segment_map): Likewise on overlay
+       PT_LOAD segments.
+       * elf.c (elf_sort_segments): New function.
+       (assign_file_positions_except_relocs): Use shortcuts to elfheader
+       and elf_tdata.  Seek to e_phoff not sizeof_ehdr to write program
+       headers.  Move PT_PHDR check..
+       (assign_file_positions_for_non_load_sections): ..and code setting
+       PT_PHDR p_vaddr and p_paddr, and code setting __ehdr_start value..
+       (assign_file_positions_for_load_sections): ..to here.  Sort
+       PT_LOAD headers.  Delete header_pad code.  Use actual number of
+       headers rather than allocated in calculating size for program
+       headers.  Don't assume program headers follow ELF file header.
+       Simplify pt_load_count code.  Only set "off" for PT_LOAD or
+       PT_NOTE in cores.
+       (rewrite_elf_program_header): Set p_vaddr_offset for segments
+       that include file and program headers.
+       (copy_elf_program_header): Likewise, replacing header_size code.
+
 2019-10-21  Alan Modra  <amodra@gmail.com>
 
        PR 452
index 58eebf6d75834b17e96f8593eb4b39d1ae924230..ddac3b372bf2c84d67fed2b9267bbe637af50daf 100644 (file)
@@ -197,6 +197,7 @@ nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
                 included the file header and phdrs.  */
              seg->includes_filehdr = 0;
              seg->includes_phdrs = 0;
+             seg->no_sort_lma = 1;
              /* Also strip out empty segments.  */
              if (seg->count == 0)
                {
index 314c866c3f10ba6e8e4b8ed8fd4ba66fbf83d7d2..38872d7757e3a7ae5336f9a28a4e2ae8e533f737 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -5296,6 +5296,48 @@ elf_sort_sections (const void *arg1, const void *arg2)
   return sec1->target_index - sec2->target_index;
 }
 
+/* This qsort comparison functions sorts PT_LOAD segments first and
+   by p_paddr, for assign_file_positions_for_load_sections.  */
+
+static int
+elf_sort_segments (const void *arg1, const void *arg2)
+{
+  const struct elf_segment_map *m1 = *(const struct elf_segment_map **) arg1;
+  const struct elf_segment_map *m2 = *(const struct elf_segment_map **) arg2;
+
+  if (m1->p_type != m2->p_type)
+    {
+      if (m1->p_type == PT_NULL)
+       return 1;
+      if (m2->p_type == PT_NULL)
+       return -1;
+      return m1->p_type < m2->p_type ? -1 : 1;
+    }
+  if (m1->includes_filehdr != m2->includes_filehdr)
+    return m1->includes_filehdr ? -1 : 1;
+  if (m1->no_sort_lma != m2->no_sort_lma)
+    return m1->no_sort_lma ? -1 : 1;
+  if (m1->p_type == PT_LOAD && !m1->no_sort_lma)
+    {
+      bfd_vma lma1, lma2;
+      lma1 = 0;
+      if (m1->p_paddr_valid)
+       lma1 = m1->p_paddr;
+      else if (m1->count != 0)
+       lma1 = m1->sections[0]->lma + m1->p_vaddr_offset;
+      lma2 = 0;
+      if (m2->p_paddr_valid)
+       lma2 = m2->p_paddr;
+      else if (m2->count != 0)
+       lma2 = m2->sections[0]->lma + m2->p_vaddr_offset;
+      if (lma1 != lma2)
+       return lma1 < lma2 ? -1 : 1;
+    }
+  if (m1->idx != m2->idx)
+    return m1->idx < m2->idx ? -1 : 1;
+  return 0;
+}
+
 /* Ian Lance Taylor writes:
 
    We shouldn't be using % with a negative signed number.  That's just
@@ -5382,14 +5424,14 @@ assign_file_positions_for_load_sections (bfd *abfd,
 {
   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_segment_map *m;
+  struct elf_segment_map *phdr_load_seg;
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   file_ptr off;
   bfd_size_type maxpagesize;
-  unsigned int pt_load_count = 0;
-  unsigned int alloc;
+  unsigned int alloc, actual;
   unsigned int i, j;
-  bfd_vma header_pad = 0;
+  struct elf_segment_map **sorted_seg_map;
 
   if (link_info == NULL
       && !_bfd_elf_map_sections_to_segments (abfd, link_info))
@@ -5397,11 +5439,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
   alloc = 0;
   for (m = elf_seg_map (abfd); m != NULL; m = m->next)
-    {
-      ++alloc;
-      if (m->header_size)
-       header_pad = m->header_size;
-    }
+    m->idx = alloc++;
 
   if (alloc)
     {
@@ -5418,10 +5456,17 @@ assign_file_positions_for_load_sections (bfd *abfd,
   elf_elfheader (abfd)->e_phnum = alloc;
 
   if (elf_program_header_size (abfd) == (bfd_size_type) -1)
-    elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr;
+    {
+      actual = alloc;
+      elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr;
+    }
   else
-    BFD_ASSERT (elf_program_header_size (abfd)
-               >= alloc * bed->s->sizeof_phdr);
+    {
+      actual = elf_program_header_size (abfd) / bed->s->sizeof_phdr;
+      BFD_ASSERT (elf_program_header_size (abfd)
+                 == actual * bed->s->sizeof_phdr);
+      BFD_ASSERT (actual >= alloc);
+    }
 
   if (alloc == 0)
     {
@@ -5438,36 +5483,16 @@ assign_file_positions_for_load_sections (bfd *abfd,
      See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments
      where the layout is forced to according to a larger size in the
      last iterations for the testcase ld-elf/header.  */
-  BFD_ASSERT (elf_program_header_size (abfd) % bed->s->sizeof_phdr
-             == 0);
-  phdrs = (Elf_Internal_Phdr *)
-     bfd_zalloc2 (abfd,
-                 (elf_program_header_size (abfd) / bed->s->sizeof_phdr),
-                 sizeof (Elf_Internal_Phdr));
+  phdrs = bfd_zalloc (abfd, (actual * sizeof (*phdrs)
+                            + alloc * sizeof (*sorted_seg_map)));
+  sorted_seg_map = (struct elf_segment_map **) (phdrs + actual);
   elf_tdata (abfd)->phdr = phdrs;
   if (phdrs == NULL)
     return FALSE;
 
-  maxpagesize = 1;
-  if ((abfd->flags & D_PAGED) != 0)
-    maxpagesize = bed->maxpagesize;
-
-  off = bed->s->sizeof_ehdr;
-  off += alloc * bed->s->sizeof_phdr;
-  if (header_pad < (bfd_vma) off)
-    header_pad = 0;
-  else
-    header_pad -= off;
-  off += header_pad;
-
-  for (m = elf_seg_map (abfd), p = phdrs, j = 0;
-       m != NULL;
-       m = m->next, p++, j++)
+  for (m = elf_seg_map (abfd), j = 0; m != NULL; m = m->next, j++)
     {
-      asection **secpp;
-      bfd_vma off_adjust;
-      bfd_boolean no_contents;
-
+      sorted_seg_map[j] = m;
       /* If elf_segment_map is not from map_sections_to_segments, the
         sections may not be correctly ordered.  NOTE: sorting should
         not be done to the PT_NOTE section of a corefile, which may
@@ -5482,12 +5507,48 @@ assign_file_positions_for_load_sections (bfd *abfd,
          qsort (m->sections, (size_t) m->count, sizeof (asection *),
                 elf_sort_sections);
        }
+    }
+  if (alloc > 1)
+    qsort (sorted_seg_map, alloc, sizeof (*sorted_seg_map),
+          elf_sort_segments);
+
+  maxpagesize = 1;
+  if ((abfd->flags & D_PAGED) != 0)
+    maxpagesize = bed->maxpagesize;
+
+  /* Sections must map to file offsets past the ELF file header.  */
+  off = bed->s->sizeof_ehdr;
+  /* And if one of the PT_LOAD headers doesn't include the program
+     headers then we'll be mapping program headers in the usual
+     position after the ELF file header.  */
+  phdr_load_seg = NULL;
+  for (j = 0; j < alloc; j++)
+    {
+      m = sorted_seg_map[j];
+      if (m->p_type != PT_LOAD)
+       break;
+      if (m->includes_phdrs)
+       {
+         phdr_load_seg = m;
+         break;
+       }
+    }
+  if (phdr_load_seg == NULL)
+    off += actual * bed->s->sizeof_phdr;
+
+  for (j = 0; j < alloc; j++)
+    {
+      asection **secpp;
+      bfd_vma off_adjust;
+      bfd_boolean no_contents;
 
       /* An ELF segment (described by Elf_Internal_Phdr) may contain a
         number of sections with contents contributing to both p_filesz
         and p_memsz, followed by a number of sections with no contents
         that just contribute to p_memsz.  In this loop, OFF tracks next
         available file offset for PT_LOAD and PT_NOTE segments.  */
+      m = sorted_seg_map[j];
+      p = phdrs + m->idx;
       p->p_type = m->p_type;
       p->p_flags = m->p_flags;
 
@@ -5518,14 +5579,18 @@ assign_file_positions_for_load_sections (bfd *abfd,
            maxpagesize = m->p_align;
 
          p->p_align = maxpagesize;
-         pt_load_count += 1;
        }
       else if (m->p_align_valid)
        p->p_align = m->p_align;
       else if (m->count == 0)
        p->p_align = 1 << bed->s->log_file_align;
-      else
-       p->p_align = 0;
+
+      if (m == phdr_load_seg)
+       {
+         if (!m->includes_filehdr)
+           p->p_offset = off;
+         off += actual * bed->s->sizeof_phdr;
+       }
 
       no_contents = FALSE;
       off_adjust = 0;
@@ -5574,7 +5639,8 @@ assign_file_positions_for_load_sections (bfd *abfd,
          /* Broken hardware and/or kernel require that files do not
             map the same page with different permissions on some hppa
             processors.  */
-         if (pt_load_count > 1
+         if (j != 0
+             && (abfd->flags & D_PAGED) != 0
              && bed->no_page_alias
              && (off & (maxpagesize - 1)) != 0
              && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize))
@@ -5612,33 +5678,38 @@ assign_file_positions_for_load_sections (bfd *abfd,
        for (i = 0; i < m->count; i++)
          elf_section_type (m->sections[i]) = SHT_NOTE;
 
-      p->p_offset = 0;
-      p->p_filesz = 0;
-      p->p_memsz = 0;
-
       if (m->includes_filehdr)
        {
          if (!m->p_flags_valid)
            p->p_flags |= PF_R;
          p->p_filesz = bed->s->sizeof_ehdr;
          p->p_memsz = bed->s->sizeof_ehdr;
-         if (m->count > 0)
+         if (p->p_type == PT_LOAD)
            {
-             if (p->p_vaddr < (bfd_vma) off
-                 || (!m->p_paddr_valid
-                     && p->p_paddr < (bfd_vma) off))
+             if (m->count > 0)
                {
-                 _bfd_error_handler
-                   (_("%pB: not enough room for program headers,"
-                      " try linking with -N"),
-                    abfd);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
+                 if (p->p_vaddr < (bfd_vma) off
+                     || (!m->p_paddr_valid
+                         && p->p_paddr < (bfd_vma) off))
+                   {
+                     _bfd_error_handler
+                       (_("%pB: not enough room for program headers,"
+                          " try linking with -N"),
+                        abfd);
+                     bfd_set_error (bfd_error_bad_value);
+                     return FALSE;
+                   }
+                 p->p_vaddr -= off;
+                 if (!m->p_paddr_valid)
+                   p->p_paddr -= off;
                }
-
-             p->p_vaddr -= off;
+           }
+         else if (sorted_seg_map[0]->includes_filehdr)
+           {
+             Elf_Internal_Phdr *filehdr = phdrs + sorted_seg_map[0]->idx;
+             p->p_vaddr = filehdr->p_vaddr;
              if (!m->p_paddr_valid)
-               p->p_paddr -= off;
+               p->p_paddr = filehdr->p_paddr;
            }
        }
 
@@ -5646,25 +5717,33 @@ assign_file_positions_for_load_sections (bfd *abfd,
        {
          if (!m->p_flags_valid)
            p->p_flags |= PF_R;
-
+         p->p_filesz += actual * bed->s->sizeof_phdr;
+         p->p_memsz += actual * bed->s->sizeof_phdr;
          if (!m->includes_filehdr)
            {
-             p->p_offset = bed->s->sizeof_ehdr;
-
-             if (m->count > 0)
+             if (p->p_type == PT_LOAD)
+               {
+                 elf_elfheader (abfd)->e_phoff = p->p_offset;
+                 if (m->count > 0)
+                   {
+                     p->p_vaddr -= off - p->p_offset;
+                     if (!m->p_paddr_valid)
+                       p->p_paddr -= off - p->p_offset;
+                   }
+               }
+             else if (phdr_load_seg != NULL)
                {
-                 p->p_vaddr -= off - p->p_offset;
+                 Elf_Internal_Phdr *phdr = phdrs + phdr_load_seg->idx;
+                 bfd_vma phdr_off = 0;
+                 if (phdr_load_seg->includes_filehdr)
+                   phdr_off = bed->s->sizeof_ehdr;
+                 p->p_vaddr = phdr->p_vaddr + phdr_off;
                  if (!m->p_paddr_valid)
-                   p->p_paddr -= off - p->p_offset;
+                   p->p_paddr = phdr->p_paddr + phdr_off;
+                 p->p_offset = phdr->p_offset + phdr_off;
                }
-           }
-
-         p->p_filesz += alloc * bed->s->sizeof_phdr;
-         p->p_memsz += alloc * bed->s->sizeof_phdr;
-         if (m->count)
-           {
-             p->p_filesz += header_pad;
-             p->p_memsz += header_pad;
+             else
+               p->p_offset = bed->s->sizeof_ehdr;
            }
        }
 
@@ -5726,16 +5805,19 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
              if (this_hdr->sh_type != SHT_NOBITS)
                {
-                 if (p->p_filesz + adjust < p->p_memsz)
+                 if (p->p_type == PT_LOAD)
                    {
-                     /* We have a PROGBITS section following NOBITS ones.
-                        Allocate file space for the NOBITS section(s) and
-                        zero it.  */
-                     adjust = p->p_memsz - p->p_filesz;
-                     if (!write_zeros (abfd, off, adjust))
-                       return FALSE;
+                     if (p->p_filesz + adjust < p->p_memsz)
+                       {
+                         /* We have a PROGBITS section following NOBITS ones.
+                            Allocate file space for the NOBITS section(s) and
+                            zero it.  */
+                         adjust = p->p_memsz - p->p_filesz;
+                         if (!write_zeros (abfd, off, adjust))
+                           return FALSE;
+                       }
+                     off += adjust;
                    }
-                 off += adjust;
                  p->p_filesz += adjust;
                }
            }
@@ -5824,6 +5906,22 @@ assign_file_positions_for_load_sections (bfd *abfd,
 
       off -= off_adjust;
 
+      /* PR ld/20815 - Check that the program header segment, if
+        present, will be loaded into memory.  */
+      if (p->p_type == PT_PHDR
+         && phdr_load_seg == NULL
+         && !(bed->elf_backend_allow_non_load_phdr != NULL
+              && bed->elf_backend_allow_non_load_phdr (abfd, phdrs, alloc)))
+       {
+         /* The fix for this error is usually to edit the linker script being
+            used and set up the program headers manually.  Either that or
+            leave room for the headers at the start of the SECTIONS.  */
+         _bfd_error_handler (_("%pB: error: PHDR segment not covered"
+                               " by LOAD segment"),
+                             abfd);
+         return FALSE;
+       }
+
       /* Check that all sections are in a PT_LOAD segment.
         Don't check funky gdb generated core files.  */
       if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core)
@@ -5863,6 +5961,57 @@ assign_file_positions_for_load_sections (bfd *abfd,
     }
 
   elf_next_file_pos (abfd) = off;
+
+  if (link_info != NULL
+      && phdr_load_seg != NULL
+      && phdr_load_seg->includes_filehdr)
+    {
+      /* There is a segment that contains both the file headers and the
+        program headers, so provide a symbol __ehdr_start pointing there.
+        A program can use this to examine itself robustly.  */
+
+      struct elf_link_hash_entry *hash
+       = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+                               FALSE, FALSE, TRUE);
+      /* If the symbol was referenced and not defined, define it.  */
+      if (hash != NULL
+         && (hash->root.type == bfd_link_hash_new
+             || hash->root.type == bfd_link_hash_undefined
+             || hash->root.type == bfd_link_hash_undefweak
+             || hash->root.type == bfd_link_hash_common))
+       {
+         asection *s = NULL;
+         bfd_vma filehdr_vaddr = phdrs[phdr_load_seg->idx].p_vaddr;
+
+         if (phdr_load_seg->count != 0)
+           /* The segment contains sections, so use the first one.  */
+           s = phdr_load_seg->sections[0];
+         else
+           /* Use the first (i.e. lowest-addressed) section in any segment.  */
+           for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+             if (m->p_type == PT_LOAD && m->count != 0)
+               {
+                 s = m->sections[0];
+                 break;
+               }
+
+         if (s != NULL)
+           {
+             hash->root.u.def.value = filehdr_vaddr - s->vma;
+             hash->root.u.def.section = s;
+           }
+         else
+           {
+             hash->root.u.def.value = filehdr_vaddr;
+             hash->root.u.def.section = bfd_abs_section_ptr;
+           }
+
+         hash->root.type = bfd_link_hash_defined;
+         hash->def_regular = 1;
+         hash->non_elf = 0;
+       }
+    }
+
   return TRUE;
 }
 
@@ -5908,11 +6057,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   struct elf_segment_map *m;
-  struct elf_segment_map *hdrs_segment;
-  bfd_vma filehdr_vaddr, filehdr_paddr;
-  bfd_vma phdrs_vaddr, phdrs_paddr;
   file_ptr off;
-  unsigned int count;
 
   i_shdrpp = elf_elfsections (abfd);
   end_hdrpp = i_shdrpp + elf_numsections (abfd);
@@ -5970,86 +6115,11 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
       else
        off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
     }
+  elf_next_file_pos (abfd) = off;
 
   /* Now that we have set the section file positions, we can set up
      the file positions for the non PT_LOAD segments.  */
-  count = 0;
-  filehdr_vaddr = 0;
-  filehdr_paddr = 0;
-  phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
-  phdrs_paddr = 0;
-  hdrs_segment = NULL;
   phdrs = elf_tdata (abfd)->phdr;
-  for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++)
-    {
-      ++count;
-      if (p->p_type != PT_LOAD)
-       continue;
-
-      if (m->includes_filehdr)
-       {
-         filehdr_vaddr = p->p_vaddr;
-         filehdr_paddr = p->p_paddr;
-       }
-      if (m->includes_phdrs)
-       {
-         phdrs_vaddr = p->p_vaddr;
-         phdrs_paddr = p->p_paddr;
-         if (m->includes_filehdr)
-           {
-             hdrs_segment = m;
-             phdrs_vaddr += bed->s->sizeof_ehdr;
-             phdrs_paddr += bed->s->sizeof_ehdr;
-           }
-       }
-    }
-
-  if (hdrs_segment != NULL && link_info != NULL)
-    {
-      /* There is a segment that contains both the file headers and the
-        program headers, so provide a symbol __ehdr_start pointing there.
-        A program can use this to examine itself robustly.  */
-
-      struct elf_link_hash_entry *hash
-       = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
-                               FALSE, FALSE, TRUE);
-      /* If the symbol was referenced and not defined, define it.  */
-      if (hash != NULL
-         && (hash->root.type == bfd_link_hash_new
-             || hash->root.type == bfd_link_hash_undefined
-             || hash->root.type == bfd_link_hash_undefweak
-             || hash->root.type == bfd_link_hash_common))
-       {
-         asection *s = NULL;
-         if (hdrs_segment->count != 0)
-           /* The segment contains sections, so use the first one.  */
-           s = hdrs_segment->sections[0];
-         else
-           /* Use the first (i.e. lowest-addressed) section in any segment.  */
-           for (m = elf_seg_map (abfd); m != NULL; m = m->next)
-             if (m->count != 0)
-               {
-                 s = m->sections[0];
-                 break;
-               }
-
-         if (s != NULL)
-           {
-             hash->root.u.def.value = filehdr_vaddr - s->vma;
-             hash->root.u.def.section = s;
-           }
-         else
-           {
-             hash->root.u.def.value = filehdr_vaddr;
-             hash->root.u.def.section = bfd_abs_section_ptr;
-           }
-
-         hash->root.type = bfd_link_hash_defined;
-         hash->def_regular = 1;
-         hash->non_elf = 0;
-       }
-    }
-
   for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++)
     {
       if (p->p_type == PT_GNU_RELRO)
@@ -6195,22 +6265,8 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
                }
            }
        }
-      else if (m->includes_filehdr)
-       {
-         p->p_vaddr = filehdr_vaddr;
-         if (! m->p_paddr_valid)
-           p->p_paddr = filehdr_paddr;
-       }
-      else if (m->includes_phdrs)
-       {
-         p->p_vaddr = phdrs_vaddr;
-         if (! m->p_paddr_valid)
-           p->p_paddr = phdrs_paddr;
-       }
     }
 
-  elf_next_file_pos (abfd) = off;
-
   return TRUE;
 }
 
@@ -6310,8 +6366,8 @@ assign_file_positions_except_relocs (bfd *abfd,
       /* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=.  */
       if (link_info != NULL && bfd_link_pie (link_info))
        {
-         unsigned int num_segments = elf_elfheader (abfd)->e_phnum;
-         Elf_Internal_Phdr *segment = elf_tdata (abfd)->phdr;
+         unsigned int num_segments = i_ehdrp->e_phnum;
+         Elf_Internal_Phdr *segment = tdata->phdr;
          Elf_Internal_Phdr *end_segment = &segment[num_segments];
 
          /* Find the lowest p_vaddr in PT_LOAD segments.  */
@@ -6326,42 +6382,16 @@ assign_file_positions_except_relocs (bfd *abfd,
            i_ehdrp->e_type = ET_EXEC;
        }
 
-      /* Write out the program headers.  */
-      alloc = elf_elfheader (abfd)->e_phnum;
-      if (alloc == 0)
-       return TRUE;
-
-      /* PR ld/20815 - Check that the program header segment, if present, will
-        be loaded into memory.  FIXME: The check below is not sufficient as
-        really all PT_LOAD segments should be checked before issuing an error
-        message.  Plus the PHDR segment does not have to be the first segment
-        in the program header table.  But this version of the check should
-        catch all real world use cases.
-
+      /* Write out the program headers.
         FIXME: We used to have code here to sort the PT_LOAD segments into
         ascending order, as per the ELF spec.  But this breaks some programs,
         including the Linux kernel.  But really either the spec should be
         changed or the programs updated.  */
-      if (alloc > 1
-         && tdata->phdr[0].p_type == PT_PHDR
-         && (bed->elf_backend_allow_non_load_phdr == NULL
-             || !bed->elf_backend_allow_non_load_phdr (abfd, tdata->phdr,
-                                                       alloc))
-         && tdata->phdr[1].p_type == PT_LOAD
-         && (tdata->phdr[1].p_vaddr > tdata->phdr[0].p_vaddr
-             || (tdata->phdr[1].p_vaddr + tdata->phdr[1].p_memsz
-                 < tdata->phdr[0].p_vaddr + tdata->phdr[0].p_memsz)))
-       {
-         /* The fix for this error is usually to edit the linker script being
-            used and set up the program headers manually.  Either that or
-            leave room for the headers at the start of the SECTIONS.  */
-         _bfd_error_handler (_("%pB: error: PHDR segment not covered"
-                               " by LOAD segment"),
-                             abfd);
-         return FALSE;
-       }
+      alloc = i_ehdrp->e_phnum;
+      if (alloc == 0)
+       return TRUE;
 
-      if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
+      if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) != 0
          || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
        return FALSE;
     }
@@ -7185,14 +7215,18 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
          pointer_to_map = &map->next;
 
          if (p_paddr_valid
-             && !bed->want_p_paddr_set_to_zero
-             && matching_lma->lma != map->p_paddr
-             && !map->includes_filehdr
-             && !map->includes_phdrs)
-           /* There is some padding before the first section in the
-              segment.  So, we must account for that in the output
-              segment's vma.  */
-           map->p_vaddr_offset = map->p_paddr - matching_lma->lma;
+             && !bed->want_p_paddr_set_to_zero)
+           {
+             bfd_vma hdr_size = 0;
+             if (map->includes_filehdr)
+               hdr_size = iehdr->e_ehsize;
+             if (map->includes_phdrs)
+               hdr_size += iehdr->e_phnum * iehdr->e_phentsize;
+
+             /* Account for padding before the first section in the
+                segment.  */
+             map->p_vaddr_offset = map->p_paddr + hdr_size - matching_lma->lma;
+           }
 
          free (sections);
          continue;
@@ -7441,7 +7475,6 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
       Elf_Internal_Shdr *this_hdr;
       asection *first_section = NULL;
       asection *lowest_section;
-      bfd_boolean no_contents = TRUE;
 
       /* Compute how many sections are in this segment.  */
       for (section = ibfd->sections, section_count = 0;
@@ -7453,8 +7486,6 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            {
              if (first_section == NULL)
                first_section = section;
-             if (elf_section_type (section) != SHT_NOBITS)
-               no_contents = FALSE;
              section_count++;
            }
        }
@@ -7549,27 +7580,20 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            }
        }
 
-      if (map->includes_filehdr && lowest_section != NULL)
-       {
-         /* Try to keep the space used by the headers plus any
-            padding fixed.  If there are sections with file contents
-            in this segment then the lowest sh_offset is the best
-            guess.  Otherwise the segment only has file contents for
-            the headers, and p_filesz is the best guess.  */
-         if (no_contents)
-           map->header_size = segment->p_filesz;
-         else
-           map->header_size = lowest_section->filepos;
-       }
-
       if (section_count == 0)
        map->p_vaddr_offset = segment->p_vaddr;
-      else if (!map->includes_phdrs
-              && !map->includes_filehdr
-              && map->p_paddr_valid)
-       /* Account for padding before the first section.  */
-       map->p_vaddr_offset = (segment->p_paddr
-                              - (lowest_section ? lowest_section->lma : 0));
+      else if (map->p_paddr_valid)
+       {
+         /* Account for padding before the first section in the segment.  */
+         bfd_vma hdr_size = 0;
+         if (map->includes_filehdr)
+           hdr_size = iehdr->e_ehsize;
+         if (map->includes_phdrs)
+           hdr_size += iehdr->e_phnum * iehdr->e_phentsize;
+
+         map->p_vaddr_offset = (map->p_paddr + hdr_size
+                                - (lowest_section ? lowest_section->lma : 0));
+       }
 
       map->count = section_count;
       *pointer_to_map = map;
index e75d999fd51fa12bb5e3b53eb18e7f7390a01211..b557c865b3eb2d0b9497ac32e5cd714eeb1331b3 100644 (file)
@@ -5302,6 +5302,7 @@ spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
              && spu_elf_section_data ((*p)->sections[0])->u.o.ovl_index != 0)
            {
              m = *p;
+             m->no_sort_lma = 1;
              *p = m->next;
              *p_overlay = m;
              p_overlay = &m->next;
index 412d71459e077001a2d21320e7905160c5fa4b7c..1b3a519f6ce3d4a320b878bfd0306ec70dd05ff4 100644 (file)
@@ -1,3 +1,9 @@
+2019-10-25  Alan Modra  <amodra@gmail.com>
+
+       PR 4499
+       * elf/internal.h (struct elf_segment_map): Delete header_size.
+       Add no_sort_lma and idx.
+
 2019-10-16  Alan Modra  <amodra@gmail.com>
 
        PR 13616
index 59e3ede2e03d92e3e4c03b9a6540ec8c553dd753..794c16812eea6c3cb6acda720203920549364500 100644 (file)
@@ -273,8 +273,6 @@ struct elf_segment_map
   bfd_vma p_align;
   /* Segment size in file and memory */
   bfd_vma p_size;
-  /* Required size of filehdr + phdrs, if non-zero */
-  bfd_vma header_size;
   /* Whether the p_flags field is valid; if not, the flags are based
      on the section flags.  */
   unsigned int p_flags_valid : 1;
@@ -291,6 +289,13 @@ struct elf_segment_map
   unsigned int includes_filehdr : 1;
   /* Whether this segment includes the program headers.  */
   unsigned int includes_phdrs : 1;
+  /* Assume this PT_LOAD header has an lma of zero when sorting
+     headers before assigning file offsets.  PT_LOAD headers with this
+     flag set are placed after one with includes_filehdr set, and
+     before PT_LOAD headers without this flag set.  */
+  unsigned int no_sort_lma : 1;
+  /* Index holding original order before sorting segments.  */
+  unsigned int idx;
   /* Number of sections (may be 0).  */
   unsigned int count;
   /* Sections.  Actual number of elements is in count field.  */
This page took 0.038194 seconds and 4 git commands to generate.