From 0864d55193d9ad757c26cba29da1de1c00be4ba8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 9 Apr 2008 00:48:13 +0000 Subject: [PATCH] * 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. --- gold/ChangeLog | 16 +++++++++ gold/i386.cc | 1 + gold/options.cc | 9 ++++- gold/options.h | 18 ++++++++++ gold/symtab.cc | 67 ++++++++++++++++++++++++++++++++++++++ gold/symtab.h | 4 +++ gold/target.h | 11 +++++++ gold/testsuite/testfile.cc | 1 + gold/x86_64.cc | 1 + 9 files changed, 127 insertions(+), 1 deletion(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 5ca3cfc5be6..73347b19d31 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,21 @@ 2008-04-08 Ian Lance Taylor + * 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 b7bf36203a4..7cfe117854b 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 b6e4711881c..a80f32cb960 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -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_() { } diff --git a/gold/options.h b/gold/options.h index b95a70524a2..487603fa87f 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 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 a216b3bcbdb..91a2b1ea692 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& sym, const elfcpp::Sym& 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 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 e262cd4cc59..fb5828b2e07 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 a71cbc66289..30fa0086ca6 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 d33078f5f80..4551c44dd8e 100644 --- a/gold/testsuite/testfile.cc +++ b/gold/testsuite/testfile.cc @@ -88,6 +88,7 @@ const Target::Target_info Target_test::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 f384417694b..34f54c8e761 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) -- 2.30.2