Ignore degenerate PT_LOAD segments
[deliverable/binutils-gdb.git] / bfd / elf.c
index db1e076b554a83be5db6234c11e89d26805fb527..b069b592652dfd4d5c82478c71ba1b67538953fa 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -5861,50 +5861,75 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
     {
       if (p->p_type == PT_GNU_RELRO)
        {
-         const Elf_Internal_Phdr *lp;
-         struct elf_segment_map *lm;
+         bfd_vma start, end;
 
          if (link_info != NULL)
            {
              /* During linking the range of the RELRO segment is passed
-                in link_info.  */
+                in link_info.  Note that there may be padding between
+                relro_start and the first RELRO section.  */
+             start = link_info->relro_start;
+             end = link_info->relro_end;
+           }
+         else if (m->count != 0)
+           {
+             if (!m->p_size_valid)
+               abort ();
+             start = m->sections[0]->vma;
+             end = start + m->p_size;
+           }
+         else
+           {
+             start = 0;
+             end = 0;
+           }
+
+         if (start < end)
+           {
+             struct elf_segment_map *lm;
+             const Elf_Internal_Phdr *lp;
+             unsigned int i;
+
+             /* Find a LOAD segment containing a section in the RELRO
+                segment.  */
              for (lm = elf_seg_map (abfd), lp = phdrs;
                   lm != NULL;
                   lm = lm->next, lp++)
                {
                  if (lp->p_type == PT_LOAD
-                     && lp->p_vaddr < link_info->relro_end
+                     && lp->p_memsz != 0
                      && lm->count != 0
-                     && lm->sections[0]->vma >= link_info->relro_start)
+                     && lm->sections[lm->count - 1]->vma >= start
+                     && lm->sections[0]->vma < end)
                    break;
                }
-
              BFD_ASSERT (lm != NULL);
-           }
-         else
-           {
-             /* Otherwise we are copying an executable or shared
-                library, but we need to use the same linker logic.  */
-             for (lp = phdrs; lp < phdrs + count; ++lp)
+
+             /* Find the section starting the RELRO segment.  */
+             for (i = 0; i < lm->count; i++)
                {
-                 if (lp->p_type == PT_LOAD
-                     && lp->p_paddr == p->p_paddr)
+                 asection *s = lm->sections[i];
+                 if (s->vma >= start
+                     && s->vma < end
+                     && s->size != 0)
                    break;
                }
-           }
+             BFD_ASSERT (i < lm->count);
+
+             p->p_vaddr = lm->sections[i]->vma;
+             p->p_paddr = lm->sections[i]->lma;
+             p->p_offset = lm->sections[i]->filepos;
+             p->p_memsz = end - p->p_vaddr;
+             p->p_filesz = p->p_memsz;
+
+             /* The RELRO segment typically ends a few bytes into
+                .got.plt but other layouts are possible.  In cases
+                where the end does not match any loaded section (for
+                instance is in file padding), trim p_filesz back to
+                correspond to the end of loaded section contents.  */
+             if (p->p_filesz > lp->p_vaddr + lp->p_filesz - p->p_vaddr)
+               p->p_filesz = lp->p_vaddr + lp->p_filesz - p->p_vaddr;
 
-         if (lp < phdrs + count)
-           {
-             p->p_vaddr = lp->p_vaddr;
-             p->p_paddr = lp->p_paddr;
-             p->p_offset = lp->p_offset;
-             if (link_info != NULL)
-               p->p_filesz = link_info->relro_end - lp->p_vaddr;
-             else if (m->p_size_valid)
-               p->p_filesz = m->p_size;
-             else
-               abort ();
-             p->p_memsz = p->p_filesz;
              /* Preserve the alignment and flags if they are valid. The
                 gold linker generates RW/4 for the PT_GNU_RELRO section.
                 It is better for objcopy/strip to honor these attributes
@@ -6114,7 +6139,9 @@ assign_file_positions_except_relocs (bfd *abfd,
         changed or the programs updated.  */
       if (alloc > 1
          && tdata->phdr[0].p_type == PT_PHDR
-         && ! bed->elf_backend_allow_non_load_phdr (abfd, tdata->phdr, alloc)
+         && (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)
@@ -7580,7 +7607,16 @@ _bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded)
               but the SHT_GROUP section is, then adjust its size.  */
            else if (s->output_section == discarded
                     && isec->output_section != discarded)
-             removed += 4;
+             {
+               struct bfd_elf_section_data *elf_sec = elf_section_data (s);
+               removed += 4;
+               if (elf_sec->rel.hdr != NULL
+                   && (elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0)
+                 removed += 4;
+               if (elf_sec->rela.hdr != NULL
+                   && (elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0)
+                 removed += 4;
+             }
            s = elf_next_in_group (s);
            if (s == first)
              break;
@@ -7590,18 +7626,26 @@ _bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded)
            if (discarded != NULL)
              {
                /* If we've been called for ld -r, then we need to
-                  adjust the input section size.  This function may
-                  be called multiple times, so save the original
-                  size.  */
+                  adjust the input section size.  */
                if (isec->rawsize == 0)
                  isec->rawsize = isec->size;
                isec->size = isec->rawsize - removed;
+               if (isec->size <= 4)
+                 {
+                   isec->size = 0;
+                   isec->flags |= SEC_EXCLUDE;
+                 }
              }
            else
              {
                /* Adjust the output section size when called from
                   objcopy. */
                isec->output_section->size -= removed;
+               if (isec->output_section->size <= 4)
+                 {
+                   isec->output_section->size = 0;
+                   isec->output_section->flags |= SEC_EXCLUDE;
+                 }
              }
          }
       }
This page took 0.026954 seconds and 4 git commands to generate.