This is the mail archive of the binutils-cvs@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]

[binutils-gdb] Start of relro segment adjustment


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6c1aca3e2d408ef4874bd882a7f0e2cd944bbf09

commit 6c1aca3e2d408ef4874bd882a7f0e2cd944bbf09
Author: Alan Modra <amodra@gmail.com>
Date:   Wed Apr 1 19:19:27 2015 +1030

    Start of relro segment adjustment
    
    Adjusting the start of the relro segment in order to make it end
    exactly on a page boundary runs into difficulties when sections in the
    relro segment are aligned;  Adjusting the start by (next_page - end)
    sometimes results in more than that adjustment occurring at the end,
    overrunning the page boundary.  So when that occurs we try a new lower
    start position by masking the adjusted start with the maximum section
    alignment.  However, we didn't consider that this masked start address
    may in fact be before the initial relro base, which is silly since
    that can only increase padding at the relro end.
    
    I've also moved some calculations closer to where they are used, and
    comments closer to the relevant statements.
    
    	* ldlang.c (lang_size_sections): When alignment of sections
    	results in relro base adjustment being too large, don't go lower
    	than the initial value.
    	* ldexp.c (fold_binary <DATA_SEGMENT_RELRO_END>): Comment.
    	* scripttempl/elf.sc (DATA_SEGMENT_ALIGN): Omit SEGMENT_SIZE
    	alignment when SEGMENT_SIZE is the same as MAXPAGESIZE.

Diff:
---
 ld/ChangeLog          |  9 +++++++++
 ld/ldexp.c            |  2 ++
 ld/ldlang.c           | 33 +++++++++++++++++----------------
 ld/scripttempl/elf.sc |  6 +++++-
 4 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/ld/ChangeLog b/ld/ChangeLog
index 6b929aa..b8c506f 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,14 @@
 2015-04-01  Alan Modra  <amodra@gmail.com>
 
+	* ldlang.c (lang_size_sections): When alignment of sections
+	results in relro base adjustment being too large, don't go lower
+	than the initial value.
+	* ldexp.c (fold_binary <DATA_SEGMENT_RELRO_END>): Comment.
+	* scripttempl/elf.sc (DATA_SEGMENT_ALIGN): Omit SEGMENT_SIZE
+	alignment when SEGMENT_SIZE is the same as MAXPAGESIZE.
+
+2015-04-01  Alan Modra  <amodra@gmail.com>
+
 	* emultempl/elf32.em (gld${EMULATION_NAME}_before_allocation): Don't
 	init ehdr_start_save.
 
diff --git a/ld/ldexp.c b/ld/ldexp.c
index ac66cc0..9cd9e29 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -588,6 +588,8 @@ fold_binary (etree_type *tree)
 	  break;
 
 	case DATA_SEGMENT_RELRO_END:
+	  /* Operands swapped!  DATA_SEGMENT_RELRO_END(offset,exp)
+	     has offset in expld.result and exp in lhs.  */
 	  expld.dataseg.relro = exp_dataseg_relro_end;
 	  if (expld.phase == lang_first_phase_enum
 	      || expld.section != bfd_abs_section_ptr)
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 8880821..13e7b1a 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -5382,20 +5382,20 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
   if (expld.dataseg.phase == exp_dataseg_end_seen
       && link_info.relro && expld.dataseg.relro_end)
     {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
-	 to put expld.dataseg.relro_end on a (common) page boundary.  */
-      bfd_vma min_base, relro_end, maxpage;
+      bfd_vma initial_base, min_base, relro_end, maxpage;
 
       expld.dataseg.phase = exp_dataseg_relro_adjust;
       maxpage = expld.dataseg.maxpagesize;
-      /* MIN_BASE is the absolute minimum address we are allowed to start the
-	 read-write segment (byte before will be mapped read-only).  */
-      min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1);
+      initial_base = expld.dataseg.base;
+      /* Try to put expld.dataseg.relro_end on a (common) page boundary.  */
       expld.dataseg.base += (-expld.dataseg.relro_end
 			     & (expld.dataseg.pagesize - 1));
       /* Compute the expected PT_GNU_RELRO segment end.  */
       relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
 		   & ~(expld.dataseg.pagesize - 1));
+      /* MIN_BASE is the absolute minimum address we are allowed to start the
+	 read-write segment (byte before will be mapped read-only).  */
+      min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1);
       if (min_base + maxpage < expld.dataseg.base)
 	{
 	  expld.dataseg.base -= maxpage;
@@ -5420,16 +5420,17 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 		&& sec->alignment_power > max_alignment_power)
 	      max_alignment_power = sec->alignment_power;
 
-	  if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
-	    {
-	      /* Aligning the adjusted base guarantees the padding
-		 between sections won't change.  This is better than
-		 simply subtracting 1 << max_alignment_power which is
-		 what we used to do here.  */
-	      expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
-	      lang_reset_memory_regions ();
-	      one_lang_size_sections_pass (relax, check_regions);
-	    }
+	  /* Aligning the adjusted base guarantees the padding
+	     between sections won't change.  This is better than
+	     simply subtracting 1 << max_alignment_power which is
+	     what we used to do here.  */
+	  expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
+	  /* It doesn't make much sense to go lower than the initial
+	     base.  That can only increase padding.  */
+	  if (expld.dataseg.base < initial_base)
+	    expld.dataseg.base = initial_base;
+	  lang_reset_memory_regions ();
+	  one_lang_size_sections_pass (relax, check_regions);
 	}
       link_info.relro_start = expld.dataseg.base;
       link_info.relro_end = expld.dataseg.relro_end;
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index c9c80b0..b4f52eb 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -128,7 +128,11 @@ DATA_SEGMENT_ALIGN="ALIGN(${SEGMENT_SIZE}) + (. & (${MAXPAGESIZE} - 1))"
 DATA_SEGMENT_RELRO_END=""
 DATA_SEGMENT_END=""
 if test -n "${COMMONPAGESIZE}"; then
-  DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+  if test "${SEGMENT_SIZE}" != "${MAXPAGESIZE}"; then
+    DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+  else
+    DATA_SEGMENT_ALIGN="DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})"
+  fi
   DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);"
   DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);"
 fi


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