ld: Add lang_size_relro_segment
authorH.J. Lu <hjl.tools@gmail.com>
Mon, 13 Nov 2017 01:22:15 +0000 (17:22 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Mon, 13 Nov 2017 01:22:24 +0000 (17:22 -0800)
Break lang_size_sections down into separate functions so that they can
also be used for text-only LOAD segment.  lang_size_relro_segment will
call lang_size_relro_segment_1 and lang_size_segment for both GNU_RELRO
segment and text-only LOAD segment.

* ldlang.c (lang_size_segment): New function.
(lang_size_relro_segment_1): Likewise.
(lang_size_relro_segment): Likewise.
(lang_size_sections): Rewrite to call lang_size_relro_segment.

ld/ChangeLog
ld/ldlang.c

index bee75c182429b6630602b2825e88fbd171425d60..16fed166355551574eee86687742b87e25e8e304 100644 (file)
@@ -1,3 +1,10 @@
+2017-11-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * ldlang.c (lang_size_segment): New function.
+       (lang_size_relro_segment_1): Likewise.
+       (lang_size_relro_segment): Likewise.
+       (lang_size_sections): Rewrite to call lang_size_relro_segment.
+
 2017-11-12  H.J. Lu  <hongjiu.lu@intel.com>
 
        * ldexp.c (fold_unary): Extract the DATA_SEGMENT_END case to ...
index 2cb16476924b90241e87707d66d247306e75ffb2..6bb9e472a23ddfaedc87230419b9fda6a9c3f1ac 100644 (file)
@@ -5589,90 +5589,136 @@ one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
                        0, 0, relax, check_regions);
 }
 
-void
-lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+static bfd_boolean
+lang_size_segment (seg_align_type *seg)
 {
-  expld.phase = lang_allocating_phase_enum;
-  expld.dataseg.phase = exp_seg_none;
+  /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
+     a page could be saved in the data segment.  */
+  bfd_vma first, last;
 
-  one_lang_size_sections_pass (relax, check_regions);
-  if (expld.dataseg.phase == exp_seg_end_seen
-      && link_info.relro && expld.dataseg.relro_end)
+  first = -seg->base & (seg->pagesize - 1);
+  last = seg->end & (seg->pagesize - 1);
+  if (first && last
+      && ((seg->base & ~(seg->pagesize - 1))
+         != (seg->end & ~(seg->pagesize - 1)))
+      && first + last <= seg->pagesize)
     {
-      bfd_vma initial_base, relro_end, desired_end;
-      asection *sec;
+      seg->phase = exp_seg_adjust;
+      return TRUE;
+    }
 
-      /* Compute the expected PT_GNU_RELRO segment end.  */
-      relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
-                  & ~(expld.dataseg.pagesize - 1));
+  seg->phase = exp_seg_done;
+  return FALSE;
+}
 
