From d7475e036f69ff7ac78252db74a65fe4d617c4ee Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sun, 12 Nov 2017 17:20:09 -0800 Subject: [PATCH] ld: Add fold_segment_align/fold_segment_relro_end/fold_segment_end Extract DATA_SEGMENT_END/DATA_SEGMENT_ALIGN/DATA_SEGMENT_RELRO_END cases for GNU_RELRO segment into separate functions so that they can also be used for text-only LOAD segment. * 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 ... (fold_segment_align): New function. (fold_binary): Extract the DATA_SEGMENT_RELRO_END case to ... (fold_segment_relro_end): New function. --- ld/ChangeLog | 9 +++ ld/ldexp.c | 194 ++++++++++++++++++++++++++++----------------------- 2 files changed, 114 insertions(+), 89 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 0a39d744394..bee75c18242 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2017-11-12 H.J. Lu + + * 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 ... + (fold_segment_align): New function. + (fold_binary): Extract the DATA_SEGMENT_RELRO_END case to ... + (fold_segment_relro_end): New function. + 2017-11-12 H.J. Lu * ldexp.h (phase_enum): Rename exp_dataseg_none, diff --git a/ld/ldexp.c b/ld/ldexp.c index 5633e507148..83d9f8f2a7f 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -342,6 +342,30 @@ update_definedness (const char *name, struct bfd_link_hash_entry *h) return ret; } +static void +fold_segment_end (seg_align_type *seg) +{ + if (expld.phase == lang_first_phase_enum + || expld.section != bfd_abs_section_ptr) + { + expld.result.valid_p = FALSE; + } + else if (seg->phase == exp_seg_align_seen + || seg->phase == exp_seg_relro_seen) + { + seg->phase = exp_seg_end_seen; + seg->end = expld.result.value; + } + else if (seg->phase == exp_seg_done + || seg->phase == exp_seg_adjust + || seg->phase == exp_seg_relro_adjust) + { + /* OK. */ + } + else + expld.result.valid_p = FALSE; +} + static void fold_unary (etree_type *tree) { @@ -389,25 +413,7 @@ fold_unary (etree_type *tree) break; case DATA_SEGMENT_END: - if (expld.phase == lang_first_phase_enum - || expld.section != bfd_abs_section_ptr) - { - expld.result.valid_p = FALSE; - } - else if (expld.dataseg.phase == exp_seg_align_seen - || expld.dataseg.phase == exp_seg_relro_seen) - { - expld.dataseg.phase = exp_seg_end_seen; - expld.dataseg.end = expld.result.value; - } - else if (expld.dataseg.phase == exp_seg_done - || expld.dataseg.phase == exp_seg_adjust - || expld.dataseg.phase == exp_seg_relro_adjust) - { - /* OK. */ - } - else - expld.result.valid_p = FALSE; + fold_segment_end (&expld.dataseg); break; default: @@ -443,6 +449,84 @@ arith_result_section (const etree_value_type *lhs) } } +static void +fold_segment_align (seg_align_type *seg, etree_value_type *lhs) +{ + seg->relro = exp_seg_relro_start; + if (expld.phase == lang_first_phase_enum + || expld.section != bfd_abs_section_ptr) + expld.result.valid_p = FALSE; + else + { + bfd_vma maxpage = lhs->value; + bfd_vma commonpage = expld.result.value; + + expld.result.value = align_n (expld.dot, maxpage); + if (seg->phase == exp_seg_relro_adjust) + expld.result.value = seg->base; + else if (seg->phase == exp_seg_adjust) + { + if (commonpage < maxpage) + expld.result.value += ((expld.dot + commonpage - 1) + & (maxpage - commonpage)); + } + else + { + expld.result.value += expld.dot & (maxpage - 1); + if (seg->phase == exp_seg_done) + { + /* OK. */ + } + else if (seg->phase == exp_seg_none) + { + seg->phase = exp_seg_align_seen; + seg->base = expld.result.value; + seg->pagesize = commonpage; + seg->maxpagesize = maxpage; + seg->relro_end = 0; + } + else + expld.result.valid_p = FALSE; + } + } +} + +static void +fold_segment_relro_end (seg_align_type *seg, etree_value_type *lhs) +{ + /* Operands swapped! XXX_SEGMENT_RELRO_END(offset,exp) has offset + in expld.result and exp in lhs. */ + seg->relro = exp_seg_relro_end; + seg->relro_offset = expld.result.value; + if (expld.phase == lang_first_phase_enum + || expld.section != bfd_abs_section_ptr) + expld.result.valid_p = FALSE; + else if (seg->phase == exp_seg_align_seen + || seg->phase == exp_seg_adjust + || seg->phase == exp_seg_relro_adjust + || seg->phase == exp_seg_done) + { + if (seg->phase == exp_seg_align_seen + || seg->phase == exp_seg_relro_adjust) + seg->relro_end = lhs->value + expld.result.value; + + if (seg->phase == exp_seg_relro_adjust + && (seg->relro_end & (seg->pagesize - 1))) + { + seg->relro_end += seg->pagesize - 1; + seg->relro_end &= ~(seg->pagesize - 1); + expld.result.value = seg->relro_end - expld.result.value; + } + else + expld.result.value = lhs->value; + + if (seg->phase == exp_seg_align_seen) + seg->phase = exp_seg_relro_seen; + } + else + expld.result.valid_p = FALSE; +} + static void fold_binary (etree_type *tree) { @@ -573,79 +657,11 @@ fold_binary (etree_type *tree) break; case DATA_SEGMENT_ALIGN: - expld.dataseg.relro = exp_seg_relro_start; - if (expld.phase == lang_first_phase_enum - || expld.section != bfd_abs_section_ptr) - expld.result.valid_p = FALSE; - else - { - bfd_vma maxpage = lhs.value; - bfd_vma commonpage = expld.result.value; - - expld.result.value = align_n (expld.dot, maxpage); - if (expld.dataseg.phase == exp_seg_relro_adjust) - expld.result.value = expld.dataseg.base; - else if (expld.dataseg.phase == exp_seg_adjust) - { - if (commonpage < maxpage) - expld.result.value += ((expld.dot + commonpage - 1) - & (maxpage - commonpage)); - } - else - { - expld.result.value += expld.dot & (maxpage - 1); - if (expld.dataseg.phase == exp_seg_done) - { - /* OK. */ - } - else if (expld.dataseg.phase == exp_seg_none) - { - expld.dataseg.phase = exp_seg_align_seen; - expld.dataseg.base = expld.result.value; - expld.dataseg.pagesize = commonpage; - expld.dataseg.maxpagesize = maxpage; - expld.dataseg.relro_end = 0; - } - else - expld.result.valid_p = FALSE; - } - } + fold_segment_align (&expld.dataseg, &lhs); 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_seg_relro_end; - expld.dataseg.relro_offset = expld.result.value; - if (expld.phase == lang_first_phase_enum - || expld.section != bfd_abs_section_ptr) - expld.result.valid_p = FALSE; - else if (expld.dataseg.phase == exp_seg_align_seen - || expld.dataseg.phase == exp_seg_adjust - || expld.dataseg.phase == exp_seg_relro_adjust - || expld.dataseg.phase == exp_seg_done) - { - if (expld.dataseg.phase == exp_seg_align_seen - || expld.dataseg.phase == exp_seg_relro_adjust) - expld.dataseg.relro_end = lhs.value + expld.result.value; - - if (expld.dataseg.phase == exp_seg_relro_adjust - && (expld.dataseg.relro_end - & (expld.dataseg.pagesize - 1))) - { - expld.dataseg.relro_end += expld.dataseg.pagesize - 1; - expld.dataseg.relro_end &= ~(expld.dataseg.pagesize - 1); - expld.result.value = (expld.dataseg.relro_end - - expld.result.value); - } - else - expld.result.value = lhs.value; - - if (expld.dataseg.phase == exp_seg_align_seen) - expld.dataseg.phase = exp_seg_relro_seen; - } - else - expld.result.valid_p = FALSE; + fold_segment_relro_end (&expld.dataseg, &lhs); break; default: -- 2.30.2