diff options
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 95 |
1 files changed, 44 insertions, 51 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index 5dd3df1..cf13932 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -6370,101 +6370,94 @@ lang_size_segment (seg_align_type *seg) static bfd_vma lang_size_relro_segment_1 (seg_align_type *seg) { - bfd_vma relro_end, desired_relro_base; - asection *sec, *relro_sec = NULL; + bfd_vma relro_end, desired_end; + asection *sec, *prev_sec = NULL; + bool remove_page_gap = false; 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_relro_base = relro_end - seg->relro_offset; + desired_end = 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 the relro section so that the - relro segment ends on the page bounary? */ + /* 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_relro_base - end; + 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_relro_base = start; - relro_sec = sec; - seen_reloc_section = true; + desired_end = start; + prev_sec = sec->prev; } - else if (seen_reloc_section) + } + + 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) { - /* Stop searching if we see a non-relro section after seeing - relro sections. */ + /* The 1-page gap before the RELRO segment may be removed. */ + remove_page_gap = ((prev_sec->vma + prev_sec->size + + seg->maxpagesize) < desired_end); + break; } } - if (relro_sec != NULL - && seg->maxpagesize >= (1U << max_alignment_power)) + if (remove_page_gap) { - asection *prev_sec; - bfd_vma prev_sec_end_plus_1_page; - - /* 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; + /* 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; - prev_sec_end_plus_1_page = (prev_sec->vma + prev_sec->size - + seg->maxpagesize); - if (prev_sec_end_plus_1_page < desired_relro_base) + /* 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)) { - 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) + /* 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) { - /* Subtract the maximum page size if therer is still a - 1-page gap. */ - desired_relro_base -= seg->maxpagesize; + desired_end -= seg->maxpagesize; relro_end -= seg->maxpagesize; } else { - /* Align the relro segment. */ - desired_relro_base = aligned_relro_base; + desired_end &= ~(seg->maxpagesize - 1); relro_end &= ~(seg->maxpagesize - 1); } - } - } + } + } - seg->phase = exp_seg_relro_adjust; - ASSERT (desired_relro_base_reduced - || desired_relro_base >= seg->base); - seg->base = desired_relro_base; + seg->base = desired_end; return relro_end; } |