From 2edab91c10dcae30a93ce7d9f8088b8b33ee55eb Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 22 Jan 2014 11:43:03 +1030 Subject: [PATCH] Make assignments to dot keep an empty output section. An assignment to dot in an output section that allocates space of course keeps the output section. Here, I'm changing the behaviour for assignments that don't allocate space. The idea is not so much to allow people to force output of an empty section with ". = .", but to fix cases where an otherwise empty section has padding added by an alignment expression that changes with relaxation or .eh_frame editing. Such a section might have zero size before relaxation and so be stripped incorrectly. ld/ * ld.texinfo (Output Section Discarding): Mention assigning to dot as a way of keeping otherwise empty sections. * ldexp.c (is_dot, is_value, is_sym_value, is_dot_ne_0, is_dot_plus_0, is_align_conditional): New predicates. (exp_fold_tree_1): Set SEC_KEEP when assigning to dot inside an output section, except for some special cases. * scripttempl/elfmicroblaze.sc: Use canonical form to align at end of .heap and .stack. ld/testsuite/ * ld-shared/elf-offset.ld: Align end of .bss with canonical form of ALIGN that allows an empty .bss to be removed. * ld-arm/arm-dyn.ld: Likewise. * ld-arm/arm-lib.ld: Likewise. * ld-elfvsb/elf-offset.ld: Likewise. * ld-mips-elf/mips-dyn.ld: Likewise. * ld-mips-elf/mips-lib.ld: Likewise. * ld-arm/arm-no-rel-plt.ld: Remove duplicate ALIGN. * ld-powerpc/vle-multiseg-1.ld: Remove ALIGN at start of section. ALIGN address of section instead. * ld-powerpc/vle-multiseg-2.ld: Likewise. * ld-powerpc/vle-multiseg-3.ld: Likewise. * ld-powerpc/vle-multiseg-4.ld: Likewise. * ld-powerpc/vle-multiseg-6.ld: Likewise. * ld-scripts/empty-aligned.d: Check section headers not program headers. Remove xfail and notarget. * ld-scripts/empty-aligned.t: Use canonical ALIGN for end of .text2. --- ld/ChangeLog | 11 +++ ld/ld.texinfo | 13 ++- ld/ldexp.c | 97 +++++++++++++++++++++++ ld/scripttempl/elfmicroblaze.sc | 4 +- ld/testsuite/ChangeLog | 20 +++++ ld/testsuite/ld-arm/arm-dyn.ld | 2 +- ld/testsuite/ld-arm/arm-lib.ld | 2 +- ld/testsuite/ld-arm/arm-no-rel-plt.ld | 1 - ld/testsuite/ld-elfvsb/elf-offset.ld | 2 +- ld/testsuite/ld-mips-elf/mips-dyn.ld | 2 +- ld/testsuite/ld-mips-elf/mips-lib.ld | 2 +- ld/testsuite/ld-powerpc/vle-multiseg-1.ld | 3 +- ld/testsuite/ld-powerpc/vle-multiseg-2.ld | 3 +- ld/testsuite/ld-powerpc/vle-multiseg-3.ld | 3 +- ld/testsuite/ld-powerpc/vle-multiseg-4.ld | 3 +- ld/testsuite/ld-powerpc/vle-multiseg-6.ld | 3 - ld/testsuite/ld-scripts/empty-aligned.d | 14 +--- ld/testsuite/ld-scripts/empty-aligned.t | 8 +- ld/testsuite/ld-shared/elf-offset.ld | 2 +- 19 files changed, 157 insertions(+), 38 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index b5071d9c01..3d73b06c6a 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,14 @@ +2014-01-22 Alan Modra + + * ld.texinfo (Output Section Discarding): Mention assigning to dot + as a way of keeping otherwise empty sections. + * ldexp.c (is_dot, is_value, is_sym_value, is_dot_ne_0, + is_dot_plus_0, is_align_conditional): New predicates. + (exp_fold_tree_1): Set SEC_KEEP when assigning to dot inside an + output section, except for some special cases. + * scripttempl/elfmicroblaze.sc: Use canonical form to align at + end of .heap and .stack. + 2014-01-20 Marcus Shawcroft * emulparams/aarch64linuxb.sh (ELF_INTERPRETER_NAME): Define. diff --git a/ld/ld.texinfo b/ld/ld.texinfo index ae3d568721..a8e5ea69a7 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -4406,9 +4406,9 @@ scripts. @cindex discarding sections @cindex sections, discarding @cindex removing sections -The linker will not create output sections with no contents. This is -for convenience when referring to input sections that may or may not -be present in any of the input files. For example: +The linker will not normally create output sections with no contents. +This is for convenience when referring to input sections that may or +may not be present in any of the input files. For example: @smallexample .foo : @{ *(.foo) @} @end smallexample @@ -4416,7 +4416,12 @@ be present in any of the input files. For example: will only create a @samp{.foo} section in the output file if there is a @samp{.foo} section in at least one input file, and if the input sections are not all empty. Other link script directives that allocate -space in an output section will also create the output section. +space in an output section will also create the output section. So +too will assignments to dot even if the assignment does not create +space, except for @samp{. = 0}, @samp{. = . + 0}, @samp{. = sym}, +@samp{. = . + sym} and @samp{. = ALIGN (. != 0, expr, 1)} when +@samp{sym} is an absolute symbol of value 0 defined in the script. +This allows you to force output of an empty section with @samp{. = .}. The linker will ignore address assignments (@pxref{Output Section Address}) on discarded output sections, except when the linker script defines diff --git a/ld/ldexp.c b/ld/ldexp.c index 9a529dbb65..cc3be6d235 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -790,6 +790,89 @@ fold_name (etree_type *tree) } } +/* Return true if TREE is '.'. */ + +static bfd_boolean +is_dot (const etree_type *tree) +{ + return (tree->type.node_class == etree_name + && tree->type.node_code == NAME + && tree->name.name[0] == '.' + && tree->name.name[1] == 0); +} + +/* Return true if TREE is a constant equal to VAL. */ + +static bfd_boolean +is_value (const etree_type *tree, bfd_vma val) +{ + return (tree->type.node_class == etree_value + && tree->value.value == val); +} + +/* Return true if TREE is an absolute symbol equal to VAL defined in + a linker script. */ + +static bfd_boolean +is_sym_value (const etree_type *tree, bfd_vma val) +{ + struct bfd_link_hash_entry *h; + struct lang_definedness_hash_entry *def; + + return (tree->type.node_class == etree_name + && tree->type.node_code == NAME + && (def = lang_symbol_defined (tree->name.name)) != NULL + && def->by_script + && def->iteration == (lang_statement_iteration & 1) + && (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd, + &link_info, + tree->name.name, + FALSE, FALSE, TRUE)) != NULL + && h->type == bfd_link_hash_defined + && h->u.def.section == bfd_abs_section_ptr + && h->u.def.value == val); +} + +/* Return true if TREE is ". != 0". */ + +static bfd_boolean +is_dot_ne_0 (const etree_type *tree) +{ + return (tree->type.node_class == etree_binary + && tree->type.node_code == NE + && is_dot (tree->binary.lhs) + && is_value (tree->binary.rhs, 0)); +} + +/* Return true if TREE is ". = . + 0" or ". = . + sym" where sym is an + absolute constant with value 0 defined in a linker script. */ + +static bfd_boolean +is_dot_plus_0 (const etree_type *tree) +{ + return (tree->type.node_class == etree_binary + && tree->type.node_code == '+' + && is_dot (tree->binary.lhs) + && (is_value (tree->binary.rhs, 0) + || is_sym_value (tree->binary.rhs, 0))); +} + +/* Return true if TREE is "ALIGN (. != 0 ? some_expression : 1)". */ + +static bfd_boolean +is_align_conditional (const etree_type *tree) +{ + if (tree->type.node_class == etree_unary + && tree->type.node_code == ALIGN_K) + { + tree = tree->unary.child; + return (tree->type.node_class == etree_trinary + && is_dot_ne_0 (tree->trinary.cond) + && is_value (tree->trinary.rhs, 1)); + } + return 0; +} + static void exp_fold_tree_1 (etree_type *tree) { @@ -854,6 +937,20 @@ exp_fold_tree_1 (etree_type *tree) exp_fold_tree_1 (tree->assign.src); expld.assigning_to_dot = FALSE; + /* If we are assigning to dot inside an output section + arrange to keep the section, except for certain + expressions that evaluate to zero. We ignore . = 0, + . = . + 0, and . = ALIGN (. != 0 ? expr : 1). */ + if (expld.phase == lang_mark_phase_enum + && expld.section != bfd_abs_section_ptr + && !(expld.result.valid_p + && expld.result.value == 0 + && (is_value (tree->assign.src, 0) + || is_sym_value (tree->assign.src, 0) + || is_dot_plus_0 (tree->assign.src) + || is_align_conditional (tree->assign.src)))) + expld.section->flags |= SEC_KEEP; + if (!expld.result.valid_p) { if (expld.phase != lang_mark_phase_enum) diff --git a/ld/scripttempl/elfmicroblaze.sc b/ld/scripttempl/elfmicroblaze.sc index a54b89193c..8d2e6f220f 100644 --- a/ld/scripttempl/elfmicroblaze.sc +++ b/ld/scripttempl/elfmicroblaze.sc @@ -183,7 +183,7 @@ SECTIONS ${RELOCATING+*(.bss.*)} ${RELOCATING+*(.gnu.linkonce.b.*)} ${RELOCATING+*(COMMON)} - ${RELOCATING+. = ALIGN(4);} + ${RELOCATING+. = ALIGN(. != 0 ? 4 : 1);} ${RELOCATING+PROVIDE (__bss_end = .);} @@ -203,7 +203,7 @@ SECTIONS .stack : { ${RELOCATING+ _stack_end = .;} ${RELOCATING+ . += _STACK_SIZE;} - ${RELOCATING+ . = ALIGN(8);} + ${RELOCATING+ . = ALIGN(. != 0 ? 8 : 1);} ${RELOCATING+ _stack = .;} ${RELOCATING+ _end = .;} } diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index a09242852d..5fdf831d9e 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,23 @@ +2014-01-22 Alan Modra + + * ld-shared/elf-offset.ld: Align end of .bss with canonical form + of ALIGN that allows an empty .bss to be removed. + * ld-arm/arm-dyn.ld: Likewise. + * ld-arm/arm-lib.ld: Likewise. + * ld-elfvsb/elf-offset.ld: Likewise. + * ld-mips-elf/mips-dyn.ld: Likewise. + * ld-mips-elf/mips-lib.ld: Likewise. + * ld-arm/arm-no-rel-plt.ld: Remove duplicate ALIGN. + * ld-powerpc/vle-multiseg-1.ld: Remove ALIGN at start of section. + ALIGN address of section instead. + * ld-powerpc/vle-multiseg-2.ld: Likewise. + * ld-powerpc/vle-multiseg-3.ld: Likewise. + * ld-powerpc/vle-multiseg-4.ld: Likewise. + * ld-powerpc/vle-multiseg-6.ld: Likewise. + * ld-scripts/empty-aligned.d: Check section headers not program + headers. Remove xfail and notarget. + * ld-scripts/empty-aligned.t: Use canonical ALIGN for end of .text2. + 2014-01-21 H.J. Lu PR ld/16467 diff --git a/ld/testsuite/ld-arm/arm-dyn.ld b/ld/testsuite/ld-arm/arm-dyn.ld index bef9a182d3..71cb4c9e18 100644 --- a/ld/testsuite/ld-arm/arm-dyn.ld +++ b/ld/testsuite/ld-arm/arm-dyn.ld @@ -149,7 +149,7 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); + . = ALIGN(. != 0 ? 32 / 8 : 1); } . = ALIGN(32 / 8); _end = .; diff --git a/ld/testsuite/ld-arm/arm-lib.ld b/ld/testsuite/ld-arm/arm-lib.ld index c9482c352b..f158c230f4 100644 --- a/ld/testsuite/ld-arm/arm-lib.ld +++ b/ld/testsuite/ld-arm/arm-lib.ld @@ -141,7 +141,7 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); + . = ALIGN(. != 0 ? 32 / 8 : 1); } . = ALIGN(32 / 8); _end = .; diff --git a/ld/testsuite/ld-arm/arm-no-rel-plt.ld b/ld/testsuite/ld-arm/arm-no-rel-plt.ld index 439909c844..d8e5c9d2de 100644 --- a/ld/testsuite/ld-arm/arm-no-rel-plt.ld +++ b/ld/testsuite/ld-arm/arm-no-rel-plt.ld @@ -181,7 +181,6 @@ SECTIONS } _bss_end__ = . ; __bss_end__ = . ; . = ALIGN(32 / 8); - . = ALIGN(32 / 8); __end__ = . ; _end = .; PROVIDE (end = .); /* Stabs debugging sections. */ diff --git a/ld/testsuite/ld-elfvsb/elf-offset.ld b/ld/testsuite/ld-elfvsb/elf-offset.ld index 7c648247e7..cd90bcc906 100644 --- a/ld/testsuite/ld-elfvsb/elf-offset.ld +++ b/ld/testsuite/ld-elfvsb/elf-offset.ld @@ -131,7 +131,7 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); + . = ALIGN(. != 0 ? 32 / 8 : 1); } . = ALIGN(32 / 8); _end = . ; diff --git a/ld/testsuite/ld-mips-elf/mips-dyn.ld b/ld/testsuite/ld-mips-elf/mips-dyn.ld index e4f90d2739..b931e1b63e 100644 --- a/ld/testsuite/ld-mips-elf/mips-dyn.ld +++ b/ld/testsuite/ld-mips-elf/mips-dyn.ld @@ -179,7 +179,7 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); + . = ALIGN(. != 0 ? 32 / 8 : 1); } . = ALIGN(32 / 8); _end = .; diff --git a/ld/testsuite/ld-mips-elf/mips-lib.ld b/ld/testsuite/ld-mips-elf/mips-lib.ld index 5073d9f51c..1d66c62e33 100644 --- a/ld/testsuite/ld-mips-elf/mips-lib.ld +++ b/ld/testsuite/ld-mips-elf/mips-lib.ld @@ -173,7 +173,7 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); + . = ALIGN(. != 0 ? 32 / 8 : 1); } . = ALIGN(32 / 8); _end = .; diff --git a/ld/testsuite/ld-powerpc/vle-multiseg-1.ld b/ld/testsuite/ld-powerpc/vle-multiseg-1.ld index f2ff319fda..3fe37b9892 100644 --- a/ld/testsuite/ld-powerpc/vle-multiseg-1.ld +++ b/ld/testsuite/ld-powerpc/vle-multiseg-1.ld @@ -4,7 +4,6 @@ SECTIONS { *(.data) *(.ctors) *(.dtors) *(.eh_frame) *(.jcr) } .text_vle 0x00001000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text_vle) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.init) @@ -12,6 +11,6 @@ SECTIONS INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini_vle) } - .text_iv . : { . = ALIGN(16); *(.text_iv) } + .text_iv ALIGN(16) : { *(.text_iv) } .iv_handlers 0x0001F000 : { *(.iv_handlers) } } diff --git a/ld/testsuite/ld-powerpc/vle-multiseg-2.ld b/ld/testsuite/ld-powerpc/vle-multiseg-2.ld index 2320b61c2a..da9a79d6c4 100644 --- a/ld/testsuite/ld-powerpc/vle-multiseg-2.ld +++ b/ld/testsuite/ld-powerpc/vle-multiseg-2.ld @@ -2,7 +2,6 @@ SECTIONS { .text_vle 0x00001000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text_vle) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.init) @@ -12,6 +11,6 @@ SECTIONS } .data 0x00001400 : { *(.data) *(.ctors) *(.dtors) *(.eh_frame) *(.jcr) } - .text_iv . : { . = ALIGN(16); *(.text_iv) } + .text_iv ALIGN(16) : { *(.text_iv) } .iv_handlers 0x0001F000 : { *(.iv_handlers) } } diff --git a/ld/testsuite/ld-powerpc/vle-multiseg-3.ld b/ld/testsuite/ld-powerpc/vle-multiseg-3.ld index 0ed2f44c54..cfb1d88911 100644 --- a/ld/testsuite/ld-powerpc/vle-multiseg-3.ld +++ b/ld/testsuite/ld-powerpc/vle-multiseg-3.ld @@ -2,7 +2,6 @@ SECTIONS { .text_vle 0x00001000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text_vle) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.init) @@ -10,7 +9,7 @@ SECTIONS INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini_vle) } - .text_iv . : { . = ALIGN(16); *(.text_iv) } + .text_iv ALIGN(16) : { *(.text_iv) } .data 0x00001400 : { *(.data) *(.ctors) *(.dtors) *(.eh_frame) *(.jcr) } .iv_handlers 0x0001F000 : { *(.iv_handlers) } diff --git a/ld/testsuite/ld-powerpc/vle-multiseg-4.ld b/ld/testsuite/ld-powerpc/vle-multiseg-4.ld index 503fe06eaf..21304271eb 100644 --- a/ld/testsuite/ld-powerpc/vle-multiseg-4.ld +++ b/ld/testsuite/ld-powerpc/vle-multiseg-4.ld @@ -2,7 +2,6 @@ SECTIONS { .text_vle 0x00001000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text_vle) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.init) @@ -10,7 +9,7 @@ SECTIONS INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini_vle) } - .text_iv . : { . = ALIGN(16); *(.text_iv) } + .text_iv ALIGN(16) : { *(.text_iv) } .iv_handlers 0x0001F000 : { *(.iv_handlers) } .data 0x00020400 : { *(.data) *(.ctors) *(.dtors) *(.eh_frame) *(.jcr) } diff --git a/ld/testsuite/ld-powerpc/vle-multiseg-6.ld b/ld/testsuite/ld-powerpc/vle-multiseg-6.ld index c8d88dd831..2db76cc7c3 100644 --- a/ld/testsuite/ld-powerpc/vle-multiseg-6.ld +++ b/ld/testsuite/ld-powerpc/vle-multiseg-6.ld @@ -16,7 +16,6 @@ SECTIONS } .text_vle 0x00001000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text*) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.init*) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.fini*) @@ -24,14 +23,12 @@ SECTIONS .text_iv 0x100000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.text_iv) INPUT_SECTION_FLAGS (SHF_PPC_VLE) *(.iv_handlers) } >vle_seg2 .text 0x101000 : { - . = ALIGN(16); INPUT_SECTION_FLAGS (!SHF_PPC_VLE) *(.text*) } } diff --git a/ld/testsuite/ld-scripts/empty-aligned.d b/ld/testsuite/ld-scripts/empty-aligned.d index d9916ddca9..ff131ebd3b 100644 --- a/ld/testsuite/ld-scripts/empty-aligned.d +++ b/ld/testsuite/ld-scripts/empty-aligned.d @@ -1,14 +1,8 @@ #source: empty-aligned.s #ld: -T empty-aligned.t -#readelf: -l --wide -#xfail: "hppa64-*-*" -#notarget: frv-*-*linux* +#readelf: -S --wide #... -Program Headers: - +Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg +Align - +LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ [RWE ]+ +0x[0-9a-f]+ -! +LOAD .* -#... - +Segment Sections\.\.\. - +00 +.text +.* .text .* +!.* .text[234] .* +#pass diff --git a/ld/testsuite/ld-scripts/empty-aligned.t b/ld/testsuite/ld-scripts/empty-aligned.t index e59bc20360..5f6a38d888 100644 --- a/ld/testsuite/ld-scripts/empty-aligned.t +++ b/ld/testsuite/ld-scripts/empty-aligned.t @@ -6,14 +6,14 @@ SECTIONS { *(.text1) } - /* Same for alignment at beginning and end. */ + /* Same for alignment at beginning and end, although we need to be + careful in the expression used to align. */ .text2 ALIGN (4096) : { *(.text2) - . = ALIGN (4096); + . = ALIGN (. != 0 ? 4096 : 1); } - /* Same for alignment just at end, although we need to be careful in - the expression used to align. */ + /* Same for alignment just at end. */ .text3 : { *(.text3) diff --git a/ld/testsuite/ld-shared/elf-offset.ld b/ld/testsuite/ld-shared/elf-offset.ld index 125d879ab1..ee587f9fdd 100644 --- a/ld/testsuite/ld-shared/elf-offset.ld +++ b/ld/testsuite/ld-shared/elf-offset.ld @@ -128,7 +128,7 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. */ - . = ALIGN(32 / 8); + . = ALIGN(. != 0 ? 32 / 8 : 1); } . = ALIGN(32 / 8); _end = . ;