This is the mail archive of the binutils@sources.redhat.com 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] ELF section to segment mapping adjustments


(Re-submitting a patch that I never got a reply to, originally at
http://sourceware.org/ml/binutils/2004-08/msg00361.html.)

Looking further at what ld does when building Linux I discovered more
anomalies (all sections in the below descriptions are considered to be
page size aligned and a multiple of a page size large):

1) A non-writable section following a writable one would result in the
non-writable section to be merged into the writable segment, thus losing
the write protection. The inverse case was dealt with properly.

2) A zero-sized bss section following a writable section and preceding
a non-writable one would result in the latter again losing its write
protection.

3) A zero-sized bss section between two writable sections would result
in a needlessly splitting the sections into two segments.

The patch attempts to address all these. Built and tested on
x86_64-unknown-linux-gnu and as cross tools for a large number of targets.

Two additional questions:

Does it really make sense to have a zero-sized section contribute to the
access permissions of the segment it gets assigned to?

Shouldn't the executable permission be handled like the writeable one, i.e.
attempting to not merge sections with different permissions into one
segment?

If the answer to the first one is 'no' and/or that to the second is 'yes',
then perhaps some more adjustments to this code might be desirable.

Jan

bfd/
2004-05-10  Jan Beulich  <jbeulich@novell.com>

	* elf.c (map_sections_to_segments): Symmetrically handle segment
	splits between non-writable and writable sections when a writable
	section preceeds a non-writable one. Consider loadable/non-loadable
	state of section only when it has non-zero size.
	(elf_sort_sections): Consider loadable state only after comparing
	sizes.

ld/testsuite/
2005-05-10  Jan Beulich  <jbeulich@novell.com>

	* ld-elf/seg.*: New.

--- /home/jbeulich/src/binutils/mainline/2005-05-06/bfd/elf.c	2005-05-06 08:24:21.000000000 +0200
+++ 2005-05-06/bfd/elf.c	2005-05-10 09:24:55.000000000 +0200
@@ -3442,13 +3442,14 @@ map_sections_to_segments (bfd *abfd)
   struct elf_segment_map *mfirst;
   struct elf_segment_map **pm;
   struct elf_segment_map *m;
-  asection *last_hdr;
+  asection *last_hdr, *last_nz;
   bfd_vma last_size;
   unsigned int phdr_index;
   bfd_vma maxpagesize;
   asection **hdrpp;
   bfd_boolean phdr_in_segment = TRUE;
   bfd_boolean writable;
+  int loadable; /* 0: indifferent, < 0: no, > 0: yes */
   int tls_count = 0;
   asection *first_tls = NULL;
   asection *dynsec, *eh_frame_hdr;
@@ -3524,9 +3525,11 @@ map_sections_to_segments (bfd *abfd)
      a few bytes of the end of the first section.  */
   last_hdr = NULL;
   last_size = 0;
+  last_nz = NULL;
   phdr_index = 0;
   maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
   writable = FALSE;
+  loadable = 0;
   dynsec = bfd_get_section_by_name (abfd, ".dynamic");
   if (dynsec != NULL
       && (dynsec->flags & SEC_LOAD) == 0)
@@ -3579,11 +3582,12 @@ map_sections_to_segments (bfd *abfd)
              skip a page in the segment, then we need a new segment.  */
 	  new_segment = TRUE;
 	}
-      else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
-	       && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+      else if (loadable < 0
+	       && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0
+	       && hdr->size != 0)
 	{
-	  /* We don't want to put a loadable section after a
-             nonloadable section in the same segment.
+	  /* We don't want to put a non-empty loadable section after
+             a nonloadable section in the same segment.
              Consider .tbss sections as loadable for this purpose.  */
 	  new_segment = TRUE;
 	}
@@ -3594,9 +3598,9 @@ map_sections_to_segments (bfd *abfd)
              file, then there is no other reason for a new segment.  */
 	  new_segment = FALSE;
 	}
