diff --git a/ld/ChangeLog b/ld/ChangeLog index 68853ce91f..d39892c06d 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,21 @@ +2004-10-04 Jakub Jelinek + + * ldgram.y (DATA_SEGMENT_RELRO_END): Add one argument. + * scripttempl/elf.sc (DATA_SEGMENT_RELRO_END): Add 0 as first + argument. + (DATA_SEGMENT_RELRO_GOTPLT_END): Pass $SEPARATE_GOTPLT as first + and . as second argument. + (GOTPLT): Move $DATA_SEGMENT_RELRO_GOTPLT_END before the section. + * ldexp.c (fold_unary): Remove DATA_SEGMENT_RELRO_END handling here. + (fold_binary): Add it here. Insert padding to make relro_end + COMMONPAGESIZE bytes aligned. For DATA_SEGMENT_ALIGN in + exp_dataseg_relro_adjust phase just use previously computed + exp_data_seg.base. + * ldlang.c (lang_size_sections): Set exp_data_seg.base for + relro_adjust here. Call lang_size_sections_1 once more if there + was too big padding at DATA_SEGMENT_RELRO_END. + * ld.texinfo (DATA_SEGMENT_RELRO_END): Add documentation. + 2004-10-01 Paul Brook * emulparams/armelf.sh: Add unwinding table sections. diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 047933aaf0..10134a648a 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -4545,6 +4545,21 @@ evaluation purposes. . = DATA_SEGMENT_END(.); @end smallexample +@item DATA_SEGMENT_RELRO_END(@var{offset}, @var{exp}) +@kindex DATA_SEGMENT_RELRO_END(@var{offset}, @var{exp}) +This defines the end of the @code{PT_GNU_RELRO} segment when +@samp{-z relro} option is used. Second argument is returned. +When @samp{-z relro} option is not present, @code{DATA_SEGMENT_RELRO_END} +does nothing, otherwise @code{DATA_SEGMENT_ALIGN} is padded so that +@var{exp} + @var{offset} is aligned to the most commonly used page +boundary for particular target. If present in the linker script, +it must always come in between @code{DATA_SEGMENT_ALIGN} and +@code{DATA_SEGMENT_END}. + +@smallexample + . = DATA_SEGMENT_RELRO_END(24, .); +@end smallexample + @item DEFINED(@var{symbol}) @kindex DEFINED(@var{symbol}) @cindex symbol defaults diff --git a/ld/ldexp.c b/ld/ldexp.c index de239b2252..4110f57ec4 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -265,25 +265,6 @@ fold_unary (etree_type *tree, result.valid_p = FALSE; break; - case DATA_SEGMENT_RELRO_END: - if (allocation_done != lang_first_phase_enum - && (exp_data_seg.phase == exp_dataseg_align_seen - || exp_data_seg.phase == exp_dataseg_adjust - || exp_data_seg.phase == exp_dataseg_relro_adjust - || allocation_done != lang_allocating_phase_enum)) - { - if (exp_data_seg.phase == exp_dataseg_align_seen - || exp_data_seg.phase == exp_dataseg_relro_adjust) - exp_data_seg.relro_end - = result.value + current_section->bfd_section->vma; - if (exp_data_seg.phase == exp_dataseg_align_seen) - exp_data_seg.phase = exp_dataseg_relro_seen; - result.value = dot - current_section->bfd_section->vma; - } - else - result.valid_p = FALSE; - break; - case DATA_SEGMENT_END: if (allocation_done != lang_first_phase_enum && current_section == abs_output_section @@ -422,13 +403,7 @@ fold_binary (etree_type *tree, result.value = align_n (dot, maxpage); if (exp_data_seg.phase == exp_dataseg_relro_adjust) - { - /* Attempt to align DATA_SEGMENT_RELRO_END at - a common page boundary. */ - exp_data_seg.base += (-exp_data_seg.relro_end - & (other.value - 1)); - result.value = exp_data_seg.base; - } + result.value = exp_data_seg.base; else if (exp_data_seg.phase != exp_dataseg_adjust) { result.value += dot & (maxpage - 1); @@ -448,6 +423,32 @@ fold_binary (etree_type *tree, result.valid_p = FALSE; break; + case DATA_SEGMENT_RELRO_END: + if (allocation_done != lang_first_phase_enum + && (exp_data_seg.phase == exp_dataseg_align_seen + || exp_data_seg.phase == exp_dataseg_adjust + || exp_data_seg.phase == exp_dataseg_relro_adjust + || allocation_done != lang_allocating_phase_enum)) + { + if (exp_data_seg.phase == exp_dataseg_align_seen + || exp_data_seg.phase == exp_dataseg_relro_adjust) + exp_data_seg.relro_end + = result.value + other.value; + if (exp_data_seg.phase == exp_dataseg_relro_adjust + && (exp_data_seg.relro_end + & (exp_data_seg.pagesize - 1))) + { + exp_data_seg.relro_end += exp_data_seg.pagesize - 1; + exp_data_seg.relro_end &= ~(exp_data_seg.pagesize - 1); + result.value = exp_data_seg.relro_end - other.value; + } + if (exp_data_seg.phase == exp_dataseg_align_seen) + exp_data_seg.phase = exp_dataseg_relro_seen; + } + else + result.valid_p = FALSE; + break; + default: FAIL (); } diff --git a/ld/ldgram.y b/ld/ldgram.y index 75f4e70089..f4f4589327 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -808,8 +808,8 @@ exp : { $$ = exp_binop(ALIGN_K,$3,$5); } | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' { $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); } - | DATA_SEGMENT_RELRO_END '(' exp ')' - { $$ = exp_unop(DATA_SEGMENT_RELRO_END, $3); } + | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')' + { $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); } | DATA_SEGMENT_END '(' exp ')' { $$ = exp_unop(DATA_SEGMENT_END, $3); } | BLOCK '(' exp ')' diff --git a/ld/ldlang.c b/ld/ldlang.c index 5988635e42..55a42bebe0 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -3286,10 +3286,44 @@ lang_size_sections { /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try to put exp_data_seg.relro on a (common) page boundary. */ + bfd_vma old_base, relro_end; exp_data_seg.phase = exp_dataseg_relro_adjust; + old_base = exp_data_seg.base; + exp_data_seg.base += (-exp_data_seg.relro_end + & (exp_data_seg.pagesize - 1)); + /* Compute the expected PT_GNU_RELRO segment end. */ + relro_end = (exp_data_seg.relro_end + exp_data_seg.pagesize - 1) + & (exp_data_seg.pagesize - 1); result = lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax, check_regions); + if (exp_data_seg.relro_end > relro_end) + { + /* The alignment of sections between DATA_SEGMENT_ALIGN + and DATA_SEGMENT_RELRO_END caused huge padding to be + inserted at DATA_SEGMENT_RELRO_END. Try some other base. */ + asection *sec; + unsigned int max_alignment_power = 0; + + /* Find maximum alignment power of sections between + DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */ + for (sec = output_bfd->sections; sec; sec = sec->next) + if (sec->vma >= exp_data_seg.base + && sec->vma < exp_data_seg.relro_end + && sec->alignment_power > max_alignment_power) + max_alignment_power = sec->alignment_power; + + if (((bfd_vma) 1 << max_alignment_power) < exp_data_seg.pagesize) + { + if (exp_data_seg.base - (1 << max_alignment_power) + < old_base) + exp_data_seg.base += exp_data_seg.pagesize; + exp_data_seg.base -= (1 << max_alignment_power); + result = lang_size_sections_1 (s, output_section_statement, + prev, fill, dot, relax, + check_regions); + } + } link_info.relro_start = exp_data_seg.base; link_info.relro_end = exp_data_seg.relro_end; } diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc index 245ab030bd..d560f58fe6 100644 --- a/ld/scripttempl/elf.sc +++ b/ld/scripttempl/elf.sc @@ -90,9 +90,9 @@ if test -n "${COMMONPAGESIZE}"; then DATA_SEGMENT_ALIGN="ALIGN (${SEGMENT_SIZE}) - ((${MAXPAGESIZE} - .) & (${MAXPAGESIZE} - 1)); . = DATA_SEGMENT_ALIGN (${MAXPAGESIZE}, ${COMMONPAGESIZE})" DATA_SEGMENT_END=". = DATA_SEGMENT_END (.);" if test -n "${SEPARATE_GOTPLT}"; then - DATA_SEGMENT_RELRO_GOTPLT_END=". = DATA_SEGMENT_RELRO_END (. + ${SEPARATE_GOTPLT});" + DATA_SEGMENT_RELRO_GOTPLT_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT}, .);" else - DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (.);" + DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (0, .);" fi fi INTERP=".interp ${RELOCATING-0} : { *(.interp) }" @@ -102,7 +102,8 @@ if test -z "$GOT"; then GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) }" else GOT=".got ${RELOCATING-0} : { *(.got) }" - GOTPLT=".got.plt ${RELOCATING-0} : { ${RELOCATING+${DATA_SEGMENT_RELRO_GOTPLT_END}} *(.got.plt) }" + GOTPLT="${RELOCATING+${DATA_SEGMENT_RELRO_GOTPLT_END}} + .got.plt ${RELOCATING-0} : { *(.got.plt) }" fi fi DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"