From 3194163592008a9e575d577921647ab91b09c77b Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 8 Aug 2002 03:50:18 +0000 Subject: [PATCH] Check symbols with undefine version. --- bfd/ChangeLog | 8 ++ bfd/elflink.h | 133 ++++++++++++++++++++--------- include/ChangeLog | 5 ++ include/bfdlink.h | 7 ++ ld/ChangeLog | 14 +++ ld/ld.texinfo | 6 ++ ld/ldlang.c | 2 + ld/ldmain.c | 1 + ld/lexsup.c | 8 +- ld/testsuite/ChangeLog | 8 ++ ld/testsuite/ld-elfvers/vers.exp | 4 +- ld/testsuite/ld-elfvers/vers1.map | 3 - ld/testsuite/ld-elfvers/vers18.map | 3 - ld/testsuite/ld-elfvers/vers8.map | 3 - 14 files changed, 152 insertions(+), 53 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 41dc63ea619..40a824e683e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2002-08-07 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. + 2002-08-08 Alan Modra * elflink.h (elf_link_output_extsym): Don't output symbols from diff --git a/bfd/elflink.h b/bfd/elflink.h index 59cc397a209..b1732e43c2f 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -2938,6 +2938,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, 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,54 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, return false; } + /* Make all global versions with definiton. */ + for (t = verdefs; t != NULL; t = t->next) + 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 == NULL + || (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 != NULL + && (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 +3081,28 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, 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) + 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 +4331,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 +4355,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 +4415,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; diff --git a/include/ChangeLog b/include/ChangeLog index ea51a95c307..39f18740bd0 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2002-08-07 H.J. Lu + + * bfdlink.h (bfd_link_info): Add allow_undefined_version. + (bfd_elf_version_expr): Add symver and script. + 2002-07-31 Ian Dall * bfdlink.h (bfd_link_common_skip_ar_symbols): New enum. diff --git a/include/bfdlink.h b/include/bfdlink.h index c36564f6948..4998fe3dbf7 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -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. */ diff --git a/ld/ChangeLog b/ld/ChangeLog index a587652de5b..1afde2ac3ce 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,17 @@ +2002-08-07 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. + 2002-08-07 Nick Clifton * emultempl/armelf.em (arm_elf_before_allocation): Only search for diff --git a/ld/ld.texinfo b/ld/ld.texinfo index dadc75b726d..12030c06f17 100644 --- a/ld/ld.texinfo +++ b/ld/ld.texinfo @@ -1102,6 +1102,12 @@ select which function is most appropriate for the current architecture. 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 diff --git a/ld/ldlang.c b/ld/ldlang.c index c2608291002..a777e5a4358 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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; diff --git a/ld/ldmain.c b/ld/ldmain.c index b50ef431599..84baa4ddf0a 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -240,6 +240,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; diff --git a/ld/lexsup.c b/ld/lexsup.c index ddaf692935f..4acb4fd6a94 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -127,7 +127,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) @@ -322,6 +323,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}, @@ -767,6 +770,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; diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index b492850d3f0..0c2e3b90899 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2002-08-07 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. + 2002-07-30 John David Anglin * ld-discard/discard.exp, ld-scripts/phdrs.exp, ld-scripts/phdrs2.exp, diff --git a/ld/testsuite/ld-elfvers/vers.exp b/ld/testsuite/ld-elfvers/vers.exp index 1acc0e6559f..738072926ce 100644 --- a/ld/testsuite/ld-elfvers/vers.exp +++ b/ld/testsuite/ld-elfvers/vers.exp @@ -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 flags solibname verexp versymexp symexp } 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" diff --git a/ld/testsuite/ld-elfvers/vers1.map b/ld/testsuite/ld-elfvers/vers1.map index 8fc37bcaf0f..767915cd7f8 100644 --- a/ld/testsuite/ld-elfvers/vers1.map +++ b/ld/testsuite/ld-elfvers/vers1.map @@ -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 { diff --git a/ld/testsuite/ld-elfvers/vers18.map b/ld/testsuite/ld-elfvers/vers18.map index eac2b0e3dcb..8dcff39b6f0 100644 --- a/ld/testsuite/ld-elfvers/vers18.map +++ b/ld/testsuite/ld-elfvers/vers18.map @@ -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 { diff --git a/ld/testsuite/ld-elfvers/vers8.map b/ld/testsuite/ld-elfvers/vers8.map index 26359559d9f..c24fb107afe 100644 --- a/ld/testsuite/ld-elfvers/vers8.map +++ b/ld/testsuite/ld-elfvers/vers8.map @@ -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 { -- 2.30.2