PR 10980
authorIan Lance Taylor <ian@airs.com>
Wed, 6 Jan 2010 05:30:24 +0000 (05:30 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 6 Jan 2010 05:30:24 +0000 (05:30 +0000)
* 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.

gold/ChangeLog
gold/gold.cc
gold/options.h
gold/script.cc
gold/script.h

index 87c7af4115466a85075ea3aac1c968291296e4b0..e1c51e4c74d9e65c95618e409dcb6ff5ce3f5a92 100644 (file)
@@ -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
index 15a8946642e0d8870efeb998677a1aa35378efbf..825198120ce59518468883a66b82f973706af19b 100644 (file)
@@ -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();
 
index 85c81e4c23db4199e99ec04f11e47da66cd38792..817cac7e65f007cce806c27ed11f0c5b2fc0c667 100644 (file)
@@ -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"));
index 53919e6b01652439ace6b488a16f886a2971a646..423904054726b4a352a42cae97df19ad372be3c6 100644 (file)
@@ -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()
 {
index a7e0186bde4497afc7b61dd310f0ad56781cc827..710afd0eea51adddd0c7d6f2c133ead08e784081 100644 (file)
@@ -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
   {