-      /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END.  */
-      desired_end = relro_end - expld.dataseg.relro_offset;
+static bfd_vma
+lang_size_relro_segment_1 (seg_align_type *seg)
+{
+  bfd_vma relro_end, desired_end;
+  asection *sec;
 
-      /* For sections in the relro segment..  */
-      for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
-       if ((sec->flags & SEC_ALLOC) != 0
-           && sec->vma >= expld.dataseg.base
-           && sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset)
-         {
-           /* Where do we want to put this section so that it ends as
-              desired?  */
-           bfd_vma start, end, bump;
-
-           end = start = sec->vma;
-           if (!IS_TBSS (sec))
-             end += TO_ADDR (sec->size);
-           bump = desired_end - end;
-           /* We'd like to increase START by BUMP, but we must heed
-              alignment so the increase might be less than optimum.  */
-           start += bump;
-           start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
-           /* This is now the desired end for the previous section.  */
-           desired_end = start;
-         }
+  /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end.  */
+  relro_end = ((seg->relro_end + seg->pagesize - 1)
+              & ~(seg->pagesize - 1));
+
+  /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END.  */
+  desired_end = relro_end - seg->relro_offset;
+
+  /* For sections in the relro segment..  */
+  for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
+    if ((sec->flags & SEC_ALLOC) != 0
+       && sec->vma >= seg->base
+       && sec->vma < seg->relro_end - seg->relro_offset)
+      {
+       /* Where do we want to put this section so that it ends as
+          desired?  */
+       bfd_vma start, end, bump;
+
+       end = start = sec->vma;
+       if (!IS_TBSS (sec))
+         end += TO_ADDR (sec->size);
+       bump = desired_end - end;
+       /* We'd like to increase START by BUMP, but we must heed
+          alignment so the increase might be less than optimum.  */
+       start += bump;
+       start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+       /* This is now the desired end for the previous section.  */
+       desired_end = start;
+      }
+
+  seg->phase = exp_seg_relro_adjust;
+  ASSERT (desired_end >= seg->base);
+  seg->base = desired_end;
+  return relro_end;
+}
+
+static bfd_boolean
+lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  bfd_boolean do_reset = FALSE;
+  bfd_boolean do_data_relro;
+  bfd_vma data_initial_base, data_relro_end;
+
+  if (link_info.relro && expld.dataseg.relro_end)
+    {
+      do_data_relro = TRUE;
+      data_initial_base = expld.dataseg.base;
+      data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
+    }
+  else
+    {
+      do_data_relro = FALSE;
+      data_initial_base = data_relro_end = 0;
+    }
 
-      expld.dataseg.phase = exp_seg_relro_adjust;
-      ASSERT (desired_end >= expld.dataseg.base);
-      initial_base = expld.dataseg.base;
-      expld.dataseg.base = desired_end;
+  if (do_data_relro)
+    {
       lang_reset_memory_regions ();
       one_lang_size_sections_pass (relax, check_regions);
 
-      if (expld.dataseg.relro_end > relro_end)
+      /* Assignments to dot, or to output section address in a user
+        script have increased padding over the original.  Revert.  */
+      if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
        {
-         /* Assignments to dot, or to output section address in a
-            user script have increased padding over the original.
-            Revert.  */
-         expld.dataseg.base = initial_base;
-         lang_reset_memory_regions ();
-         one_lang_size_sections_pass (relax, check_regions);
+         expld.dataseg.base = data_initial_base;;
+         do_reset = TRUE;
        }
-
-      link_info.relro_start = expld.dataseg.base;
-      link_info.relro_end = expld.dataseg.relro_end;
     }
-  else if (expld.dataseg.phase == exp_seg_end_seen)
+
+  if (!do_data_relro && lang_size_segment (&expld.dataseg))
+    do_reset = TRUE;
+
+  return do_reset;
+}
+
+void
+lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  expld.phase = lang_allocating_phase_enum;
+  expld.dataseg.phase = exp_seg_none;
+
+  one_lang_size_sections_pass (relax, check_regions);
+
+  if (expld.dataseg.phase != exp_seg_end_seen)
+    expld.dataseg.phase = exp_seg_done;
+
+  if (expld.dataseg.phase == exp_seg_end_seen)
     {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
-        a page could be saved in the data segment.  */
-      bfd_vma first, last;
+      bfd_boolean do_reset
+       = lang_size_relro_segment (relax, check_regions);
 
-      first = -expld.dataseg.base & (expld.dataseg.pagesize - 1);
-      last = expld.dataseg.end & (expld.dataseg.pagesize - 1);
-      if (first && last
-         && ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1))
-             != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1)))
-         && first + last <= expld.dataseg.pagesize)
+      if (do_reset)
        {
-         expld.dataseg.phase = exp_seg_adjust;
          lang_reset_memory_regions ();
          one_lang_size_sections_pass (relax, check_regions);
        }
-      else
-       expld.dataseg.phase = exp_seg_done;
+
+      if (link_info.relro && expld.dataseg.relro_end)
+       {
+         link_info.relro_start = expld.dataseg.base;
+         link_info.relro_end = expld.dataseg.relro_end;
+       }
     }
-  else
-    expld.dataseg.phase = exp_seg_done;
 }
 
 static lang_output_section_statement_type *current_section;