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.
This commit is contained in:
parent
fe8afbc48f
commit
62dfdd4d1c
|
@ -1,5 +1,16 @@
|
||||||
2010-01-05 Ian Lance Taylor <iant@google.com>
|
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
|
* options.h (class General_options): Use DEFINE_bool_alias for
|
||||||
allow_multiple_definition.
|
allow_multiple_definition.
|
||||||
* resolve.cc (Symbol_table::should_override): Don't test
|
* resolve.cc (Symbol_table::should_override): Don't test
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// gold.cc -- main linker functions
|
// 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>.
|
// Written by Ian Lance Taylor <iant@google.com>.
|
||||||
|
|
||||||
// This file is part of gold.
|
// 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.
|
// TODO: if this is too slow, do this as a task, rather than inline.
|
||||||
symtab->detect_odr_violations(task, options.output_file_name());
|
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.
|
// Create any automatic note sections.
|
||||||
layout->create_notes();
|
layout->create_notes();
|
||||||
|
|
||||||
|
|
|
@ -971,6 +971,10 @@ class General_options
|
||||||
DEFINE_set(trace_symbol, options::TWO_DASHES, 'y',
|
DEFINE_set(trace_symbol, options::TWO_DASHES, 'y',
|
||||||
N_("Trace references to symbol"), N_("SYMBOL"));
|
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', "",
|
DEFINE_string(Y, options::EXACTLY_ONE_DASH, 'Y', "",
|
||||||
N_("Default search path for Solaris compatibility"),
|
N_("Default search path for Solaris compatibility"),
|
||||||
N_("PATH"));
|
N_("PATH"));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// script.cc -- handle linker scripts for gold.
|
// 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>.
|
// Written by Ian Lance Taylor <iant@google.com>.
|
||||||
|
|
||||||
// This file is part of gold.
|
// This file is part of gold.
|
||||||
|
@ -1793,23 +1793,25 @@ Keyword_to_parsecode::keyword_to_parsecode(const char* keyword,
|
||||||
|
|
||||||
// A single version expression.
|
// A single version expression.
|
||||||
// For example, pattern="std::map*" and language="C++".
|
// 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_expression(const std::string& a_pattern,
|
||||||
Version_script_info::Language a_language,
|
Version_script_info::Language a_language,
|
||||||
bool a_exact_match)
|
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;
|
std::string pattern;
|
||||||
Version_script_info::Language language;
|
Version_script_info::Language language;
|
||||||
// If false, we use glob() to match pattern. If true, we use strcmp().
|
// If false, we use glob() to match pattern. If true, we use strcmp().
|
||||||
bool exact_match;
|
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.
|
// A list of expressions.
|
||||||
struct Version_expression_list
|
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
|
// Look up SYMBOL_NAME in the list of versions. If CHECK_GLOBAL is
|
||||||
// true look at the globally visible symbols, otherwise look at the
|
// true look at the globally visible symbols, otherwise look at the
|
||||||
// symbols listed as "local:". Return true if the symbol is found,
|
// 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)
|
if (pversion != NULL)
|
||||||
*pversion = pe->second->tag;
|
*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)
|
if (allocated != NULL)
|
||||||
free (allocated);
|
free (allocated);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2043,6 +2077,50 @@ Version_script_info::get_symbol_version_helper(const char* symbol_name,
|
||||||
return false;
|
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*
|
struct Version_dependency_list*
|
||||||
Version_script_info::allocate_dependency_list()
|
Version_script_info::allocate_dependency_list()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// script.h -- handle linker scripts for gold -*- C++ -*-
|
// 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>.
|
// Written by Ian Lance Taylor <iant@google.com>.
|
||||||
|
|
||||||
// This file is part of gold.
|
// This file is part of gold.
|
||||||
|
@ -196,6 +196,11 @@ class Version_script_info
|
||||||
void
|
void
|
||||||
build_lookup_tables();
|
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.
|
// Print contents to the FILE. This is for debugging.
|
||||||
void
|
void
|
||||||
print(FILE*) const;
|
print(FILE*) const;
|
||||||
|
@ -209,6 +214,9 @@ class Version_script_info
|
||||||
bool check_global,
|
bool check_global,
|
||||||
std::string* pversion) const;
|
std::string* pversion) const;
|
||||||
|
|
||||||
|
void
|
||||||
|
matched_symbol(const Version_tree*, const char*) const;
|
||||||
|
|
||||||
// Fast lookup information for a glob pattern.
|
// Fast lookup information for a glob pattern.
|
||||||
struct Glob
|
struct Glob
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue