X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felflink.c;h=a973cd59a342262d137548007e56b32b74770905;hb=e38bc3b5244a70367b51990962e12f6847eee6fd;hp=7793e82a3b49cbd31b27141b46b2427b3f83329a;hpb=a010d60faf972bb62f0470f70c4c68cce38752ac;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elflink.c b/bfd/elflink.c index 7793e82a3b..a973cd59a3 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -2,21 +2,21 @@ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. -This file is part of BFD, the Binary File Descriptor library. + This file is part of BFD, the Binary File Descriptor library. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" @@ -57,8 +57,7 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) return FALSE; } - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); + flags = bed->dynamic_sec_flags; s = bfd_make_section (abfd, ".got"); if (s == NULL @@ -87,8 +86,9 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) bed->got_symbol_offset, NULL, FALSE, bed->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; h->type = STT_OBJECT; + h->other = STV_HIDDEN; if (! info->executable && ! bfd_elf_link_record_dynamic_symbol (info, h)) @@ -131,10 +131,9 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) else abfd = elf_hash_table (info)->dynobj; - /* Note that we set the SEC_IN_MEMORY flag for all of these - sections. */ - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); + bed = get_elf_backend_data (abfd); + + flags = bed->dynamic_sec_flags; /* A dynamically linked executable has a .interp section, but a shared library does not. */ @@ -156,8 +155,6 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) elf_hash_table (info)->eh_info.hdr_sec = s; } - bed = get_elf_backend_data (abfd); - /* Create sections to hold version informations. These are removed if they are not needed. */ s = bfd_make_section (abfd, ".gnu.version_d"); @@ -217,7 +214,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; h->type = STT_OBJECT; if (! info->executable @@ -253,14 +250,16 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and .rel[a].bss sections. */ - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); + flags = bed->dynamic_sec_flags; pltflags = flags; - pltflags |= SEC_CODE; if (bed->plt_not_loaded) + /* We do not clear SEC_ALLOC here because we still want the OS to + allocate space for the section; it's just that there's nothing + to read in from the object file. */ pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); + else + pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD; if (bed->plt_readonly) pltflags |= SEC_READONLY; @@ -282,7 +281,7 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) FALSE, get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; h->type = STT_OBJECT; if (! info->executable @@ -369,7 +368,7 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info, if (h->root.type != bfd_link_hash_undefined && h->root.type != bfd_link_hash_undefweak) { - h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; + h->forced_local = 1; return TRUE; } @@ -445,15 +444,15 @@ bfd_elf_record_link_assignment (bfd *output_bfd ATTRIBUTE_UNUSED, h->root.type = bfd_link_hash_new; if (h->root.type == bfd_link_hash_new) - h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; + h->non_elf = 0; /* If this symbol is being provided by the linker script, and it is currently defined by a dynamic object, but not by a regular object, then mark it as undefined so that the generic linker will force the correct value. */ if (provide - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + && h->def_dynamic + && !h->def_regular) h->root.type = bfd_link_hash_undefined; /* If this symbol is not being provided by the linker script, and it is @@ -461,14 +460,14 @@ bfd_elf_record_link_assignment (bfd *output_bfd ATTRIBUTE_UNUSED, then clear out any version information because the symbol will not be associated with the dynamic object any more. */ if (!provide - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + && h->def_dynamic + && !h->def_regular) h->verinfo.verdef = NULL; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; - if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC - | ELF_LINK_HASH_REF_DYNAMIC)) != 0 + if ((h->def_dynamic + || h->ref_dynamic || info->shared) && h->dynindx == -1) { @@ -478,10 +477,10 @@ bfd_elf_record_link_assignment (bfd *output_bfd ATTRIBUTE_UNUSED, /* If this is a weak defined symbol, and we know a corresponding real symbol from the same dynamic object, make sure the real symbol is also made into a dynamic symbol. */ - if (h->weakdef != NULL - && h->weakdef->dynindx == -1) + if (h->u.weakdef != NULL + && h->u.weakdef->dynindx == -1) { - if (! bfd_elf_link_record_dynamic_symbol (info, h->weakdef)) + if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) return FALSE; } } @@ -635,8 +634,7 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *dynobj = elf_hash_table (info)->dynobj; if (dynobj != NULL - && (ip = bfd_get_section_by_name (dynobj, p->name)) - != NULL + && (ip = bfd_get_section_by_name (dynobj, p->name)) != NULL && (ip->flags & SEC_LINKER_CREATED) && ip->output_section == p) return TRUE; @@ -715,13 +713,13 @@ _bfd_elf_merge_symbol (bfd *abfd, bfd_boolean *type_change_ok, bfd_boolean *size_change_ok) { - asection *sec; + asection *sec, *oldsec; struct elf_link_hash_entry *h; struct elf_link_hash_entry *flip; int bind; bfd *oldbfd; bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon; - bfd_boolean newweak, oldweak; + bfd_boolean newweak, oldweak, old_asneeded; *skip = FALSE; *override = FALSE; @@ -755,30 +753,35 @@ _bfd_elf_merge_symbol (bfd *abfd, if (h->root.type == bfd_link_hash_new) { - h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + h->non_elf = 0; return TRUE; } - /* OLDBFD is a BFD associated with the existing symbol. */ + /* 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; break; } @@ -790,7 +793,7 @@ _bfd_elf_merge_symbol (bfd *abfd, dynamic object, which we do want to handle here. */ if (abfd == oldbfd && ((abfd->flags & DYNAMIC) == 0 - || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || !h->def_regular)) return TRUE; /* NEWDYN and OLDDYN indicate whether the new or old symbol, @@ -846,25 +849,81 @@ _bfd_elf_merge_symbol (bfd *abfd, else olddef = TRUE; + /* If the old definition came from an as-needed dynamic library which + wasn't found to be needed, treat the sym as undefined. */ + old_asneeded = FALSE; + if (newdyn + && olddyn + && (elf_dyn_lib_class (oldbfd) & DYN_AS_NEEDED) != 0) + old_asneeded = TRUE; + + /* Check TLS symbol. */ + if ((ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS) + && ELF_ST_TYPE (sym->st_info) != h->type) + { + bfd *ntbfd, *tbfd; + bfd_boolean ntdef, tdef; + asection *ntsec, *tsec; + + if (h->type == STT_TLS) + { + ntbfd = abfd; + ntsec = sec; + ntdef = newdef; + tbfd = oldbfd; + tsec = oldsec; + tdef = olddef; + } + else + { + ntbfd = oldbfd; + ntsec = oldsec; + ntdef = olddef; + tbfd = abfd; + tsec = sec; + tdef = newdef; + } + + if (tdef && ntdef) + (*_bfd_error_handler) + (_("%s: TLS definition in %B section %A mismatches non-TLS definition in %B section %A"), + tbfd, tsec, ntbfd, ntsec, h->root.root.string); + else if (!tdef && !ntdef) + (*_bfd_error_handler) + (_("%s: TLS reference in %B mismatches non-TLS reference in %B"), + tbfd, ntbfd, h->root.root.string); + else if (tdef) + (*_bfd_error_handler) + (_("%s: TLS definition in %B section %A mismatches non-TLS reference in %B"), + tbfd, tsec, ntbfd, h->root.root.string); + else + (*_bfd_error_handler) + (_("%s: TLS reference in %B mismatches non-TLS definition in %B section %A"), + tbfd, ntbfd, ntsec, h->root.root.string); + + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + /* We need to remember if a symbol has a definition in a dynamic object or is weak in all dynamic objects. Internal and hidden visibility will make it unavailable to dynamic objects. */ - if (newdyn && (h->elf_link_hash_flags & ELF_LINK_DYNAMIC_DEF) == 0) + if (newdyn && !h->dynamic_def) { if (!bfd_is_und_section (sec)) - h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_DEF; + h->dynamic_def = 1; else { /* Check if this symbol is weak in all dynamic objects. If it is the first time we see it in a dynamic object, we mark if it is weak. Otherwise, we clear it. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0) + if (!h->ref_dynamic) { if (bind == STB_WEAK) - h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_WEAK; + h->dynamic_weak = 1; } else if (bind != STB_WEAK) - h->elf_link_hash_flags &= ~ELF_LINK_DYNAMIC_WEAK; + h->dynamic_weak = 0; } } @@ -876,7 +935,7 @@ _bfd_elf_merge_symbol (bfd *abfd, { *skip = TRUE; /* Make sure this symbol is dynamic. */ - h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + h->ref_dynamic = 1; /* A protected symbol has external availability. Make sure it is recorded as dynamic. @@ -888,7 +947,7 @@ _bfd_elf_merge_symbol (bfd *abfd, } else if (!newdyn && ELF_ST_VISIBILITY (sym->st_other) != STV_DEFAULT - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0) + && h->def_dynamic) { /* If the new symbol with non-default visibility comes from a relocatable file and the old definition comes from a dynamic @@ -896,17 +955,16 @@ _bfd_elf_merge_symbol (bfd *abfd, if ((*sym_hash)->root.type == bfd_link_hash_indirect) h = *sym_hash; - if ((h->root.und_next || info->hash->undefs_tail == &h->root) + if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root) && bfd_is_und_section (sec)) { /* If the new symbol is undefined and the old symbol was also undefined before, we need to make sure _bfd_generic_link_add_one_symbol doesn't mess - up the linker hash table undefs list. Since the old + up the linker hash table undefs list. Since the old definition came from a dynamic object, it is still on the undefs list. */ h->root.type = bfd_link_hash_undefined; - /* FIXME: What if the new symbol is weak undefined? */ h->root.u.undef.abfd = abfd; } else @@ -915,11 +973,11 @@ _bfd_elf_merge_symbol (bfd *abfd, h->root.u.undef.abfd = NULL; } - if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + if (h->def_dynamic) { - h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC; - h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_DYNAMIC - | ELF_LINK_DYNAMIC_DEF); + h->def_dynamic = 0; + h->ref_dynamic = 1; + h->dynamic_def = 1; } /* FIXME: Should we check type and size for protected symbol? */ h->size = 0; @@ -1001,8 +1059,9 @@ _bfd_elf_merge_symbol (bfd *abfd, if (olddyn && olddef + && !old_asneeded && h->root.type == bfd_link_hash_defined - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && h->def_dynamic && (h->root.u.def.section->flags & SEC_ALLOC) != 0 && (h->root.u.def.section->flags & SEC_LOAD) == 0 && h->size > 0 @@ -1052,7 +1111,7 @@ _bfd_elf_merge_symbol (bfd *abfd, if (newdyn && newdef - && (olddef + && ((olddef && !old_asneeded) || (h->root.type == bfd_link_hash_common && (newweak || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))) @@ -1102,14 +1161,14 @@ _bfd_elf_merge_symbol (bfd *abfd, symbol is a function or is weak. */ flip = NULL; - if (! newdyn + if ((!newdyn || old_asneeded) && (newdef || (bfd_is_com_section (sec) && (oldweak || h->type == STT_FUNC))) && olddyn && olddef - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0) + && h->def_dynamic) { /* Change the hash table entry to undefined, and let _bfd_generic_link_add_one_symbol do the right thing with the @@ -1191,10 +1250,10 @@ _bfd_elf_merge_symbol (bfd *abfd, h->root.u.i.link = (struct bfd_link_hash_entry *) flip; (*bed->elf_backend_copy_indirect_symbol) (bed, flip, h); flip->root.u.undef.abfd = h->root.u.undef.abfd; - if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + if (h->def_dynamic) { - h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC; - flip->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + h->def_dynamic = 0; + flip->ref_dynamic = 1; } } @@ -1317,13 +1376,12 @@ _bfd_elf_add_default_symbol (bfd *abfd, h->root.type = bfd_link_hash_indirect; h->root.u.i.link = (struct bfd_link_hash_entry *) hi; - if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + if (h->def_dynamic) { - h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC; - hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; - if (hi->elf_link_hash_flags - & (ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_DEF_REGULAR)) + h->def_dynamic = 0; + hi->ref_dynamic = 1; + if (hi->ref_regular + || hi->def_regular) { if (! bfd_elf_link_record_dynamic_symbol (info, hi)) return FALSE; @@ -1353,14 +1411,12 @@ _bfd_elf_add_default_symbol (bfd *abfd, if (! dynamic) { if (info->shared - || ((hi->elf_link_hash_flags - & ELF_LINK_HASH_REF_DYNAMIC) != 0)) + || hi->ref_dynamic) *dynsym = TRUE; } else { - if ((hi->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR) != 0) + if (hi->ref_regular) *dynsym = TRUE; } } @@ -1424,14 +1480,12 @@ nondefault: if (! dynamic) { if (info->shared - || ((hi->elf_link_hash_flags - & ELF_LINK_HASH_REF_DYNAMIC) != 0)) + || hi->ref_dynamic) *dynsym = TRUE; } else { - if ((hi->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR) != 0) + if (hi->ref_regular) *dynsym = TRUE; } } @@ -1457,8 +1511,8 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data) h = (struct elf_link_hash_entry *) h->root.u.i.link; if (h->dynindx == -1 - && (h->elf_link_hash_flags - & (ELF_LINK_HASH_DEF_REGULAR | ELF_LINK_HASH_REF_REGULAR)) != 0) + && (h->def_regular + || h->ref_regular)) { struct bfd_elf_version_tree *t; struct bfd_elf_version_expr *d; @@ -1513,8 +1567,8 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, /* We only care about symbols defined in shared objects with version information. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 - || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + if (!h->def_dynamic + || h->def_regular || h->dynindx == -1 || h->verinfo.verdef == NULL) return TRUE; @@ -1604,7 +1658,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) /* We only need version numbers for symbols defined in regular objects. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + if (!h->def_regular) return TRUE; bed = get_elf_backend_data (sinfo->output_bfd); @@ -1629,7 +1683,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) if (*p == '\0') { if (hidden) - h->elf_link_hash_flags |= ELF_LINK_HIDDEN; + h->hidden = 1; return TRUE; } @@ -1724,7 +1778,7 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) } if (hidden) - h->elf_link_hash_flags |= ELF_LINK_HIDDEN; + h->hidden = 1; } /* If we don't have a version for this symbol, see if we can find @@ -2102,29 +2156,33 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, DEF_REGULAR and REF_REGULAR correctly. This is the only way to permit a non-ELF file to correctly refer to a symbol defined in an ELF dynamic object. */ - if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0) + if (h->non_elf) { while (h->root.type == bfd_link_hash_indirect) h = (struct elf_link_hash_entry *) h->root.u.i.link; if (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak) - h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK); + { + h->ref_regular = 1; + h->ref_regular_nonweak = 1; + } else { if (h->root.u.def.section->owner != NULL && (bfd_get_flavour (h->root.u.def.section->owner) == bfd_target_elf_flavour)) - h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK); + { + h->ref_regular = 1; + h->ref_regular_nonweak = 1; + } else - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; } if (h->dynindx == -1 - && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)) + && (h->def_dynamic + || h->ref_dynamic)) { if (! bfd_elf_link_record_dynamic_symbol (eif->info, h)) { @@ -2135,7 +2193,7 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, } else { - /* Unfortunately, ELF_LINK_NON_ELF is only correct if the symbol + /* Unfortunately, NON_ELF is only correct if the symbol was first seen in a non-ELF file. Fortunately, if the symbol was first seen in an ELF file, we're probably OK unless the symbol was defined in a non-ELF file. Catch that case here. @@ -2143,27 +2201,26 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, a dynamic object, and then later in a non-ELF regular object. */ if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && !h->def_regular && (h->root.u.def.section->owner != NULL ? (bfd_get_flavour (h->root.u.def.section->owner) != bfd_target_elf_flavour) : (bfd_is_abs_section (h->root.u.def.section) - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) == 0))) - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + && !h->def_dynamic))) + h->def_regular = 1; } /* If this is a final link, and the symbol was defined as a common symbol in a regular object file, and there was no definition in any dynamic object, then the linker will have allocated space for - the symbol in a common section but the ELF_LINK_HASH_DEF_REGULAR + the symbol in a common section but the DEF_REGULAR flag will not have been set. */ if (h->root.type == bfd_link_hash_defined - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && !h->def_regular + && h->ref_regular + && !h->def_dynamic && (h->root.u.def.section->owner->flags & DYNAMIC) == 0) - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; /* If -Bsymbolic was used (which means to bind references to global symbols to the definition within the shared object), and this @@ -2171,12 +2228,12 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, need a PLT entry. Likewise, if the symbol has non-default visibility. If the symbol has hidden or internal visibility, we will force it local. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0 + if (h->needs_plt && eif->info->shared && is_elf_hash_table (eif->info->hash) && (eif->info->symbolic || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + && h->def_regular) { const struct elf_backend_data *bed; bfd_boolean force_local; @@ -2201,11 +2258,11 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, /* If this is a weak defined symbol in a dynamic object, and we know the real definition in the dynamic object, copy interesting flags over to the real definition. */ - if (h->weakdef != NULL) + if (h->u.weakdef != NULL) { struct elf_link_hash_entry *weakdef; - weakdef = h->weakdef; + weakdef = h->u.weakdef; if (h->root.type == bfd_link_hash_indirect) h = (struct elf_link_hash_entry *) h->root.u.i.link; @@ -2213,13 +2270,13 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, || h->root.type == bfd_link_hash_defweak); BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined || weakdef->root.type == bfd_link_hash_defweak); - BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC); + BFD_ASSERT (weakdef->def_dynamic); /* If the real definition is defined by a regular object file, don't do anything special. See the longer description in _bfd_elf_adjust_dynamic_symbol, below. */ - if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) - h->weakdef = NULL; + if (weakdef->def_regular) + h->u.weakdef = NULL; else { const struct elf_backend_data *bed; @@ -2272,11 +2329,11 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) to the dynamic symbol table. FIXME: Do we normally need to worry about symbols which are defined by one dynamic object and referenced by another one? */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0 - && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 - || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 - || ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 - && (h->weakdef == NULL || h->weakdef->dynindx == -1)))) + if (!h->needs_plt + && (h->def_regular + || !h->def_dynamic + || (!h->ref_regular + && (h->u.weakdef == NULL || h->u.weakdef->dynindx == -1)))) { h->plt = elf_hash_table (eif->info)->init_offset; return TRUE; @@ -2284,14 +2341,14 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) /* If we've already adjusted this symbol, don't do it again. This can happen via a recursive call. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + if (h->dynamic_adjusted) return TRUE; /* Don't look at this symbol again. Note that we must set this after checking the above conditions, because we may look at a symbol once, decide not to do anything, and then get called recursively later after REF_REGULAR is set below. */ - h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED; + h->dynamic_adjusted = 1; /* If this is a weak definition, and we know a real definition, and the real symbol is not itself defined by a regular object file, @@ -2321,15 +2378,15 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) wind up at different memory locations. The tzset call will set _timezone, leaving timezone unchanged. */ - if (h->weakdef != NULL) + if (h->u.weakdef != NULL) { /* If we get to this point, we know there is an implicit reference by a regular object file via the weak symbol H. FIXME: Is this really true? What if the traversal finds - H->WEAKDEF before it finds H? */ - h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + H->U.WEAKDEF before it finds H? */ + h->u.weakdef->ref_regular = 1; - if (! _bfd_elf_adjust_dynamic_symbol (h->weakdef, eif)) + if (! _bfd_elf_adjust_dynamic_symbol (h->u.weakdef, eif)) return FALSE; } @@ -2340,7 +2397,7 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) code, and the assembly code fails to set the symbol type. */ if (h->size == 0 && h->type == STT_NOTYPE - && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0) + && !h->needs_plt) (*_bfd_error_handler) (_("warning: type and size of dynamic symbol `%s' are not defined"), h->root.root.string); @@ -2405,7 +2462,7 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h, /* If it was forced local, then clearly it's not dynamic. */ if (h->dynindx == -1) return FALSE; - if (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) + if (h->forced_local) return FALSE; /* Identify the cases where name binding rules say that a @@ -2431,7 +2488,7 @@ _bfd_elf_dynamic_symbol_p (struct elf_link_hash_entry *h, } /* If it isn't defined locally, then clearly it's dynamic. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + if (!h->def_regular) return TRUE; /* Otherwise, the symbol is dynamic if binding rules don't tell @@ -2459,11 +2516,11 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h, /* Do nothing. */; /* If we don't have a definition in a regular file, then we can't resolve locally. The sym is either undefined or dynamic. */ - else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + else if (!h->def_regular) return FALSE; /* Forced local symbols resolve locally. */ - if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + if (h->forced_local) return TRUE; /* As do non-dynamic symbols. */ @@ -2657,6 +2714,10 @@ _bfd_elf_add_dynamic_entry (struct bfd_link_info *info, if (! is_elf_hash_table (hash_table)) return FALSE; + if (info->warn_shared_textrel && info->shared && tag == DT_TEXTREL) + _bfd_error_handler + (_("warning: creating a DT_TEXTREL in a shared object.")); + bed = get_elf_backend_data (hash_table->dynobj); s = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); BFD_ASSERT (s != NULL); @@ -2844,6 +2905,8 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info) _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p, &def); p += sizeof (Elf_External_Verdef); + if (def.vd_aux != sizeof (Elf_External_Verdef)) + continue; for (i = 0; i < def.vd_cnt; ++i) { _bfd_elf_swap_verdaux_in (output_bfd, @@ -2946,7 +3009,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) || !is_elf_hash_table (hash_table) || hash_table->root.creator != abfd->xvec) { - bfd_set_error (bfd_error_invalid_operation); + if (info->relocatable) + bfd_set_error (bfd_error_invalid_operation); + else + bfd_set_error (bfd_error_wrong_format); goto error_return; } } @@ -3290,7 +3356,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (dynamic) { /* Read in any version definitions. */ - if (! _bfd_elf_slurp_version_tables (abfd)) + if (!_bfd_elf_slurp_version_tables (abfd, + info->default_imported_symver)) goto error_free_sym; /* Read in the symbol versions, but don't bother to convert them @@ -3367,6 +3434,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) sec = bfd_section_from_elf_index (abfd, isym->st_shndx); if (sec == NULL) sec = bfd_abs_section_ptr; + else if (sec->kept_section) + { + /* Symbols from discarded section are undefined. */ + sec = bfd_und_section_ptr; + isym->st_shndx = SHN_UNDEF; + } else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) value -= sec->vma; } @@ -3442,99 +3515,109 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) unsigned int vernum = 0; bfd_boolean skip; - if (ever != NULL) + if (ever == NULL) + { + if (info->default_imported_symver) + /* Use the default symbol version created earlier. */ + iver.vs_vers = elf_tdata (abfd)->cverdefs; + else + iver.vs_vers = 0; + } + else + _bfd_elf_swap_versym_in (abfd, ever, &iver); + + vernum = iver.vs_vers & VERSYM_VERSION; + + /* If this is a hidden symbol, or if it is not version + 1, we append the version name to the symbol name. + However, we do not modify a non-hidden absolute + symbol, because it might be the version symbol + itself. FIXME: What if it isn't? */ + if ((iver.vs_vers & VERSYM_HIDDEN) != 0 + || (vernum > 1 && ! bfd_is_abs_section (sec))) { - _bfd_elf_swap_versym_in (abfd, ever, &iver); - vernum = iver.vs_vers & VERSYM_VERSION; - - /* If this is a hidden symbol, or if it is not version - 1, we append the version name to the symbol name. - However, we do not modify a non-hidden absolute - symbol, because it might be the version symbol - itself. FIXME: What if it isn't? */ - if ((iver.vs_vers & VERSYM_HIDDEN) != 0 - || (vernum > 1 && ! bfd_is_abs_section (sec))) + const char *verstr; + size_t namelen, verlen, newlen; + char *newname, *p; + + if (isym->st_shndx != SHN_UNDEF) { - const char *verstr; - size_t namelen, verlen, newlen; - char *newname, *p; + if (vernum > elf_tdata (abfd)->cverdefs) + verstr = NULL; + else if (vernum > 1) + verstr = + elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + else + verstr = ""; - if (isym->st_shndx != SHN_UNDEF) + if (verstr == NULL) { - if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info) - { - (*_bfd_error_handler) - (_("%B: %s: invalid version %u (max %d)"), - abfd, name, vernum, - elf_tdata (abfd)->dynverdef_hdr.sh_info); - bfd_set_error (bfd_error_bad_value); - goto error_free_vers; - } - else if (vernum > 1) - verstr = - elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; - else - verstr = ""; + (*_bfd_error_handler) + (_("%B: %s: invalid version %u (max %d)"), + abfd, name, vernum, + elf_tdata (abfd)->cverdefs); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; } - else + } + else + { + /* We cannot simply test for the number of + entries in the VERNEED section since the + numbers for the needed versions do not start + at 0. */ + Elf_Internal_Verneed *t; + + verstr = NULL; + for (t = elf_tdata (abfd)->verref; + t != NULL; + t = t->vn_nextref) { - /* We cannot simply test for the number of - entries in the VERNEED section since the - numbers for the needed versions do not start - at 0. */ - Elf_Internal_Verneed *t; - - verstr = NULL; - for (t = elf_tdata (abfd)->verref; - t != NULL; - t = t->vn_nextref) - { - Elf_Internal_Vernaux *a; + Elf_Internal_Vernaux *a; - for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + { + if (a->vna_other == vernum) { - if (a->vna_other == vernum) - { - verstr = a->vna_nodename; - break; - } + verstr = a->vna_nodename; + break; } - if (a != NULL) - break; - } - if (verstr == NULL) - { - (*_bfd_error_handler) - (_("%B: %s: invalid needed version %d"), - abfd, name, vernum); - bfd_set_error (bfd_error_bad_value); - goto error_free_vers; } + if (a != NULL) + break; + } + if (verstr == NULL) + { + (*_bfd_error_handler) + (_("%B: %s: invalid needed version %d"), + abfd, name, vernum); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; } + } - namelen = strlen (name); - verlen = strlen (verstr); - newlen = namelen + verlen + 2; - if ((iver.vs_vers & VERSYM_HIDDEN) == 0 - && isym->st_shndx != SHN_UNDEF) - ++newlen; + namelen = strlen (name); + verlen = strlen (verstr); + newlen = namelen + verlen + 2; + if ((iver.vs_vers & VERSYM_HIDDEN) == 0 + && isym->st_shndx != SHN_UNDEF) + ++newlen; - newname = bfd_alloc (abfd, newlen); - if (newname == NULL) - goto error_free_vers; - memcpy (newname, name, namelen); - p = newname + namelen; - *p++ = ELF_VER_CHR; - /* If this is a defined non-hidden version symbol, - we add another @ to the name. This indicates the - default version of the symbol. */ - if ((iver.vs_vers & VERSYM_HIDDEN) == 0 - && isym->st_shndx != SHN_UNDEF) - *p++ = ELF_VER_CHR; - memcpy (p, verstr, verlen + 1); + newname = bfd_alloc (abfd, newlen); + if (newname == NULL) + goto error_free_vers; + memcpy (newname, name, namelen); + p = newname + namelen; + *p++ = ELF_VER_CHR; + /* If this is a defined non-hidden version symbol, + we add another @ to the name. This indicates the + default version of the symbol. */ + if ((iver.vs_vers & VERSYM_HIDDEN) == 0 + && isym->st_shndx != SHN_UNDEF) + *p++ = ELF_VER_CHR; + memcpy (p, verstr, verlen + 1); - name = newname; - } + name = newname; } if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value, @@ -3599,7 +3682,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) && (flags & BSF_WEAK) != 0 && ELF_ST_TYPE (isym->st_info) != STT_FUNC && is_elf_hash_table (hash_table) - && h->weakdef == NULL) + && h->u.weakdef == NULL) { /* Keep a list of all weak defined non function symbols from a dynamic object, using the weakdef field. Later in this @@ -3613,7 +3696,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) dynamic object, and we will be using that previous definition anyhow. */ - h->weakdef = weaks; + h->u.weakdef = weaks; weaks = h; new_weakdef = TRUE; } @@ -3636,9 +3719,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (is_elf_hash_table (hash_table)) { - int old_flags; bfd_boolean dynsym; - int new_flag; /* Check the alignment when a common symbol is involved. This can change when a common symbol is overridden by a normal @@ -3730,6 +3811,14 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, dynamic); + /* If this symbol has default visibility and the user has requested + we not re-export it, then mark it as hidden. */ + if (definition && !dynamic + && (abfd->no_export + || (abfd->my_archive && abfd->my_archive->no_export)) + && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) + isym->st_other = STV_HIDDEN | (isym->st_other & ~ ELF_ST_VISIBILITY (-1)); + if (isym->st_other != 0 && !dynamic) { unsigned char hvis, symvis, other, nvis; @@ -3756,39 +3845,36 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) the number of dynamic symbols we find. A dynamic symbol is one which is referenced or defined by both a regular object and a shared object. */ - old_flags = h->elf_link_hash_flags; dynsym = FALSE; if (! dynamic) { if (! definition) { - new_flag = ELF_LINK_HASH_REF_REGULAR; + h->ref_regular = 1; if (bind != STB_WEAK) - new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK; + h->ref_regular_nonweak = 1; } else - new_flag = ELF_LINK_HASH_DEF_REGULAR; + h->def_regular = 1; if (! info->executable - || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC - | ELF_LINK_HASH_REF_DYNAMIC)) != 0) + || h->def_dynamic + || h->ref_dynamic) dynsym = TRUE; } else { if (! definition) - new_flag = ELF_LINK_HASH_REF_DYNAMIC; + h->ref_dynamic = 1; else - new_flag = ELF_LINK_HASH_DEF_DYNAMIC; - if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR - | ELF_LINK_HASH_REF_REGULAR)) != 0 - || (h->weakdef != NULL + h->def_dynamic = 1; + if (h->def_regular + || h->ref_regular + || (h->u.weakdef != NULL && ! new_weakdef - && h->weakdef->dynindx != -1)) + && h->u.weakdef->dynindx != -1)) dynsym = TRUE; } - h->elf_link_hash_flags |= new_flag; - /* Check to see if we need to add an indirect symbol for the default name. */ if (definition || h->root.type == bfd_link_hash_common) @@ -3818,11 +3904,11 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) goto error_free_vers; - if (h->weakdef != NULL + if (h->u.weakdef != NULL && ! new_weakdef - && h->weakdef->dynindx == -1) + && h->u.weakdef->dynindx == -1) { - if (! bfd_elf_link_record_dynamic_symbol (info, h->weakdef)) + if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) goto error_free_vers; } } @@ -3842,8 +3928,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (!add_needed && definition && dynsym - && (h->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR) != 0) + && h->ref_regular) { int ret; const char *soname = elf_dt_name (abfd); @@ -3861,6 +3946,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) goto error_free_vers; } + elf_dyn_lib_class (abfd) &= ~DYN_AS_NEEDED; + add_needed = TRUE; ret = elf_add_dt_needed_tag (info, soname, add_needed); if (ret < 0) @@ -3988,8 +4075,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) size_t i, j, idx; hlook = weaks; - weaks = hlook->weakdef; - hlook->weakdef = NULL; + weaks = hlook->u.weakdef; + hlook->u.weakdef = NULL; BFD_ASSERT (hlook->root.type == bfd_link_hash_defined || hlook->root.type == bfd_link_hash_defweak @@ -4040,7 +4127,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) break; else if (h != hlook) { - hlook->weakdef = h; + hlook->u.weakdef = h; /* If the weak definition is in the list of dynamic symbols, make sure the real definition is put @@ -4483,7 +4570,7 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data) /* And store it in the struct so that we can put it in the hash table later. */ - h->elf_hash_value = ha; + h->u.elf_hash_value = ha; if (alc != NULL) free (alc); @@ -4868,8 +4955,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, /* Mark this version if there is a definition and it is not defined in a shared object. */ if (newh != NULL - && ((newh->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) == 0) + && !newh->def_dynamic && (newh->root.type == bfd_link_hash_defined || newh->root.type == bfd_link_hash_defweak)) d->symver = 1; @@ -4917,7 +5003,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, return FALSE; /* Add some entries to the .dynamic section. We fill in some of the - values later, in elf_bfd_final_link, but we must add the entries + values later, in bfd_elf_final_link, but we must add the entries now so that we know the final size of the .dynamic section. */ /* If there are initialization and/or finalization functions to @@ -4928,8 +5014,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, FALSE, FALSE) : NULL); if (h != NULL - && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_DEF_REGULAR)) != 0) + && (h->ref_regular + || h->def_regular)) { if (!_bfd_elf_add_dynamic_entry (info, DT_INIT, 0)) return FALSE; @@ -4940,8 +5026,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, FALSE, FALSE) : NULL); if (h != NULL - && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_DEF_REGULAR)) != 0) + && (h->ref_regular + || h->def_regular)) { if (!_bfd_elf_add_dynamic_entry (info, DT_FINI, 0)) return FALSE; @@ -5034,7 +5120,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, if (verdefs != NULL && verdefs->vernum == 0) verdefs = verdefs->next; - if (verdefs == NULL) + if (verdefs == NULL && !info->create_default_symver) _bfd_strip_section_from_output (info, s); else { @@ -5044,6 +5130,9 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, bfd_byte *p; Elf_Internal_Verdef def; Elf_Internal_Verdaux defaux; + struct bfd_link_hash_entry *bh; + struct elf_link_hash_entry *h; + const char *name; cdefs = 0; size = 0; @@ -5053,6 +5142,13 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, size += sizeof (Elf_External_Verdaux); ++cdefs; + /* Make space for the default version. */ + if (info->create_default_symver) + { + size += sizeof (Elf_External_Verdef); + ++cdefs; + } + for (t = verdefs; t != NULL; t = t->next) { struct bfd_elf_version_deps *n; @@ -5078,9 +5174,17 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, def.vd_flags = VER_FLG_BASE; def.vd_ndx = 1; def.vd_cnt = 1; - def.vd_aux = sizeof (Elf_External_Verdef); - def.vd_next = (sizeof (Elf_External_Verdef) - + sizeof (Elf_External_Verdaux)); + if (info->create_default_symver) + { + def.vd_aux = 2 * sizeof (Elf_External_Verdef); + def.vd_next = sizeof (Elf_External_Verdef); + } + else + { + def.vd_aux = sizeof (Elf_External_Verdef); + def.vd_next = (sizeof (Elf_External_Verdef) + + sizeof (Elf_External_Verdaux)); + } if (soname_indx != (bfd_size_type) -1) { @@ -5088,10 +5192,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, soname_indx); def.vd_hash = bfd_elf_hash (soname); defaux.vda_name = soname_indx; + name = soname; } else { - const char *name; bfd_size_type indx; name = basename (output_bfd->filename); @@ -5107,6 +5211,38 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, _bfd_elf_swap_verdef_out (output_bfd, &def, (Elf_External_Verdef *) p); p += sizeof (Elf_External_Verdef); + if (info->create_default_symver) + { + /* Add a symbol representing this version. */ + bh = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, dynobj, name, BSF_GLOBAL, bfd_abs_section_ptr, + 0, NULL, FALSE, + get_elf_backend_data (dynobj)->collect, &bh))) + return FALSE; + h = (struct elf_link_hash_entry *) bh; + h->non_elf = 0; + h->def_regular = 1; + h->type = STT_OBJECT; + h->verinfo.vertree = NULL; + + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + /* Create a duplicate of the base version with the same + aux block, but different flags. */ + def.vd_flags = 0; + def.vd_ndx = 2; + def.vd_aux = sizeof (Elf_External_Verdef); + if (verdefs) + def.vd_next = (sizeof (Elf_External_Verdef) + + sizeof (Elf_External_Verdaux)); + else + def.vd_next = 0; + _bfd_elf_swap_verdef_out (output_bfd, &def, + (Elf_External_Verdef *) p); + p += sizeof (Elf_External_Verdef); + } _bfd_elf_swap_verdaux_out (output_bfd, &defaux, (Elf_External_Verdaux *) p); p += sizeof (Elf_External_Verdaux); @@ -5115,8 +5251,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, { unsigned int cdeps; struct bfd_elf_version_deps *n; - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; cdeps = 0; for (n = t->deps; n != NULL; n = n->next) @@ -5130,8 +5264,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, get_elf_backend_data (dynobj)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->non_elf = 0; + h->def_regular = 1; h->type = STT_OBJECT; h->verinfo.vertree = t; @@ -5144,7 +5278,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, && t->locals.list == NULL && ! t->used) def.vd_flags |= VER_FLG_WEAK; - def.vd_ndx = t->vernum + 1; + def.vd_ndx = t->vernum + (info->create_default_symver ? 2 : 1); def.vd_cnt = cdeps + 1; def.vd_hash = bfd_elf_hash (t->name); def.vd_aux = sizeof (Elf_External_Verdef); @@ -5341,7 +5475,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, s = bfd_get_section_by_name (dynobj, ".gnu.version"); BFD_ASSERT (s != NULL); if (dynsymcount == 0 - || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL)) + || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL + && !info->create_default_symver)) { _bfd_strip_section_from_output (info, s); /* The DYNSYMCOUNT might have changed if we were going to @@ -5668,6 +5803,14 @@ elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) bfd_byte *erel, *erelend; asection *o = lo->u.indirect.section; + if (o->contents == NULL && o->size != 0) + { + /* This is a reloc section that is being handled as a normal + section. See bfd_section_from_shdr. We can't combine + relocs in this case. */ + free (sort); + return 0; + } erel = o->contents; erelend = o->contents + o->size; p = sort + o->output_offset / ext_size * sort_elt; @@ -5995,12 +6138,12 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) /* Decide whether to output this symbol in this pass. */ if (eoinfo->localsyms) { - if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + if (!h->forced_local) return TRUE; } else { - if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + if (h->forced_local) return TRUE; } @@ -6011,8 +6154,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) references in regular files have already been handled). If we are reporting errors for this situation then do so now. */ if (h->root.type == bfd_link_hash_undefined - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 + && h->ref_dynamic + && !h->ref_regular && ! elf_link_check_versioned_symbol (finfo->info, bed, h) && finfo->info->unresolved_syms_in_shared_libs != RM_IGNORE) { @@ -6029,9 +6172,10 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) shared libraries. */ if (! finfo->info->relocatable && (! finfo->info->shared) - && (h->elf_link_hash_flags - & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK)) - == (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC) + && h->forced_local + && h->ref_dynamic + && !h->dynamic_def + && !h->dynamic_weak && ! elf_link_check_versioned_symbol (finfo->info, bed, h)) { (*_bfd_error_handler) @@ -6052,10 +6196,10 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) output it. */ if (h->indx == -2) strip = FALSE; - else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + else if ((h->def_dynamic + || h->ref_dynamic) + && !h->def_regular + && !h->ref_regular) strip = TRUE; else if (finfo->info->strip == strip_all) strip = TRUE; @@ -6075,13 +6219,13 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) nothing else to do unless it is a forced local symbol. */ if (strip && h->dynindx == -1 - && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + && !h->forced_local) return TRUE; sym.st_value = 0; sym.st_size = h->size; sym.st_other = h->other; - if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + if (h->forced_local) sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type); else if (h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_defweak) @@ -6168,11 +6312,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for forced local syms when non-shared is due to a historical quirk. */ if ((h->dynindx != -1 - || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + || h->forced_local) && ((finfo->info->shared && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak)) - || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + || !h->forced_local) && elf_hash_table (finfo->info)->dynamic_sections_created) { if (! ((*bed->elf_backend_finish_dynamic_symbol) @@ -6190,13 +6334,13 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) because it might not be marked as undefined until the finish_dynamic_symbol routine gets through with it. */ if (sym.st_shndx == SHN_UNDEF - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 + && h->ref_regular && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL || ELF_ST_BIND (sym.st_info) == STB_WEAK)) { int bindtype; - if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0) + if (h->ref_regular_nonweak) bindtype = STB_GLOBAL; else bindtype = STB_WEAK; @@ -6209,7 +6353,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT && ELF_ST_BIND (sym.st_info) != STB_WEAK && h->root.type == bfd_link_hash_undefined - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + && !h->def_regular) { (*_bfd_error_handler) (_("%B: %s symbol `%s' isn't defined"), @@ -6241,7 +6385,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) bed->s->swap_symbol_out (finfo->output_bfd, &sym, esym, 0); bucketcount = elf_hash_table (finfo->info)->bucketcount; - bucket = h->elf_hash_value % bucketcount; + bucket = h->u.elf_hash_value % bucketcount; hash_entry_size = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; bucketpos = ((bfd_byte *) finfo->hash_sec->contents @@ -6257,7 +6401,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) Elf_Internal_Versym iversym; Elf_External_Versym *eversym; - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + if (!h->def_regular) { if (h->verinfo.verdef == NULL) iversym.vs_vers = 0; @@ -6270,9 +6414,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) iversym.vs_vers = 1; else iversym.vs_vers = h->verinfo.vertree->vernum + 1; + if (finfo->info->create_default_symver) + iversym.vs_vers++; } - if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0) + if (h->hidden) iversym.vs_vers |= VERSYM_HIDDEN; eversym = (Elf_External_Versym *) finfo->symver_sec->contents; @@ -6322,30 +6468,40 @@ elf_section_ignore_discarded_relocs (asection *sec) return FALSE; } -/* Return TRUE if we should complain about a reloc in SEC against a - symbol defined in a discarded section. */ - -static bfd_boolean -elf_section_complain_discarded (asection *sec) +enum action_discarded + { + COMPLAIN = 1, + PRETEND = 2 + }; + +/* Return a mask saying how ld should treat relocations in SEC against + symbols defined in discarded sections. If this function returns + COMPLAIN set, ld will issue a warning message. If this function + returns PRETEND set, and the discarded section was link-once and the + same size as the kept link-once section, ld will pretend that the + symbol was actually defined in the kept section. Otherwise ld will + zero the reloc (at least that is the intent, but some cooperation by + the target dependent code is needed, particularly for REL targets). */ + +static unsigned int +elf_action_discarded (asection *sec) { - if (strncmp (".stab", sec->name, 5) == 0 - && (!sec->name[5] || - (sec->name[5] == '.' && ISDIGIT (sec->name[6])))) - return FALSE; + if (sec->flags & SEC_DEBUGGING) + return PRETEND; if (strcmp (".eh_frame", sec->name) == 0) - return FALSE; + return 0; if (strcmp (".gcc_except_table", sec->name) == 0) - return FALSE; + return 0; if (strcmp (".PARISC.unwind", sec->name) == 0) - return FALSE; + return 0; if (strcmp (".fixup", sec->name) == 0) - return FALSE; + return 0; - return TRUE; + return COMPLAIN | PRETEND; } /* Find a match between a section and a member of a section group. */ @@ -6640,7 +6796,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) if (!elf_section_ignore_discarded_relocs (o)) { Elf_Internal_Rela *rel, *relend; - bfd_boolean complain = elf_section_complain_discarded (o); + unsigned int action = elf_action_discarded (o); rel = internal_relocs; relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel; @@ -6651,6 +6807,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) struct elf_link_hash_entry *h = NULL; const char *sym_name; + if (r_symndx == STN_UNDEF) + continue; + if (r_symndx >= locsymcount || (elf_bad_symtab (input_bfd) && finfo->sections[r_symndx] == NULL)) @@ -6671,51 +6830,17 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) { Elf_Internal_Sym *sym = isymbuf + r_symndx; ps = &finfo->sections[r_symndx]; - sym_name = bfd_elf_local_sym_name (input_bfd, sym); + sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym); } /* Complain if the definition comes from a discarded section. */ if ((sec = *ps) != NULL && elf_discarded_section (sec)) { - if ((o->flags & SEC_DEBUGGING) != 0) - { - BFD_ASSERT (r_symndx != 0); - - /* Try to preserve debug information. - FIXME: This is quite broken. Modifying - the symbol here means we will be changing - all uses of the symbol, not just those in - debug sections. The only thing that makes - this half reasonable is that debug sections - tend to come after other sections. Of - course, that doesn't help with globals. - ??? All link-once sections of the same name - ought to define the same set of symbols, so - it would seem that globals ought to always - be defined in the kept section. */ - if (sec->kept_section != NULL) - { - asection *member; + asection *kept; - /* Check if it is a linkonce section or - member of a comdat group. */ - if (elf_sec_group (sec) == NULL - && sec->size == sec->kept_section->size) - { - *ps = sec->kept_section; - continue; - } - else if (elf_sec_group (sec) != NULL - && (member = match_group_member (sec, sec->kept_section)) - && sec->size == member->size) - { - *ps = member; - continue; - } - } - } - else if (complain) + BFD_ASSERT (r_symndx != 0); + if (action & COMPLAIN) { (*_bfd_error_handler) (_("`%s' referenced in section `%A' of %B: " @@ -6723,6 +6848,30 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) o, input_bfd, sec, sec->owner, sym_name); } + /* Try to do the best we can to support buggy old + versions of gcc. If we've warned, or this is + debugging info, pretend that the symbol is + really defined in the kept linkonce section. + FIXME: This is quite broken. Modifying the + symbol here means we will be changing all later + uses of the symbol, not just in this section. + The only thing that makes this half reasonable + is that we warn in non-debug sections, and + debug sections tend to come after other + sections. */ + kept = sec->kept_section; + if (kept != NULL && (action & PRETEND)) + { + if (elf_sec_group (sec) != NULL) + kept = match_group_member (sec, kept); + if (kept != NULL + && sec->size == kept->size) + { + *ps = kept; + continue; + } + } + /* Remove the symbol reference from the reloc, but don't kill the reloc completely. This is so that a zero value will be written into the section, @@ -6843,7 +6992,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) symbol. We set the rel_hash entry for this reloc to point to the global hash table entry for this symbol. The symbol index is then - set at the end of elf_bfd_final_link. */ + set at the end of bfd_elf_final_link. */ indx = r_symndx - extsymoff; rh = elf_sym_hashes (input_bfd)[indx]; while (rh->root.type == bfd_link_hash_indirect @@ -7149,7 +7298,8 @@ elf_reloc_link_order (bfd *output_bfd, else sym_name = link_order->u.reloc.p->u.name; if (! ((*info->callbacks->reloc_overflow) - (info, sym_name, howto->name, addend, NULL, NULL, 0))) + (info, NULL, sym_name, howto->name, addend, NULL, + NULL, (bfd_vma) 0))) { free (buf); return FALSE; @@ -7583,8 +7733,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) if (! _bfd_elf_compute_section_file_positions (abfd, info)) goto error_return; - /* That created the reloc sections. Set their sizes, and assign - them file positions, and allocate some buffers. */ + /* Set sizes, and assign file positions for reloc sections. */ for (o = abfd->sections; o != NULL; o = o->next) { if ((o->flags & SEC_RELOC) != 0) @@ -8574,26 +8723,26 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp) h = (struct elf_link_hash_entry *) h->root.u.i.link; /* Those that are not vtables. */ - if (h->vtable_parent == NULL) + if (h->vtable == NULL || h->vtable->parent == NULL) return TRUE; /* Those vtables that do not have parents, we cannot merge. */ - if (h->vtable_parent == (struct elf_link_hash_entry *) -1) + if (h->vtable->parent == (struct elf_link_hash_entry *) -1) return TRUE; /* If we've already been done, exit. */ - if (h->vtable_entries_used && h->vtable_entries_used[-1]) + if (h->vtable->used && h->vtable->used[-1]) return TRUE; /* Make sure the parent's table is up to date. */ - elf_gc_propagate_vtable_entries_used (h->vtable_parent, okp); + elf_gc_propagate_vtable_entries_used (h->vtable->parent, okp); - if (h->vtable_entries_used == NULL) + if (h->vtable->used == NULL) { /* None of this table's entries were referenced. Re-use the parent's table. */ - h->vtable_entries_used = h->vtable_parent->vtable_entries_used; - h->vtable_entries_size = h->vtable_parent->vtable_entries_size; + h->vtable->used = h->vtable->parent->vtable->used; + h->vtable->size = h->vtable->parent->vtable->size; } else { @@ -8601,9 +8750,9 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp) bfd_boolean *cu, *pu; /* Or the parent's entries into ours. */ - cu = h->vtable_entries_used; + cu = h->vtable->used; cu[-1] = TRUE; - pu = h->vtable_parent->vtable_entries_used; + pu = h->vtable->parent->vtable->used; if (pu != NULL) { const struct elf_backend_data *bed; @@ -8611,7 +8760,7 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp) bed = get_elf_backend_data (h->root.u.def.section->owner); log_file_align = bed->s->log_file_align; - n = h->vtable_parent->vtable_entries_size >> log_file_align; + n = h->vtable->parent->vtable->size >> log_file_align; while (n--) { if (*pu) @@ -8639,7 +8788,7 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp) /* Take care of both those symbols that do not describe vtables as well as those that are not loaded. */ - if (h->vtable_parent == NULL) + if (h->vtable == NULL || h->vtable->parent == NULL) return TRUE; BFD_ASSERT (h->root.type == bfd_link_hash_defined @@ -8661,11 +8810,11 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp) if (rel->r_offset >= hstart && rel->r_offset < hend) { /* If the entry is in use, do nothing. */ - if (h->vtable_entries_used - && (rel->r_offset - hstart) < h->vtable_entries_size) + if (h->vtable->used + && (rel->r_offset - hstart) < h->vtable->size) { bfd_vma entry = (rel->r_offset - hstart) >> log_file_align; - if (h->vtable_entries_used[entry]) + if (h->vtable->used[entry]) continue; } /* Otherwise, kill it. */ @@ -8687,7 +8836,7 @@ elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC)) + && h->ref_dynamic) h->root.u.def.section->flags |= SEC_KEEP; return TRUE; @@ -8808,6 +8957,12 @@ bfd_elf_gc_record_vtinherit (bfd *abfd, return FALSE; win: + if (!child->vtable) + { + child->vtable = bfd_zalloc (abfd, sizeof (*child->vtable)); + if (!child->vtable) + return FALSE; + } if (!h) { /* This *should* only be the absolute section. It could potentially @@ -8815,10 +8970,10 @@ bfd_elf_gc_record_vtinherit (bfd *abfd, would be bad. It isn't worth paging in the local symbols to be sure though; that case should simply be handled by the assembler. */ - child->vtable_parent = (struct elf_link_hash_entry *) -1; + child->vtable->parent = (struct elf_link_hash_entry *) -1; } else - child->vtable_parent = h; + child->vtable->parent = h; return TRUE; } @@ -8834,10 +8989,17 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, const struct elf_backend_data *bed = get_elf_backend_data (abfd); unsigned int log_file_align = bed->s->log_file_align; - if (addend >= h->vtable_entries_size) + if (!h->vtable) + { + h->vtable = bfd_zalloc (abfd, sizeof (*h->vtable)); + if (!h->vtable) + return FALSE; + } + + if (addend >= h->vtable->size) { size_t size, bytes, file_align; - bfd_boolean *ptr = h->vtable_entries_used; + bfd_boolean *ptr = h->vtable->used; /* While the symbol is undefined, we have to be prepared to handle a zero size. */ @@ -8868,7 +9030,7 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, { size_t oldbytes; - oldbytes = (((h->vtable_entries_size >> log_file_align) + 1) + oldbytes = (((h->vtable->size >> log_file_align) + 1) * sizeof (bfd_boolean)); memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes); } @@ -8880,11 +9042,11 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, return FALSE; /* And arrange for that done flag to be at index -1. */ - h->vtable_entries_used = ptr + 1; - h->vtable_entries_size = size; + h->vtable->used = ptr + 1; + h->vtable->size = size; } - h->vtable_entries_used[addend >> log_file_align] = TRUE; + h->vtable->used[addend >> log_file_align] = TRUE; return TRUE; } @@ -9201,88 +9363,11 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) return ret; } -struct already_linked_section -{ - asection *sec; - asection *linked; -}; - -/* Check if the member of a single member comdat group matches a - linkonce section and vice versa. */ -static bfd_boolean -try_match_symbols_in_sections - (struct bfd_section_already_linked_hash_entry *h, void *info) -{ - struct bfd_section_already_linked *l; - struct already_linked_section *s - = (struct already_linked_section *) info; - - if (elf_sec_group (s->sec) == NULL) - { - /* It is a linkonce section. Try to match it with the member of a - single member comdat group. */ - for (l = h->entry; l != NULL; l = l->next) - if ((l->sec->flags & SEC_GROUP)) - { - asection *first = elf_next_in_group (l->sec); - - if (first != NULL - && elf_next_in_group (first) == first - && bfd_elf_match_symbols_in_sections (first, s->sec)) - { - s->linked = first; - return FALSE; - } - } - } - else - { - /* It is the member of a single member comdat group. Try to match - it with a linkonce section. */ - for (l = h->entry; l != NULL; l = l->next) - if ((l->sec->flags & SEC_GROUP) == 0 - && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL - && bfd_elf_match_symbols_in_sections (l->sec, s->sec)) - { - s->linked = l->sec; - return FALSE; - } - } - - return TRUE; -} - -static bfd_boolean -already_linked (asection *sec, asection *group) -{ - struct already_linked_section result; - - result.sec = sec; - result.linked = NULL; - - bfd_section_already_linked_table_traverse - (try_match_symbols_in_sections, &result); - - if (result.linked) - { - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = result.linked; - - /* Also discard the group section. */ - if (group) - group->output_section = bfd_abs_section_ptr; - - return TRUE; - } - - return FALSE; -} - void _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec) { flagword flags; - const char *name; + const char *name, *p; struct bfd_section_already_linked *l; struct bfd_section_already_linked_hash_entry *already_linked_list; asection *group; @@ -9332,7 +9417,13 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec) name = bfd_get_section_name (abfd, sec); - already_linked_list = bfd_section_already_linked_table_lookup (name); + if (strncmp (name, ".gnu.linkonce.", sizeof (".gnu.linkonce.") - 1) == 0 + && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) + p++; + else + p = name; + + already_linked_list = bfd_section_already_linked_table_lookup (p); for (l = already_linked_list->entry; l != NULL; l = l->next) { @@ -9342,10 +9433,11 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec) a linkonce section with a linkonce section, and ignore comdat section. */ if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP) + && strcmp (name, l->sec->name) == 0 && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL) { /* The section has already been linked. See if we should - issue a warning. */ + issue a warning. */ switch (flags & SEC_LINK_DUPLICATES) { default: @@ -9366,6 +9458,36 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec) (_("%B: duplicate section `%A' has different size\n"), abfd, sec); break; + + case SEC_LINK_DUPLICATES_SAME_CONTENTS: + if (sec->size != l->sec->size) + (*_bfd_error_handler) + (_("%B: duplicate section `%A' has different size\n"), + abfd, sec); + else if (sec->size != 0) + { + bfd_byte *sec_contents, *l_sec_contents; + + if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents)) + (*_bfd_error_handler) + (_("%B: warning: could not read contents of section `%A'\n"), + abfd, sec); + else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec, + &l_sec_contents)) + (*_bfd_error_handler) + (_("%B: warning: could not read contents of section `%A'\n"), + l->sec->owner, l->sec); + else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0) + (*_bfd_error_handler) + (_("%B: warning: duplicate section `%A' has different contents\n"), + abfd, sec); + + if (sec_contents) + free (sec_contents); + if (l_sec_contents) + free (l_sec_contents); + } + break; } /* Set the output_section field so that lang_add_section @@ -9404,15 +9526,39 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec) section. We only record the discarded comdat group. Otherwise the undiscarded group will be discarded incorrectly later since itself has been recorded. */ - if (! already_linked (elf_next_in_group (sec), group)) + for (l = already_linked_list->entry; l != NULL; l = l->next) + if ((l->sec->flags & SEC_GROUP) == 0 + && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL + && bfd_elf_match_symbols_in_sections (l->sec, + elf_next_in_group (sec))) + { + elf_next_in_group (sec)->output_section = bfd_abs_section_ptr; + elf_next_in_group (sec)->kept_section = l->sec; + group->output_section = bfd_abs_section_ptr; + break; + } + if (l == NULL) return; } else /* There is no direct match. But for linkonce section, we should check if there is a match with comdat group member. We always record the linkonce section, discarded or not. */ - already_linked (sec, group); - + for (l = already_linked_list->entry; l != NULL; l = l->next) + if (l->sec->flags & SEC_GROUP) + { + asection *first = elf_next_in_group (l->sec); + + if (first != NULL + && elf_next_in_group (first) == first + && bfd_elf_match_symbols_in_sections (first, sec)) + { + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l->sec; + break; + } + } + /* This is the first section with this name. Record it. */ bfd_section_already_linked_table_insert (already_linked_list, sec); }