diff options
-rw-r--r-- | gold/ChangeLog | 11 | ||||
-rw-r--r-- | gold/gold.cc | 9 | ||||
-rw-r--r-- | gold/options.h | 4 | ||||
-rw-r--r-- | gold/script.cc | 90 | ||||
-rw-r--r-- | gold/script.h | 10 |
5 files changed, 116 insertions, 8 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 87c7af4..e1c51e4 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,16 @@ 2010-01-05 Ian Lance Taylor <iant@google.com> + PR 10980 + * options.h (class General_options): Add --undefined-version. + * script.cc (struct Version_expression): Add was_matched_by_symbol + field. + (Version_script_info::matched_symbol): New function. + (Version_script_info::get_symbol_version_helper): Call + matched_symbol. + (Version_script_info::check_unmatched_names): New function. + * script.h (class Version_script_info): Update declarations. + * gold.cc (queue_middle_tasks): Handle --no-undefined-version. + * options.h (class General_options): Use DEFINE_bool_alias for allow_multiple_definition. * resolve.cc (Symbol_table::should_override): Don't test diff --git a/gold/gold.cc b/gold/gold.cc index 15a8946..8251981 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -1,6 +1,6 @@ // gold.cc -- main linker functions -// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor <iant@google.com>. // This file is part of gold. @@ -443,6 +443,13 @@ queue_middle_tasks(const General_options& options, // TODO: if this is too slow, do this as a task, rather than inline. symtab->detect_odr_violations(task, options.output_file_name()); + // Do the --no-undefined-version check. + if (!parameters->options().undefined_version()) + { + Script_options* so = layout->script_options(); + so->version_script_info()->check_unmatched_names(symtab); + } + // Create any automatic note sections. layout->create_notes(); diff --git a/gold/options.h b/gold/options.h index 85c81e4..817cac7 100644 --- a/gold/options.h +++ b/gold/options.h @@ -971,6 +971,10 @@ class General_options DEFINE_set(trace_symbol, options::TWO_DASHES, 'y', N_("Trace references to symbol"), N_("SYMBOL")); + DEFINE_bool(undefined_version, options::TWO_DASHES, '\0', true, + N_("Allow unused version in script (default)"), + N_("Do not allow unused version in script")); + DEFINE_string(Y, options::EXACTLY_ONE_DASH, 'Y', "", N_("Default search path for Solaris compatibility"), N_("PATH")); diff --git a/gold/script.cc b/gold/script.cc index 53919e6..4239040 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -1,6 +1,6 @@ // script.cc -- handle linker scripts for gold. -// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor <iant@google.com>. // This file is part of gold. @@ -1793,23 +1793,25 @@ Keyword_to_parsecode::keyword_to_parsecode(const char* keyword, // A single version expression. // For example, pattern="std::map*" and language="C++". -// PATTERN should be from the stringpool. -struct -Version_expression +struct Version_expression { Version_expression(const std::string& a_pattern, Version_script_info::Language a_language, bool a_exact_match) - : pattern(a_pattern), language(a_language), exact_match(a_exact_match) + : pattern(a_pattern), language(a_language), exact_match(a_exact_match), + was_matched_by_symbol(false) { } std::string pattern; Version_script_info::Language language; // If false, we use glob() to match pattern. If true, we use strcmp(). bool exact_match; + // True if --no-undefined-version is in effect and we found this + // version in get_symbol_version. We use mutable because this + // struct is generally not modifiable after it has been created. + mutable bool was_matched_by_symbol; }; - // A list of expressions. struct Version_expression_list { @@ -1965,6 +1967,27 @@ Version_script_info::build_expression_list_lookup( } } +// Record that we have matched a name found in the version script. + +void +Version_script_info::matched_symbol(const Version_tree* version_tree, + const char* name) const +{ + const struct Version_expression_list* global = version_tree->global; + for (size_t i = 0; i < global->expressions.size(); ++i) + { + const Version_expression& expression(global->expressions[i]); + if (expression.pattern == name + && (expression.exact_match + || strpbrk(expression.pattern.c_str(), "?*[") == NULL)) + { + expression.was_matched_by_symbol = true; + return; + } + } + gold_unreachable(); +} + // Look up SYMBOL_NAME in the list of versions. If CHECK_GLOBAL is // true look at the globally visible symbols, otherwise look at the // symbols listed as "local:". Return true if the symbol is found, @@ -2015,8 +2038,19 @@ Version_script_info::get_symbol_version_helper(const char* symbol_name, { if (pversion != NULL) *pversion = pe->second->tag; + + // If we are using --no-undefined-version, and this is a + // global symbol, we have to record that we have found this + // symbol, so that we don't warn about it. We have to do + // this now, because otherwise we have no way to get from a + // non-C language back to the demangled name that we + // matched. + if (check_global && !parameters->options().undefined_version()) + this->matched_symbol(pe->second, name_to_match); + if (allocated != NULL) free (allocated); + return true; } @@ -2043,6 +2077,50 @@ Version_script_info::get_symbol_version_helper(const char* symbol_name, return false; } +// Give an error if any exact symbol names (not wildcards) appear in a +// version script, but there is no such symbol. + +void +Version_script_info::check_unmatched_names(const Symbol_table* symtab) const +{ + for (size_t i = 0; i < this->version_trees_.size(); ++i) + { + const Version_tree* vt = this->version_trees_[i]; + if (vt->global == NULL) + continue; + for (size_t j = 0; j < vt->global->expressions.size(); ++j) + { + const Version_expression& expression(vt->global->expressions[j]); + + // Ignore cases where we used the version because we saw a + // symbol that we looked up. Note that + // WAS_MATCHED_BY_SYMBOL will be true even if the symbol was + // not a definition. That's OK as in that case we most + // likely gave an undefined symbol error anyhow. + if (expression.was_matched_by_symbol) + continue; + + // Just ignore names which are in languages other than C. + // We have no way to look them up in the symbol table. + if (expression.language != LANGUAGE_C) + continue; + + // Ignore wildcard patterns. + if (!expression.exact_match + && strpbrk(expression.pattern.c_str(), "?*[") != NULL) + continue; + + if (symtab->lookup(expression.pattern.c_str(), + vt->tag.c_str()) == NULL) + { + gold_error(_("version script assignment of %s to symbol %s " + "failed: symbol not defined"), + vt->tag.c_str(), expression.pattern.c_str()); + } + } + } +} + struct Version_dependency_list* Version_script_info::allocate_dependency_list() { diff --git a/gold/script.h b/gold/script.h index a7e0186..710afd0 100644 --- a/gold/script.h +++ b/gold/script.h @@ -1,6 +1,6 @@ // script.h -- handle linker scripts for gold -*- C++ -*- -// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. // Written by Ian Lance Taylor <iant@google.com>. // This file is part of gold. @@ -196,6 +196,11 @@ class Version_script_info void build_lookup_tables(); + // Give an error if there are any unmatched names in the version + // script. + void + check_unmatched_names(const Symbol_table*) const; + // Print contents to the FILE. This is for debugging. void print(FILE*) const; @@ -209,6 +214,9 @@ class Version_script_info bool check_global, std::string* pversion) const; + void + matched_symbol(const Version_tree*, const char*) const; + // Fast lookup information for a glob pattern. struct Glob { |