* options.h (class General_options): Define --wrap as a special
authorIan Lance Taylor <ian@airs.com>
Wed, 9 Apr 2008 00:48:13 +0000 (00:48 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 9 Apr 2008 00:48:13 +0000 (00:48 +0000)
option.  Add wrap_symbols_ field.
(General_options::any_wrap_symbols): New function.
(General_options::is_wrap_symbol): New function.
* options.cc (General_options::parse_wrap): New function.
(General_options::General_options): Initialize wrap_symbols_.
* symtab.cc (Symbol_table::wrap_symbol): New function.
(Symbol_table::add_from_object): Handle --wrap.
* symtab.h (class Symbol_table): Declare wrap_symbol.
* target.h (Target::wrap_char): New function.
(Target::Target_info): Add wrap_char field.
* i386.cc (Target_i386::i386_info): Initialize wrap_char.
* x86_64.cc (Target_x86_64::x86_64_info): Likewise.
* testsuite/testfile.cc (Target_test::test_target_info):
Likewise.

gold/ChangeLog
gold/i386.cc
gold/options.cc
gold/options.h
gold/symtab.cc
gold/symtab.h
gold/target.h
gold/testsuite/testfile.cc
gold/x86_64.cc

index 5ca3cfc5be6007c9786830fcf741f11040705a66..73347b19d311e93f0ecb7d74b55517be7f631f72 100644 (file)
@@ -1,5 +1,21 @@
 2008-04-08  Ian Lance Taylor  <iant@google.com>
 
+       * options.h (class General_options): Define --wrap as a special
+       option.  Add wrap_symbols_ field.
+       (General_options::any_wrap_symbols): New function.
+       (General_options::is_wrap_symbol): New function.
+       * options.cc (General_options::parse_wrap): New function.
+       (General_options::General_options): Initialize wrap_symbols_.
+       * symtab.cc (Symbol_table::wrap_symbol): New function.
+       (Symbol_table::add_from_object): Handle --wrap.
+       * symtab.h (class Symbol_table): Declare wrap_symbol.
+       * target.h (Target::wrap_char): New function.
+       (Target::Target_info): Add wrap_char field.
+       * i386.cc (Target_i386::i386_info): Initialize wrap_char.
+       * x86_64.cc (Target_x86_64::x86_64_info): Likewise.
+       * testsuite/testfile.cc (Target_test::test_target_info):
+       Likewise.
+
        * errors.cc (Errors::undefined_symbol): Mention symbol version if
        there is one.
 
index b7bf36203a4c39c020aa2b4c83af8a63d54f9c3a..7cfe117854b126e2de3db40346e1de0192ea1ed1 100644 (file)
@@ -373,6 +373,7 @@ const Target::Target_info Target_i386::i386_info =
   false,               // has_resolve
   true,                        // has_code_fill
   true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
   "/usr/lib/libc.so.1",        // dynamic_linker
   0x08048000,          // default_text_segment_address
   0x1000,              // abi_pagesize (overridable by -z max-page-size)
index b6e4711881c417687bf92ea1c5ab3bb06b0e3dc1..a80f32cb960046ceec9789705fc7704eb8aa8d1f 100644 (file)
@@ -324,6 +324,13 @@ General_options::parse_version_script(const char*, const char* arg,
     gold::gold_fatal(_("unable to parse version script file %s"), arg);
 }
 
+void
+General_options::parse_wrap(const char*, const char* arg,
+                           Command_line*)
+{
+  this->wrap_symbols_.insert(std::string(arg));
+}
+
 void
 General_options::parse_start_group(const char*, const char*,
                                    Command_line* cmdline)
@@ -581,7 +588,7 @@ namespace gold
 
 General_options::General_options()
   : execstack_status_(General_options::EXECSTACK_FROM_INPUT), static_(false),
-    do_demangle_(false)
+    do_demangle_(false), wrap_symbols_()
 {
 }
 
index b95a70524a2fbed96f1b5caf83aa21a73e7ec5c7..487603fa87fe167085611246d72127b6e0efef7b 100644 (file)
@@ -620,6 +620,9 @@ class General_options
               N_("Include all archive contents"),
               N_("Include only needed archive contents"));
 
+  DEFINE_special(wrap, options::TWO_DASHES, '\0',
+                N_("Use wrapper functions for SYMBOL"), N_("SYMBOL"));
+
   DEFINE_special(start_group, options::TWO_DASHES, '(',
                  N_("Start a library search group"), NULL);
   DEFINE_special(end_group, options::TWO_DASHES, ')',
@@ -702,6 +705,19 @@ class General_options
   do_demangle() const
   { return this->do_demangle_; }
 
+  // Whether there are any symbols to wrap.
+  bool
+  any_wrap_symbols() const
+  { return !this->wrap_symbols_.empty(); }
+
+  // Whether to wrap SYMBOL.
+  bool
+  is_wrap_symbol(const char* symbol) const
+  {
+    return (this->wrap_symbols_.find(std::string(symbol))
+           != this->wrap_symbols_.end());
+  }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -745,6 +761,8 @@ class General_options
   bool static_;
   // Whether to do demangling.
   bool do_demangle_;
+  // List of symbols used with --wrap.
+  Unordered_set<std::string> wrap_symbols_;
 };
 
 // The position-dependent options.  We use this to store the state of
index a216b3bcbdbd1bcb1c564add4e0542de0b113e22..91a2b1ea692fb1667c12595a85bce88f167a6a21 100644 (file)
@@ -478,6 +478,54 @@ Symbol_table::force_local(Symbol* sym)
   this->forced_locals_.push_back(sym);
 }
 
