diff options
author | Alan Modra <amodra@gmail.com> | 2014-01-22 11:43:03 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2014-01-22 11:58:29 +1030 |
commit | 2edab91c10dcae30a93ce7d9f8088b8b33ee55eb (patch) | |
tree | 883bbadffed39aea4c78262946e12a35660b5bbe /ld/ldexp.c | |
parent | 4584ec12076e088cf36965b88ef8710ca85491f9 (diff) | |
download | gdb-2edab91c10dcae30a93ce7d9f8088b8b33ee55eb.zip gdb-2edab91c10dcae30a93ce7d9f8088b8b33ee55eb.tar.gz gdb-2edab91c10dcae30a93ce7d9f8088b8b33ee55eb.tar.bz2 |
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.
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r-- | ld/ldexp.c | 97 |
1 files changed, 97 insertions, 0 deletions
@@ -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) |