This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH] Try to avoid unneeded gaps with -z relro
- From: Jakub Jelinek <jakub at redhat dot com>
- To: binutils at sources dot redhat dot com
- Cc: Ulrich Drepper <drepper at redhat dot com>
- Date: Mon, 13 Dec 2004 17:46:24 +0100
- Subject: [PATCH] Try to avoid unneeded gaps with -z relro
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
When linking i686 libc.so which is -z relro, we sometimes end up with
unneeded gap between RE and RW segments:
[17] .eh_frame PROGBITS 001234d8 1234d8 004108 00 A 0 0 4
[18] .gcc_except_table PROGBITS 001275e0 1275e0 000252 00 A 0 0 1
[19] .tdata PROGBITS 001295f4 1285f4 000008 00 WAT 0 0 4
[20] .tbss NOBITS 001295fc 1285fc 000020 00 WAT 0 0 4
...
LOAD 0x000000 0x00000000 0x00000000 0x127832 0x127832 R E 0x1000
LOAD 0x1285f4 0x001295f4 0x001295f4 0x02a50 0x056a8 RW 0x1000
This is because when calculating the base of the RW segment, we first
align 0x127832 up to maxpagesize == pagesize boundary, i.e. 0x128000
(this step is necessary, 0x128000 is the smallest address where RW segment
could start), then in case DATA_SEGMENT_ALIGN we:
result.value += dot & (maxpage - 1);
which means exp_data_seg.base is 0x128832 and then add in adjustement
to make sure end of relro segment is page aligned:
exp_data_seg.base += (-exp_data_seg.relro_end
& (exp_data_seg.pagesize - 1));
In this case 0x1285f4 would be better, but lang_size_sections doesn't have
enough information to try this.
The following patch adds additional exp_data_seg fields that are used solely
for -z relro and allow lang_size_sections to make better choices.
Ok to commit?
2004-12-13 Jakub Jelinek <jakub@redhat.com>
* ldexp.h (exp_data_seg): Add min_base and maxpagesize fields.
* ldexp.c (fold_binary) <case DATA_SEGMENT_ALIGN>: Initialize them.
* ldlang.c (lang_size_sections): Use them to avoid wasting virtual
address space at DATA_SEGMENT_ALIGN.
--- ld/ldexp.h.jj 2004-12-09 14:21:39.000000000 +0100
+++ ld/ldexp.h 2004-12-13 16:38:26.116870243 +0100
@@ -100,7 +100,7 @@ extern struct exp_data_seg {
exp_dataseg_relro_adjust,
exp_dataseg_adjust
} phase;
- bfd_vma base, relro_end, end, pagesize;
+ bfd_vma base, min_base, relro_end, end, pagesize, maxpagesize;
} exp_data_seg;
/* A maps from a segment name to a base address. */
--- ld/ldexp.c.jj 2004-12-09 14:21:39.000000000 +0100
+++ ld/ldexp.c 2004-12-13 16:38:43.427776138 +0100
@@ -435,8 +435,10 @@ fold_binary (etree_type *tree,
if (allocation_done == lang_allocating_phase_enum)
{
exp_data_seg.phase = exp_dataseg_align_seen;
+ exp_data_seg.min_base = align_n (dot, maxpage);
exp_data_seg.base = result.value;
exp_data_seg.pagesize = other.value;
+ exp_data_seg.maxpagesize = maxpage;
exp_data_seg.relro_end = 0;
}
}
--- ld/ldlang.c.jj 2004-12-09 14:21:39.000000000 +0100
+++ ld/ldlang.c 2004-12-13 16:51:33.065231485 +0100
@@ -3858,15 +3858,21 @@ 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;
+ bfd_vma old_min_base, relro_end, maxpage;
exp_data_seg.phase = exp_dataseg_relro_adjust;
- old_base = exp_data_seg.base;
+ old_min_base = exp_data_seg.min_base;
+ maxpage = exp_data_seg.maxpagesize;
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);
+ if (old_min_base + maxpage < exp_data_seg.base)
+ {
+ exp_data_seg.base -= maxpage;
+ relro_end -= maxpage;
+ }
result = lang_size_sections_1 (s, output_section_statement, prev, fill,
dot, relax, check_regions);
if (exp_data_seg.relro_end > relro_end)
@@ -3888,7 +3894,7 @@ lang_size_sections
if (((bfd_vma) 1 << max_alignment_power) < exp_data_seg.pagesize)
{
if (exp_data_seg.base - (1 << max_alignment_power)
- < old_base)
+ < old_min_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,
Jakub