bfd/ 2002-08-05 H.J. Lu * elflink.h (NAME(bfd_elf,size_dynamic_sections)): Check symbol with undefined version. (elf_link_assign_sym_version): Match a default symbol with a version without definition. Set the `defined' field to true. include/ 2002-08-05 H.J. Lu * bfdlink.h (bfd_elf_version_expr): Add "defined". ld/ 2002-08-05 H.J. Lu * ldlang.c (lang_new_vers_pattern): Set the `defined' field to false. --- binutils/bfd/elflink.h.defver Fri Jul 26 23:41:26 2002 +++ binutils/bfd/elflink.h Mon Aug 5 20:58:22 2002 @@ -2938,6 +2938,8 @@ NAME(bfd_elf,size_dynamic_sections) (out struct elf_info_failed eif; struct elf_link_hash_entry *h; asection *dynstr; + struct bfd_elf_version_tree *t; + struct bfd_elf_version_expr *d; *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (*sinterpptr != NULL || info->shared); @@ -3030,6 +3032,26 @@ NAME(bfd_elf,size_dynamic_sections) (out if (asvinfo.failed) return false; + /* Check if all global versions have a definiton. */ + for (t = asvinfo.verdefs; t != NULL; t = t->next) + { + if (t->globals != NULL) + { + for (d = t->globals; d != NULL; d = d->next) + { + if (!d->defined && strchr (d->pattern, '*') == NULL) + { + (*_bfd_error_handler) + (_("%s: undefined version: %s"), + d->pattern, t->name); + bfd_set_error (bfd_error_bad_value); + asvinfo.failed = true; + return false; + } + } + } + } + /* Find all symbols which were defined in a dynamic object and make the backend pick a reasonable value for them. */ elf_link_hash_traverse (elf_hash_table (info), @@ -4274,6 +4296,10 @@ elf_link_assign_sym_version (h, data) struct bfd_elf_version_tree *t; struct bfd_elf_version_tree *local_ver; struct bfd_elf_version_expr *d; + const char *verstr, *name; + size_t namelen, verlen, newlen; + char *newname; + struct elf_link_hash_entry *newh; /* See if can find what version this symbol is in. If the symbol is supposed to be local, then don't actually register @@ -4287,9 +4313,41 @@ elf_link_assign_sym_version (h, data) { if ((*d->match) (d, h->root.root.string)) { - h->verinfo.vertree = t; - local_ver = NULL; - break; + name = h->root.root.string; + namelen = strlen (name); + verstr = t->name; + verlen = strlen (verstr); + newlen = namelen + verlen + 2; + + newname = (char *) bfd_malloc + ((bfd_size_type) newlen); + if (newname == NULL) + goto error_return; + memcpy (newname, name, namelen); + + /* Check the hidden versioned definition. */ + p = newname + namelen; + *p++ = ELF_VER_CHR; + memcpy (p, verstr, verlen + 1); + newh = elf_link_hash_lookup + (elf_hash_table (info), newname, false, + false, false); + free (newname); + + d->defined = true; + + if (!newh + || ((newh->root.type + != bfd_link_hash_defined) + && (newh->root.type + != bfd_link_hash_defweak))) + { + /* There is a version without definition. + Make it as the default definition. */ + h->verinfo.vertree = t; + local_ver = NULL; + break; + } } } @@ -4332,11 +4390,6 @@ elf_link_assign_sym_version (h, data) hide the default one. */ if (h->dynindx != -1 && h->verinfo.vertree != NULL) { - const char *verstr, *name; - size_t namelen, verlen, newlen; - char *newname; - struct elf_link_hash_entry *newh; - name = h->root.root.string; namelen = strlen (name); verstr = h->verinfo.vertree->name; --- binutils/include/bfdlink.h.defver Wed Jul 31 08:54:09 2002 +++ binutils/include/bfdlink.h Mon Aug 5 19:50:41 2002 @@ -602,6 +602,7 @@ struct bfd_elf_version_expr const char *pattern; /* Matching function. */ int (*match) PARAMS((struct bfd_elf_version_expr *, const char *)); + boolean defined; }; /* Version dependencies. */ --- binutils/ld/ldlang.c.defver Tue Jul 30 14:38:18 2002 +++ binutils/ld/ldlang.c Mon Aug 5 19:52:35 2002 @@ -5132,6 +5132,7 @@ lang_new_vers_pattern (orig, new, lang) ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret); ret->next = orig; ret->pattern = new; + ret->defined = false; if (lang == NULL || strcasecmp (lang, "C") == 0) ret->match = lang_vers_match_lang_c;