diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 3e54ab1..b229061 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2208,6 +2208,8 @@ extern bfd_boolean _bfd_elf_gc_mark extern bfd_boolean _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *, elf_gc_mark_hook_fn); +extern asection * _bfd_elf_gc_mark_debug_special_section_group (asection *); + extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets (bfd *, struct bfd_link_info *); diff --git a/bfd/elflink.c b/bfd/elflink.c index e768634..559bbac 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -11943,6 +11943,55 @@ _bfd_elf_gc_mark (struct bfd_link_info *info, return ret; } +/* Scan and mark sections in a section group. + Return pointer to last member of this group. */ + +asection * +_bfd_elf_gc_mark_debug_special_section_group (asection *grp) +{ + /* Point to first section of section group. */ + asection *ssec; + /* Point to last section of section group. */ + asection *esec; + /* Used to iterate the section group. */ + asection *msec; + + bfd_boolean is_special_grp = TRUE; + bfd_boolean is_debug_grp = TRUE; + + /* First scan to see if group contains any section other than debug + and special section. */ + ssec = esec = msec = elf_next_in_group (grp); + do + { + if ((msec->flags & SEC_DEBUGGING) == 0) + is_debug_grp = FALSE; + + if ((msec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) != 0) + is_special_grp = FALSE; + + esec = msec; + msec = elf_next_in_group (msec); + } + while (msec != ssec); + + /* If this is a pure debug section group or pure special section group, + keep all sections in this group. */ + if (is_debug_grp || is_special_grp) + { + ssec = esec = msec = elf_next_in_group (grp); + do + { + msec->gc_mark = 1; + esec = msec; + msec = elf_next_in_group (msec); + } + while (msec != ssec); + } + + return esec; +} + /* Keep debug and special sections. */ bfd_boolean @@ -11982,14 +12031,24 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, if (!some_kept) continue; - /* Keep debug and special sections like .comment when they are - not part of a group, or when we have single-member groups. */ + /* To follow the ELF gABI rule that we should keep all sections + in a section group or none of them, debug sections and special + sections like .comment in below two cases will be kept: + 1) section that doesn't belong to a section group + 2) all sections in a section group which contains just either + debug sections or special sections. */ for (isec = ibfd->sections; isec != NULL; isec = isec->next) - if ((elf_next_in_group (isec) == NULL - || elf_next_in_group (isec) == isec) - && ((isec->flags & SEC_DEBUGGING) != 0 - || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)) - isec->gc_mark = 1; + { + /* Scan section group to either keep all included sections or + none of them. By setting iterator isec to the last member of + grouped sections, let the outer for loop skip those scanned + sections. */ + if ((isec->flags & SEC_GROUP) != 0) + isec = _bfd_elf_gc_mark_debug_special_section_group (isec); + else if ((isec->flags & SEC_DEBUGGING) != 0 + || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + isec->gc_mark = 1; + } if (! debug_frag_seen) continue;