From 8ba4f8f6c2586f873422ffcf002bbb5d78c4e0b6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Cl=C3=A9ment=20Chigot?= Date: Thu, 29 Jul 2021 09:50:37 +0200 Subject: [PATCH] bfd: ensure that symbols targeted by DWARF relocations are kept in XCOFF This patch improves XCOFF garbage collector pass, in order to keep symbols being referenced only by special sections like DWARF sections. bfd/ * xcofflink.c (xcoff_mark): Replace SEC_MARK by gc_mark. Look through relocations even if xcoff_section_data is NULL. (xcoff_sweep): Check if any sections of a file is kept before adding its special sections. Call xcoff_mark for special sessions being kept instead of just marking them. (SEC_MARK): Remove (xcoff_mark_symbol): Replace SEC_MARK by gc_mark. (xcoff_keep_symbol_p): Likewise. (bfd_xcoff_size_dynamic_sections): Likewise. (xcoff_find_tc0): Likewise. --- bfd/xcofflink.c | 185 +++++++++++++++++++++++++++--------------------- 1 file changed, 106 insertions(+), 79 deletions(-) diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index a00ae895e41..3ca74ce0277 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -35,11 +35,6 @@ #undef STRING_SIZE_SIZE #define STRING_SIZE_SIZE 4 -/* We reuse the SEC_ROM flag as a mark flag for garbage collection. - This flag will only be used on input sections. */ - -#define SEC_MARK (SEC_ROM) - /* The list of import files. */ struct xcoff_import_file @@ -2880,7 +2875,7 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) hsec = h->root.u.def.section; if (! bfd_is_abs_section (hsec) - && (hsec->flags & SEC_MARK) == 0) + && hsec->gc_mark == 0) { if (! xcoff_mark (info, hsec)) return false; @@ -2888,7 +2883,7 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) } if (h->toc_section != NULL - && (h->toc_section->flags & SEC_MARK) == 0) + && h->toc_section->gc_mark == 0) { if (! xcoff_mark (info, h->toc_section)) return false; @@ -2931,17 +2926,21 @@ static bool xcoff_mark (struct bfd_link_info *info, asection *sec) { if (bfd_is_const_section (sec) - || (sec->flags & SEC_MARK) != 0) + || sec->gc_mark != 0) + return true; + + sec->gc_mark = 1; + + if (sec->owner->xvec != info->output_bfd->xvec) + return true; + + if (coff_section_data (sec->owner, sec) == NULL) return true; - sec->flags |= SEC_MARK; - if (sec->owner->xvec == info->output_bfd->xvec - && coff_section_data (sec->owner, sec) != NULL - && xcoff_section_data (sec->owner, sec) != NULL) + if (xcoff_section_data (sec->owner, sec) != NULL) { struct xcoff_link_hash_entry **syms; - struct internal_reloc *rel, *relend; asection **csects; unsigned long i, first, last; @@ -2958,64 +2957,67 @@ xcoff_mark (struct bfd_link_info *info, asection *sec) if (!xcoff_mark_symbol (info, syms[i])) return false; } + } + + /* Look through the section relocs. */ + if ((sec->flags & SEC_RELOC) != 0 + && sec->reloc_count > 0) + { + struct internal_reloc *rel, *relend; - /* Look through the section relocs. */ - if ((sec->flags & SEC_RELOC) != 0 - && sec->reloc_count > 0) + rel = xcoff_read_internal_relocs (sec->owner, sec, true, + NULL, false, NULL); + if (rel == NULL) + return false; + relend = rel + sec->reloc_count; + for (; rel < relend; rel++) { - rel = xcoff_read_internal_relocs (sec->owner, sec, true, - NULL, false, NULL); - if (rel == NULL) - return false; - relend = rel + sec->reloc_count; - for (; rel < relend; rel++) - { - struct xcoff_link_hash_entry *h; + struct xcoff_link_hash_entry *h; - if ((unsigned int) rel->r_symndx - > obj_raw_syment_count (sec->owner)) - continue; + if ((unsigned int) rel->r_symndx + > obj_raw_syment_count (sec->owner)) + continue; - h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx]; - if (h != NULL) - { - if ((h->flags & XCOFF_MARK) == 0) - { - if (!xcoff_mark_symbol (info, h)) - return false; - } - } - else + h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx]; + if (h != NULL) + { + if ((h->flags & XCOFF_MARK) == 0) { - asection *rsec; - - rsec = xcoff_data (sec->owner)->csects[rel->r_symndx]; - if (rsec != NULL - && (rsec->flags & SEC_MARK) == 0) - { - if (!xcoff_mark (info, rsec)) - return false; - } + if (!xcoff_mark_symbol (info, h)) + return false; } + } + else + { + asection *rsec; - /* See if this reloc needs to be copied into the .loader - section. */ - if (xcoff_need_ldrel_p (info, rel, h, sec)) + rsec = xcoff_data (sec->owner)->csects[rel->r_symndx]; + if (rsec != NULL + && rsec->gc_mark == 0) { - ++xcoff_hash_table (info)->ldrel_count; - if (h != NULL) - h->flags |= XCOFF_LDREL; + if (!xcoff_mark (info, rsec)) + return false; } } - if (! info->keep_memory - && coff_section_data (sec->owner, sec) != NULL - && ! coff_section_data (sec->owner, sec)->keep_relocs) + /* See if this reloc needs to be copied into the .loader + section. */ + if ((sec->flags & SEC_DEBUGGING) == 0 + && xcoff_need_ldrel_p (info, rel, h, sec)) { - free (coff_section_data (sec->owner, sec)->relocs); - coff_section_data (sec->owner, sec)->relocs = NULL; + ++xcoff_hash_table (info)->ldrel_count; + if (h != NULL) + h->flags |= XCOFF_LDREL; } } + + if (! info->keep_memory + && coff_section_data (sec->owner, sec) != NULL + && ! coff_section_data (sec->owner, sec)->keep_relocs) + { + free (coff_section_data (sec->owner, sec)->relocs); + coff_section_data (sec->owner, sec)->relocs = NULL; + } } return true; @@ -3035,27 +3037,52 @@ xcoff_sweep (struct bfd_link_info *info) for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) { asection *o; + bool some_kept = false; + + /* As says below keep all sections from non-XCOFF + input files. */ + if (sub->xvec != info->output_bfd->xvec) + some_kept = true; + else + { + /* See whether any section is already marked. */ + for (o = sub->sections; o != NULL; o = o->next) + if (o->gc_mark) + some_kept = true; + } + /* If no section in this file will be kept, then we can + toss out debug sections. */ + if (!some_kept) + { + for (o = sub->sections; o != NULL; o = o->next) + { + o->size = 0; + o->reloc_count = 0; + } + continue; + } + + /* Keep all sections from non-XCOFF input files. Keep + special sections. Keep .debug sections for the + moment. */ for (o = sub->sections; o != NULL; o = o->next) { - if ((o->flags & SEC_MARK) == 0) + if (o->gc_mark == 1) + continue; + + if (sub->xvec != info->output_bfd->xvec + || o == xcoff_hash_table (info)->debug_section + || o == xcoff_hash_table (info)->loader_section + || o == xcoff_hash_table (info)->linkage_section + || o == xcoff_hash_table (info)->descriptor_section + || (bfd_section_flags (o) & SEC_DEBUGGING) + || strcmp (o->name, ".debug") == 0) + xcoff_mark (info, o); + else { - /* Keep all sections from non-XCOFF input files. Keep - special sections. Keep .debug sections for the - moment. */ - if (sub->xvec != info->output_bfd->xvec - || o == xcoff_hash_table (info)->debug_section - || o == xcoff_hash_table (info)->loader_section - || o == xcoff_hash_table (info)->linkage_section - || o == xcoff_hash_table (info)->descriptor_section - || (bfd_section_flags (o) & SEC_DEBUGGING) - || strcmp (o->name, ".debug") == 0) - o->flags |= SEC_MARK; - else - { - o->size = 0; - o->reloc_count = 0; - } + o->size = 0; + o->reloc_count = 0; } } } @@ -3457,7 +3484,7 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd, if (xcoff_hash_table (info)->gc && !bfd_is_abs_section (csect) && !bfd_is_und_section (csect) - && (csect->flags & SEC_MARK) == 0) + && csect->gc_mark == 0) return 0; /* An XCOFF linker always removes C_STAT symbols. */ @@ -3769,7 +3796,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, (a) one of the input files did or (b) we end up creating TOC references as part of the link process. */ if (o != xcoff_hash_table (info)->toc_section - && (o->flags & SEC_MARK) == 0) + && o->gc_mark == 0) { if (! xcoff_mark (info, o)) goto error_return; @@ -3806,7 +3833,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd, if (sec != NULL && gc - && (sec->flags & SEC_MARK) == 0) + && sec->gc_mark == 0) sec = NULL; special_sections[i] = sec; @@ -5103,7 +5130,7 @@ xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *flinfo) input_bfd != NULL; input_bfd = input_bfd->link.next) for (sec = input_bfd->sections; sec != NULL; sec = sec->next) - if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec)) + if (sec->gc_mark != 0 && xcoff_toc_section_p (sec)) { start = sec->output_section->vma + sec->output_offset; if (toc_start > start) @@ -5135,7 +5162,7 @@ xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *flinfo) input_bfd != NULL; input_bfd = input_bfd->link.next) for (sec = input_bfd->sections; sec != NULL; sec = sec->next) - if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec)) + if (sec->gc_mark != 0 && xcoff_toc_section_p (sec)) { start = sec->output_section->vma + sec->output_offset; if (start < best_address -- 2.30.2