This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/6] ld: Create a new LOAD segment for text-only LOAD segment


When there is a text-only LOAD segment, create a new LOAD segment if the
previous section contains text and the current section doesn't or vice
versa:

Elf file type is DYN (Shared object file)
Entry point 0x200ff0
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
  LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
  LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
  LOAD           0x200f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW  0x200000
  DYNAMIC        0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

This is to prevent executing data in read-only sections as instructions.

Also don't put a writable section in a read-only segment if there is a
RELRO segment.

Since there are more than 2 LOAD segments, the minimum file size is
bigger than the maximum page size which is 2MB (0x200000):

-rwxr-xr-x 1 hjl hjl 2104892 Nov 12 11:53 libfoo.so

"-z max-page-size=0x1000" can be used to reduce the maximum page size to
4KB (0x1000):

-rwxr-xr-x 1 hjl hjl 11836 Nov 12 13:22 libfoo.so

Elf file type is DYN (Shared object file)
Entry point 0x1ff0
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x1000
  LOAD           0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
  LOAD           0x001000 0x00002000 0x00002000 0x00058 0x00058 R   0x1000
  LOAD           0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW  0x1000
  DYNAMIC        0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

	PR ld/22393
	* elf.c (_bfd_elf_map_sections_to_segments): When there is a
	text-only LOAD segment, create a new LOAD segment if the
	previous section contains text and the current section doesn't
	or vice versa.  Don't put a writable section in a read-only
	segment if there is a RELRO segment.
---
 bfd/elf.c | 32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/bfd/elf.c b/bfd/elf.c
index 694e43540f..9c5de9675c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4555,6 +4555,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       asection **hdrpp;
       bfd_boolean phdr_in_segment = TRUE;
       bfd_boolean writable;
+      bfd_boolean executable;
       int tls_count = 0;
       asection *first_tls = NULL;
       asection *first_mbind = NULL;
@@ -4643,6 +4644,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       if (maxpagesize == 0)
 	maxpagesize = 1;
       writable = FALSE;
+      executable = FALSE;
       dynsec = bfd_get_section_by_name (abfd, ".dynamic");
       if (dynsec != NULL
 	  && (dynsec->flags & SEC_LOAD) == 0)
@@ -4745,18 +4747,27 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 		 file, then there is no other reason for a new segment.  */
 	      new_segment = FALSE;
 	    }
+	  else if (info != NULL
+		   && info->text_end > info->text_start
+		   && executable != ((hdr->flags & SEC_CODE) != 0))
+	    {
+	      new_segment = TRUE;
+	    }
 	  else if (! writable
 		   && (hdr->flags & SEC_READONLY) == 0
-		   && (((last_hdr->lma + last_size - 1) & -maxpagesize)
-		       != (hdr->lma & -maxpagesize)))
+		   && ((info != NULL
+			&& info->relro_end > info->relro_start)
+		       || (((last_hdr->lma + last_size - 1) & -maxpagesize)
+			   != (hdr->lma & -maxpagesize))))
 	    {
 	      /* We don't want to put a writable section in a read only
 		 segment, unless they are on the same page in memory
-		 anyhow.  We already know that the last section does not
-		 bring us past the current section on the page, so the
-		 only case in which the new section is not on the same
-		 page as the previous section is when the previous section
-		 ends precisely on a page boundary.  */
+		 anyhow and there is no RELRO segment.  We already
+		 know that the last section does not bring us past the
+		 current section on the page, so the only case in which
+		 the new section is not on the same page as the previous
+		 section is when the previous section ends precisely on
+		 a page boundary.  */
 	      new_segment = TRUE;
 	    }
 	  else
@@ -4778,6 +4789,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 	    {
 	      if ((hdr->flags & SEC_READONLY) == 0)
 		writable = TRUE;
+	      if ((hdr->flags & SEC_CODE) != 0)
+		executable = TRUE;
 	      last_hdr = hdr;
 	      /* .tbss sections effectively have zero size.  */
 	      if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
@@ -4803,6 +4816,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
 	  else
 	    writable = FALSE;
 
+	  if ((hdr->flags & SEC_CODE) == 0)
+	    executable = FALSE;
+	  else
+	    executable = TRUE;
+
 	  last_hdr = hdr;
 	  /* .tbss sections effectively have zero size.  */
 	  if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
-- 
2.13.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]