aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2010-01-06 05:30:24 +0000
committerIan Lance Taylor <ian@airs.com>2010-01-06 05:30:24 +0000
commit62dfdd4d1c7c79e81318115d1da67d4cb2b2e6d1 (patch)
tree7a61965b9e5e13b174ba0bc012cc432488828ba0 /gold/script.cc
parent cpu/ (diff)
downloadbinutils-gdb-62dfdd4d1c7c79e81318115d1da67d4cb2b2e6d1.tar.gz
binutils-gdb-62dfdd4d1c7c79e81318115d1da67d4cb2b2e6d1.tar.bz2
binutils-gdb-62dfdd4d1c7c79e81318115d1da67d4cb2b2e6d1.zip
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.
Diffstat (limited to 'gold/script.cc')
-rw-r--r--gold/script.cc90
1 files changed, 84 insertions, 6 deletions
diff --git a/gold/script.cc b/gold/script.cc
index 53919e6b016..42390405472 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()
{