From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12223 invoked by alias); 13 Dec 2004 16:46:42 -0000 Mailing-List: contact binutils-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sources.redhat.com Received: (qmail 12075 invoked from network); 13 Dec 2004 16:46:27 -0000 Received: from unknown (HELO sunsite.mff.cuni.cz) (195.113.15.26) by sourceware.org with SMTP; 13 Dec 2004 16:46:27 -0000 Received: from sunsite.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.mff.cuni.cz (8.13.1/8.13.1) with ESMTP id iBDGkOPg014478; Mon, 13 Dec 2004 17:46:24 +0100 Received: (from jj@localhost) by sunsite.mff.cuni.cz (8.13.1/8.13.1/Submit) id iBDGkOXD014475; Mon, 13 Dec 2004 17:46:24 +0100 Date: Mon, 13 Dec 2004 16:46:00 -0000 From: Jakub Jelinek To: binutils@sources.redhat.com Cc: Ulrich Drepper Subject: [PATCH] Try to avoid unneeded gaps with -z relro Message-ID: <20041213164624.GJ5149@sunsite.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i X-SW-Source: 2004-12/txt/msg00152.txt.bz2 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 * ldexp.h (exp_data_seg): Add min_base and maxpagesize fields. * ldexp.c (fold_binary) : 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