PR22829, objcopy/strip removes PT_GNU_RELRO from lld binaries

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

PR22829, objcopy/strip removes PT_GNU_RELRO from lld binaries

Alan Modra-3
lld lays out the relro segment differently to GNU ld, not bothering to
include the first few bytes of .got.plt and padding out to a page at
the end of the segment.  This patch teaches binutils to recognize the
different (and somewhat inferior) layout as valid.

bfd/
        PR 22829
        * elf.c (assign_file_positions_for_non_load_sections): Rewrite
        PT_GNU_RELRO setup.
ld/
        * testsuite/ld-x86-64/pr14207.d: Adjust relro p_filesz.

diff --git a/bfd/elf.c b/bfd/elf.c
index db1e076..0503154 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -5861,50 +5861,74 @@ 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
       && 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
diff --git a/ld/testsuite/ld-x86-64/pr14207.d b/ld/testsuite/ld-x86-64/pr14207.d
index b71d705..6830d03 100644
--- a/ld/testsuite/ld-x86-64/pr14207.d
+++ b/ld/testsuite/ld-x86-64/pr14207.d
@@ -13,7 +13,7 @@ Program Headers:
   LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x0001c8 0x0001c8 R   0x200000
   LOAD           0x000b.8 0x0000000000200b.8 0x0000000000200b.8 0x0004.0 0x000c.8 RW  0x200000
   DYNAMIC        0x000b.0 0x0000000000200b.0 0x0000000000200b.0 0x0001.0 0x0001.0 RW  0x8
-  GNU_RELRO      0x000b.8 0x0000000000200b.8 0x0000000000200b.8 0x0004.8 0x0004.8 R   0x1
+  GNU_RELRO      0x000b.8 0x0000000000200b.8 0x0000000000200b.8 0x0004.0 0x0004.8 R   0x1
 
  Section to Segment mapping:
   Segment Sections...

--
Alan Modra
Australia Development Lab, IBM