diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2015-03-29 05:54:11 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-03-29 07:57:33 -0700 |
commit | aaf369402fca008edf055b1dc88515740b9c4a4d (patch) | |
tree | 6ad14cb15513a9aed56e893bb1aec127e168312a | |
parent | b9d94d62d1197f7b26d93dba1532d7d005342bb8 (diff) | |
download | binutils-gdb-users/hjl/pr18176.tar.gz |
Reduce file size for PT_GNU_RELRO segmentusers/hjl/pr18176
When a padding in file is used to align PT_GNU_RELRO segment, the maximum
padding size is maximum page size minus 1. This patch trades memory size
for file size by increasing address of the first section in PT_GNU_RELRO
segment to avoid padding if file size will be reduced by more than maximum
page minus a page and memory size will be increased by less than a page.
ld/
PR ld/18176
* ldexp.h (ldexp_control): Add first_sec.
* ldlang.c (lang_size_sections_1): Reduce file size for
PT_GNU_RELRO segment by increasing address of the first section
in PT_GNU_RELRO segment.
(lang_size_sections): Set and reset expld.dataseg.first_sec when
realigning sections in PT_GNU_RELRO segment.
ld/testsuite/
PR ld/18176
* ld-x86-64/pr18176.d: New file.
* ld-x86-64/pr18176.s: Likewise.
* ld-x86-64/pr18176.t: Likewise.
* ld-x86-64/x86-64.exp: Run pr18176.
-rw-r--r-- | ld/ldexp.h | 2 | ||||
-rw-r--r-- | ld/ldlang.c | 66 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/pr18176.d | 9 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/pr18176.s | 52 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/pr18176.t | 39 | ||||
-rw-r--r-- | ld/testsuite/ld-x86-64/x86-64.exp | 1 |
6 files changed, 152 insertions, 17 deletions
diff --git a/ld/ldexp.h b/ld/ldexp.h index 10fcf3d96ce..44d30fb10e0 100644 --- a/ld/ldexp.h +++ b/ld/ldexp.h @@ -158,6 +158,8 @@ struct ldexp_control { bfd_vma base, min_base, relro_end, end, pagesize, maxpagesize; + asection *first_sec; + enum relro_enum relro; union lang_statement_union *relro_start_stat; diff --git a/ld/ldlang.c b/ld/ldlang.c index 888082147a1..b38d9a0057f 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -4858,6 +4858,7 @@ lang_size_sections_1 } else { + bfd_vma savedot; if (os->addr_tree == NULL) { /* No address specified for this section, get one @@ -4914,21 +4915,45 @@ lang_size_sections_1 section_alignment = os->section_alignment; /* Align to what the section needs. */ + savedot = newdot; if (section_alignment > 0) - { - bfd_vma savedot = newdot; - newdot = align_power (newdot, section_alignment); + newdot = align_power (newdot, section_alignment); - dotdelta = newdot - savedot; - if (dotdelta != 0 - && (config.warn_section_align - || os->addr_tree != NULL) - && expld.phase != lang_mark_phase_enum) - einfo (_("%P: warning: changing start of section" - " %s by %lu bytes\n"), - os->name, (unsigned long) dotdelta); + if (expld.dataseg.first_sec == os->bfd_section) + { + /* If a padding in file will be used for PT_GNU_RELRO + segment, check if we can reduce the padding by + increase the address of the first relro section. + It is a tradeoff between memory size and file size. + We only do it if file size will be reduced by more + than maximum page minus a page and memory size will + be increased by less than a page. */ + bfd_vma pad + = ((newdot - expld.dataseg.min_base) + % expld.dataseg.maxpagesize); + if (pad) + { + bfd_vma nextdot + = expld.dataseg.maxpagesize - pad; + nextdot = align_power (newdot + nextdot, + section_alignment); + if (((nextdot - newdot) + < expld.dataseg.pagesize) + && pad > (expld.dataseg.maxpagesize + - expld.dataseg.pagesize)) + newdot = nextdot; + } } + dotdelta = newdot - savedot; + if (dotdelta != 0 + && (config.warn_section_align + || os->addr_tree != NULL) + && expld.phase != lang_mark_phase_enum) + einfo (_("%P: warning: changing start of section" + " %s by %lu bytes\n"), + os->name, (unsigned long) dotdelta); + bfd_set_section_vma (0, os->bfd_section, newdot); os->bfd_section->output_offset = 0; @@ -5409,16 +5434,21 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) and DATA_SEGMENT_RELRO_END can cause excessive padding to be inserted at DATA_SEGMENT_RELRO_END. Try to start a bit lower so that the section alignments will fit in. */ - asection *sec; + asection *sec, *first_sec = NULL; unsigned int max_alignment_power = 0; /* Find maximum alignment power of sections between DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */ - for (sec = link_info.output_bfd->sections; sec; sec = sec->next) - if (sec->vma >= expld.dataseg.base - && sec->vma < expld.dataseg.relro_end - && sec->alignment_power > max_alignment_power) - max_alignment_power = sec->alignment_power; + for (sec = link_info.output_bfd->sections; + sec && sec->vma < expld.dataseg.relro_end; + sec = sec->next) + if (sec->vma >= expld.dataseg.base) + { + if (first_sec == NULL) + first_sec = sec; + if (sec->alignment_power > max_alignment_power) + max_alignment_power = sec->alignment_power; + } if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize) { @@ -5427,8 +5457,10 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) simply subtracting 1 << max_alignment_power which is what we used to do here. */ expld.dataseg.base &= ~((1 << max_alignment_power) - 1); + expld.dataseg.first_sec = first_sec; lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); + expld.dataseg.first_sec = NULL; } } link_info.relro_start = expld.dataseg.base; diff --git a/ld/testsuite/ld-x86-64/pr18176.d b/ld/testsuite/ld-x86-64/pr18176.d new file mode 100644 index 00000000000..3a0853937c8 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr18176.d @@ -0,0 +1,9 @@ +#name: PR ld/18176 +#as: --64 +#ld: -melf_x86_64 -shared -z relro -T pr18176.t -z max-page-size=0x200000 -z common-page-size=0x1000 +#readelf: -l --wide +#target: x86_64-*-linux* + +#... + GNU_RELRO 0x04bd07 0x000000000024bd07 0x000000000024bd07 0x0022f9 0x0022f9 R 0x1 +#pass diff --git a/ld/testsuite/ld-x86-64/pr18176.s b/ld/testsuite/ld-x86-64/pr18176.s new file mode 100644 index 00000000000..405355f6eb2 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr18176.s @@ -0,0 +1,52 @@ + .section .init,"ax",@progbits + .p2align 2 + .space 0x1a + .section .text,"ax",@progbits + .p2align 4 + .space 0x3ab96 + .section .fini,"ax",@progbits + .p2align 2 + .space 0x9 + .section .foo_hdr,"a",@progbits + .p2align 2 + .space 0xd14 + .section .foo,"a",@progbits + .p2align 3 + .space 0x4d5c + .section .rodata,"a",@progbits + .p2align 6 + .space 0xa54d + .section .xxx,"a",@progbits + .space 0xf43 + .section .yyy,"aw",@progbits + .space 0x1 + .section .init_array,"aw",@init_array + .p2align 3 + .space 0x10 + .section .fini_array,"aw",@fini_array + .p2align 3 + .space 0x8 + .section .tdata,"awT",%progbits + .p2align 3 + .space 0x4 + .section .tbss,"awT",%nobits + .p2align 3 + .space 0x40 + .section .data.rel.ro,"aw",%progbits + .p2align 6 + .space 0x1b60 + .section .jcr,"aw",@progbits + .p2align 3 + .space 0x8 + .section .bar,"aw",@progbits + .p2align 3 + .space 0x640 + .section .data,"aw",%progbits + .p2align 5 + .space 0x70 + .section .bss,"aw",%nobits + .p2align 6 + .space 0x8a0 + .section BUS_ERROR_MAP,"aw",%progbits + .p2align 3 + .space 0x230 diff --git a/ld/testsuite/ld-x86-64/pr18176.t b/ld/testsuite/ld-x86-64/pr18176.t new file mode 100644 index 00000000000..480c0cd99a7 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr18176.t @@ -0,0 +1,39 @@ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS; + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .init : { *(.init) } + .text : { *(.text) } + .fini : { *(.fini) } + .rodata : { *(.rodata) } + .foo_hdr : { *(.foo_hdr) } + .foo : { *(.foo) } + .xxx : { *(.xxx) } + . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + .yyy : { *(.yyy) } + .tdata : { *(.tdata) } + .tbss : { *(.tbss) } + .init_array : { *(.init_array) } + .fini_array : { *(.fini_array) } + .jcr : { *(.jcr) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .bar : { *(.bar) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) } + .data : { *(.data) } + __bss_start = .; + .bss : + { + *(.bss) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /DISCARD/ : { *(.*) } +} diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 7bceb7fe908..98514ed0ad2 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -318,6 +318,7 @@ run_dump_test "mov1d" run_dump_test "pr17935-1" run_dump_test "pr17935-2" run_dump_test "pr18160" +run_dump_test "pr18176" # Must be native with the C compiler if { [isnative] && [which $CC] != 0 } { |