+// Adjust NAME for wrapping, and update *NAME_KEY if necessary.  This
+// is only called for undefined symbols, when at least one --wrap
+// option was used.
+
+const char*
+Symbol_table::wrap_symbol(Object* object, const char* name,
+                         Stringpool::Key* name_key)
+{
+  // For some targets, we need to ignore a specific character when
+  // wrapping, and add it back later.
+  char prefix = '\0';
+  if (name[0] == object->target()->wrap_char())
+    {
+      prefix = name[0];
+      ++name;
+    }
+
+  if (parameters->options().is_wrap_symbol(name))
+    {
+      // Turn NAME into __wrap_NAME.
+      std::string s;
+      if (prefix != '\0')
+       s += prefix;
+      s += "__wrap_";
+      s += name;
+
+      // This will give us both the old and new name in NAMEPOOL_, but
+      // that is OK.  Only the versions we need will wind up in the
+      // real string table in the output file.
+      return this->namepool_.add(s.c_str(), true, name_key);
+    }
+
+  const char* const real_prefix = "__real_";
+  const size_t real_prefix_length = strlen(real_prefix);
+  if (strncmp(name, real_prefix, real_prefix_length) == 0
+      && parameters->options().is_wrap_symbol(name + real_prefix_length))
+    {
+      // Turn __real_NAME into NAME.
+      std::string s;
+      if (prefix != '\0')
+       s += prefix;
+      s += name + real_prefix_length;
+      return this->namepool_.add(s.c_str(), true, name_key);
+    }
+
+  return name;
+}
+
 // Add one symbol from OBJECT to the symbol table.  NAME is symbol
 // name and VERSION is the version; both are canonicalized.  DEF is
 // whether this is the default version.
@@ -517,6 +565,25 @@ Symbol_table::add_from_object(Object* object,
                              const elfcpp::Sym<size, big_endian>& sym,
                              const elfcpp::Sym<size, big_endian>& orig_sym)
 {
+  // For an undefined symbol, we may need to adjust the name using
+  // --wrap.
+  if (orig_sym.get_st_shndx() == elfcpp::SHN_UNDEF
+      && parameters->options().any_wrap_symbols())
+    {
+      const char* wrap_name = this->wrap_symbol(object, name, &name_key);
+      if (wrap_name != name)
+       {
+         // If we see a reference to malloc with version GLIBC_2.0,
+         // and we turn it into a reference to __wrap_malloc, then we
+         // discard the version number.  Otherwise the user would be
+         // required to specify the correct version for
+         // __wrap_malloc.
+         version = NULL;
+         version_key = 0;
+         name = wrap_name;
+       }
+    }
+
   Symbol* const snull = NULL;
   std::pair<typename Symbol_table_type::iterator, bool> ins =
     this->table_.insert(std::make_pair(std::make_pair(name_key, version_key),
index e262cd4cc5972f743f45b26eafde51430401371f..fb5828b2e0700da13c90504b2fd20ba8112645fb 100644 (file)
@@ -1213,6 +1213,10 @@ class Symbol_table
   void
   force_local(Symbol*);
 
+  // Adjust NAME and *NAME_KEY for wrapping.
+  const char*
+  wrap_symbol(Object* object, const char*, Stringpool::Key* name_key);
+
   // Whether we should override a symbol, based on flags in
   // resolve.cc.
   static bool
index a71cbc66289034de622586ce1983be02e1ce7539..30fa0086ca638eca16a2684f35af2deab81692c1 100644 (file)
@@ -132,6 +132,15 @@ class Target
   is_default_stack_executable() const
   { return this->pti_->is_default_stack_executable; }
 
+  // Return a character which may appear as a prefix for a wrap
+  // symbol.  If this character appears, we strip it when checking for
+  // wrapping and add it back when forming the final symbol name.
+  // This should be '\0' if not special prefix is required, which is
+  // the normal case.
+  char
+  wrap_char() const
+  { return this->pti_->wrap_char; }
+
   // This is called to tell the target to complete any sections it is
   // handling.  After this all sections must have their final size.
   void
@@ -179,6 +188,8 @@ class Target
     // Whether an object file with no .note.GNU-stack sections implies
     // that the stack should be executable.
     bool is_default_stack_executable;
+    // Prefix character to strip when checking for wrapping.
+    char wrap_char;
     // The default dynamic linker name.
     const char* dynamic_linker;
     // The default text segment address.
index d33078f5f801ab9190531bb9b12b29da300d1f05..4551c44dd8e17a152239c5931bb8b4ca30414e9c 100644 (file)
@@ -88,6 +88,7 @@ const Target::Target_info Target_test<size, big_endian>::test_target_info =
   false,                               // has_resolve
   false,                               // has_code_fill
   false,                               // is_default_stack_executable
+  '\0',                                        // wrap_char
   "/dummy",                            // dynamic_linker
   0x08000000,                          // default_text_segment_address
   0x1000,                              // abi_pagesize
index f384417694bdf4dff8cebd5afe3415f72f6c57d7..34f54c8e761533d2c81aff8c09ebf5f7e50e9f73 100644 (file)
@@ -369,6 +369,7 @@ const Target::Target_info Target_x86_64::x86_64_info =
   false,               // has_resolve
   true,                        // has_code_fill
   true,                        // is_default_stack_executable
+  '\0',                        // wrap_char
   "/lib/ld64.so.1",     // program interpreter
   0x400000,            // default_text_segment_address
   0x1000,              // abi_pagesize (overridable by -z max-page-size)