-      else if (! writable
-	       && (hdr->flags & SEC_READONLY) == 0
-	       && (((last_hdr->lma + last_size - 1)
+      else if (! writable == ! (hdr->flags & SEC_READONLY)
+	       && last_nz != NULL
+	       && (((last_nz->lma + last_nz->size - 1)
 		    & ~(maxpagesize - 1))
 		   != (hdr->lma & ~(maxpagesize - 1))))
 	{
@@ -3615,33 +3619,33 @@ map_sections_to_segments (bfd *abfd)
 	  new_segment = FALSE;
 	}
 
-      if (! new_segment)
+      if (new_segment)
 	{
-	  if ((hdr->flags & SEC_READONLY) == 0)
-	    writable = TRUE;
-	  last_hdr = hdr;
-	  /* .tbss sections effectively have zero size.  */
-	  if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
-	    last_size = hdr->size;
-	  else
-	    last_size = 0;
-	  continue;
-	}
+	  /* We need a new program segment.  We must create a new program
+	     header holding all the sections from phdr_index until hdr.  */
 
-      /* We need a new program segment.  We must create a new program
-         header holding all the sections from phdr_index until hdr.  */
-
-      m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
-      if (m == NULL)
-	goto error_return;
+	  m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
+	  if (m == NULL)
+	    goto error_return;
 
-      *pm = m;
-      pm = &m->next;
+	  *pm = m;
+	  pm = &m->next;
+	  phdr_index = i;
+	  phdr_in_segment = FALSE;
+	  writable = FALSE;
+	  loadable = 0;
+	  last_nz = NULL;
+	}
 
       if ((hdr->flags & SEC_READONLY) == 0)
 	writable = TRUE;
-      else
-	writable = FALSE;
+      if (hdr->size != 0)
+	{
+	  if ((hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+	    loadable = 1;
+	  else
+	    loadable = -1;
+	}
 
       last_hdr = hdr;
       /* .tbss sections effectively have zero size.  */
@@ -3649,8 +3653,8 @@ map_sections_to_segments (bfd *abfd)
 	last_size = hdr->size;
       else
 	last_size = 0;
-      phdr_index = i;
-      phdr_in_segment = FALSE;
+      if (last_size != 0)
+	last_nz = hdr;
     }
 
   /* Create a final PT_LOAD program segment.  */
@@ -3815,27 +3819,6 @@ elf_sort_sections (const void *arg1, con
   else if (sec1->vma > sec2->vma)
     return 1;
 
-  /* Put !SEC_LOAD sections after SEC_LOAD ones.  */
-
-#define TOEND(x) (((x)->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0)
-
-  if (TOEND (sec1))
-    {
-      if (TOEND (sec2))
-	{
-	  /* If the indicies are the same, do not return 0
-	     here, but continue to try the next comparison.  */
-	  if (sec1->target_index - sec2->target_index != 0)
-	    return sec1->target_index - sec2->target_index;
-	}
-      else
-	return 1;
-    }
-  else if (TOEND (sec2))
-    return -1;
-
-#undef TOEND
-
   /* Sort by size, to put zero sized sections
      before others at the same address.  */
 
@@ -3847,6 +3830,15 @@ elf_sort_sections (const void *arg1, con
   if (size1 > size2)
     return 1;
 
+  /* Put !SEC_LOAD sections after SEC_LOAD ones.  */
+
+#define TOEND(x) (((x)->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0)
+
+  if (TOEND (sec1) != TOEND (sec2))
+    return TOEND (sec1) - TOEND (sec2);
+
+#undef TOEND
+
   return sec1->target_index - sec2->target_index;
 }
 
--- /home/jbeulich/src/binutils/mainline/2005-05-06/ld/testsuite/ld-elf/seg.d	1970-01-01 01:00:00.000000000 +0100
+++ 2005-05-06-elf-seg/ld/testsuite/ld-elf/seg.d	2005-05-09 12:34:37.000000000 +0200
@@ -0,0 +1,20 @@
+#source: seg.s
+#ld: -T seg.ld
+#objdump: -p
+#xfail: "avr-*-*" "cr16c-*-*" "crx-*-*" "dlx-*-*" "h8300-*-*" "hppa64-*-*"
+#xfail: "i960-*-*" "ip2k-*-*" "m32r-*-*" "m88k-*-*" "mips-*-*" "msp430-*-*"
+
+.*:.*elf.*
+#...
+Program Header:
+[ 	]*LOAD[ 	].*
+[ 	]*filesz (0x0*1000+) memsz \1 flags r-x
+[ 	]*LOAD[ 	].*
+[ 	]*filesz (0x0*3000+) memsz \1 flags rw-
+[ 	]*LOAD[ 	].*
+[ 	]*filesz (0x0*1000+) memsz \1 flags r-x
+[ 	]*LOAD[ 	].*
+[ 	]*filesz (0x0*1000+) memsz \1 flags rw-
+[ 	]*LOAD[ 	].*
+[ 	]*filesz (0x0*1000+) memsz \1 flags r-x
+#pass
--- /home/jbeulich/src/binutils/mainline/2005-05-06/ld/testsuite/ld-elf/seg.ld	1970-01-01 01:00:00.000000000 +0100
+++ 2005-05-06-elf-seg/ld/testsuite/ld-elf/seg.ld	2004-08-27 13:22:05.000000000 +0200
@@ -0,0 +1,13 @@
+SECTIONS {
+	. = 0xABC00000;
+	.text : { *(.text) }
+	.rodata : { *(.rodata) }
+	.data : { *(.data) }
+	.bss : { *(.bss) }
+	.write1 : { *(.write1) }
+	.write2 : { *(.write2) }
+	.exec1 : { *(.exec1) }
+	.write3 : { *(.write3) }
+	.bss3 : { *(.bss3) }
+	.exec2 : { *(.exec2) }
+}
--- /home/jbeulich/src/binutils/mainline/2005-05-06/ld/testsuite/ld-elf/seg.s	1970-01-01 01:00:00.000000000 +0100
+++ 2005-05-06-elf-seg/ld/testsuite/ld-elf/seg.s	2005-05-09 10:48:55.000000000 +0200
@@ -0,0 +1,39 @@
+ .equiv	PAGESIZE, 0x100000
+
+.global	_start
+
+ .text
+_start:
+ .byte	0x11
+
+ .section	.rodata, "a", "progbits"
+ .p2align	4
+const:
+ .fill	PAGESIZE - 16, 1, 0x22
+
+ .data
+data:
+ .fill	PAGESIZE, 1, 0x33
+
+ .section	.write1, "aw", "progbits"
+write1:
+ .fill	PAGESIZE, 1, 0x44
+
+ .section	.write2, "aw", "progbits"
+write2:
+ .fill	PAGESIZE, 1, 0x55
+
+ .section	.exec1, "ax", "progbits"
+exec1:
+ .fill	PAGESIZE, 1, 0x66
+
+ .section	.write3, "aw", "progbits"
+write3:
+ .fill	PAGESIZE, 1, 0x77
+
+ .section	.bss3, "aw", "nobits"
+bss3:
+
+ .section	.exec2, "ax", "progbits"
+exec2:
+ .fill	PAGESIZE, 1, 0x88

Attachment: binutils-mainline-elf-segments.patch
Description: Text document


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