aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ld/ChangeLog7
-rw-r--r--ld/ldlang.c174
2 files changed, 117 insertions, 64 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index bee75c1..16fed16 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,5 +1,12 @@
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 ...
(fold_segment_end): New function.
(fold_binary): Extract the DATA_SEGMENT_ALIGN case to ...
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 2cb1647..6bb9e47 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -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;