From c804c6f98d342c3d46f73d7a7ec6229d5ab1c9f3 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 14 Jan 2022 13:48:36 -0800 Subject: ld: Rewrite lang_size_relro_segment_1 1. Compute the desired PT_GNU_RELRO segment base and find the maximum section alignment of sections starting from the PT_GNU_RELRO segment. 2. Find the first preceding load section. 3. Don't add the 1-page gap between the first preceding load section and the relro segment if the maximum page size >= the maximum section alignment. Align the PT_GNU_RELRO segment first. Subtract the maximum page size if therer is still a 1-page gap. PR ld/28743 PR ld/28819 * ldlang.c (lang_size_relro_segment_1): Rewrite. * testsuite/ld-x86-64/pr28743-1.d: New file. * testsuite/ld-x86-64/pr28743-1.s: Likewise. * testsuite/ld-x86-64/x86-64.exp: Run pr28743-1. --- ld/ldlang.c | 95 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 44 deletions(-) (limited to 'ld/ldlang.c') diff --git a/ld/ldlang.c b/ld/ldlang.c index 93fcfc4..4e6511b 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -6370,94 +6370,101 @@ lang_size_segment (seg_align_type *seg) static bfd_vma lang_size_relro_segment_1 (seg_align_type *seg) { - bfd_vma relro_end, desired_end; - asection *sec, *prev_sec = NULL; - bool remove_page_gap = false; + bfd_vma relro_end, desired_relro_base; + asection *sec, *relro_sec = NULL; unsigned int max_alignment_power = 0; + bool seen_reloc_section = false; + bool desired_relro_base_reduced = false; /* 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; + desired_relro_base = relro_end - seg->relro_offset; - /* For sections in the relro segment.. */ + /* For sections in the relro segment. */ for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev) if ((sec->flags & SEC_ALLOC) != 0) { + /* Record the maximum alignment for all sections starting from + the relro segment. */ if (sec->alignment_power > max_alignment_power) max_alignment_power = sec->alignment_power; if (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? */ + /* Where do we want to put the relro section so that the + relro segment ends on the page bounary? */ bfd_vma start, end, bump; end = start = sec->vma; if (!IS_TBSS (sec)) end += TO_ADDR (sec->size); - bump = desired_end - end; + bump = desired_relro_base - 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; - prev_sec = sec->prev; + desired_relro_base = start; + relro_sec = sec; + seen_reloc_section = true; } - } - - seg->phase = exp_seg_relro_adjust; - ASSERT (desired_end >= seg->base); - - for (; prev_sec; prev_sec = prev_sec->prev) - if ((prev_sec->flags & SEC_ALLOC) != 0) - { - if (prev_sec->alignment_power > max_alignment_power) - max_alignment_power = prev_sec->alignment_power; - - if (prev_sec->size != 0) + else if (seen_reloc_section) { - /* The 1-page gap before the RELRO segment may be removed. */ - remove_page_gap = ((prev_sec->vma + prev_sec->size - + seg->maxpagesize) < desired_end); - + /* Stop searching if we see a non-relro section after seeing + relro sections. */ break; } } - if (remove_page_gap) + if (relro_sec != NULL + && seg->maxpagesize >= (1U << max_alignment_power)) { - /* Find the maximum section alignment. */ - for (sec = prev_sec; sec; sec = sec->prev) - if ((sec->flags & SEC_ALLOC) != 0 - && sec->alignment_power > max_alignment_power) - max_alignment_power = sec->alignment_power; + asection *prev_sec; + bfd_vma prev_sec_end_plus_1_page; - /* Remove the 1-page gap before the RELRO segment only if the - maximum page size >= the maximum section alignment. */ - if (seg->maxpagesize >= (1U << max_alignment_power)) + /* Find the first preceding load section. */ + for (prev_sec = relro_sec->prev; + prev_sec != NULL; + prev_sec = prev_sec->prev) + if ((prev_sec->flags & SEC_ALLOC) != 0) + break; + + prev_sec_end_plus_1_page = (prev_sec->vma + prev_sec->size + + seg->maxpagesize); + if (prev_sec_end_plus_1_page < desired_relro_base) { - /* If the preceding section size is greater than the maximum - page size, subtract the maximum page size. Otherwise, - align the RELRO segment to the maximum page size. */ - if (prev_sec->size > seg->maxpagesize) + bfd_vma aligned_relro_base; + + desired_relro_base_reduced = true; + + /* Don't add the 1-page gap before the relro segment. Align + the relro segment first. */ + aligned_relro_base = (desired_relro_base + & ~(seg->maxpagesize - 1)); + if (prev_sec_end_plus_1_page < aligned_relro_base) { - desired_end -= seg->maxpagesize; + /* Subtract the maximum page size if therer is still a + 1-page gap. */ + desired_relro_base -= seg->maxpagesize; relro_end -= seg->maxpagesize; } else { - desired_end &= ~(seg->maxpagesize - 1); + /* Align the relro segment. */ + desired_relro_base = aligned_relro_base; relro_end &= ~(seg->maxpagesize - 1); } - } - } + } + } - seg->base = desired_end; + seg->phase = exp_seg_relro_adjust; + ASSERT (desired_relro_base_reduced + || desired_relro_base >= seg->base); + seg->base = desired_relro_base; return relro_end; } -- cgit v1.1