From d0bf826b37bdeb1ad98dc2d601b450bd5b9043e5 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 19 Feb 2010 01:47:16 +0000 Subject: [PATCH] bfd/ * elf.c (_bfd_elf_fixup_group_sections): New function, split out from.. (_bfd_elf_copy_private_header_data): ..here. * elflink.c (_bfd_elf_size_group_sections): New function. (bfd_elf_size_dynamic_sections): Call it. * elf-bfd.h (_bfd_elf_size_group_sections): Declare. (_bfd_elf_fixup_group_sections): Declare. ld/ * ldlang.c (unique_section_p): Add os param. Allow group sections to match /DISCARD/. Update all callers. * emultempl/genelf.em (gld${EMULATION_NAME}_before_allocation): New. (LDEMUL_BEFORE_ALLOCATION): Define. ld/testsuite/ * ld-elf/group.ld: Discard .dropme sections. * ld-elf/group10.d, * ld-elf/group10.s: New test. --- bfd/ChangeLog | 9 +++++ bfd/elf-bfd.h | 4 +++ bfd/elf.c | 78 +++++++++++++++++++++++++++++++------------ bfd/elflink.c | 18 ++++++++++ ld/ChangeLog | 7 ++++ ld/emultempl/genelf.em | 10 ++++++ ld/ldlang.c | 37 ++++++++++++-------- ld/testsuite/ChangeLog | 5 +++ ld/testsuite/ld-elf/group.ld | 2 +- ld/testsuite/ld-elf/group10.d | 11 ++++++ ld/testsuite/ld-elf/group10.s | 14 ++++++++ 11 files changed, 159 insertions(+), 36 deletions(-) create mode 100644 ld/testsuite/ld-elf/group10.d create mode 100644 ld/testsuite/ld-elf/group10.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8e0e2dd..a09058a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2010-02-19 Alan Modra + + * elf.c (_bfd_elf_fixup_group_sections): New function, split out from.. + (_bfd_elf_copy_private_header_data): ..here. + * elflink.c (_bfd_elf_size_group_sections): New function. + (bfd_elf_size_dynamic_sections): Call it. + * elf-bfd.h (_bfd_elf_size_group_sections): Declare. + (_bfd_elf_fixup_group_sections): Declare. + 2010-02-18 Matthew Gretton-Dann * elf32-arm.c (elf32_arm_merge_eabi_attributes): Add support for diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 6d4b8dd..74348d3 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1773,6 +1773,10 @@ extern void _bfd_elf_link_just_syms (asection *, struct bfd_link_info *); extern void _bfd_elf_copy_link_hash_symbol_type (bfd *, struct bfd_link_hash_entry *, struct bfd_link_hash_entry *); +extern bfd_boolean _bfd_elf_size_group_sections + (struct bfd_link_info *); +extern bfd_boolean _bfd_elf_fixup_group_sections +(bfd *, asection *); extern bfd_boolean _bfd_elf_copy_private_header_data (bfd *, bfd *); extern bfd_boolean _bfd_elf_copy_private_symbol_data diff --git a/bfd/elf.c b/bfd/elf.c index 85ece8b..20b82a7 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -6137,58 +6137,92 @@ _bfd_elf_copy_private_section_data (bfd *ibfd, NULL); } -/* Copy private header information. */ +/* Look at all the SHT_GROUP sections in IBFD, making any adjustments + necessary if we are removing either the SHT_GROUP section or any of + the group member sections. DISCARDED is the value that a section's + output_section has if the section will be discarded, NULL when this + function is called from objcopy, bfd_abs_section_ptr when called + from the linker. */ bfd_boolean -_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) +_bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded) { asection *isec; - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - /* Copy over private BFD data if it has not already been copied. - This must be done here, rather than in the copy_private_bfd_data - entry point, because the latter is called after the section - contents have been set, which means that the program headers have - already been worked out. */ - if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) - { - if (! copy_private_bfd_data (ibfd, obfd)) - return FALSE; - } - for (isec = ibfd->sections; isec != NULL; isec = isec->next) if (elf_section_type (isec) == SHT_GROUP) { asection *first = elf_next_in_group (isec); asection *s = first; + bfd_size_type removed = 0; + while (s != NULL) { /* If this member section is being output but the SHT_GROUP section is not, then clear the group info set up by _bfd_elf_copy_private_section_data. */ - if (s->output_section != NULL - && isec->output_section == NULL) + if (s->output_section != discarded + && isec->output_section == discarded) { elf_section_flags (s->output_section) &= ~SHF_GROUP; elf_group_name (s->output_section) = NULL; } /* Conversely, if the member section is not being output but the SHT_GROUP section is, then adjust its size. */ - else if (s->output_section == NULL - && isec->output_section != NULL) - isec->output_section->size -= 4; + else if (s->output_section == discarded + && isec->output_section != discarded) + removed += 4; s = elf_next_in_group (s); if (s == first) break; } + if (removed != 0) + { + if (discarded != NULL) + { + /* If we've been called for ld -r, then we need to + adjust the input section size. This function may + be called multiple times, so save the original + size. */ + if (isec->rawsize == 0) + isec->rawsize = isec->size; + isec->size = isec->rawsize - removed; + } + else + { + /* Adjust the output section size when called from + objcopy. */ + isec->output_section->size -= removed; + } + } } return TRUE; } +/* Copy private header information. */ + +bfd_boolean +_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) +{ + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + /* Copy over private BFD data if it has not already been copied. + This must be done here, rather than in the copy_private_bfd_data + entry point, because the latter is called after the section + contents have been set, which means that the program headers have + already been worked out. */ + if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return FALSE; + } + + return _bfd_elf_fixup_group_sections (ibfd, NULL); +} + /* Copy private symbol information. If this symbol is in a section which we did not map into a BFD section, try to map the section index correctly. We use special macro definitions for the mapped diff --git a/bfd/elflink.c b/bfd/elflink.c index a325c00..9fb347b 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -5481,6 +5481,20 @@ compute_bucket_count (struct bfd_link_info *info, return best_size; } +/* Size any SHT_GROUP section for ld -r. */ + +bfd_boolean +_bfd_elf_size_group_sections (struct bfd_link_info *info) +{ + bfd *ibfd; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour + && !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr)) + return FALSE; + return TRUE; +} + /* Set up the sizes and contents of the ELF dynamic sections. This is called by the ELF linker emulation before_allocation routine. We must set the sizes of the sections before the linker sets the @@ -5555,6 +5569,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, elf_hash_table (info)->init_plt_refcount = elf_hash_table (info)->init_plt_offset; + if (info->relocatable + && !_bfd_elf_size_group_sections (info)) + return FALSE; + /* The backend may have to create some sections regardless of whether we're dynamic or not. */ if (bed->elf_backend_always_size_sections diff --git a/ld/ChangeLog b/ld/ChangeLog index cc2b5e6..ce42f17 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2010-02-19 Alan Modra + + * ldlang.c (unique_section_p): Add os param. Allow group + sections to match /DISCARD/. Update all callers. + * emultempl/genelf.em (gld${EMULATION_NAME}_before_allocation): New. + (LDEMUL_BEFORE_ALLOCATION): Define. + 2010-02-15 Nick Clifton * po/vi.po: Updated Vietnamese translation. diff --git a/ld/emultempl/genelf.em b/ld/emultempl/genelf.em index 1a6c539..62af4de 100644 --- a/ld/emultempl/genelf.em +++ b/ld/emultempl/genelf.em @@ -48,6 +48,15 @@ gld${EMULATION_NAME}_after_open (void) } static void +gld${EMULATION_NAME}_before_allocation (void) +{ + if (link_info.relocatable + && !_bfd_elf_size_group_sections (&link_info)) + einfo ("%X%P: can not size group sections: %E\n"); + before_allocation_default (); +} + +static void gld${EMULATION_NAME}_after_allocation (void) { gld${EMULATION_NAME}_map_segments (FALSE); @@ -56,4 +65,5 @@ EOF # Put these extra routines in ld_${EMULATION_NAME}_emulation # LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open +LDEMUL_BEFORE_ALLOCATION=gld${EMULATION_NAME}_before_allocation LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation diff --git a/ld/ldlang.c b/ld/ldlang.c index fd75a5b..ce5a11c 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -195,7 +195,8 @@ input_statement_is_archive_path (const char *file_spec, char *sep, } static bfd_boolean -unique_section_p (const asection *sec) +unique_section_p (const asection *sec, + const lang_output_section_statement_type *os) { struct unique_sections *unam; const char *secnam; @@ -203,7 +204,8 @@ unique_section_p (const asection *sec) if (link_info.relocatable && sec->owner != NULL && bfd_is_group_section (sec->owner, sec)) - return TRUE; + return !(os != NULL + && strcmp (os->name, DISCARD_SECTION_NAME) == 0); secnam = sec->name; for (unam = unique_section_list; unam; unam = unam->next) @@ -445,12 +447,15 @@ output_section_callback_fast (lang_wild_statement_type *ptr, struct wildcard_list *sec, asection *section, lang_input_statement_type *file, - void *output ATTRIBUTE_UNUSED) + void *output) { lang_section_bst_type *node; lang_section_bst_type **tree; + lang_output_section_statement_type *os; - if (unique_section_p (section)) + os = (lang_output_section_statement_type *) output; + + if (unique_section_p (section, os)) return; node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type)); @@ -2415,9 +2420,12 @@ output_section_callback (lang_wild_statement_type *ptr, void *output) { lang_statement_union_type *before; + lang_output_section_statement_type *os; + + os = (lang_output_section_statement_type *) output; /* Exclude sections that match UNIQUE_SECTION_LIST. */ - if (unique_section_p (section)) + if (unique_section_p (section, os)) return; before = wild_sort (ptr, sec, file, section); @@ -2428,16 +2436,14 @@ output_section_callback (lang_wild_statement_type *ptr, of the current list. */ if (before == NULL) - lang_add_section (&ptr->children, section, - (lang_output_section_statement_type *) output); + lang_add_section (&ptr->children, section, os); else { lang_statement_list_type list; lang_statement_union_type **pp; lang_list_init (&list); - lang_add_section (&list, section, - (lang_output_section_statement_type *) output); + lang_add_section (&list, section, os); /* If we are discarding the section, LIST.HEAD will be NULL. */ @@ -2464,14 +2470,18 @@ check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED, struct wildcard_list *sec ATTRIBUTE_UNUSED, asection *section, lang_input_statement_type *file ATTRIBUTE_UNUSED, - void *data) + void *output) { + lang_output_section_statement_type *os; + + os = (lang_output_section_statement_type *) output; + /* Exclude sections that match UNIQUE_SECTION_LIST. */ - if (unique_section_p (section)) + if (unique_section_p (section, os)) return; if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0) - ((lang_output_section_statement_type *) data)->all_input_readonly = FALSE; + os->all_input_readonly = FALSE; } /* This is passed a file name which must have been seen already and @@ -5848,7 +5858,8 @@ lang_place_orphans (void) const char *name = s->name; int constraint = 0; - if (config.unique_orphan_sections || unique_section_p (s)) + if (config.unique_orphan_sections + || unique_section_p (s, NULL)) constraint = SPECIAL; if (!ldemul_place_orphan (s, name, constraint)) diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 8e075ed..e170dfc 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-02-19 Alan Modra + + * ld-elf/group.ld: Discard .dropme sections. + * ld-elf/group10.d, * ld-elf/group10.s: New test. + 2010-02-18 Matthew Gretton-Dann * ld-arm/attr-merge-6.attr: Add new test. Missed off last commit. diff --git a/ld/testsuite/ld-elf/group.ld b/ld/testsuite/ld-elf/group.ld index 58d78da..123ab26 100644 --- a/ld/testsuite/ld-elf/group.ld +++ b/ld/testsuite/ld-elf/group.ld @@ -2,5 +2,5 @@ SECTIONS { . = 0x1000; .text : { *(.text) *(.rodata.brlt) } - /DISCARD/ : { *(.reginfo) } + /DISCARD/ : { *(.dropme) *(.reginfo) } } diff --git a/ld/testsuite/ld-elf/group10.d b/ld/testsuite/ld-elf/group10.d new file mode 100644 index 0000000..d22a70a --- /dev/null +++ b/ld/testsuite/ld-elf/group10.d @@ -0,0 +1,11 @@ +#source: group10.s +#ld: -r -T group.ld +#readelf: -Sg --wide + +#... +group section \[[ 0-9]+\] `foo_group' \[foo_group\] contains 4 sections: + \[Index\] Name + \[[ 0-9]+\] \.text.* + \[[ 0-9]+\] \.rodata\.str.* + \[[ 0-9]+\] \.data.* + \[[ 0-9]+\] \.keepme.* diff --git a/ld/testsuite/ld-elf/group10.s b/ld/testsuite/ld-elf/group10.s new file mode 100644 index 0000000..57704b4 --- /dev/null +++ b/ld/testsuite/ld-elf/group10.s @@ -0,0 +1,14 @@ + .section .text.foo,"axG",%progbits,foo_group + .word 0 + + .section .rodata.str.1,"aMSG",%progbits,1,foo_group + .asciz "abc" + + .section .data.foo,"waG",%progbits,foo_group + .word 1 + + .section .dropme,"G",%progbits,foo_group + .word 2 + + .section .keepme,"G",%progbits,foo_group + .word 3 -- 2.7.4