aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog16
-rw-r--r--gold/i386.cc1
-rw-r--r--gold/options.cc9
-rw-r--r--gold/options.h18
-rw-r--r--gold/symtab.cc67
-rw-r--r--gold/symtab.h4
-rw-r--r--gold/target.h11
-rw-r--r--gold/testsuite/testfile.cc1
-rw-r--r--gold/x86_64.cc1
9 files changed, 127 insertions, 1 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 5ca3cfc..73347b1 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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.
diff --git a/gold/i386.cc b/gold/i386.cc
index b7bf362..7cfe117 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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)
diff --git a/gold/options.cc b/gold/options.cc
index b6e4711..a80f32c 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -325,6 +325,13 @@ General_options::parse_version_script(const char*, const char* 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_()
{
}
diff --git a/gold/options.h b/gold/options.h
index b95a705..487603f 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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
diff --git a/gold/symtab.cc b/gold/symtab.cc
index a216b3b..91a2b1e 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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),
diff --git a/gold/symtab.h b/gold/symtab.h
index e262cd4..fb5828b 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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
diff --git a/gold/target.h b/gold/target.h
index a71cbc6..30fa008 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -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.
diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc
index d33078f..4551c44 100644
--- a/gold/testsuite/testfile.cc
+++ b/gold/testsuite/testfile.cc
@@ -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
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index f3844176..34f54c8 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -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)