bfd/ 2002-08-06 H.J. Lu * elflink.h (NAME(bfd_elf,size_dynamic_sections)): Check symbol with undefined version if needed. (elf_link_assign_sym_version): Match a default symbol with a version without definition. No need to hide the default definition separately. include/ 2002-08-06 H.J. Lu * bfdlink.h (bfd_link_info): Add allow_undefined_version. (bfd_elf_version_expr): Add symver and script. ld/ 2002-08-06 H.J. Lu * ld.texinfo: Document --no-undefined-version. * ldlang.c (lang_new_vers_pattern): Set the `symver' and `script.' fields to 0. * ldmain.c (main): Initialize the allow_undefined_version to true. * lexsup.c (OPTION_NO_UNDEFINED_VERSION): New. (ld_options): Add --no-undefined-version. (parse_args): Support OPTION_NO_UNDEFINED_VERSION. ld/testsuite 2002-08-06 H.J. Lu * ld-elfvers/vers.exp: Add --no-undefined-version. * ld-elfvers/vers1.map: Remove the unused foo1 and foo2. * ld-elfvers/vers8.map: Likewise. * ld-elfvers/vers18.map: Likewise. --- binutils/bfd/elflink.h.defver Fri Jul 26 23:41:26 2002 +++ binutils/bfd/elflink.h Wed Aug 7 13:20:15 2002 @@ -2938,6 +2938,9 @@ 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; + boolean all_defined; *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (*sinterpptr != NULL || info->shared); @@ -3018,6 +3021,55 @@ NAME(bfd_elf,size_dynamic_sections) (out return false; } + /* Make all global versions with definiton. */ + for (t = verdefs; t != NULL; t = t->next) + if (t->globals != NULL) + for (d = t->globals; d != NULL; d = d->next) + if (!d->symver && strchr (d->pattern, '*') == NULL) + { + const char *verstr, *name; + size_t namelen, verlen, newlen; + char *newname, *p; + struct elf_link_hash_entry *newh; + + name = d->pattern; + namelen = strlen (name); + verstr = t->name; + verlen = strlen (verstr); + newlen = namelen + verlen + 3; + + newname = (char *) bfd_malloc ((bfd_size_type) newlen); + if (newname == NULL) + return false; + 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); + if (!newh + || (newh->root.type != bfd_link_hash_defined + && newh->root.type != bfd_link_hash_defweak)) + { + /* Check the default versioned definition. */ + *p++ = ELF_VER_CHR; + memcpy (p, verstr, verlen + 1); + newh = elf_link_hash_lookup (elf_hash_table (info), + newname, false, false, + false); + } + free (newname); + + /* Mark this version if there is a definition. */ + if (newh + && (newh->root.type == bfd_link_hash_defined + || newh->root.type == bfd_link_hash_defweak)) + d->symver = 1; + } + /* Attach all the symbols to their version information. */ asvinfo.output_bfd = output_bfd; asvinfo.info = info; @@ -3030,6 +3082,31 @@ NAME(bfd_elf,size_dynamic_sections) (out if (asvinfo.failed) return false; + if (!info->allow_undefined_version) + { + /* Check if all global versions have a definiton. */ + all_defined = true; + for (t = verdefs; t != NULL; t = t->next) + if (t->globals != NULL) + for (d = t->globals; d != NULL; d = d->next) + { + if (!d->symver && !d->script + && strchr (d->pattern, '*') == NULL) + { + (*_bfd_error_handler) + (_("%s: undefined version: %s"), + d->pattern, t->name); + all_defined = false; + } + } + + if (!all_defined) + { + bfd_set_error (bfd_error_bad_value); + 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), @@ -4258,7 +4335,6 @@ elf_link_assign_sym_version (h, data) (_("%s: undefined versioned symbol name %s"), bfd_get_filename (sinfo->output_bfd), h->root.root.string); bfd_set_error (bfd_error_bad_value); - error_return: sinfo->failed = true; return false; } @@ -4283,18 +4359,34 @@ elf_link_assign_sym_version (h, data) { if (t->globals != NULL) { + boolean matched; + + matched = false; for (d = t->globals; d != NULL; d = d->next) { if ((*d->match) (d, h->root.root.string)) { - h->verinfo.vertree = t; - local_ver = NULL; - break; + if (d->symver) + matched = true; + else + { + /* There is a version without definition. Make + the symbol the default definition for this + version. */ + h->verinfo.vertree = t; + local_ver = NULL; + d->script = 1; + break; + } } } if (d != NULL) break; + else if (matched) + /* There is no undefined version for this symbol. Hide the + default one. */ + (*bed->elf_backend_hide_symbol) (info, h, true); } if (t->locals != NULL) @@ -4327,43 +4419,6 @@ elf_link_assign_sym_version (h, data) (*bed->elf_backend_hide_symbol) (info, h, true); } } - - /* We need to check if a hidden versioned definition should - 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; - 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); - - if (newh - && (newh->root.type == bfd_link_hash_defined - || newh->root.type == bfd_link_hash_defweak)) - /* We found a hidden versioned definition. Hide the - default one. */ - (*bed->elf_backend_hide_symbol) (info, h, true); - - free (newname); - } } return true; --- binutils/include/bfdlink.h.defver Wed Jul 31 08:54:09 2002 +++ binutils/include/bfdlink.h Wed Aug 7 13:13:42 2002 @@ -262,6 +262,9 @@ struct bfd_link_info /* true if ok to have multiple definition. */ boolean allow_multiple_definition; + /* true if ok to have version with no definition. */ + boolean allow_undefined_version; + /* Which symbols to strip. */ enum bfd_link_strip strip; @@ -602,6 +605,10 @@ struct bfd_elf_version_expr const char *pattern; /* Matching function. */ int (*match) PARAMS((struct bfd_elf_version_expr *, const char *)); + /* Defined by ".symver". */ + unsigned int symver: 1; + /* Defined by version script. */ + unsigned int script : 1; }; /* Version dependencies. */ --- binutils/ld/ld.texinfo.defver Mon Jul 15 19:21:32 2002 +++ binutils/ld/ld.texinfo Wed Aug 7 13:27:27 2002 @@ -1102,6 +1102,12 @@ select which function is most appropriat I.E. dynamically select an appropriate memset function. Apparently it is also normal for HPPA shared libraries to have undefined symbols. +@kindex --no-undefined-version +@item --no-undefined-version +Normally when a symbol has an undefined version, the linker will ignore +it. This option disallows symbols with undefined version and a fatal error +will be issued instead. + @kindex --no-warn-mismatch @item --no-warn-mismatch Normally @command{ld} will give an error if you try to link together input --- binutils/ld/ldlang.c.defver Tue Jul 30 14:38:18 2002 +++ binutils/ld/ldlang.c Tue Aug 6 08:09:44 2002 @@ -5132,6 +5132,8 @@ lang_new_vers_pattern (orig, new, lang) ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret); ret->next = orig; ret->pattern = new; + ret->symver = 0; + ret->script = 0; if (lang == NULL || strcasecmp (lang, "C") == 0) ret->match = lang_vers_match_lang_c; --- binutils/ld/ldmain.c.defver Wed Jul 31 08:54:17 2002 +++ binutils/ld/ldmain.c Wed Aug 7 13:06:49 2002 @@ -241,6 +241,7 @@ main (argc, argv) link_info.no_undefined = false; link_info.allow_shlib_undefined = false; link_info.allow_multiple_definition = false; + link_info.allow_undefined_version = true; link_info.strip = strip_none; link_info.discard = discard_sec_merge; link_info.keep_memory = true; --- binutils/ld/lexsup.c.defver Tue May 21 22:43:13 2002 +++ binutils/ld/lexsup.c Wed Aug 7 13:23:03 2002 @@ -128,7 +128,8 @@ int parsing_defsym = 0; #define OPTION_TARGET_HELP (OPTION_UNIQUE + 1) #define OPTION_ALLOW_SHLIB_UNDEFINED (OPTION_TARGET_HELP + 1) #define OPTION_ALLOW_MULTIPLE_DEFINITION (OPTION_ALLOW_SHLIB_UNDEFINED + 1) -#define OPTION_DISCARD_NONE (OPTION_ALLOW_MULTIPLE_DEFINITION + 1) +#define OPTION_NO_UNDEFINED_VERSION (OPTION_ALLOW_MULTIPLE_DEFINITION + 1) +#define OPTION_DISCARD_NONE (OPTION_NO_UNDEFINED_VERSION + 1) #define OPTION_SPARE_DYNAMIC_TAGS (OPTION_DISCARD_NONE + 1) #define OPTION_NO_DEFINE_COMMON (OPTION_SPARE_DYNAMIC_TAGS + 1) #define OPTION_NOSTDLIB (OPTION_NO_DEFINE_COMMON + 1) @@ -328,6 +329,8 @@ static const struct ld_option ld_options '\0', NULL, N_("Allow undefined symbols in shared objects"), TWO_DASHES }, { {"allow-multiple-definition", no_argument, NULL, OPTION_ALLOW_MULTIPLE_DEFINITION}, '\0', NULL, N_("Allow multiple definitions"), TWO_DASHES }, + { {"no-undefined-version", no_argument, NULL, OPTION_NO_UNDEFINED_VERSION}, + '\0', NULL, N_("Disallow undefined version"), TWO_DASHES }, { {"no-warn-mismatch", no_argument, NULL, OPTION_NO_WARN_MISMATCH}, '\0', NULL, N_("Don't warn about mismatched input files"), TWO_DASHES}, { {"no-whole-archive", no_argument, NULL, OPTION_NO_WHOLE_ARCHIVE}, @@ -769,6 +772,9 @@ parse_args (argc, argv) case OPTION_ALLOW_MULTIPLE_DEFINITION: link_info.allow_multiple_definition = true; break; + case OPTION_NO_UNDEFINED_VERSION: + link_info.allow_undefined_version = false; + break; case OPTION_NO_WARN_MISMATCH: command_line.warn_mismatch = false; break; --- binutils/ld/testsuite/ld-elfvers/vers.exp.defver Tue Jul 30 14:38:25 2002 +++ binutils/ld/testsuite/ld-elfvers/vers.exp Wed Aug 7 13:31:26 2002 @@ -62,7 +62,7 @@ set tmpdir tmpdir set VOBJDUMP_FLAGS --private-headers set DOBJDUMP_FLAGS --dynamic-syms set SOBJDUMP_FLAGS --syms -set shared --shared +set shared "--shared --no-undefined-version" set script --version-script proc test_ar { test lib object expect } { @@ -643,7 +643,7 @@ proc build_exec { test source execname f global CC global CFLAGS - set shared --shared + set shared "--shared --no-undefined-version" set script --version-script if ![ld_compile "$CC -S $CFLAGS" $srcdir/$subdir/$source $tmpdir/$execname.s] { unresolved "$test" --- binutils/ld/testsuite/ld-elfvers/vers1.map.defver Thu Jun 3 11:02:11 1999 +++ binutils/ld/testsuite/ld-elfvers/vers1.map Tue Aug 6 08:50:55 2002 @@ -1,6 +1,4 @@ VERS_1.1 { - global: - foo1; local: hide_old*; hide_original*; @@ -8,7 +6,6 @@ VERS_1.1 { }; VERS_1.2 { - foo2; } VERS_1.1; VERS_2.0 { --- binutils/ld/testsuite/ld-elfvers/vers18.map.defver Tue Aug 6 09:06:44 2002 +++ binutils/ld/testsuite/ld-elfvers/vers18.map Tue Aug 6 09:04:19 2002 @@ -1,6 +1,4 @@ VERS_1.1 { - global: - foo1; local: hide_old*; hide_original*; @@ -8,7 +6,6 @@ VERS_1.1 { }; VERS_1.2 { - foo2; } VERS_1.1; VERS_2.0 { --- binutils/ld/testsuite/ld-elfvers/vers8.map.defver Thu Jun 3 11:02:11 1999 +++ binutils/ld/testsuite/ld-elfvers/vers8.map Tue Aug 6 09:03:59 2002 @@ -1,7 +1,5 @@ VERSION { VERS_1.1 { - global: - foo1; local: hide_old*; hide_original*; @@ -9,7 +7,6 @@ VERSION { }; VERS_1.2 { - foo2; } VERS_1.1; VERS_2.0 {