Start of relro segment adjustment
authorAlan Modra <amodra@gmail.com>
Wed, 1 Apr 2015 08:49:27 +0000 (19:19 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 1 Apr 2015 09:07:58 +0000 (19:37 +1030)
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.

ld/ChangeLog
ld/ldexp.c
ld/ldlang.c
ld/scripttempl/elf.sc

index 6b929aac24d5c0e28b90d8435220ed9fd80dd825..b8c506f2cf2e5a7ded3c22f817253734af56d916 100644 (file)
@@ -1,3 +1,12 @@
+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
index ac66cc02aef23556cf6b3d8b8c104498a4026d21..9cd9e29d813f665402b1ead4cfd8881a541167f4 100644 (file)
@@ -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)
index 888082147a1794cfd096fe306d05f2a82d55f6a2..13e7b1a3b991f6849aad2290027467fb114a179a 100644 (file)
@@ -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;
index c9c80b0cc3ed7a8df252586be1835d909428b44a..b4f52eba4afc960384aee50b128413bf6d91503c 100644 (file)
@@ -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
This page took 0.031232 seconds and 4 git commands to generate.