X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felflink.c;h=3de00e10eee140b7eb29725b57d05d1530b6bd9c;hb=32ae0d80cd430150ad9536aa160f34f504e129bc;hp=15909c205d514ca98ea7fa380787fd9b8f52074b;hpb=3a81e8251e18c6266f5b1c5147a9264da30fc5f0;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elflink.c b/bfd/elflink.c index 15909c205d..3de00e10ee 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -1,7 +1,5 @@ /* ELF linking support for BFD. - Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 - Free Software Foundation, Inc. + Copyright (C) 1995-2014 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -87,7 +85,8 @@ _bfd_elf_define_linkage_sym (bfd *abfd, h->def_regular = 1; h->non_elf = 0; h->type = STT_OBJECT; - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; bed = get_elf_backend_data (abfd); (*bed->elf_backend_hide_symbol) (info, h, TRUE); @@ -575,7 +574,8 @@ bfd_elf_record_link_assignment (bfd *output_bfd, if (hidden) { bed = get_elf_backend_data (output_bfd); - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; + if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) + h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; (*bed->elf_backend_hide_symbol) (info, h, TRUE); } @@ -951,11 +951,6 @@ _bfd_elf_merge_symbol (bfd *abfd, bed = get_elf_backend_data (abfd); - /* This code is for coping with dynamic objects, and is only useful - if we are doing an ELF link. */ - if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) - return TRUE; - /* For merging, we only care about real symbols. But we need to make sure that indirect symbol dynamic flags are updated. */ hi = h; @@ -963,6 +958,49 @@ _bfd_elf_merge_symbol (bfd *abfd, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the + existing symbol. */ + + oldbfd = NULL; + oldsec = NULL; + switch (h->root.type) + { + default: + break; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + oldbfd = h->root.u.undef.abfd; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + oldbfd = h->root.u.def.section->owner; + oldsec = h->root.u.def.section; + break; + + case bfd_link_hash_common: + oldbfd = h->root.u.c.p->section->owner; + oldsec = h->root.u.c.p->section; + if (pold_alignment) + *pold_alignment = h->root.u.c.p->alignment_power; + break; + } + if (poldbfd && *poldbfd == NULL) + *poldbfd = oldbfd; + + /* Differentiate strong and weak symbols. */ + newweak = bind == STB_WEAK; + oldweak = (h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_undefweak); + if (pold_weak) + *pold_weak = oldweak; + + /* This code is for coping with dynamic objects, and is only useful + if we are doing an ELF link. */ + if (!(*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) + return TRUE; + /* We have to check it for every instance since the first few may be references and not all compilers emit symbol type for undefined symbols. */ @@ -1007,45 +1045,6 @@ _bfd_elf_merge_symbol (bfd *abfd, return TRUE; } - /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the - existing symbol. */ - - switch (h->root.type) - { - default: - oldbfd = NULL; - oldsec = NULL; - break; - - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - oldbfd = h->root.u.undef.abfd; - oldsec = NULL; - break; - - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - oldbfd = h->root.u.def.section->owner; - oldsec = h->root.u.def.section; - break; - - case bfd_link_hash_common: - oldbfd = h->root.u.c.p->section->owner; - oldsec = h->root.u.c.p->section; - if (pold_alignment) - *pold_alignment = h->root.u.c.p->alignment_power; - break; - } - if (poldbfd && *poldbfd == NULL) - *poldbfd = oldbfd; - - /* Differentiate strong and weak symbols. */ - newweak = bind == STB_WEAK; - oldweak = (h->root.type == bfd_link_hash_defweak - || h->root.type == bfd_link_hash_undefweak); - if (pold_weak) - *pold_weak = oldweak; - /* In cases involving weak versioned symbols, we may wind up trying to merge a symbol with itself. Catch that here, to avoid the confusion that results if we try to override a symbol with @@ -1088,20 +1087,19 @@ _bfd_elf_merge_symbol (bfd *abfd, /* When we try to create a default indirect symbol from the dynamic definition with the default version, we skip it if its type and - the type of existing regular definition mismatch. We only do it - if the existing regular definition won't be dynamic. */ + the type of existing regular definition mismatch. */ if (pold_alignment == NULL - && !info->shared - && !info->export_dynamic - && !h->ref_dynamic && newdyn && newdef && !olddyn - && (olddef || h->root.type == bfd_link_hash_common) - && ELF_ST_TYPE (sym->st_info) != h->type - && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE - && h->type != STT_NOTYPE - && !(newfunc && oldfunc)) + && (((olddef || h->root.type == bfd_link_hash_common) + && ELF_ST_TYPE (sym->st_info) != h->type + && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE + && h->type != STT_NOTYPE + && !(newfunc && oldfunc)) + || (olddef + && ((h->type == STT_GNU_IFUNC) + != (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))))) { *skip = TRUE; return TRUE; @@ -1438,7 +1436,10 @@ _bfd_elf_merge_symbol (bfd *abfd, if (!(oldbfd != NULL && (oldbfd->flags & BFD_PLUGIN) != 0 && (abfd->flags & BFD_PLUGIN) == 0)) - *skip = TRUE; + { + newdef = FALSE; + *skip = TRUE; + } /* Merge st_other. If the symbol already has a dynamic index, but visibility says it should not be visible, turn it into a @@ -1600,6 +1601,7 @@ _bfd_elf_add_default_symbol (bfd *abfd, bfd_boolean override; char *p; size_t len, shortlen; + asection *tmp_sec; /* If this symbol has a version, and it is the default version, we create an indirect symbol from the default name to the fully @@ -1626,7 +1628,8 @@ _bfd_elf_add_default_symbol (bfd *abfd, actually going to define an indirect symbol. */ type_change_ok = FALSE; size_change_ok = FALSE; - if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, &value, + tmp_sec = sec; + if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, &hi, poldbfd, NULL, NULL, &skip, &override, &type_change_ok, &size_change_ok)) return FALSE; @@ -1701,6 +1704,12 @@ _bfd_elf_add_default_symbol (bfd *abfd, ht = (struct elf_link_hash_entry *) hi->root.u.i.link; (*bed->elf_backend_copy_indirect_symbol) (info, ht, hi); + /* A reference to the SHORTNAME symbol from a dynamic library + will be satisfied by the versioned symbol at runtime. In + effect, we have a reference to the versioned symbol. */ + ht->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; + hi->dynamic_def |= ht->dynamic_def; + /* See if the new flags lead us to realize that the symbol must be dynamic. */ if (! *dynsym) @@ -1734,8 +1743,9 @@ nondefault: /* Once again, merge with any existing symbol. */ type_change_ok = FALSE; size_change_ok = FALSE; - if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, &value, - &hi, NULL, NULL, NULL, &skip, &override, + tmp_sec = sec; + if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, + &hi, poldbfd, NULL, NULL, &skip, &override, &type_change_ok, &size_change_ok)) return FALSE; @@ -1769,6 +1779,8 @@ nondefault: if (hi->root.type == bfd_link_hash_indirect) { (*bed->elf_backend_copy_indirect_symbol) (info, h, hi); + h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; + hi->dynamic_def |= h->dynamic_def; /* See if the new flags lead us to realize that the symbol must be dynamic. */ @@ -3307,6 +3319,18 @@ _bfd_elf_relocs_compatible (const bfd_target *input, return ibed->relocs_compatible == obed->relocs_compatible; } +/* Make a special call to the linker "notice" function to tell it that + we are about to handle an as-needed lib, or have finished + processing the lib. */ + +bfd_boolean +_bfd_elf_notice_as_needed (bfd *ibfd, + struct bfd_link_info *info, + enum notice_asneeded_action act) +{ + return (*info->callbacks->notice) (info, NULL, ibfd, NULL, act, 0, NULL); +} + /* Add symbols from an ELF object file to the linker hash table. */ static bfd_boolean @@ -3336,14 +3360,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) unsigned int old_size = 0; unsigned int old_count = 0; void *old_tab = NULL; - void *old_hash; void *old_ent; struct bfd_link_hash_entry *old_undefs = NULL; struct bfd_link_hash_entry *old_undefs_tail = NULL; long old_dynsymcount = 0; bfd_size_type old_dynstr_size = 0; size_t tabsize = 0; - size_t hashsize = 0; + asection *s; htab = elf_hash_table (info); bed = get_elf_backend_data (abfd); @@ -3385,75 +3408,64 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) symbol. This differs from .gnu.warning sections, which generate warnings when they are included in an output file. */ /* PR 12761: Also generate this warning when building shared libraries. */ - if (info->executable || info->shared) + for (s = abfd->sections; s != NULL; s = s->next) { - asection *s; + const char *name; - for (s = abfd->sections; s != NULL; s = s->next) + name = bfd_get_section_name (abfd, s); + if (CONST_STRNEQ (name, ".gnu.warning.")) { - const char *name; + char *msg; + bfd_size_type sz; + + name += sizeof ".gnu.warning." - 1; - name = bfd_get_section_name (abfd, s); - if (CONST_STRNEQ (name, ".gnu.warning.")) + /* If this is a shared object, then look up the symbol + in the hash table. If it is there, and it is already + been defined, then we will not be using the entry + from this shared object, so we don't need to warn. + FIXME: If we see the definition in a regular object + later on, we will warn, but we shouldn't. The only + fix is to keep track of what warnings we are supposed + to emit, and then handle them all at the end of the + link. */ + if (dynamic) { - char *msg; - bfd_size_type sz; - - name += sizeof ".gnu.warning." - 1; - - /* If this is a shared object, then look up the symbol - in the hash table. If it is there, and it is already - been defined, then we will not be using the entry - from this shared object, so we don't need to warn. - FIXME: If we see the definition in a regular object - later on, we will warn, but we shouldn't. The only - fix is to keep track of what warnings we are supposed - to emit, and then handle them all at the end of the - link. */ - if (dynamic) - { - struct elf_link_hash_entry *h; + struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); + h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); - /* FIXME: What about bfd_link_hash_common? */ - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - /* We don't want to issue this warning. Clobber - the section size so that the warning does not - get copied into the output file. */ - s->size = 0; - continue; - } - } + /* FIXME: What about bfd_link_hash_common? */ + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + continue; + } - sz = s->size; - msg = (char *) bfd_alloc (abfd, sz + 1); - if (msg == NULL) - goto error_return; + sz = s->size; + msg = (char *) bfd_alloc (abfd, sz + 1); + if (msg == NULL) + goto error_return; - if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) - goto error_return; + if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) + goto error_return; - msg[sz] = '\0'; + msg[sz] = '\0'; - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_WARNING, s, 0, msg, - FALSE, bed->collect, NULL))) - goto error_return; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, BSF_WARNING, s, 0, msg, + FALSE, bed->collect, NULL))) + goto error_return; - if (! info->relocatable) - { - /* Clobber the section size so that the warning does - not get copied into the output file. */ - s->size = 0; + if (!info->relocatable && info->executable) + { + /* Clobber the section size so that the warning does + not get copied into the output file. */ + s->size = 0; - /* Also set SEC_EXCLUDE, so that symbols defined in - the warning section don't get copied to the output. */ - s->flags |= SEC_EXCLUDE; - } + /* Also set SEC_EXCLUDE, so that symbols defined in + the warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE; } } } @@ -3479,7 +3491,6 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) goto error_return; else { - asection *s; const char *soname = NULL; char *audit = NULL; struct bfd_link_needed_list *rpath = NULL, *runpath = NULL; @@ -3698,7 +3709,7 @@ error_free_dyn: extsymoff = hdr->sh_info; } - sym_hash = NULL; + sym_hash = elf_sym_hashes (abfd); if (extsymcount != 0) { isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, @@ -3706,13 +3717,16 @@ error_free_dyn: if (isymbuf == NULL) goto error_return; - /* We store a pointer to the hash table entry for each external - symbol. */ - amt = extsymcount * sizeof (struct elf_link_hash_entry *); - sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt); if (sym_hash == NULL) - goto error_free_sym; - elf_sym_hashes (abfd) = sym_hash; + { + /* We store a pointer to the hash table entry for each + external symbol. */ + amt = extsymcount * sizeof (struct elf_link_hash_entry *); + sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt); + if (sym_hash == NULL) + goto error_free_sym; + elf_sym_hashes (abfd) = sym_hash; + } } if (dynamic) @@ -3762,8 +3776,7 @@ error_free_dyn: } tabsize = htab->root.table.size * sizeof (struct bfd_hash_entry *); - hashsize = extsymcount * sizeof (struct elf_link_hash_entry *); - old_tab = bfd_malloc (tabsize + entsize + hashsize); + old_tab = bfd_malloc (tabsize + entsize); if (old_tab == NULL) goto error_free_vers; @@ -3775,16 +3788,13 @@ error_free_dyn: /* Make a special call to the linker "notice" function to tell it that we are about to handle an as-needed lib. */ - if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, - notice_as_needed, 0, NULL)) + if (!(*bed->notice_as_needed) (abfd, info, notice_as_needed)) goto error_free_vers; - /* Clone the symbol table and sym hashes. Remember some - pointers into the symbol table, and dynamic symbol count. */ - old_hash = (char *) old_tab + tabsize; - old_ent = (char *) old_hash + hashsize; + /* Clone the symbol table. Remember some pointers into the + symbol table, and dynamic symbol count. */ + old_ent = (char *) old_tab + tabsize; memcpy (old_tab, htab->root.table.table, tabsize); - memcpy (old_hash, sym_hash, hashsize); old_undefs = htab->root.undefs; old_undefs_tail = htab->root.undefs_tail; old_table = htab->root.table.table; @@ -3841,7 +3851,6 @@ error_free_dyn: flags = BSF_NO_FLAGS; sec = NULL; value = isym->st_value; - *sym_hash = NULL; common = bed->common_definition (isym); bind = ELF_ST_BIND (isym->st_info); @@ -4428,23 +4437,21 @@ error_free_dyn: int ret; const char *soname = elf_dt_name (abfd); + info->callbacks->minfo ("%!", soname, old_bfd, + h->root.root.string); + /* A symbol from a library loaded via DT_NEEDED of some other library is referenced by a regular object. Add a DT_NEEDED entry for it. Issue an error if --no-add-needed is used and the reference was not a weak one. */ if (old_bfd != NULL - && h->ref_regular_nonweak && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) { (*_bfd_error_handler) (_("%B: undefined reference to symbol '%s'"), old_bfd, name); - (*_bfd_error_handler) - (_("note: '%s' is defined in DSO %B" - " so try adding it to the linker command line"), - abfd, name); - bfd_set_error (bfd_error_invalid_operation); + bfd_set_error (bfd_error_missing_dso); goto error_free_vers; } @@ -4478,16 +4485,13 @@ error_free_dyn: unsigned int i; /* Restore the symbol table. */ - if (bed->as_needed_cleanup) - (*bed->as_needed_cleanup) (abfd, info); - old_hash = (char *) old_tab + tabsize; - old_ent = (char *) old_hash + hashsize; - sym_hash = elf_sym_hashes (abfd); + old_ent = (char *) old_tab + tabsize; + memset (elf_sym_hashes (abfd), 0, + extsymcount * sizeof (struct elf_link_hash_entry *)); htab->root.table.table = old_table; htab->root.table.size = old_size; htab->root.table.count = old_count; memcpy (htab->root.table.table, old_tab, tabsize); - memcpy (sym_hash, old_hash, hashsize); htab->root.undefs = old_undefs; htab->root.undefs_tail = old_undefs_tail; _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size); @@ -4542,8 +4546,7 @@ error_free_dyn: /* Make a special call to the linker "notice" function to tell it that symbols added for crefs may need to be removed. */ - if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, - notice_not_needed, 0, NULL)) + if (!(*bed->notice_as_needed) (abfd, info, notice_not_needed)) goto error_free_vers; free (old_tab); @@ -4556,8 +4559,7 @@ error_free_dyn: if (old_tab != NULL) { - if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, - notice_needed, 0, NULL)) + if (!(*bed->notice_as_needed) (abfd, info, notice_needed)) goto error_free_vers; free (old_tab); old_tab = NULL; @@ -4668,7 +4670,7 @@ error_free_dyn: struct elf_link_hash_entry *hlook; asection *slook; bfd_vma vlook; - size_t i, j, idx; + size_t i, j, idx = 0; hlook = weaks; weaks = hlook->u.weakdef; @@ -7471,6 +7473,7 @@ struct elf_outext_info bfd_boolean localsyms; bfd_boolean need_second_pass; bfd_boolean second_pass; + bfd_boolean file_sym_done; struct elf_final_link_info *flinfo; }; @@ -8094,17 +8097,14 @@ elf_link_sort_cmp2 (const void *A, const void *B) { const struct elf_link_sort_rela *a = (const struct elf_link_sort_rela *) A; const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B; - int copya, copyb; - if (a->u.offset < b->u.offset) + if (a->type < b->type) return -1; - if (a->u.offset > b->u.offset) + if (a->type > b->type) return 1; - copya = (a->type == reloc_class_copy) * 2 + (a->type == reloc_class_plt); - copyb = (b->type == reloc_class_copy) * 2 + (b->type == reloc_class_plt); - if (copya < copyb) + if (a->u.offset < b->u.offset) return -1; - if (copya > copyb) + if (a->u.offset > b->u.offset) return 1; if (a->rela->r_offset < b->rela->r_offset) return -1; @@ -8331,7 +8331,7 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; (*swap_in) (abfd, erel, s->rela); - s->type = (*bed->elf_backend_reloc_type_class) (s->rela); + s->type = (*bed->elf_backend_reloc_type_class) (info, o, s->rela); s->u.sym_mask = r_sym_mask; p += sort_elt; erel += ext_size; @@ -8692,6 +8692,22 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) || h->root.type == bfd_link_hash_defweak) && h->root.u.def.section->output_section != NULL)) return TRUE; + + if (!eoinfo->file_sym_done + && (eoinfo->second_pass ? eoinfo->flinfo->filesym_count == 1 + : eoinfo->flinfo->filesym_count > 1)) + { + /* Output a FILE symbol so that following locals are not associated + with the wrong input file. */ + memset (&sym, 0, sizeof (sym)); + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + sym.st_shndx = SHN_ABS; + if (!elf_link_output_sym (eoinfo->flinfo, NULL, &sym, + bfd_und_section_ptr, NULL)) + return FALSE; + + eoinfo->file_sym_done = TRUE; + } } else { @@ -9533,7 +9549,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) file, so the contents field will not have been set by any of the routines which work on output files. */ if (elf_section_data (o)->this_hdr.contents != NULL) - contents = elf_section_data (o)->this_hdr.contents; + { + contents = elf_section_data (o)->this_hdr.contents; + if (bed->caches_rawsize + && o->rawsize != 0 + && o->rawsize < o->size) + { + memcpy (flinfo->contents, contents, o->rawsize); + contents = flinfo->contents; + } + } else { contents = flinfo->contents; @@ -10976,17 +11001,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) } } - /* Output a FILE symbol so that following locals are not associated - with the wrong input file. */ - memset (&elfsym, 0, sizeof (elfsym)); - elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); - elfsym.st_shndx = SHN_ABS; - - if (flinfo.filesym_count > 1 - && !elf_link_output_sym (&flinfo, NULL, &elfsym, - bfd_und_section_ptr, NULL)) - return FALSE; - /* Output any global symbols that got converted to local in a version script or due to symbol visibility. We do this in a separate step since ELF requires all local symbols to appear @@ -10998,15 +11012,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) eoinfo.localsyms = TRUE; eoinfo.need_second_pass = FALSE; eoinfo.second_pass = FALSE; + eoinfo.file_sym_done = FALSE; bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); if (eoinfo.failed) return FALSE; - if (flinfo.filesym_count == 1 - && !elf_link_output_sym (&flinfo, NULL, &elfsym, - bfd_und_section_ptr, NULL)) - return FALSE; - if (eoinfo.need_second_pass) { eoinfo.second_pass = TRUE; @@ -11821,23 +11831,30 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, { asection *isec; bfd_boolean some_kept; + bfd_boolean debug_frag_seen; if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) continue; - /* Ensure all linker created sections are kept, and see whether - any other section is already marked. */ - some_kept = FALSE; + /* Ensure all linker created sections are kept, + see if any other section is already marked, + and note if we have any fragmented debug sections. */ + debug_frag_seen = some_kept = FALSE; for (isec = ibfd->sections; isec != NULL; isec = isec->next) { if ((isec->flags & SEC_LINKER_CREATED) != 0) isec->gc_mark = 1; else if (isec->gc_mark) some_kept = TRUE; + + if (debug_frag_seen == FALSE + && (isec->flags & SEC_DEBUGGING) + && CONST_STRNEQ (isec->name, ".debug_line.")) + debug_frag_seen = TRUE; } /* If no section in this file will be kept, then we can - toss out debug sections. */ + toss out the debug and special sections. */ if (!some_kept) continue; @@ -11849,6 +11866,45 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, && ((isec->flags & SEC_DEBUGGING) != 0 || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)) isec->gc_mark = 1; + + if (! debug_frag_seen) + continue; + + /* Look for CODE sections which are going to be discarded, + and find and discard any fragmented debug sections which + are associated with that code section. */ + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + if ((isec->flags & SEC_CODE) != 0 + && isec->gc_mark == 0) + { + unsigned int ilen; + asection *dsec; + + ilen = strlen (isec->name); + + /* Association is determined by the name of the debug section + containing the name of the code section as a suffix. For + example .debug_line.text.foo is a debug section associated + with .text.foo. */ + for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next) + { + unsigned int dlen; + + if (dsec->gc_mark == 0 + || (dsec->flags & SEC_DEBUGGING) == 0) + continue; + + dlen = strlen (dsec->name); + + if (dlen > ilen + && strncmp (dsec->name + (dlen - ilen), + isec->name, ilen) == 0) + { + dsec->gc_mark = 0; + break; + } + } + } } return TRUE; } @@ -11936,7 +11992,9 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info) info we collected before. */ if (gc_sweep_hook && (o->flags & SEC_RELOC) != 0 - && o->reloc_count > 0 + && o->reloc_count != 0 + && !((info->strip == strip_all || info->strip == strip_debugger) + && (o->flags & SEC_DEBUGGING) != 0) && !bfd_is_abs_section (o->output_section)) { Elf_Internal_Rela *internal_relocs; @@ -12084,14 +12142,19 @@ bfd_boolean bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info = (struct bfd_link_info *) inf; + struct bfd_elf_dynamic_list *d = info->dynamic_list; if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && (h->ref_dynamic - || ((!info->executable || info->export_dynamic) - && h->def_regular + || (h->def_regular && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN + && (!info->executable + || info->export_dynamic + || (h->dynamic + && d != NULL + && (*d->match) (&d->head, NULL, h->root.root.string))) && (strchr (h->root.root.string, ELF_VER_CHR) != NULL || !bfd_hide_sym_by_version (info->version_info, h->root.root.string)))))